Object ellipticity based on the moment invariants - Matlab - image

Following a question about Hu moments and a question regarding object Ellipse Variance I used the code from this link to try to calculate ellipticity based on the moment invariants like in the image below (Based on A Beginner’s Guide to Image Shape Feature Extraction Techniques).
I the code I used (only checking the first 2 objects) I do not get a value close to 1 (which should indicate an Ellipticity) when I have an ellipse object. Can someone please explain what I did wrong?
code:
clc;
clear;
close all;
% Image processing
I= rgb2gray(imread('https://az877327.vo.msecnd.net/~/media/images/products/2005/other/mipix%20ellipses%20full%20frame.jpg?v=1&h=550&w=800&crop=1'));
bw = imbinarize(I);
bw = imfill(bw,'holes');
bw = bwareaopen(bw, 100);
imshow(bw)
hold on;
[B,L] = bwboundaries(bw,'noholes');
stats = regionprops(L,'Centroid','Image');
%Loop - data acquisition
for i = 1 : 2 %numel(stats)
b = B{i};
c = stats(i).Centroid;
f = stats(i).Image;
y = b(:,1);
x = b(:,2);
plot( b(:,2),b(:,1),'Color','red','linewidth',1);
text(c(1),c(2),num2str(i),'Color','red');
%based on https://raw.githubusercontent.com/dipum/dipum-toolbox/master/dipum/invmoments.m
[M,N] = size(f);
[x,y] = meshgrid(1:N,1:M);
% Turn x,y, and F into column vectors to make the summations a bit
% easier to compute in the following.
x = x(:);
y = y(:);
f = f(:);
% DIPUM3E equation (13-27)
m.m00 = sum(f);
% Protect against divide-by-zero warnings.
if (m.m00 == 0)
m.m00 = eps;
end
% The other central moments:
m.m10 = sum(x .* f);
m.m01 = sum(y .* f);
m.m11 = sum(x .* y .* f);
m.m20 = sum(x.^2 .* f);
m.m02 = sum(y.^2 .* f);
m.m30 = sum(x.^3 .* f);
m.m03 = sum(y.^3 .* f);
m.m12 = sum(x .* y.^2 .* f);
m.m21 = sum(x.^2 .* y .* f);
% DIPUM3E equations (13-28) through (13-30).
xbar = m.m10 / m.m00;
ybar = m.m01 / m.m00;
e.eta11 = (m.m11 - ybar*m.m10) / m.m00^2;
e.eta20 = (m.m20 - xbar*m.m10) / m.m00^2;
e.eta02 = (m.m02 - ybar*m.m01) / m.m00^2;
e.eta30 = (m.m30 - 3 * xbar * m.m20 + 2 * xbar^2 * m.m10) / ...
m.m00^2.5;
e.eta03 = (m.m03 - 3 * ybar * m.m02 + 2 * ybar^2 * m.m01) / ...
m.m00^2.5;
e.eta21 = (m.m21 - 2 * xbar * m.m11 - ybar * m.m20 + ...
2 * xbar^2 * m.m01) / m.m00^2.5;
e.eta12 = (m.m12 - 2 * ybar * m.m11 - xbar * m.m02 + ...
2 * ybar^2 * m.m10) / m.m00^2.5;
% DIPUM3E Table 13.8.
phi(1) = e.eta20 + e.eta02;
phi(2) = (e.eta20 - e.eta02)^2 + 4*e.eta11^2;
phi(3) = (e.eta30 - 3*e.eta12)^2 + (3*e.eta21 - e.eta03)^2;
phi(4) = (e.eta30 + e.eta12)^2 + (e.eta21 + e.eta03)^2;
phi(5) = (e.eta30 - 3*e.eta12) * (e.eta30 + e.eta12) * ...
( (e.eta30 + e.eta12)^2 - 3*(e.eta21 + e.eta03)^2 ) + ...
(3*e.eta21 - e.eta03) * (e.eta21 + e.eta03) * ...
( 3*(e.eta30 + e.eta12)^2 - (e.eta21 + e.eta03)^2 );
phi(6) = (e.eta20 - e.eta02) * ( (e.eta30 + e.eta12)^2 - ...
(e.eta21 + e.eta03)^2 ) + ...
4 * e.eta11 * (e.eta30 + e.eta12) * (e.eta21 + e.eta03);
phi(7) = (3*e.eta21 - e.eta03) * (e.eta30 + e.eta12) * ...
( (e.eta30 + e.eta12)^2 - 3*(e.eta21 + e.eta03)^2 ) + ...
(3*e.eta12 - e.eta30) * (e.eta21 + e.eta03) * ...
( 3*(e.eta30 + e.eta12)^2 - (e.eta21 + e.eta03)^2 );
disp('Object number:');
disp(i);
Is = (m.m20 * m.m02-m.m11^2)/m.m00^4;
Em1= 16*pi^2*Is
Em2= (16*pi^2*Is)^-1
min(Em1, Em2)
end

