Wednesday, June 25, 2008

A4 - Enhancement by Histogram Manipulation

HISTOGRAM MANIPULATION: LINEAR CDF

This activity is designed to improve the quality of an image by manipulating its histogram. Histogram manipulation enhances certain image features such as brightness and contrast. The image below is a good example for histogram manipulation since as shown, the image seems to be too dark.


*http://www.dphclub.com/tutorials/images/war-time-1.jpg

The observation that the image is dark is supported by plotting its histogram. The histogram of a grayscale image is equal to the graylevel probability distribution function (PDF) if normalized by the total number of pixels. (AP186 Notes, Maricor Soriano, 2008) Observe that pixel values of the image cluster on the darker region of the PDF, that is near the lower values of the gray level. The lowest pixel value of the image is equal to 15 while the highest is 114.



We then get the Cumulative Distribution Function (CDF) of the image from its PDF, simply by getting the cumulative sum of the values in the PDF.



The CDF is nonlinear and the values cluster on the darker region of the CDF. We then use this CDF to map each pixel of the original image to a new array with the CDF as the mapping function. The resulting image is shown below.



As observed, the image is much brighter than the original. This is because, after mapping the original image using its CDF, the pixel values of the image is 'stretched' within the 0-255 gray levels, therefore values where evenly distrbuted within the gray level The histogram plot below signifies that a slightly even distribution actually happened.


Since the values were evenly distributed (relatively) among the gray levels, the expected CDF must be linear. The 'ringings' on the lower part is caused by contributions from the darker gray levels which are relatively more than those present in the lighter side. (see histogram) This is again due to the fact that the original image has more darker values than lighter ones.

Here is the code I used:
---

getf('imhist.sci');

im=imread('image_tc.jpg'); //opens a 24 bit image
im=im(:,:,1);
imwrite(im(:,:), 'image_gs.jpg'); //converts to 8 bit grayscale image
im=imread('image_gs.jpg'); //saves the grayscale image
[val,num]=imhist(im);
imsize=size(im,1)*size(im,2);
normCDF=cumsum(num/imsize);
h=scf(1); plot(val, num/imsize);
h=scf(2); plot(val,normCDF);

//pixel mapping using CDF of image
imnew=[];
for i=1:size(im,1)
for j=1:size(im,2)
imnew(i,j)=normCDF(find(im(i,j)==val));
end
end

imwrite(imnew,'image_enhanced.jpg'); // saves enhanced image after mapping
imenhanced=imread('image_enhanced.jpg');
[val,num]=imhist(imenhanced);
imsize=size(imenhanced,1)*size(imenhanced,2);
normCDF=cumsum(num/imsize);
h=scf(3); plot(val, num/imsize);
h=scf(4); plot(val,normCDF);
---
***imhist.sci is the histogram plotting code written by Jeric Tugaff


HISTOGRAM MANIPULATION: NON-LINEAR CDF

Below is a flowchart of pixel backprojection using a non-linear CDF, as summarized by Dr. Maricor Soriano in her lecture notes.



The following is an enhanced image after mapping the original pixel values using a nonlinear CDF given by the equation G=1/2+ 1/2(tanh(16*((z-128)/255))) where z is from 0-255.



The histogram of this enhanced image is shown below with its CDF as well. The blue plot is the CDF used for mapping while the red plot is the CDF of the enhanced image. The difference in the CDF is probably due to the interpolation method I used in pixel backprojection. (click CDF plot for a clearer view)


I observed that the sigmoid CDF I used didn't enhance the image well as seen with the naked eye. I experimented with using a parabolic function as my desired CDF.

G=(z.^2);
G=G/max(G);

where z is again between 0-255. I divided it with its maximum value to obtain a function with 1 as the highest value. The enhanced image is shown below.



Below is the histogram and CDF of this image. The blue plot is the desired CDF, red plot is the CDF of the enhanced image. (click CDF plot for a clearer view) The difference in the CDF is probably due to the interpolation method I used in pixel backprojection.


Here is the code I used:
---

getf('imhist.sci');

im=imread('image_tc.jpg'); //opens a 24 bit image
im=im(:,:,1);
imwrite(im(:,:), 'image_gs.jpg'); //converts to 8 bit grayscale image
im=imread('image_gs.jpg');
[val,num]=imhist(im);
imsize=size(im,1)*size(im,2);
normCDF=cumsum(num/imsize);
h=scf(1); plot(val, num/imsize);
h=scf(2); plot(val,normCDF);

