How to interpret a RGB array in R - image

I'm having troubles with interpreting the RGB values I get from an image read in R.
The array I get show values from 0-1, when the RGB colour range is from 0-255. I tried to convert it back to the 0-255 range adjusting a script like this,
picturemax <- max(picture)
picturemin <- min(picture)
p.picture <- as.numeric(picture)
if (picturemax > 255 || picturemin < 0)
p.picture <- (picture - picturemin)/(picturemax - picturemin)
p.picture
retrieved from https://stat.ethz.ch/pipermail/r-help/2003-January/029098.html
I just change the values in the script from 0-1 to 0-255, but the array still show 0-1 values, just different ones.
My picture-files are also very large, and the array does not fit in the R Console. As I would like to get the RGB data in to an excel sheet or as a text file, I don't know what to do or how to attack that problem.
I apologize if my questions are too basic, but I'm happy for all the help I can get.
Any suggestions?
Cheers,
Maria

If you want to transform values from (0,1) to (0,255), why don't you just multiply them by 255 ?
To export your matrices as text files to be read by a spreadsheet or another application, you should look at the write.table function. But if your data are too large to fit in the console, I doubt opening them in Excel or an equivalent would be very helpful.

Related

A proper way to convert 2D Array into RGB or GrayScale image for precision difference

I have a 2D CNN model where I perform a classification task. My images are all coming from a sensor data after conversion.
So, normally, my way is to convert them into images using the following approach
newsize = (9, 1000)
pic = acc_normalized[0]
img = Image.fromarray(np.uint8(pic*255), 'L')
img = img.resize(newsize)
image_path = "Images_Accel"
image_name = "D1." + str(2)
img.save(f"{image_path}/{image_name}.jpeg")
This is what I obtain:
However, their precision is sort of important. For instance, some of the numerical values are like:
117.79348187327987 or 117.76568758022673.
As you see in the above line, their difference is the digits, when I use uint8, it only takes 117 to when converting it into image pixels and it looks the same, right? But, I'd like to make them different. In some cases, the difference is even at the 8th or 10th digit.
So, when I try to use mode F and save them .jpeg in Image.fromarray line it gives me error and says that PIL cannot write mode F to jpeg.
Then, I tried to first convert them RGB like following;
img = Image.fromarray(pic, 'RGB')
I am not including np.float32 just before pic or not multiplying it by 255 as it is. Then, I convert this image to grayscale. This is what I got for RGB image;
After converting RGB into grayscale:
As you see, it seems that there is a critical different between the first pic and the last pic. So, what should be the proper way to use them in 2D CNN classification? or, should I convert them into RGB and choose grayscale in CNN implementation and a channel of 1? My image dimensions 1000x9. I can even change this dimension like 250x36 or 100x90. It doesn't matter too much. By the way, in the CNN network, I am able to get more than 90% test accuracy when I use the first-type of image.
The main problem here is using which image conversion method I'll be able to take into account those precision differences across the pixels. Would you give me some idea?
---- EDIT -----
Using .tiff format I made some quick comparisons.
First of all, my data looks like the following;
So, if I convert this first reading into an image using the following code where I use np.float64 and L gives me a grayscale image;
newsize = (9, 1000)
pic = acc_normalized[0]
img = Image.fromarray(np.float64(pic), 'L')
img = img.resize(newsize)
image_path = "Images_Accel"
image_name = "D1." + str(2)
img.save(f"{image_path}/{image_name}.tiff")
It gives me this image;
Then, the first 15x9 matrix seems like following image; The contradiction is that if you take a closer look at the numerical array, for instance (1,4) member, it's a complete black where the numerical array is equal to 0.4326132099074307. For grayscale images, black means that it's close to 0 cause it makes white if it's close to 1. However, if it's making a row operation, there is another value closer to 0 and I was expecting to see it black at (1,5) location. If it does a column operation, there is again something wrong. As I said, this data has been already normalized and varies within 0 and 1. So, what's the logic that it converts the array into an image? What kind of operation it does?
Secondly, if I first get an RGB image of the data and then convert it into a grayscale image, why I am not having exactly the same image as what I obtained first? Should the image coming from direct grayscale conversion (L method, np.float64) and the one coming from RGB-based (first I get RGB then convert it to grayscale) be the same? There is a difference in black-white pixels in those images. I do not know why we have it.
---- EDIT 2 ----
.tiff image with F mode and np.float32 gives the following;
I don't really understand your question, but you seem to want to store image differences that are less than 1, i.e. less than the resolution of integer values.
To do so, you need to use an image format that can store floats. JPEG, PNG, GIF, TGA and BMP cannot store floats. Instead, use TIFF, EXR or PFM formats which can handle floats.
Alternatively, you can create 16-bit PNG images wherein each pixel can store values in range 0..65535. So, say the maximum difference you wanted to store was 60 you could calculate the difference and multiply it by 1000 and round it to make an integer in range 0..60000 and store as 16-bit PNG.
You could record the scale factor as a comment within the image if it is variable.