As I said in the comments, you need to use the central moments rather than raw moments as your code is doing. See Measuring Shape: Ellipticity, Rectangularity, and Triangularity
Removing the unnecessary calculations for eta and phi, the last part of your code should be:
% Calculate Raw Moments:
m.m10 = sum(x .* f);
m.m01 = sum(y .* f);
m.m11 = sum(x .* y .* f);
m.m20 = sum(x.^2 .* f);
m.m02 = sum(y.^2 .* f);
m.m30 = sum(x.^3 .* f);
m.m03 = sum(y.^3 .* f);
m.m12 = sum(x .* y.^2 .* f);
m.m21 = sum(x.^2 .* y .* f);
% DIPUM3E equations (13-28) through (13-30).
xbar = m.m10 / m.m00;
ybar = m.m01 / m.m00;
% Calculate Central Moments:
m.mu11 = m.m11 - xbar*m.m01;
m.mu20 = m.m20 - xbar*m.m10;
m.mu02 = m.m02 - ybar*m.m01;
disp('Object number:');
disp(i);
Is = (m.mu20 * m.mu02 - m.mu11^2)/m.m00^4;
Em1= 16*pi^2*Is
Em2= (16*pi^2*Is)^-1
min(Em1, Em2)
With these changes, the results for the first two objects are:
Object number:
1
Em1 = 1.000005232603003
Em2 = 9.999947674243773e-01
ans = 9.999947674243773e-01
Object number:
2
Em1 = 9.999818710527637e-01
Em2 = 1.000018129275901
ans = 9.999818710527637e-01

Related

Leveberg-Marquard Optimization for Intensity-based Image Alignment Matlab Failed