z=[0:255];
G=(1+(tanh(16*((z-128)/255))))/2;
//G=(z.^2);
//G=G/max(G);
h=scf(5); plot(z,G,'b');

imnew=[];
imnew2=[];
for i=1:size(im,1)
for j=1:size(im,2)
imnew(i,j)=normCDF(find(im(i,j)==val));
end
end

imnew2=interp1(G,z,imnew);
imnew2=round(imnew2);
h=scf(3); imshow(imnew2,[0 255]);

[val,num]=imhist(imnew2);
imsize=size(imnew2,1)*size(imnew2,2);
normCDF=cumsum(num/imsize);
h=scf(4); plot(val, num/imsize);
h=scf(5); plot(val,normCDF,'r');
---
***imhist.sci is the histogram plotting code written by Jeric Tugaff

--o0o--

Collaborator: Jeric Tugaff
...thank you for the histogram plotting code and for the interp1 syntax

--o0o--
Grade: 10/10 since image was enhanced thru histogram manipulation and that CDF of enhanced image is almost the same as that of the desired CDF, especially for the nonlinear part.

Tuesday, June 24, 2008

A3 - Image Types and Basic Image Enhancements

Image Types

1. Truecolor Image


*photographed by Kate Dado

FileName: truecolor.jpg
FileSize: 35662
Format: JPEG
Width: 300
Height: 400
Depth: 8
StorageType: truecolor
NumberOfColors: 0
ResolutionUnit: inch
XResolution: 72.000000
YResolution: 72.000000

2. Grayscale Image


*http://www.jnevins.com/Angelwebgrayscale.jpg

FileName: grayscale.jpg
FileSize: 47925
Format: JPEG
Width: 378
Height: 504
Depth: 8
StorageType: indexed
NumberOfColors: 256
ResolutionUnit: inch
XResolution: 72.000000
YResolution: 72.000000

3. Indexed Image


*http://imgtops.sourceforge.net/bakeoff/o-png8.png

FileName: indexed.png
FileSize: 139332
Format: PNG
Width: 400
Height: 400
Depth: 8
StorageType: indexed
NumberOfColors: 256
ResolutionUnit: centimeter
XResolution: 72.000000
YResolution: 72.000000

4. Binary Image

Shown below is a truecolor image of a flower.


*photographed by Kate Dado

To obtain a binary image from this truecolor image, I first converted it to grayscale using the following code.

im=imread('flower.jpg');
im=im(:,:,1);
imwrite(im,'flower_gs.jpg');



I then examined the histogram of flower_gs.jpg using...

(a) GIMP



and

(b) SciLab Histogram Plotting Code (© Jeric Tugaff)

im=imread('flower_gs.jpg');
val=[];
num=[];
counter=1;
for i=0:1:255
[x,y]=find(im==i);
val(counter)=i;
num(counter)=length(x);
counter=counter+1;
end
plot(val, num);


From the histogram, we see that there are two significant clusters of pixel values, one on the black side (0) and one on the white side (255). Therefore, we can choose a value for thresholding the image to separate the background from the region of interest (ROI), by simply examining the image histogram. Then we incorporate this threshold value to convert flower_gs.jpg to binary.

thresh=150;
im=im2bw(im,thresh/255);


FileName: binary.gif
FileSize: 19608
Format: GIF
Width: 400
Height: 300
Depth: 8
StorageType: indexed
NumberOfColors: 256
ResolutionUnit: centimeter
XResolution: 72.000000
YResolution: 72.000000

Thresholding and Area Calculation Part 2

Thresholding is done by examining the histogram of an image, as detailed above. Shown is a scanned image of a leaf.

im=imread('leaf.jpg');



For purposes, which I'll explain later, I cropped the image.**

im=imread('cropleaf.jpg');



This is a truecolor image, and so, I first converted it to grayscale to obtain its histogram.

im=imread('cropleaf_gs.jpg');





Two peaks are evident on the histogram, a hint that the image is of good quality, and that we can separate the leaf from the background. We then again find a threshold to be used for converting the image into binary.

thresh=175;
im=im2bw(im,thresh/255);




To calculate the area of the leaf, using Green's theorem (see this), we first incorporate the following code.

im=1-im;



Effectively, this inverts the pixel values such that the area bounded by the contour of the leaf would be 1's (white) and those outside are 0's (black). This is important since what we are going to calculate the area of the leaf, not the area outside the leaf (or the background).

Using Green's theorem, the area calculated is 21466.5 pixels.