Read RGB image into binary and display it as RGB in Matlab

This question is based on the one asked earlier Understanding image steganography by LSB substitution method
In order to make the code efficient and reduce the mean square error (MSE) the suggestion was: "read the file as is with and convert it to bits with de2bi(fread(fopen(filename)), 8). Embed these bits to your cover image with the minimum k factor required, probably 1 or 2. When you extract your secret, you'll be able to reconstruct the original file." This is what I have been trying but somewhere I am doing wrong as I am not getting any display. However, the MSE has indeed reduced. Basically, I am confused as to how to convert the image to binary, perform the algorithm on that data and display the image after extraction.
Can somebody please help?
I've made some modifications to your code to get this to work regardless of what the actual image is. However, they both need to be either colour or grayscale. There are also some errors your code that would not allow me to run it on my version of MATLAB.
Firstly, you aren't reading in the images properly. You're opening up a byte stream for the images, then using imread on the byte stream to read in the image. That's wrong - just provide a path to the actual file.
Secondly, the images are already in uint8, so you can perform the permuting and shifting of bits natively on this.
The rest of your code is the same as before, except for the image resizing. You don't need to specify the number of channels. Also, there was a syntax error with bitcmp. I used 'uint8' instead of the value 8 as my version of MATLAB requires that you specify a string of the expected data type. The value 8 here I'm assuming you mean 8 bits, so it makes sense to put 'uint8' here.
I'll also read your images directly from Stack Overflow. I'll assume the dinosaur image is the cover while the flower is the message:
%%% Change
x = imread('https://i.stack.imgur.com/iod2d.png'); % cover message
y = imread('https://i.stack.imgur.com/Sg5mr.png'); % message image
n = input('Enter the no of LSB bits to be subsituted- ');
%%% Change
S = uint8(bitor(bitand(x,bitcmp(2^n-1,'uint8')),bitshift(y,n-8))); %Stego
E = uint8(bitand(255,bitshift(S,8-n))); %Extracted
origImg = double(y); %message image
distImg = double(E); %extracted image
[M N d] = size(origImg);
distImg1=imresize(distImg,[M N]); % Change
figure(1),imshow(x);title('1.Cover image')
figure(2),imshow(y);title('2.Message to be hide')
figure(3),imshow((abs(S)),[]);title('3.Stegnographic image')
figure(4),imshow(real(E),[]); title('4.Extracted image');
This runs for me and I manage to reconstruct the message image. Choosing the number of bits to be about 4 gives you a good compromise between the cover and message image.
Loading the byte stream instead of the pixel array of the secret will result to a smaller payload. How smaller it'll be depends on the image format and how repetitive the colours are.
imread() requires a filename and loads a pixel array if said filename is a valid image file. Loading the byte stream of the file and passing that to imread() makes no sense. What you want is this
% read in the byte stream of a file
fileID = fopen(filename);
secretBytes = fread(fileID);
fclose(fileID);
% write it back to a file
fileID = fopen(filename);
fwrite(fileID, secretBytes);
fclose(fileID);
Note that the cover image is loaded as a pixel array, because you'll need to modify it.
The size of your payload is length(secretBytes) * 8 and this must fit in your cover image. If you decide to embed k bits per pixel, for all your colour planes, the following requirement must be met
secretBytes * 8 <= prod(size(coverImage)) * k
If you want to embed in only one colour plane, regardless of whether your cover medium is an RGB or greyscale, you need to modify that to
secretBytes * 8 <= size(coverImage,1) * size(coverImage,2) * k
If this requirement isn't met, you can choose to
stop the process
ask the user for a smaller file to embed
increase k
include more colour planes, if available
The following is a prototype for embedding in one colour plane in the least significant bit only (k = 1).
HEADER_LEN = 24;
coverImage = imread('lena.png');
secretBytes = uint8('Hello world'); % this could be any byte stream
%% EMBEDDING
coverPlane = coverImage(:,:,1); % this assumes an RGB image
bits = de2bi(secretBytes,8)';
bits = [de2bi(numel(bits), HEADER_LEN) bits(:)'];
nBits = length(bits);
coverPlane(1:nBits) = bitset(coverPlane(1:nBits),1,bits);
coverImage(:,:,1) = coverPlane;
%% EXTRACTION
nBits = bi2de(bitget(coverPlane(1:HEADER_LEN),1));
extBits = bitget(coverPlane(HEADER_LEN+1:HEADER_LEN+nBits),1);
extractedBytes = bi2de(reshape(extBits',8,length(extBits)/8)')';
Along with your message bytes you have to embed the length of the secret, so the extractor knows how many bits to extract.
If you embed with k > 1 or in more than one colour planes, the logic becomes more complicated and you have to be careful how you implement the changes.
For example, you can choose to embed in each colour plane at a time until you run out of bits to hide, or you can flatten the whole pixel array with coverImage(:), which will embed in the RGB of each pixel, one pixel at a time until you run out of bits.
If you embed with k > 1, you have to pad your bits vector with 0s until its length is divisible by k. Then you can combine your bits in groups of k with
bits = bi2de(reshape(a',k,length(bits)/k)')';
And to embed them, you want to resort back to using bitand() and bitor().
coverPlane(1:nBits) = bitor(bitand(coverPlane(1:nBits), bitcmp(2^k-1,'uint8')), bits);
There are more details, like extracting exactly 24 bits for the message length and I can't stress enough you have to think very carefully how you implement all of those things. You can't just stitch parts from different code snippets and expect everything to do what you want it to do.

"Submatrix incorrectly defined" when trying to decrease color depth of greyscale images

I'm trying to make Scilab receive a certain JPEG image then transform it into a matrix of values between 0 and 255 (normal 8bit depth image) and then rearrange those values into smaller depths. The proposal is to make all the options from 1bit to 7bits which translates into 2, 4, 8, 16, 32, 64 and 128 different levels of color for them respectively.
We're doing it with greyscale images to make things simpler, since we can simply get any of the 3 channels and work with it as a matrix of rows and columns. I know there are many better ways of doing this, but I need to do it using Scilab since it's for a image processing course at University (signals and linear systems subject from Electrical Engineering to be exact).
What I could come up with, and it worked fine for the test-matrices that I tried, is this:
function y=bits(x,p)
[rows, columns]=size(x);
y=zeros(rows,columns);
aux=round(linspace(0,255,2^p)); //define which values the output can have
for i=1:rows //varies rows
for j=1:columns //varies columns
[aux2,minpos]=min(abs(aux-x(i,j)));//calculates the closest value between the input and the possible output values
y(i,j)=aux(minpos); //get the calculated closest value and puts it at the output
end
end
endfunction
What I can't understand is why it works fine for any hand-made matrix but when I try to send it something bigger (I mean, which more rows and columns) it gives the "Submatrix incorrectly defined." error at line 8 which is the " y(i,j)=aux(minpos);" line.
Edit: Just to add, I'm importing the image using "imread", which is a function of SIVP.
Any help is appreciated, thanks in advance =)
I could fix it with the following at the beginning of the function:
x=x(:,:,1);
x=double(x);
=).

Detecting black spots on image - Image Segmentation

I'm trying to segment an image with Color-Based Segmentation Using K-Means Clustering. I already created 3 clusters, and the cluster number 3 is like this image:
This cluster has 3 different colors. And I want to only display the black spots of this image. How can I do that?
The image is 500x500x3 uint8.
Those "holes" look like they are well defined with the RGB values all being set to 0. To make things easy, convert the image to grayscale, then threshold the image so that any intensities less than 5 set the output to white. I use a threshold of 5 instead to ensure that we capture object pixels in their entirety taking variations into account.
Once that's done, you can use the function bwlabel from the image processing toolbox (I'm assuming you have it as you're dealing with images) where the second output tells you how many distinct white objects there are.
Something like this could work:
im = imread('http://i.stack.imgur.com/buW8C.png');
im_gray = rgb2gray(im);
holes = im_gray < 5;
[~,count] = bwlabel(holes);
I read in the image directly from StackOverflow, convert the image to grayscale, then determine a binary mask where any intensity that is less than 5, set the output to white or true. Once we have this image, we can use bwlabel's second output to determine how many objects there are.
I get this:
>> count
count =
78
As an illustration, if we show the image where the holes appear, I get this:
>> imshow(holes);
The amount of "holes" is a bit misleading though. If you specifically take a look at the bottom right of the image, there are some noisy pixels that don't belong to any of the "holes" so we should probably filter that out. As such, a simple morphological opening filter with a suitable sized structure will help remove spurious noisy islands. As such, use imopen combined with strel to define the structuring element (I'll choose a square) as well as a suitable size of the structuring element. After, use the structuring element and filter the resulting image and you can use this image to count the number of objects.
Something like this:
%// Code the same as before
im = imread('http://i.stack.imgur.com/buW8C.png');
im_gray = rgb2gray(im);
holes = im_gray < 5;
%// Further processing
se = strel('square', 5);
holes_process = imopen(holes, se);
%// Back to where we started
[~,count] = bwlabel(holes_process);
We get the following count of objects:
>> count
count =
62
This seems a bit more realistic. I get this image now instead:
>> imshow(holes_process);