I am trying to implement the intensity-based image alignment algorithm in the paper Efficient, Robust, and Fast Global Motion Estimation for Video Coding on MATLAB. The problem is that the Levenberg-Marquardt (LM) optimization doesn't work properly, so the energy function cannot approach even a local minima due to very tiny update term computed from the LM approximation equation. I've searching for a week but still could not figure out the problem. Here is my implementation.
I have two gray images I and T equal in size (W x H) and would like to estimate a rigid transformation F (scale + rotation + translation) that aligns I onto T. This could be obtained by minimizing the following energy function
Where
According to LM, I can derive the gradient term of E with respect to each parameter a_i (i=1,4) as follow (from equation (5) in the paper).
And the terms of the Hessian matrix of E are (from equation (4) in the paper)
From the above equations, I derive the bellow MATLAB procedure to compute beta and alpha terms.
%========== 1. Compute gradient of T using Sobel filter
gx = [-1 -2 -1; 0 0 0; 1 2 1] / 4;
gy = [-1 0 1; -2 0 2; -1 0 1] / 4;
Tx = conv2( T, gx, 'same' );
Ty = conv2( T, gy, 'same' );
%========== 2. Warp I using F to compute diff_image = I(x, y) - T(F(x,y,a)). F was previously initialized by an identity matrix of size 3x3
tform = affine2d( F );
I_warp = imwarp( I, tform, 'linear', 'OutputView', imref2d( size( T ) ) );
diff_img = I_wapr - T;
% create a mask for overlaping region between two aligned images
mask = ones( size( T ) );
mask_warp = imwarp( mask, tform, 'nearest', 'OutputView', imref2d( size( T ) ) );
overlap_area = numel( mask_warp );
diff_img = diff_img .* mask;
error = sum( sum( diff_img ) ) / 2 / overlap_area;
% create x, y grids
[y, x] = ndgrid( 0 : h-1, 0 : w-1 );
x_warp = imwarp( x, t_form, 'nearest', 'OutputView', imref2d( size(T) ) );
y_warp = imwarp( y, t_form, 'nearest', 'OutputView', imref2d( size(T) ) );
%======== compute beta_i = - dE/da_i (i=1,4)
sx = Tx .* diff_img;
sy = Ty .* diff_img;
beta_1 = sum( sum( x_warp .* sx + y_warp .* sy ) );
beta_2 = sum( sum( y_warp .* sx - x_warp .* sy ) );
beta_3 = sum( sum( sx ) );
beta_4 = sum( sum( sy ) );
beta = -[beta_1; beta_2; beta_3; beta_4] / overlap_area;
%======= compute alpha_ij = (dE/da_i) * (dE/da_j) i,j = 1,4
Sxx = (Tx .^ 2) .* mask_warp;
Syy = (Ty .^ 2) .* mask_warp;
Sxy = (Tx.* Ty) .* mask_warp;
xx = x_warp .^2;
yy = y_warp .^2;
xy = x_warp .* y_warp;
alpha_11 = sum( sum( xx .* Sxx + 2 * xy .* Sxy + yy .* Syy ) );
alpha_12 = sum( sum( (yy - xx) .* Sxy + xy .* (Sxx - Syy) ) );
alpha_13 = sum( sum( x .* Sxx + y .* Sxy ) );
alpha_14 = sum( sum( x .* Sxy + y .* Syy ) );
alpha_22 = sum( sum( yy .* Sxx - 2 * xy .* Sxy + xx .* Syy ) );
alpha_23 = sum( sum( y .* Sxx - x .* Sxy ) );
alpha_24 = sum( sum( y .* Sxy - x .* Syy ) );
alpha_33 = sum( sum( Sxx ) );
alpha_34 = sum( sum( Sxy ) );
alpha_44 = sum( sum( Syy ) );
alpha = [alpha_11 alpha_12 alpha_13 alpha_14;
alpha_12 alpha_22 alpha_23 alpha_24;
alpha_13 alpha_23 alpha_33 alpha_34;
alpha_14 alpha_24 alpha_34 alpha_44] / overlap_area;
% With lamda was previously initialized by 0.0001
for i = 1 : 4
alpha(i, i) = alpha(i, i) * (lamda + 1);
end
%======== Find the update term: delta_a = alpha^(-1) * beta
delta_a = pinv( alpha ) * beta
% Or we can solve for delta_a using SVD
%[U, S, V] = svd( alpha );
%inv_S = S;
%for ii = 1 : size(S, 1)
% if S(ii, ii)
% inv_S(ii, ii) = 1 / S(ii, ii);
% end
%end
%delta_a = V * inv_S * U' * beta;
%======== Update a_i and new error value
a = [ F(1, 1)-1;
F(2, 1);
F(3, 1);
F(3, 2)];
new_a = a + delta_a;
new_F = [new_a(1)+1 -new_a(2) 0;
new_a(2) new_a(1)+1 0;
new_a(3) new_a(4) 1];
tform = affine2d( new_F );
mask_warp = imwarp( mask, tform, 'nearest', 'OutputView', imref2d(size(T)));
new_I_warp = imwarp( I, tform, 'linear', 'OutputView', imref2d(size(T)));
new_diff_img = (new_I_warp - T) .* mask_warp;
new_error = sum( sum( new_diff_img .^2 ) ) / 2/ sum( sum( mask_warp ) );
if( new_error > error )
lamda = lamda * 10;
elseif new_error < error
lamda = lamda /10;
The above process is repeated until the iteration reach the limitation or the new_error value less than a predetermined threshold. However, after each iteration, the update terms are too small that parameters make trivial movement. For example,
delta a = 1.0e-04 * [0.0011 -0.0002 0.2186 0.2079]
Is there anybody know how to fixed it? Any help would be highly appreciated.

