Single into UINT8 conversion in Matlab? - 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);

Related

Converting an image to type double

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(:))))

Quantizing Double Type Input to Double Type Output in MATLAB

I'm trying to quantize a set of double type samples with 128 level uniform quantizer and I want my output to be double type aswell. When I try to use "quantize" matlab gives an error: Inputs of class 'double' are not supported. I tried "uencode" as well but its answer was nonsense. I'm quite new to matlab and I've been working on this for hours. Any help appriciated. Thanks
uencode is supposed to give integer results. Thats the point of it. but the key point is that it assumes a symmetric range. going from -x to +x where x is the largest or smallest value in your data set. So if your data is from 0-10 your result looks like nonsense because it quantizes the values on the range -10 to 10.
In any event, you actually want the encoded value and the quantized value. I wrote a simple function to do this. It even has little help instructions (really just type "help ValueQuantizer"). I also made it very flexible so it should work with any data size (assuming you have enough memory) it can be a vector, 2d array, 3d, 4d....etc
here is an example to see how it works. Our number is a Uniform distribution from -0.5 to 3.5 this shows that unlike uencode, my function works with nonsymmetric data, and that it works with negative values
a = 4*rand(2,4,2) - .5
[encoded_vals, quant_values] = ValueQuantizer(a, 3)
produces
a(:,:,1) =
0.6041 2.1204 -0.0240 3.3390
2.2188 0.1504 1.4935 0.8615
a(:,:,2) =
1.8411 2.5051 1.5238 3.0636
0.3952 0.5204 2.2963 3.3372
encoded_vals(:,:,1) =
1 4 0 7
5 0 3 2
encoded_vals(:,:,2) =
4 5 3 6
1 1 5 7
quant_values(:,:,1) =
0.4564 1.8977 -0.0240 3.3390
2.3781 -0.0240 1.4173 0.9368
quant_values(:,:,2) =
1.8977 2.3781 1.4173 2.8585
0.4564 0.4564 2.3781 3.3390
so you can see it returns the encoded values as integers (just like uencode but without the weird symmetric assumption). Unlike uencode, this just returns everything as doubles rather than converting to uint8/16/32. The important part is it also returns the quantized values, which is what you wanted
here is the function
function [encoded_vals, quant_values] = ValueQuantizer(U, N)
% ValueQuantizer uniformly quantizes and encodes the input into N-bits
% it then returns the unsigned integer encoded values and the actual
% quantized values
%
% encoded_vals = ValueQuantizer(U,N) uniformly quantizes and encodes data
% in U. The output range is integer values in the range [0 2^N-1]
%
% [encoded_vals, quant_values] = ValueQuantizer(U, N) uniformly quantizes
% and encodes data in U. encoded_vals range is integer values [0 2^N-1]
% quant_values shows the original data U converted to the quantized level
% representing the number
if (N<2)
disp('N is out of range. N must be > 2')
return;
end
quant_values = double(U(:));
max_val = max(quant_values);
min_val = min(quant_values);
%quantizes the data
quanta_size = (max_val-min_val) / (2^N -1);
quant_values = (quant_values-min_val) ./ quanta_size;
%reshapes the data
quant_values = reshape(quant_values, size(U));
encoded_vals = round(quant_values);
%returns the original numbers in their new quantized form
quant_values = (encoded_vals .* quanta_size) + min_val;
end
As far as I can tell this should always work, but I haven't done extensive testing, good luck

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.

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));