Save an imagesc output in Matlab

I am using imagesc to get an integral image. However, I only manage to display it and then I have to save it by hand, I can't find a way to save the image from the script with imwrite or imsave. Is it possible at all?
The code:
image='C:\image.jpg';
in1= imread((image));
in=rgb2gray(in1);
in_in= cumsum(cumsum(double(in)), 2);
figure, imagesc(in_in);
You can also use the print command. For instance if you are running over multiple images and want to serialize them and save them, you can do something like:
% Create a new figure
figure (fig_ct)
% Plot your figure
% save the figure to your working directory
eval(['print -djpeg99 ' num2str(fig_ct)]);
% increment the counter for the next figure
fig_ct = fig_ct+1;
where fig_ct is just a counter. If you are interested in saving it in another format different than jpeg take a look at the documentation, you can do tiff, eps, and many more.
Hope this helps
I believe your problem may be with the fact that you are saving a double matrix that is not on the range of [0 1]. If you read the documentation, you'll see that
If the input array is of class double, and the image is a grayscale or
RGB color image, imwrite assumes the dynamic range is [0,1] and
automatically scales the data by 255 before writing it to the file as
8-bit values.
You can convert it yourself to a supported type (that's logical, uint8, uint16, or double) or get it in the range [0 1] by, for example, dividing it by the max:
imwrite (in_in / max (in_in(:)), 'out.jpg');
You may still want to further increase the dynamic range of the image you saved. For example, subtract the mininum before dividing by the max.
in_in = in_in - min (in_in(:));
in_in = in_in / max (in_in(:));
imwrite (in_in, 'out.jpg');
If you want exactly what imagesc displays
The imagesc function scales image data to the full range of the current colormap.
I don't know what exactly does it mean exactly but call imagesc requesting with 1 variable, and inspect the image handle to see the colormap and pass it to imwrite().
I'm a very new programmer, so apologies in advance if this isn't very helpful, but I just had the same problem and managed to figure it out. I used uint8 to convert it like this:
imwrite(uint8(in_in), 'in_in.jpg', 'jpg');

Resources