How can i simplify this for loop?

I need to fill a 360 element matrix with periods of 90 elements for different phiStart and phiExit values:
flute = 4;
phiStart = 0;
phiExit = 90;
phiDelta = 1;
phiPitch = 360 / flute;
for g = 0:abs(phiExit - phiStart);
for k = 0:abs(phiExit - phiStart);
for j = 0:abs(phiExit - phiStart);
for m = 0:abs(phiExit - phiStart);
for i = 0:abs(phiExit - phiStart);
answerA = phiStart + i * phiDelta;
phi(i+1) = answerA;
end
answerA = phiStart + m * phiDelta;
phi(m + phiPitch) = answerA;
end
answerA = phiStart + j * phiDelta;
phi(j + 2 * phiPitch) = answerA;
end
answerA = phiStart + k * phiDelta;
phi(k + 3 * phiPitch) = answerA;
end
answerA = phiStart + g * phiDelta;
phi(g + 4 * phiPitch) = answerA;
end
b = (phi > 0); % dummy matrix for edge cofficients
h = feedRate * sin(phi / 180 * pi);
Sorry if this makes no sense (just trying to help), I don't even know in what language it is written, but what I read in the original code points to something like
for i = 0:abs(phiExit - phiStart);
answerA = phiStart + i * phiDelta;
for j = 0:abs(flute - 1)
phi(i + j * phiPitch) = answerA;
end
end

Colour Difference DeltaE 2000

I am trying to Calculate the CIE Colour Difference DeltaE 2000 based on DE2000 Formula. I have done as per the formula provided in the website, but I am getting strange delta E values. I am confused where I have gone wrong. I have checked manytimes but I am not able to find the mistake.Can someone tell me which part of my code has problem.
function DE_2K = CIEDE2000(Lab1,Lab2)
labuno=Lab1
labdos=Lab2
L1=labuno(1)
a1=labuno(2)
b1=labuno(3)
L2=labdos(1)
a2=labdos(2)
b2=labdos(3)
%*******************************************************************
% Definition for CIE DE2000
%*******************************************************************
L_bar_dash=(L1+L2)/2;
C1 = sqrt((a1)^2+(b1)^2)
C2 = sqrt((a2)^2+(b2)^2)
C_bar = (C1+C2)/2
G = (1 -sqrt(((C_bar)^7)/((C_bar)^7+(25)^7))/2)
a1_dash = a1*(1+G)
a2_dash = a2*(1+G)
C1_dash = sqrt((a1_dash)^2+(b1)^2)
C2_dash = sqrt((a2_dash)^2+(b2)^2)
C_bar_dash = (C1_dash + C2_dash)/2
if (radtodeg(atan(b1/a1_dash)) >= 0 ) h1_dash = radtodeg(atan(b1/a1_dash))
else h1_dash = radtodeg(atan(b1/a1_dash)) + radtodeg(2*pi)
end
if (radtodeg(atan(b2/a2_dash)) >= 0 ) h2_dash = radtodeg(atan(b2/a2_dash))
else h2_dash = radtodeg(atan(b2/a2_dash)) + radtodeg(2*pi)
end
if ((h1_dash - h2_dash) > radtodeg(pi)) H_bar_dash = (h1_dash + h2_dash + radtodeg(2*pi))/2
else H_bar_dash = (h1_dash + h2_dash)/2
end
T = 1 - 0.17*radtodeg(cos(H_bar_dash-radtodeg(pi/6)))+0.24*radtodeg(cos(2*H_bar_dash))+0.32*radtodeg(cos(3*H_bar_dash + radtodeg(pi/30)))- 0.20*radtodeg(cos(4*H_bar_dash + 63))
if ((abs(h2_dash - h1_dash)) <= radtodeg(pi)) DE_h_dash = h2_dash - h1_dash
elseif(abs(h2_dash - h1_dash) > radtodeg(pi) && h2_dash <= h1_dash) DE_h_dash = h2_dash - h1_dash + radtodeg(2*pi)
else DE_h_dash = h2_dash - h1_dash - radtodeg(2*pi)
end
DE_L_dash = L2 - L1
DE_C_dash = C2_dash - C1_dash
DE_H_dash = 2 * sqrt(C1_dash * C2_dash) * radtodeg(sin(DE_h_dash/2))
S_L = 1 + ((0.015 * (L_bar_dash - 50)^2)/sqrt(20 + (L_bar_dash - 50)^2))
S_C = 1 + (0.045 * C_bar_dash)
S_H = 1 + (0.015 * C_bar_dash * T)
DE_angle = 30 * exp( - ((H_bar_dash - 275)/25)^2)
R_C = 2 * sqrt((C_bar_dash)^7/((C_bar_dash)^7 + (25)^7))
R_T = - R_C * radtodeg(sin(2 * DE_angle))
K_L = 1
K_C = 1
K_H = 1
DE_2K = sqrt( (DE_L_dash/(K_L * S_L))^2 + (DE_C_dash/(K_C * S_C))^2 + (DE_H_dash/(K_H * S_H))^2 + (R_T * (DE_C_dash/(K_C * S_C)) * (DE_H_dash/(K_H * S_H))))
end
There are some problems in your calculations:
a) if ((h1_dash - h2_dash) > radtodeg(pi)) : don't you need to take the abs of this?
b) 20*radtodeg(cos(4*H_bar_dash + 63) : you need -63 here
c) I assume your if-else structure correctly handles the three cases; you may need to check that:
....else DE_h_dash = h2_dash - h1_dash - radtodeg(2*pi)
d) sin is a number not in degrees, not in radians so no need to convert here:
radtodeg(sin(DE_h_dash/2))
e) same here: radtodeg(sin(2 * DE_angle))
f) I assume cos/sin take degrees; you many need to double check what is degrees what is radians everywhere.

