Converting an image to type double - matlab

I am reading an image with the following command:
lefty = imread('sintra2.JPG');
and imshow(); gives me a good resault. but If I try to use:
lefty = double(imread('sintra2.JPG'));
imshow() gives me a white image. I am working with a relatively big image shared here. Is there a connection?
How do I convert to double if at all it is necessary? I was told it is better to work with double when working on image processing and computer vision in MATLAB.

When you read the image, its type was uint8 and thus lefty contained the values from 0 to 255 (28 = 256). When you used double, it converted the class from uint8 to double but the values remained same i.e 0-255.
You need im2double here which not only converts the values to double precision but also rescales the values in the range 0-1 by dividing all the entries of the input by the maximum possible value of the input data type. So in your case, as the input data type is uint8 whose maximum possible value is 255, therefore all the values will be divided by 255. Note that it is possible that the maximum value in your image data may not be 255 but since the maximum possible value of uint8 is 255, so all the values will be divided by 255.
So the following is what you're looking for:
lefty = imread('sintra2.JPG');
imshow(lefty)
figure
imshow(im2double(lefty))

The problem is with the data type that imshow requires. If the image is of type int, its range should be between 0 and 255. If it is double – between 0.0 and 1.0. Try this:
lefty = imread('sintra2.JPG');
imshow(lefty)
or:
lefty = imread('sintra2.JPG');
imshow(double(lefty)/double(max(lefty(:))))

Related

how to modify values of Mat according to some condition in opencv?

In Matlab a(a>50)=0 can replace all elements of a that are greater than 50 to 0. I want to do same thing with Mat in OpenCV. How to do it?
Naah. to do that, just one line:
cv::Mat img = imread('your image path');
img.setTo(0,img>50);
as simple as that.
What you want is to truncate the image with cv::threshold.
The following should do what you require:
cv::threshold(dst, dst, 50, 0, CV_THRESH_TOZERO_INV);
this is the function definition
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html?highlight=threshold#threshold
Sometimes threshold doesn't work because you can have a diferent kind of Mat. If your Mat type supports double, threshold will crash (at least in my android studio).
You can find compare here:
http://docs.opencv.org/2.4/modules/core/doc/operations_on_arrays.html
So I use the function compare:
Mat mask = new Mat(yourMat.rows(), yourMat.cols(), CvType.CV_64FC1);
Mat ones = org.opencv.core.Mat.ones(yourMat.rows(), yourMat.cols(), CvType.CV_64FC1);
Scalar alpha = new Scalar(50, CvType.CV_64FC1);
Core.multiply(ones, alpha, ones);
Core.compare(yourMat, zeros, mask, Core.CMP_LT);
Here I am creating a matrix with only 50 in all points. After that i am comparing it with yourMat, using CMP_LT (Less than). So all pixels less than 50 will turn in 255 in your mask and 0 if bigger. It is a mask. So you can just:
yourMat.copyTo(yourMat, mask);
Now all the pixels bigger than 50 will be zero and all the other will have their own values.

The efficient way to convert datatype in Matlab (double vs. im2double)

