Image normalization: Issue with arithmetic operation - matlab

I'm trying to normalize an image, I applied the formula to do so, however I encounter a weird arithmetic operation problem in doing so.
This is my code:
IM3=imread('mdb022.pgm');
i = IM3(:,:,1);
rtemp = min(i); % find the min. value of pixels in all the columns (row vector)
rmin=min(rtemp) % find the min. value of pixel in the image
rtemp = max(i); % find the max. value of pixels in all the columns (row vector)
rmax=max(rtemp) % find the max. value of pixel in the image
a=255;
b=rmax-rmin
m=a/b % find the slope of line joining point (0,255) to (rmin,rmax)
c = 255 - m*rmax; % find the intercept of the straight line with the axis
i_new = m*i + c; % transform the image according to new slope
On the command window:
>> contrast_stretching_1
rmin =
0
rmax =
221
b =
221
m =
1
For the step m=a/b, the division should be 255 divided by 221, which is equal to 1.1538...., but why does matlab shows 1?
Can somebody enlighten me on this and help me solve this issue?
Thanks!

Change your image to double (or single)
IM3 = imread('mdb022.pgm');
I = double(IM3(:,:,1));
rmin = min(I(:));
rmax = max(I(:));
m = 255.0 ./ (rmax - rmin);
I_new = m.*(I - rmax) + 255.0;
% I_new = uint8(I_new); if you want the image as uint8

Related

Matlab Dissecting Extracting Camera Projection Matrix to position and rotation