splitting trapezoid in given proportion

I need to split trapezoid in 2 part of given size with line, parallel basement. I need to get new h1 of new trapezoid.
For example I have trapezoid of area S and I want to split it in 2 trapezoids of areas S1 and S2.
S1 = aS; S2 = (1-a)S;
S1 = (a+z)*(h1)/2;
S2 = (b+z)*(1-h1)/2;
S1/S2 = KS;
To get new h1 I compare a and b, if a != b, I solve square equation and if a == b I work like with square. But sometimes I get mistakes because of rounding (for example when I solve this analytically I get a = b and program thinks a > b). How can I handle this? Or maybe there is another better way to split trapezoid?
Here is simplifyed code:
if (base > base_prev) {
b_t = base; // base of trapezoid
h = H; //height of trapezoid
a_t = base_prev; //another base of trapezoid
KS = S1 / S2;
a_x = (a_t - b_t) * (1 + KS) / h;
b_x = 2 * KS * b_t + 2 * b_t;
c_x = -(a_t * h + b_t * h);
h_tmp = (-b_x + sqrt(b_x * b_x - 4 * a_x * c_x)) / (2 * a_x);
if (h_tmp > h || h_tmp < 0)
h_tmp = (-b_x - sqrt(b_x * b_x - 4 * a_x * c_x)) / (2 * a_x);
} else if (base < base_prev) {
b_t = base_prev;
a_t = base;
KS = S1 / S2;
a_x = (a_t - b_t) * (1 + KS) / h;
b_x = 2 * KS * b_t + 2 * b_t;
c_x = -(a_t * h + b_t * h);
h_tmp = (-b_x + sqrt(b_x * b_x - 4 * a_x * c_x)) / (2 * a_x);
if (h_tmp > h || h_tmp < 0)
h_tmp = (-b_x - sqrt(b_x * b_x - 4 * a_x * c_x)) / (2 * a_x);
}
else {
KS = S1 / S2;
h_tmp = h * KS;
}
If you're dealing with catastrophic cancellation, one approach, dating back to a classic article by Forsythe, is to use the alternative solution form x = 2c/(-b -+ sqrt(b^2 - 4ac)) for the quadratic equation ax^2 + bx + c = 0. One way to write the two roots, good for b < 0, is
x = (-b + sqrt(b^2 - 4ac))/(2a)
x = 2c/(-b + sqrt(b^2 - 4ac)),
and another, good for b >= 0, is
x = 2c/(-b - sqrt(b^2 - 4ac))
x = (-b - sqrt(b^2 - 4ac))/(2a).
Alternatively, you could use the bisection method to obtain a reasonably good guess and polish it with Newton's method.

