Wednesday, August 27, 2008

A14 -Stereometry

I have acquired the images. Still processing...


Above are two images of the same object at slightly different perspectives (The object was moved to the right by 15cm).

My code:

f = 6; //focus

b = 150;

M1 = imread('C:\Documents and Settings\AP186user20\Desktop\august12_2008\Cube1.jpg');

M2 = imread('C:\Documents and Settings\AP186user20\Desktop\august12_2008\Cube2.jpg');

M1 = im2gray(M1);

M2 = im2gray(M2);

imshow(M1,[]);

M2 = im2gray(M2);

imshow(M1,[]);

x1 = locate(10,1);

imshow(M2,[]);

x2 = locate(10,1);

z = b*f/(x2(1,:) - x1(1,:));
nx = 40;

ny = 40;

x = linspace(1,1,nx);

y = linspace(1,1,ny);

[XP,YP] = ndgrid(x,y);
ZP = interp2d(XP, YP, x1(1,:), x1(2,:), splin2d(x1(1,:), x1(2,:), z, "natural"));
//plot(x2(1,:),x2(:,1), z);

mesh(ZP)

SELF-GRADE: 6/10, hindi ko pa yari

Thanks to Beth for pictures, Rica and Aiyin for storage

Monday, August 18, 2008

A12 - Geometric Distortion Correction

August 19, 2008

We have an image of a Capiz window, an analog to a grid, whose left side is slightly tilted. We aim to correct this distortion by creating an ideal grid, then mapping into it the grayscale values of the corresponding pixels in the distorted image.


First, we choose an eminently distorted area in the image. This area is covered by a rectangle in figure 1. We designate the rectangle to be the ideal polygon, how the shape of the set of small squares in the window appear. The ideal polygon vertices are labeled as [xi, yi] , while the vertices of the distorted area are tagged as [x^i, y^i].