Comparing this with the area calculated using pixel counting* which is 21967 pixels, we see a 2.28% difference between them.

*ImageArea=sum(im);
//summing can be done since we know that the value inside the contour of the leaf are all 1's and that outside are 0's, and therefore summing the whole image will just result to the area (in pixels) of the leaf.

**The image of the leaf was cropped so that the ruler won't be included in the area calculation.

---
Thanks to...
Jeric Tugaff for the histogram plotting code. :)

---
Rating: 10/10
since a 2.28% difference between the two methods for area calculation is within the 5% acceptable limit.

Wednesday, June 18, 2008

A2 - Area Estimation for Images with Defined Edges

Activity 2 - Area Estimation for Images with Defined Edges

The goal of this activity is to get the area of a regular geometric image (i.e. circle, rectangle, triangle). To do this, we use the 'follow' command in SIP toolbox of SciLab to obtain the edge pixel values of an image and then use these values (these values form the contour of the shape) to obtain the area bounded by this contour using Green's theorem.

*AP 186 A2-Area Estimation for Images with Defined Edges, M. Soriano, 2008

The following illustrates the code which I used in implementing Green's theorem for computing areas bounded by a contour.

---
//Area Estimation for Images with Defined Edges
//Julie Mae B. Dado
//AP186

TestImg=imread('C:\Documents and Settings\AP186user03\Desktop\rect.jpg');
TestImg=im2bw(TestImg,0.5);
//imshow(TestImg);

[x,y]=follow(TestImg);
size_x=length(x);
size_y=length(y);

x1(1)=x(size_x);
x1(2:size_x)=x(1:size_x-1);

y1(1)=y(size_y);
y1(2:size_y)=y(1:size_y-1);

area=0.5*sum((x1.*y)-(y1.*x));

//theoretical area
tarea=(max(x)-min(x))*(max(y)-min(y)); //rectangle or square
//tarea=%pi*(((max(x)-min(x))/2)^2); // circle
//tarea=0.5*(max(x)-min(x))*(max(y)-min(y)); //triangle

---

RESULTS:
*Image size: 63x71
Test Image 1: Rectangle


Area Computed Using Green's Theorem: 1763
Theoretical Area (pixel count): 1763
% Error: 0%

Test Image 2: Triangle
Area Computed Using Green's Theorem: 876.5
Theoretical Area (pixel count): 860
% Error: 1.9%

Test Image 3: Circle (large)
Area Computed Using Green's Theorem: 1658
Theoretical Area (pixel count): 1661.9
% Error: 0.23%

Test Image 4: Circle (medium)
Area Computed Using Green's Theorem: 341
Theoretical Area (pixel count): 346.4
% Error: 1.6%

Test Image 5: Circle (small)
Area Computed Using Green's Theorem: 64
Theoretical Area (pixel count): 78.5
% Error: 18.5%

Observations:
1. Maximum differences between area estimation using Green's theorem (that is, obtaining pixel values for the contour) and analytical estimation of area using pixel counting were observed for circular shapes while minimum errors were observed for rectangular shapes. This error can be accounted for the pixel shape which are actually small squares. Circular shapes relatively do not have smooth contours. (this may be observed if you zoom in on a circular image)

2. For circle with smaller radii, the errors are larger. This is because the smaller the radius, the less number of pixels used to estimate the smooth shape of the circle.

3. Area estimation by obtaining pixel values of a contour used for Green's theorem are somehow limited shapes with straight sides. This technique somehow isn't suited for smooth contours unless pixel values are compensated such that it can approximate the shape with less error.

---
Thanks to...
Jeric for helping me debug my program whenever it doesn't work and for showing me how to obtain theoretical area using pixel counting.

---
Grade: 7/10
because I had a hard time debugging simple errors and that I pretty much didn't analyze how to obtain area using pixel counting.

Wednesday, June 11, 2008

A1 - Digital Scanning

I obtained this plot from Canadian Journal of Physics dated 1953.

The following table shows the pixel locations of the tick marks for both X and Y axes of the digitally scanned plot.

along x

points px py
0 140 1129
0.2 271 1129
0.4 401 1129
0.6 531 1129
0.8 661 1129
1 791 1129



along y

points px py
0 140 1129
4 140 994
8 140 859
12 140 724
16 140 589
20 140 457
24 140 324
28 140 190
32 140 60