How to accelerate matlab code?

I'm using matlab to implement a multilayer neural network. In the code I represent
the value of each node AS netValue{k}
the weight between layer k and k + 1 AS weight{k}
etc.
Since these data is three-dimensional, I have to use cell to hold a 2-D matrix to enable matrix multiply.
So it becomes really really slow to train the model, which I expect to have resulted from the usage of cell.
Can anyone tell me how to accelerate this code? Thanks
clc;
close all;
clear all;
input = [-2 : 0.4 : 2;-2:0.4:2];
ican = 4;
depth = 4; % total layer - 1, by convension
[featureNum , sampleNum] = size(input);
levelNum(1) = featureNum;
levelNum(2) = 5;
levelNum(3) = 5;
levelNum(4) = 5;
levelNum(5) = 2;
weight = cell(0);
for k = 1 : depth
weight{k} = rand(levelNum(k+1), levelNum(k)) - 2 * rand(levelNum(k+1) , levelNum(k));
threshold{k} = rand(levelNum(k+1) , 1) - 2 * rand(levelNum(k+1) , 1);
end
runCount = 0;
sumMSE = 1; % init MSE
minError = 1e-5;
afa = 0.1; % step of "gradient ascendence"
% training loop
while(runCount < 100000 & sumMSE > minError)
sumMSE = 0; % sum of MSE
for i = 1 : sampleNum % sample loop
netValue{1} = input(:,i);
for k = 2 : depth
netValue{k} = weight{k-1} * netValue{k-1} + threshold{k-1}; %calculate each layer
netValue{k} = 1 ./ (1 + exp(-netValue{k})); %apply logistic function
end
netValue{depth+1} = weight{depth} * netValue{depth} + threshold{depth}; %output layer
e = 1 + sin((pi / 4) * ican * netValue{1}) - netValue{depth + 1}; %calc error
assistS{depth} = diag(ones(size(netValue{depth+1})));
s{depth} = -2 * assistS{depth} * e;
for k = depth - 1 : -1 : 1
assistS{k} = diag((1-netValue{k+1}).*netValue{k+1});
s{k} = assistS{k} * weight{k+1}' * s{k+1};
end
for k = 1 : depth
weight{k} = weight{k} - afa * s{k} * netValue{k}';
threshold{k} = threshold{k} - afa * s{k};
end
sumMSE = sumMSE + e' * e;
end
sumMSE = sqrt(sumMSE) / sampleNum;
runCount = runCount + 1;
end
x = [-2 : 0.1 : 2;-2:0.1:2];
y = zeros(size(x));
z = 1 + sin((pi / 4) * ican .* x);
% test
for i = 1 : length(x)
netValue{1} = x(:,i);
for k = 2 : depth
netValue{k} = weight{k-1} * netValue{k-1} + threshold{k-1};
netValue{k} = 1 ./ ( 1 + exp(-netValue{k}));
end
y(:, i) = weight{depth} * netValue{depth} + threshold{depth};
end
plot(x(1,:) , y(1,:) , 'r');
hold on;
plot(x(1,:) , z(1,:) , 'g');
hold off;
Have you used the profiler to find out what functions are actually slowing down your code? It shows what lines take the most time to execute.

Resources