I have 6 points in space with known coordinates in mm and corresponding 2D pixel coordinates in the image (image size is 640x320 pixels and points coordinates have been measured from upper left of the image. also I have the focal length of the camera as 43.456mm. trying to find the camera position and orientation.
My matlab code here will give me the camera location as -572.8052
-676.7060 548.7718 and seems correct but I am having a hard time finding the orientation values (yaw pitch roll of the camera in degrees)
I know that the rotation values should be 60.3,5.6,-45.1
the last 4 lines in my code needs to be updated to output the orientation of the camera.
I would really really appreciate your help on this.
Thanks.
Here is my matlab code:
Points_2D= [135 183 ; 188 129 ; 298 256 ; 301 43 ; 497 245; 464 110];
Points_3D= [-22.987 417.601 -126.543 ; -132.474 37.67 140.702 ; ...
388.445 518.635 -574.784 ; 250.015 259.803 67.137 ; ...
405.915 -25.566 -311.834 ; 568.859 164.809 -162.604 ];
M = [0;0;0;0;0;0;0;0;0;0;0];
A = [];
for i = 1:size(Points_2D,1)
u_i = Points_2D(i,1);
v_i = Points_2D(i,2);
x_i = Points_3D(i,1);
y_i = Points_3D(i,2);
z_i = Points_3D(i,3);
A_vec_1 = [x_i y_i z_i 1 0 0 0 0 -u_i*x_i -u_i*y_i -u_i*z_i -u_i]; %
A_vec_2 = [ 0 0 0 0 x_i y_i z_i 1 -v_i*x_i -v_i*y_i -v_i*z_i -v_i]; %
A(end+1,:) = A_vec_1;
A(end+1,:) = A_vec_2;
end
[U,S,V] = svd(A);
M = V(:,end);
M = transpose(reshape(M,[],3));
Q = M(:,1:3);
m_4 = M(:,4);
Center = (-Q^-1)*m_4
k=[43.456/640 0 320 ;0 43.456/320 160;0 0 1 ];
Rotation= (Q^-1)*k;
CC=Rotation'
eul=rotm2eul(CC)
First thing first: 6 points are enough but it is likely that you have some error. To get a better performance, it is recommended to have more than 6 points, like 10-15 preferably.
Your code seems correct until:
Q = M(:,1:3);
m_4 = M(:,4);
So you are looking for extrinsic and intrinsic parameters of the camera, i.e. rotation, translation, alpha(skew in x direction), ro, beta(skew in x direction), u0, v0 (translation of camera center). So a total of 5 intrinsics, 6 extrinsic parameters.
Here is a link which explains the details how to calculate those parameters. I had a code which I didn't test thoroughly, may be some errors but it was working in my case.
Continuing from M which is the 3x4 matrix you found:
a1 = M(1, 1:3);
a2 = M(2, 1:3);
a3 = M(3, 1:3);
b = M(1:3,4);
% Decomposition of the parameters
eps = 1; %this can be -1 or +1, based on the value you choose, you will have two different results.
ro = eps/sqrt(sumsqr(a3));
r3 = ro*a3;
u0 = ro.^2*(dot(a1,a3))
v0 = ro.^2*(dot(a2,a3))
cos_theta = -dot(cross(a1,a3),cross(a2,a3))/ ...
dist_cross(a1,a3)/(dist_cross(a2,a3));
theta = acos(cos_theta);
alpha = ro^2*dist_cross(a1,a3)*sin(theta)
beta = ro^2*dist_cross(a2,a3)*sin(theta)
theta_deg = theta*180/pi
r1 = 1/dist_cross(a2,a3)*cross(a2,a3);
r2 = cross(r3,r1);
R = [r1;r2;r3] % Rotation matrix 3x3
% ro*A.inv(R) = K
K = [alpha -alpha*cot(theta) u0;
0 beta/sin(theta) v0;
0 0 1 ];
T = ro*(inv(K)*b) % Translation matrix, 1x3
where
function [dis] = dist_cross(mi,mj)
dis = sqrt(sumsqr(cross(mi,mj)));
end
I don't guarantee it is totally correct but it should help.

How integral image influence the result of local binary pattern or center symmetric local binary pattern

I know this looks somehow not related to code errors and development but
I want to know if someone can understand these codes of
integral image and local binary pattern, and tell me how they affect the resulting histograms.
Before the use of integral image the output histogram is normal, but after applying the integral image method I found that most of the histogram changed to zeros. To clarify things, the expected benefit from the use of an integral image is to speed up the process of lbp method. In fact, I haven't seen this before because I'm trying it for the first time. Does anybody who knows about this may help me please?
These are the codes of every method:
Integral image
function [outimg] = integral( image )
[y,x] = size(image);
outimg = zeros(y+1,x+1);
disp(y);
for a = 1:y+1
for b = 1:x+1
rx = b-1;
ry = a-1;
while ry>=1
while rx>=1
outimg(a,b) = outimg(a,b)+image(ry,rx);
rx = rx-1;
end
rx = b-1;
ry = ry-1;
end
% outimg(a,b) = outimg(a,b)-image(a,b);
end
end
% outimg(1,1) = image(1,1);
disp('end loop');
end
CS-LBP
function h = CSLBP(I)
%% this function takes patch or image as input and return Histogram of
%% CSLBP operator.
h = zeros(1,16);
[y,x] = size(I);
T = 0.1; % threshold given by authors in their paper
for i = 2:y-1
for j = 2:x-1
% keeping I(j,i) as center we compute CSLBP
% N0 - N4
a = ((I(i,j+1) - I(i, j-1) > T ) * 2^0 );
b = ((I(i+1,j+1) - I(i-1, j-1) > T ) * 2^1 );
c = ((I(i+1,j) - I(i-1, j) > T ) * 2^2 );
d = ((I(i+1,j-1) - I(i - 1, j + 1) > T ) * 2^3 );
e = a+b+c+d;
h(e+1) = h(e+1) + 1;
end
end
end
Matlab has an inbuilt function for creating integral images, integralimage(). If you don't want to use the computer vision system toolbox you can achieve the same result by calling:
IntIm = cumsum(cumsum(double(I)),2);
Possibly adding padding if needed. You should check out that the image is not saturated, they do that sometimes. Calculating the cumulative sum goes to integers way above the range of uint8 and uint16 quickly, I even had it happen with a double once!

Frames of type double must be in the range of 0 to 1: MATLAB

I have a video and I have made a Sobel mask for it on MATLAB. Now I have to apply that Sobel mask on each frame of the video by reading each frame through for loop. The process is something like:
Step 1: Reading frame.
step 2: Converting it to grayscale using rgb2gray.
Step 3: Converting it to double.
Here, after applying the mask when I try to write the frame on the resultant video.avi file, I get the following error:
"Frames of type double must be in the range of 0 to 1"
What is wrong with my code? The code I wrote is shown below:
vid = VideoReader('me.mp4');
frames = read(vid);
total = get(vid, 'NumberOfFrames');
write = VideoWriter('me.avi');
open(write);
mask1 = [-1 -2 -1; 0 0 0; 1 2 1]; % Horizontal mask
mask2 = [-1 0 1; -2 0 2; -1 0 1]; %Vertical Mask
for k = 1 : 125
image = frames(:,:,:,k);
obj = image;
obj1 = rgb2gray(obj);
obj2=double(obj1);
for row = 2 : size(obj2, 1) - 1
for col = 2 : size(obj2, 2) - 1
c1 = obj2(row - 1, col - 1) * mask1(1 ,1);
c2 = obj2(row - 1, col) * mask1(1 ,2);
c3 = obj2(row - 1, col + 1) * mask1(1 ,3);
c4 = obj2(row, col - 1)*mask1(2, 1);
c5 = obj2(row, col)*mask1(2, 2);
c6 = obj2(row, col + 1)*mask1(2, 3);
c7 = obj2(row + 1, col - 1)*mask1(3,1);
c8 = obj2(row + 1, col)*mask1(3,2);
c9 = obj2(row + 1, col + 1)*mask1(3,3);
c11 = obj2(row - 1, col - 1)*mask2(1 , 1);
c22 = obj2(row, col - 1)*mask2(2, 1);
c33 = obj2(row + 1, col - 1)*mask2(3, 1);
c44 = obj2(row -1, col)*mask2(1, 2);
c55 = obj2(row, col)*mask2(2 , 2);
c66 = obj2(row +1, col)*mask2(2 , 3);
c77 = obj2(row - 1, col + 1)*mask2(1 , 3);
c88 = obj2(row, col +1)*mask2(2 , 3);
c99 = obj2(row + 1, col + 1)*mask2(3 , 3);
result = c1 + c2 + c3 +c4 +c5+ c6+ c7+ c8 +c9;
result2 = c11 + c22 + c33 + c44 + c55 + c66 + c77 + c88 + c99;
%result = double(result);
%result2 = double(result2);
rim1(row, col) = ((result^2+result2^2) *1/2);
rim2(row, col) = atan(result/result2);
end
end
writeVideo(write, rim2); %This line has the problem with rim2 as rim2 is the frame i'm trying to write on the video file.
end
close(write);
rim2 has range [-pi/2, pi/2] at the end, which is not compatible with the write function which expects [0,1] range.
Convert it to [0,1] range using the mat2gray function, i.e.
writeVideo(write, mat2gray(rim2));
Your code will then work as expected (confirmed on my machine).
By the way, this doesn't affect your code, but presumably you meant to do im2double(A) rather than double(A). The former produces a "proper" grayscale image in the range [0,1], whereas the latter simply converts your uint8 image in the range [0,255] to double format (i.e. [0.0, 255.0]).
The line of rim2 inside your double for loop is using atan, which will generate values that are both positive and negative - from -pi/2 to +pi/2 exactly. rim2 is expected to have values that are only between [0,1]. I can't figure out what exactly you're doing, but it looks like you're calculating the magnitude and gradient angle at each pixel location. If you want to calculate the magnitude, you have to take the square root of the result, not simply multiply by 1/2. The calculation of the gradient (... or even the whole Sobel filter calculation...) is very funny.
I'll just assume this is working for your purposes so I'm not sure how to change the output of rim2for suitable display but perhaps you could scale it to the range of [0,1] before you write the video so that it's within this range.
Something like this would work before you write the frame:
rim2 = (rim2 - min(rim2(:))) / (max(rim2(:)) - min(rim2(:)));
writeVideo(write, rim2);
The above is your typical min-max normalization that is seen in practice. Specifically, the above will ensure that the smallest value is 0 while the largest value is 1 per frame. If you want to be consistent over all frames, simply add pi/2 then divide by pi. This assumes that the minimum is -1 and the maximum is +1 over all frames however.
rim2 = (rim2 + pi/2) / pi;
writeVideo(write, rim2);
However, I suspect you want to write the magnitude to file, not the angle. Therefore, replace the video writing with rim1 as the frame to write instead of rim2, then normalize after. Make sure your gradient calculation is correct though:
rim1(row, col) = ((result^2+result2^2)^(1/2));
% or use sqrt:
% rim1(row, col) = sqrt(result^2 + result2^2);
Now write to file:
rim1 = (rim1 - min(rim1(:))) / (max(rim1(:)) - min(rim1(:)));
writeVideo(write, rim1);
However, if I can provide a method of efficiency, don't use for loops to compute the gradient and angle. Use conv2 and ensure you use the 'same' flag or imfilter from the image processing toolbox to perform the filtering for you, then calculate the gradient and angle vectorized. Also, convert to grayscale and cast your frame in one go in the main loop. I'll assume you have the image processing toolbox as having the computer vision toolbox (you have this as you're using a VideoWriter object) together with the image processing toolbox is what most people have:
vid = VideoReader('me.mp4');
frames = read(vid);
total = get(vid, 'NumberOfFrames');
write = VideoWriter('me.avi');
open(write);
mask1 = [-1 -2 -1; 0 0 0; 1 2 1]; % Horizontal mask
mask2 = [-1 0 1; -2 0 2; -1 0 1]; %Vertical Mask
for k = 1 : 125
obj2 = double(rgb2gray(frames(:,:,:,k))); % New
grad1 = imfilter(obj2, mask1); % New
grad2 = imfilter(obj2, mask2); % New
rim1 = sqrt(grad1.^2 + grad2.^2); % New
rim2 = atan2(grad1, grad2); % New
% Normalize
rim2 = (rim2 - min(rim2(:))) / (max(rim2(:)) - min(rim2(:)));
writeVideo(write, rim2);
end
close(write);

how to get Image of same size after processing

I am estimating ridge orientation of an fingerprint image by dividing it into blocks of 41*41..image is of size 240*320..here is my code and the problem is that I am getting output image size different than input image.
% matalb code for orientation
im =imread('D:\project\116_2_5.jpg');
im = double(im);
[m,n] = size(im);
% to normalise image
nor = im - mean(im(:));
im = nor/std(nor(:));
w = 41;
% To calculate x and y gradient component using 3*3 sobel mask
[delx,dely] = gradient(im);
% Ridge orientation
for i=21:w:240-41
for j=21:w:320-41
A = delx(i-20:i+20,j-20:j+20);
B = dely(i-20:i+20,j-20:j+20);
Gxy = sum(sum(A.*B));
Gxx = sum(sum(A.*A));
Gyy = sum(sum(B.*B));
diff = Gxx-Gyy;
theta(i-20:i+20,j-20:j+20) = (pi/2) + 0.5*atan2(2*Gxy,diff);
end;
end;
but in this process i am loosing the pixels at the boundries so as to avoid the "index exceed" error i.e size of theta is m = 240-41 = 199 and n = 320-41=279..Thus my input image size is 240*320 and output image size is size 199*279..How can i get output image same as size of input image.
one more thing that i dnt have to use "blockproc" function...Thanks in advance
You can use padarray to add zeros onto your matrix:
A1 = padarray(A,[7 8],'post'); % 240+7=41*7, 320+8=41*8
B1 = padarray(B,[7 8],'post');
then generate Gxx, Gyy, and Gxy with A1 and B1.
Method 2:
Besides, I tried to simplify your code a little bit by removing the loops, for your reference:
% Ridge orientation
Gxy = delx .* dely;
Gxx = delx .* delx;
Gyy = dely .* dely;
fun = #(x) sum(x(:))*ones(size(x));
theta_Gxy = blockproc(Gxy,[41 41],fun, 'PadPartialBlocks', true);
theta_diff = blockproc(Gxx-Gyy,[41 41],fun, 'PadPartialBlocks', true);
theta0 = pi/2 + 0.5 * atan2(2 * theta_Gxy, theta_diff);
theta = theta0(1:240, 1:320);
You may check blockproc for more details.

how to use for loop for my issue

I have 2560 sample points. I want to calculate mean variance skewness kurtosis for first 512 points, next 512 so on. so totally 5 sets of output data .I want to plot 5 sets of values of mean , var , skew , kur in a graph.
I read a data from excel consisting of 2560 points
x=xlsread('dta.xls');
i=1:512;
y=x(i)
m=mean(y);
v=var(y);
i=513:1024;
y=x(i)
m=mean(y);
v=var(y);
i=1025:1536
y=x(i)
m=mean(y);
v=var(y);
plot(m)
plot(v)
like this my code s going. I tried using for loop but I couldn't able to make it.
Try something like this:
x = xlsread('dta.xls');
ns = length(x); % number of samples
bs = 512; % bin size
bc = floor(ns / bs); % bin count
m = zeros(bc, 1); % array of means
v = zeros(bc, 1); % array of variances
for i = 1 : bc
i1 = (i - 1) * bs + 1;
i2 = i * bs;
b = x(i1 : i2); % current bin
m(i) = mean(b);
v(i) = var(b);
end;
figure;
subplot(211); plot(m, '.-');
subplot(212); plot(v, '.-');
Here is a working example.
In addition to Tobias:
Correct me if I'm wrong but it seems to me that i=1:512 + 512*j always starts with 1.
In the question it should be everytime the next 512. So I have change this to:
for j=0:4
i=512*j+1 : 512+512*j
y=x(i)
m=mean(y);
v=var(y);
plot(m)
plot(v)
end