To obtain a conversion factor (pixel/unit) for each axis, simply count the number of pixels that lie within each tick mark. For cases wherein the number of pixels within tick marks of one axis ( Y-axis in my case) varies, average the values to obtain a general conversion factor. The values I obtained are the following:

x-axis: 130.2 pixels/unit (unit in this case, means, within one tick mark)
y-axis: 133.625 pixels/unit

These values are then used to obtain physical values of the points on the graph. The next step is to get the pixel values of the points the graph. I obtained the following for the scanned plot shown above.

px py
203 998
267 936
331 879
398 824
461 773
528 722
591 665
658 602
721 459
780 58

Using the conversion factor (pixel/unit) for both axes, I obtained the following physicals values by dividing the pixel values with the conversion factor. (i.e. px/130.2 for x location values)
x y
1.559139785 7.468662301
2.050691244 7.004677268
2.542242704 6.578110384
3.056835637 6.166510758
3.540706605 5.78484565
4.055299539 5.403180543
4.539170507 4.976613658
5.053763441 4.505144995
5.537634409 3.434985968
5.99078341 0.434050514
I then used Excel to plot these values and see if the same trend as the scanned plot will be observed. (Note: Image origin is different from Excel. Image origin is on the upper left corner of the image while Excel is on the lower left. For comparison, in plotting the physical values in Excel, plot values in reverse order.) This is how the plot in Excel looks The trend is much obvious with the original image superimposed on the plot. ...
Rating
10 - The trend I obtained in re-plotting the scanned copy was similar to the original plot.
...

Thanks to...

...Benj Palmares for helping with the Excel, especially with superimposing the original image.
...Jeric Tugaff for pointers in paint. _________________________________________________________________________________

A1 - Digital Scanning
EDITED VERSION: posted June 19, 2008
I obtained this plot from Canadian Journal of Physics dated 1953.

The following table shows the pixel locations of the tick marks for both X and Y axes of the digitally scanned plot.





along x



points px py
pixel values included within each tick mark
0 136 1126
135
0.2 271 1126
130
0.4 401 1126
131
0.6 532 1126
131
0.8 663 1126
131
1 794 1126 average 131.6






along y



points px py
pixel values included within each tick mark
0 136 1126
134
4 136 992
133
8 136 859
135
12 136 724
135
16 136 589
132
20 136 457
134
24 136 323
133
28 136 190
131
32 136 59 average 133.375

To obtain a conversion factor (pixel/unit) for each axis, simply count the number of pixels that lie within each tick mark. Then, average the values to obtain a general conversion factor. The values I obtained are the following:

x-axis: 131.6 pixels/one tick mark
y-axis: 133.375 pixels/one tick mark

These are then used to obtain physical values of the points on the graph. The next step is to get the pixel values of the points the graph. I obtained the following for the scanned plot shown above.

px py
203 998
267 936
331 879
398 824
461 772
528 721
590 665
658 602
721 458
780 58

Using the conversion factor for both axes, I obtained the following physicals values by dividing the pixel values with the conversion factor. (i.e. px/131.6 for x location values). These physical values, however, should be biased in order to properly correlate the points with those present in the image. Therefore, for both x and y, I subtracted the physical value of the origin from x physical values and y physical values (i.e. x biased = x-(136/131.6) and y biased = y-(1126/133.375)).

x y
1.542553191 7.482661668
2.02887538 7.017806935
2.515197568 6.590440487
3.024316109 6.178069353
3.503039514 5.78819119
4.012158055 5.405810684
4.483282675 4.985941893
5 4.513589503
5.478723404 3.433926898
5.927051672 0.434864105

x biased y biased
0.509118541 -0.959700094
0.995440729 -1.424554827
1.481762918 -1.851921275
1.990881459 -2.264292409
2.469604863 -2.654170572
2.978723404 -3.036551078
3.449848024 -3.456419869
3.96656535 -3.928772259
4.445288754 -5.008434864
4.893617021 -8.007497657

I then used Excel to plot these values and see if the same trend as the scanned plot will be observed. This can be done because the points which are now biased according to the origin can be plotted in a manner that will coincide with your scanned image given that you overlay a properly cropped image, that is cropped at the pixel value of the origin. One should also be careful in overlaying the image to your Excel plot, therefore check the limits of both your x and y axes to see if proper correlation with your cropped image is observed. The following shows the Excel plot.

The following shows the Excel plot with an overlay of the cropped image.

---
Thanks to...

... Dr. Maricor Soriano for pointing out my mistake, giving tips on how to correct that mistake and for giving me a second chance at a 10. :)