The transformation of [x, y] to [x^, y^] can be expressed by a function r and s.
x^ = r(x,y)
y ^ = s(x,y) (1)
If the polygon is not too large, we could assume that the transformations for both directions happen linearly. Thus, we guess.
x^ = c1x + c2y + c3xy + c4
y^ = c5x + c6y + c7xy + c8 (2)
From equation (2), we could obtain the transformation vectors C14 = [c1, c2, c3, c4]t and
C58 = [c5, c6, c7, c8] t, where t stands for transposed via
C14 = (inv(T) ) X
C58 = (inv(T) ) Y
where inv means inv(T) means the inverse of T, T is a 4 by 4 matrix with row i given by [xi, yi, xiyi, 1], X = [[x^1,x^2, x^3, x^4] t and Y = [y^1, y^2, y^3, y^4] t.

In the ideal rectangle, we find the corresponding pixel in the distorted image. If the corresponding coordinates are integer-valued, we simply duplicate the point intensity value into the ideal space. Otherwise, we employ the bilinear interpolation wherein if x^ or y^ is not an element of the set of integers, the value at (x^, y^) is given by
v(x^,y^) = ax^ + by^ + cx^y^ + d (3)
To find the unknowns a, b, c and d, we use the nearest neighbors of (x^,y^).

We, see that the image has been quite corrected. The sides of the squares without using bilinear interpolation are crooked. Meanwhile, the sides of the squares when bilinear interpolation was employed were straight, though the resulting image had less contrast,

//1 Call the image
M = imread('D:\ap187\distorted_capiz_window.jpg');
M = im2gray(M);
imshow(M,[]);
[m,k] = size(M);

//2 Select large subgrid vertices
g = locate(4,1);
g = [46.723164 238.70056;
99.265537 239.83051;
100.96045 41.525424;
50.112994 40.960452 ];
gprime(:,1) = g(:,2);
gprime(:,2) = g(:,1);
gprime(:,1) = abs(gprime(:,1) - m - 1);
//3 Generate ideal grid
x_1 = gprime(1,1);
x_2 = gprime(1,1);
x_3 = gprime(3,1);
x_4 = x_3;
y_1 = gprime(1,2);
y_2 = gprime(2,2);
y_3 = gprime(2,2);
y_4 = gprime(1,2);

//4 Obtain transformation matrix C
T = [x_1 y_1 x_1*y_1 1;
x_2 y_2 x_2*y_2 1;
x_3 y_3 x_3*y_3 1;
x_4 y_4 x_4*y_4 1];

X = gprime(:,1);
Y = gprime(:,2);

C14 = (inv(T))*X;
C58 = (inv(T))*Y;

//5 Map the distorted image into the ideal space (w/ bilinear interpolation)
v = zeros(m,k);

for x = 5:m-5;
for y = 5:k-5;
t = [x y x*y 1];
xhat = t*C14;
yhat = t*C58;
xhat_integer = int(xhat);
yhat_integer = int(yhat);

if xhat_integer == xhat & yhat_integer == yhat then
if xhat_integer == 0 then
xhat_integer = 1;
end
if yhat_integer == 0 then
yhat_integer = 1;
end

v(x,y) = M(xhat_integer, yhat_integer);

else
xplus = xhat_integer + 1;
xminus = xhat_integer;
yplus = yhat_integer + 1;
yminus = yhat_integer;

nearestneighbors = [xplus yplus xplus*yplus 1;
xplus yminus xplus*yminus 1;
xminus yminus xminus*yminus 1;
xminus yplus xminus*yminus 1];

vhat = [M(xplus,yplus); M(xplus,yminus); M(xminus,yminus); M(xminus,yplus)];
a_b_c_d = inv(nearestneighbors)*vhat;
nu = [x y y*x 1];
v(x,y) = nu*a_b_c_d;
end
end
end

//6 Mapping without bilinear interpolation
v2 = zeros(m,k);

for x = 5:m-5;
for y = 5:k-5;
t = [x y x*y 1];
xhat = t*C14;
yhat = t*C58;
xhat_integer = int(xhat);
yhat_integer = int(yhat);
v2(x,y) = M(xhat_integer, yhat_integer);
end
end

//7 Showing the images, M - original, v - corrected with interpolation, v2 - corrected without interpolation
subplot(221)
imshow(M,[]);
subplot(222)
imshow(v2,[]);
subplot(223)
imshow(v3,[]);

I give myself 7/10 because it took me this long to solve the problem.

Thank you to Mark Leo for some explanations.





Wednesday, August 6, 2008

A13 - Photometric Stereo

August 7, 2008
We have 4 synthetic images, namely I1, I2, I3 and I4, of a sphere illuminated from 4 different directions.
The illumination matrix is a composite of 4 vectors given by
V1 = [0.085832 0.17365 0.98106]
V2 = [0.085832 -0.17365 0.98106]
V3 = [0.17365 0 0.98481]
V4 = [0.16318 -0.34202 0.92542].



The illumination is from an infinitely far away source. The relationship between the reflected intensity I, the illumination vector L and the object surface normal N is given by
I = L*N (1).

Since we know I and L, we could get the surface normals via
g = [(inv(V'V))V'] I (2).
We normalize g by dividing by its magnitude to obtain the normalized surface normal
n^ = g/|g| (3).
This components of the normal vector can be transformed to the partial derivatives by using the relation
df/dx = -nx/nz and df/dy = -ny/nz.
The derivatives are then integrated via line integration to obtain the surface profile of the hemisphere (See Figure )2. The drawback of using line integration is that it produces small spikes in the reconstruction.


code:
loadmatfile('C:\Documents and Settings\AP186user20\Desktop\august7_2008\photos.mat',['I1','I2','I3','I4']);
subplot(221)
imshow(I1,[]);
subplot(222)
imshow(I2,[]);
subplot(223)
imshow(I3,[]);
subplot(224)
imshow(I4,[]);
[m,k] = size(I1)
I = [I1(:)'; I2(:)'; I3(:)';I4(:)'];
V = [0.085832 0.17365 0.98106;
0.085832 -0.17365 0.98106
0.17365 0 0.98481
0.16318 -0.34202 0.92542];
MoorePennrose = (inv(V'*V))*V';
g = MoorePennrose*I;
[M,K] = size(g);
for i = 1:M;
for j = 1:K;
absolutevalue = sqrt( g(1,j)*g(1,j) + g(2,j)*g(2,j) + g(3,j)*g(3,j) );
n(i,j) = g(i,j)./(absolutevalue + 1.0e-015);
end
end
//derivative along the x-axis
p = -n(1,:)./(n(3,:)+1.0e-20);
//derivative along the y-axis
q = -n(2,:)./(n(3,:)+1.0e-20);

Imagexderivative = matrix(p,m,k);
Imageyderivative = matrix(q,m,k);
x=cumsum(Imagexderivative,2);
y= cumsum(Imageyderivative,1);
Image = x+y;
mesh(Image);
Reference
[1]. Dr. Soriano's lecture notes

Self-grade: 10/10

Thursday, July 31, 2008

A11 - Camera Calibration

July 31, 2008



In this activity, we try to align the world coordinate system, which pertains to the real three-dimensional world of an object, with the two-dimensional image coordinate system captured by a camera.


We get the transformation matrix that would translate all world coordinates to the image coordinates. This transformation matrix depends on the angle the optic axis makes with respect to the object to be captured and on the intrinsic properties of the camera which are mainly affected by its focus. Denoted by A, it can be found by first realizing that













(Equation taken from Dr. Maricor Soriano's lecture notes.)


where xo, yo, zo are real world coordinates and yi, zi are image coordinates. Thus, A is given by

A = [ (inv(Q'Q)) Q'] d

where Q is the first matrix given in equation 1 and d is the column vector at the the right hand side of the equation. When there are N sample points, Q is a 2N x 11 matrix while d has a dimension of 2N x 1.

After we have determined A, we tried to predict the image coordinates of world points that were not previously sampled. The whole process is summarized by figure 1. A celfone camera was used to capture a checkerboard with two arms positioned perpendicular to each other. Each cell in the checkerboard is 1 inch x 1 inch. Twenty-five random points and their 2D projection on the image plane were used to determine the transformation matrix. Afterwards, the position in the image of five other points were interpolated using the transformation matrix. With the z plane in the real world chosen to be vertical, the left arm was designated to be the xz plane. The right arm is then the yz plane.

We could see that the predictions are accurate since some points even blocked the labeling numbers. Prediction #2, which missed the theoretical position, is not too far from where it should be.
























Self-grade: 10/10
Credits: Benj for some clarifications on the later part of the problem


//Camera Calibration
//1 Image space
d = [135 138;230 165;177 188;229 259;178 91;279 141;261 216;110 213;244 89;159 260;179 233;135 89;315 137;36 137;63 266;64 58;315 311;63 322;317 21;39 32;38 242;180 47;336 227;88 189;297 53];
//2 Object space
s = [3.5 0 1.5;0 1.5 0.5;1.5 0 -0.5;0 1.5 -3.5;1.5 0 3.5;0 4.5 1.5;0 3.5 -1.5;4.5 0 -1.5;0 2.5 3.5;2.5 0 -3.5;1.5 0 -2.5;3.5 0 3.5;0 6.5 1.5;7.5 0 1.5;6.5 0 -3.5;6.5 0 4.5;0 6.5 -4.5;6.5 0 -5.5;0 6.5 5.5;7.5 0 5.5;7.5 0 -2.5;1.5 0 5.5;0 7.5 -1.5;5.5 0 -0.5;0 5.5 4.5];
//3 Finding the transformation matrix a
Q = zeros(50, 11);
i = 1;
j = 2*i-1;
while i<>
Q(j,1:3) = s(i,1:3);
Q(j,4) = 1;
Q(j,5:8) = 0;
Q(j,9:11) = -d(i,1)*s(i,1:3);
Q(j+1,1:4) = 0;
Q(j+1,5:7) = s(i,1:3);
Q(j+1,8) = 1;
Q(j+1,9:11) = -d(i,2)*s(i,1:3);
i = i+1;
j = 2*i-1;
end;
d = matrix(d',50,1);
a = inv(Q'*Q)*Q'*d;
//Predicting the image coordinates of unsampled world points
test = [3 0 0 1;0 5 -3 1;0 3 2 1;1 0 2 1;3 0 -2 1];
newd = a*test';
newd = matrix(newd,5,3);
newd = newd';
[m,k] = size(M);
overlay = zeros(m,k);
for i = 1:size(newd,2);
overlay(round(newd(2,i)),round(newd(1,i))) = 1;
end
M = imread('D:\ap186\july29_2008\cropped.jpg');
M = im2gray(M);
subplot(121)
imshow(M,[]);
subplot(122)
imshow(overlay);

Wednesday, July 23, 2008

A11 - Preprocessing Handwritten Text







First, we get chose a portion of the grayscaled image. Then we, removed the vertical lines by knocking-out the frequencies in the Fourier transform of the image that correspond to vertical lines. These are those frequencies that lie along the vertical axis of the shifted FFT. So the mask used was a black vertical strip with a hole in the middle so as not to remove the DC component of the image.





















Next, I binarized the image. I used thresholds = 80, 90 and 100 intensity values and found out that threshold = 80 is the best. So I, tried applying the operations closing of holes and opening of holes for the image and also opening the holes for holes-closed image. I think that the image became cleaner after performing closing of holes only. Next, I thinned the characters/regions into one pixel. The final image is shown in figure 6. While not all letters are recognizable, the letters U,P and S have been, in my opinion, enhanced.
















Enjoy mag-label ng continuous regions.
Code:
//1 Calls the image and converts it to grayscale
M = imread('D:\ap186\july20_2008\toEnhance3.jpg');
M = im2gray(M);
M = M-min(min(M));
M = 255*M/max(max(M));

//3 Shows the FFT of the best binarized image,K2
FM = fft2(M);
FMshift = fftshift(abs(FM));
//4 Creation of a mask to filter the horizontal and vertical lines in the image
[m,n] = size(M);mask = ones(m,n);
mask(:,n/2-5:n/2+5) = 0;mask(m/2-3:m/2+3,n/2-3:n/2+3) = 1;

//5 Shows the image FFT and the mask to be used
subplot(121)
imshow(log(FMshift),[]);
subplot(122)
imshow(mask);

//6 Filtering of the lines; the new image is called H
FHM = FM.*fftshift(mask);
H = abs(ifft(FHM));

//7 Shows the original image, the filtered image, and the latter's FFT
subplot(131)
imshow(M,[]);
subplot(132)
imshow(H,[]);
subplot(133);
imshow(fftshift(abs(FHM)),[]);
H = H-min(min(H));
H = 255*H/max(max(H));
subplot(221)
histplot([0:255],H);
subplot(222)
L1 = im2bw(H,90/255);
L1 = 1-abs(L1);
imshow(L1);
subplot(223);
L2 = im2bw(H,100/255);
L2 = 1-abs(L2);
imshow(L2);
subplot(224);
L3 = im2bw(H,110/255);
L3 = 1-abs(L3);
imshow(L3);

//Close or Open holes for L1
L = ones(2,2);
zero = zeros(2,2);
negL = abs(zero-L);
D = dilate(L1,negL);
Close = erode(D,negL);
E = erode(Close,L);
Open = dilate(E,L);

subplot(221)
imshow(L2);
subplot(222)
imshow(Close);
subplot(223)
imshow(Open);
subplot(224)
thn = thin(Close);
imshow(thn);
lbl = bwlabel(thn);
imshow(lbl,jetcolormap(max(max(lbl))));
Grade: 8/10
processed image is not so readable

A10 - Morphological Operations














We tried to get the best estimate of the area of a punched paper by statistical analysis of a set of punched papers. We cut the image into six sub-images such as the one in figure 1 and converted them into grayscale. We looked at the histogram of their intensity values and determined that the threshold value should be set at intensity = 200.










We then performed the Morphological operations of opening and closing of holes to see what would happen. Opening of holes means to dilate with a structuring element L the image eroded with L. Closing of holes means to erode with the reflection of L the image dilated by the reflection of L. It seems that closing of holes had a better effect of producing a cleaner binary image. So I chose to continue processing this.



As shown in figure 3, the closed regions were labeled with a specific number. The area of each labeled region is determined by pixel counting.




























The histogram of the above sample is merged with the histograms of other subimages. The result is the histogram shown above. It seemed that the histogram needed no further noise eradication. The best estimate for the area was 549 px.

To check, we get the number of included pixels in a binarized image of a single punched paper. It was 519. The deviation of the best estimate from this value was around 6%.














Code:
for i = 1:7;
//1 Call image, transform it to black-and-white
M = imread(strcat(string(i)+'.jpg'));
M = im2gray(M);M = M*255;
//subplot(121)
//imshow(M,[]);
//subplot(122)
//histplot([0:255],M);
threshold = 200;
K = im2bw(M,threshold/255);
//2 Close-openL = ones(5,5);
zero = zeros(5,5);
negL = abs(zero-L);
E = erode(K,L);
D = dilate(K,negL);
Open = dilate(E,L);
Close = erode(D,negL);
subplot(131)
imshow(K);
subplot(132)
imshow(Close);
subplot(133)
imshow(Open);
//3 Label Opened image because it looks good
lbl = bwlabel(Open);
N = max(max(lbl));
//imshow(lbl,jetcolormap(N));
//4 Count area of each similarly labeled region
Area = zeros(7,N);
for j = 1:N; [x,y] = find(lbl == i);
Area(i,j) = length(x);
end
end
histplot([1:max(max(Area))],Area);
mn = mean(mean(Area))
std = stdev(Area)
//5 Eradicate noiseupperbound = mn + std + 1;
lowerbound = mn - std - 1;
Area = Area.*(Arealowerbound);
histplot([1:max(area)],Area);

Credits:

Lei Uy and Beth Prieto for helpful discussions, Benj Palmares for help in histogramming.

Self-evaluation: 9/10

I fell happy when labelling the regions because the resulting image is colorful

Wednesday, July 16, 2008

A9 - Binary Operations


July 17, 2008

The goal of this activity is to perform area estimation of cells represented by punched paper.

In figure 1, part of the entire image is binarized using a threshold pixel value that is equal to 200 where the valley in the histogram occurs.
















Next, we performed higher order morphological operations on the binarized image: opening of holes and closing of holes. We let M be the original image, K the binary image and L the structuring element. The two operations are implemented in SciLab as

M = imread('C:\Documents and Settings\AP186user20\Desktop\Circles1.jpg');
M = M - 1;
histplot([0:255,M);
threshold = 200;

K = im2bw(M,threshold/255);
L = ones(5,5);
zero = zeros(5,5);
negL = abs(zero-L);
E = erode(K,L);
D = dilate(K,negL);
Open = dilate(E,L);
Close = erode(D,negL);





















R
eference:
[1] http://www.ph.tn.tudelft.nl/Courses/FIP/noframes/fip-Morpholo.html#Heading98