I want to convert a truecolor image to double precision, and as far as I know there are two ways to do that:
double(rgb_img);
im2double(rgb_img);
Which one is more efficient?
Thanks!
They both are different.
im2double converts the range of an image between 0-1 if the datatype is uint8 or uint16. If the datatype is single or logical, im2double calls double (and doesn't scale the image range). For double datatype it just remains unchanged (neither the precision changes, nor the image range).
If you already have a double precision image, then you shouldn't call im2double, it will NOT rescale your data. You can type edit im2double and look at the code. If you just want to convert to double precision (without changing the image range), then you should call double. Otherwise call im2double but make sure, your data is not of single, double or logical type.
Example:
img=imread('cameraman.tif'); %datatype is uint8
img1=double(img); %just converts to double precision, image range between 0-255
img2=im2double(img); %converts to double precision and scales image range between 0-1
img=double(imread('cameraman.tif')); %even single datatype will give the same results
img1=double(img); %redundant since image is already double, image range 0-255
img2=im2double(img); %redundant since image is already double, image range 0-255
Here's a benchmarking code to compare double against im2double even though they don't necessarily produce the same results as explained in the other solution(s) -
N_arr = [100 200 500 1000 2000 4000]; %// datasize array
timeall = zeros(4,numel(N_arr));
for k1 = 1:numel(N_arr)
rgb_img = uint8(randi([0 255],N_arr(k1))); %// Input to functions
f = #() double(rgb_img);
timeall(1,k1) = timeit(f);
clear f
f = #() im2double(rgb_img);
timeall(2,k1) = timeit(f);
clear f
end
figure,hold on,grid on
plot(N_arr,timeall(1,:),'-ro'),plot(N_arr,timeall(2,:),'-kx')
legend('DOUBLE','IM2DOUBLE'),
xlabel('Datasize ->'),ylabel('Time(sec) ->')
Result -
Now, this makes sense because internally im2double calls double.
Now, assuming you are dealing with uint8 images, to have the same functionality with double, you need to scale it down afterwards. So you need to edit the function handle accordingly -
f = #() double(rgb_img)./255;
The plot result then were -
So, apparently not much of a difference now.

Single into UINT8 conversion in Matlab?

I have a problem in Matrix type conversion.
So, I want to extract the SIFT features from an image by using VLFEAT function " vl_covdet"
Here is the detail:
Input images = <141x142x3 uint8>
And because vl_covdet only can read 1 channel and an image with type of single , I give R channel of my input image to vl_covdet:
R_input_Images = Input images(:,:,1) <141x142 uint8>
R_Single_Images= im2single(R_input_Images);
[frames, descrs,info] = vl_covdet(R_Single_Images,'Method','multiscalehessian','EstimateAffineShape', false,'EstimateOrientation', true, 'DoubleImage', false, 'Verbose');
And now, I got features
descrs = <128x240 single> which values are ranging from 0 - 0.368
But to compute BoW, I have to use K-Means clustering from VLFEAT ("vl_hikmeans") which require uint8 input type.
descrs must be of class UINT8.
So then I tried to convert it again into uint8
descrs=uint8(descrs);
Now
descrs = <128x240 uint8> **AND ALL THE VALUES BECOME 0**.
What I have to do now??
values are ranging from 0 - 0.368
Well, if you round those to integer, it's no surprise they become zeros.
Since an image in floating-point format has range 0-1, and in uint8 format has range 0-255, try
descrs = uint8(descrs * 255);

Matlab Bug -- Matrix Elements Keep Maxing Out

There's a peculiar bug in my code that I can't seem to figure out. For context, I is an image, a matrix, consisting of scaled values from 0 to 255. GetSpatAvg is a function that is not included here. The problem I'm facing is that the elements in ngtdm always max out at 255. When this function finishes, I get the matrix ngtdm back consisting of many many values that are 255. The code is below exactly as it shows on my computer.
function ngtdm = getNGTDM(I,d)
[rowI, colI] = size(I);
ngtdm = zeros(256, 1);
for r=1+d:rowI-d
for c=1+d:colI-d
term = I(r,c)-getSpatAvg(r,c);
ngtdm(I(r,c)+1)=ngtdm(I(r,c)+1)+term;
end
end
end
I isolated a specific value in I, 254, in the code below.
function ngtdm = getNGTDM(I,d)
[rowI, colI] = size(I);
ngtdm = zeros(256, 1);
for r=1+d:rowI-d
for c=1+d:colI-d
if(I(r,c)==254)
term = I(r,c)-getSpatAvg(r,c);
disp(term);
ngtdm(I(r,c)+1)=ngtdm(I(r,c)+1)+term;
end
end
end
end
The variable 'term', in this instance was always 222. There were 369 instances of 222. Therefore the value at ngtdm(255) (254+1=255) should be larger than 255, yet the element still maxed out at 255. When I replace term with 222 as shown below:
ngtdm(I(r,c)+1)=ngtdm(I(r,c)+1)+222;
I get the correct value, a number larger than 255.
I can't seem to figure out why my element is always maxing out at 255. Could it be something to do with the fact that the values of I are scaled between 0 and 255. I'm pretty positive that getSpatAvg is not the issue because the correct value is being returned.
Thank You
It's not a bug - it sounds like you are using a uint8 datatype. If you convert to a datatype with more bits - e.g. uint16, uint32, single, double, etc - you will not run into this problem. I guess you are working with images, as images read using imread are read in as uint8 by default to save memory. Quickest fix: use I=double(I); either at the start of your function, or on the variable I before you put it into the functions.

gradient() function not working with images

I have a quick question. I'm trying to compute an images 2D gradient using the gradient() function in MATLAB, but its not working. Specifically, here's my code (The image I'm using is grayscale):
im = imread('C:\yosemite1.bmp');
g = FindImageGradients(im);
I get the following error:
??? Error using ==> rdivide Integers
can only be combined with integers of
the same class, or scalar doubles.
Error in ==> gradient at 75
g(2:n-1,:) = (f(3:n,:)-f(1:n-2,:))./h(:,ones(p,1));
Any clues on how to solve this ?
Your image data is probably being read as integers in the range [0,255] (for 8 bit per color channel), so the type of im is uint8 or other int type. Try converting it to single or double:
g = FindImageGradients(single(im));