Once we have selected the region of interest, we will slice like a pizza!
Yummy! [1]
Any shape can be divided into several slices, such as in the following image:
Figure 1: Map of the United States of America. Or better yet, United Slices of America. [2]
By separating them into smaller triangles/ slices of pizza, we can approximate the area of the entire region by simply adding the area of all the triangles. But it would be troublesome to have weird shapes that will not provide us simple triangular shapes, as what you might see at the upper right part of Figure 1. If we were to measure such a region, we should segment it not just radially. Can't imagine how to solve it? Me neither. Well, not for now. Maybe next time. :P
So here, we will be limited to the application on simple shapes generated using Paint. Why Paint? For one, I don't have Photoshop right now. Another is that GIMP can't produce shapes. And another reason is that Paint can provide the dimensions of the shape that I'm creating. Well, Paint gives the length and width of the rectangular region immediately around the shape, which is what I'm after. Using these measurements, I'm able to compute for the actual size of the shape. With Scilab, I was able to compute for the area of the image by following this flowchart:
Figure 2: Flowchart of measuring the area of a shape
I tested the code that I've written on Scilab on a circle with a diameter of 300 pixels. Also, I tried placing the circle on different locations on the image to see if it would matter (which probably won't).
Figure 3. Circles with diameters of 300 pixels on a 500x500 pixel image. As will be used in the following table, the images are labeled according to their location: (a) center, (b) upper left, (c) lower left, and (d) bottom.
In Figure 3d, the circle is tangent with the border of the image, making the outline of the circle discontinuous in a sense.
Table 1. Actual and measured area of a circular region on an image
Yes, as expected, placing the circle away from the center will not give a difference on the area measured by the code. A small difference was observed on Figure 3d. When I was doing that image on Paint, I simply dragged the circle towards the edge of the image. Perhaps I did not notice that some parts of the circle went outside the image.
Or maybe it was due to the connection at the edge of the image. So I went on investigating about it by creating this image:
Figure 4. Semicircle with diameter of 300 pixels on a 500x500 pixel image
This image was also constructed using Paint. There was a 10.97% difference from the actual area of 35342 square pixels when the area was approximated using the Scilab code. Why is there a large discrepancy? I figured out that the edge() function was not able to detect the flat side of the semicircle positioned on the boundary of the image. To be sure, I plotted the points determined by the edge() function to be the edge of the white shape:
Figure 5. Location of the points determined by the edge() function to be the boundary of the semicircle that has a diameter of 300 pixels.
In Figure 5, the lines connect all the points on the edge. Seeing that there is a low density of lines at the upper portion, there should be a small number of edge points on that part. Also, even after zooming in at the upper boundary, there were no distinct connection of lines. With that being said, the code perhaps divided the semicircle to thin slices of pizza at the bottom part. At the upper portion, it created only one triangle with one vertex at the centroid of the semicircle, and the other two vertices at the right and left corner of the flat side. Having large slices of pizzas will decrease the precision of the approximation.
Application
Our house is located on a trapezoidal lot, which makes it difficult for me to describe the dimensions of our lot whenever my friends ask about it. With the help of Google maps, I was able to capture an image of our residential area:
Figure 6. Image of our residential area [3]
I saved a 941x552 square pixel image of this using the built-in Snipping Tool of Windows 7. From Paint, I was able to determine the ratio of meters to pixels by drawing a line over the scale bar. A ten meter distance on the image corresponds to a 77 pixels distance on the image.
Have you guessed where our house is? Of coures not. XD So here it is, with the lot covered by a red trapezod:
Figure 7. Our lot marked by the red trapezoid
Figure 8. Conversion of Figure 6 to black and white
Using the same code, the area was estimated to be 37776 square pixels, which would correspond to 637 square meters. Again, with Paint, I estimated the area of the trapezoid, assuming that the two bases (lower left and upper right edges) are parallel to each other. With that method, I measured the area to be 36206 square pixels, resulting to a 4.33 percent difference with the previous value.
How should I measure the actual value?
Mothers know best.
So I asked my mom about the area of our lot, and she said that it's 678 square meters. I suppose it was based on the land title. Which makes my approximation different from the actual area by 6.02%. Not bad! I guess.
The discrepancy between the two values could have been minimized if our lot has a distinct fence. Heck, our lot is filled with trees at the edges, which made it difficult for me to estimate the actual boundary of our lot.
Or maybe it was due to the uncertainties in the scaling factor.
But with that percent difference, I think my code works just fine. So I'll give myself a grade of 10/10 for this activity. Yeah!
Before I forget, I would like to thank Dr Soriano for discussing the flow of the computation for the area measurement.
By the way, here is the code that I have written to perform the area approximation. Feel free to use it :D
circle = imread("C:\Users\Akared\Desktop\AP 186 Act 4\circle300_center.bmp");
circle_gray = rgb2gray(circle);
edge_circle = edge(circle_gray);
[c_val, r_val] = find(edge_circle);
sum_x = sum(c_val);
sum_y = sum(r_val);
Xc_temp = sum_x/size(c_val);
Yc_temp = sum_y/size(r_val);
Xc = int(Xc_temp(2)); //centroid
Yc = int(Yc_temp(2)); // centroid
X_new = c_val - abs(Xc);
Y_new = r_val - abs(Yc);
R = sqrt(X_new.^2 + Y_new.^2);
theta = atan(Y_new, X_new);
X_final = zeros(theta);
Y_final = zeros(theta);
max_theta = abs(max(theta));
add_this = max_theta*100;
for k=1:length(theta)
min_loc_temp = find(theta==min(theta));
min_loc = min_loc_temp(1);
theta(min_loc) = theta(min_loc) + add_this;//replace the current minimum to locate the next minimum on the next iteration
X_final(k) = X_final(k) + X_new(min_loc);
Y_final(k) = Y_final(k) + Y_new(min_loc);
end
total_area = 0.0;
for k=1:(length(theta)-1)
total_area = total_area + (X_final(k)*Y_final(k+1) - X_final(k+1)*Y_final(k));
end
//we still have to add the area covered by the first and last pair of pixel coordinates
total_area = total_area + X_final(length(X_final))*Y_final(1) - X_final(1)*Y_final(length(Y_final));
total_area = total_area/2.0;
disp(total_area)
References
[1] http://randommealoftheday.blogspot.com/2011/07/pepperoni-pizza-at-mammas-brick-oven.html
[2] http://slice.seriouseats.com/archives/2010/10/where-is-the-best-pizza-in-miami-florida-fl.html
[3] https://maps.google.com/
[4] Soriano, M. A5 - Area estimation of images with defined edges 2013 activity manual.
Edit (June 26, 2013):
In case you're wondering how the function edge() works on Figure 3a, here it is:
Figure 9. Plotting the output of the edge() function after adjusting to the centroid.
Since it outputs a series of pixel coordinates from the top left to bottom right of the image, the lines connecting consecutive values cross the inside of the shape. Which forced me to sort them in a manner that the order follows the outline of the shape, involving the computation of the angle with respect to the +x axis.
After sorting, I was able to create the following image:
Figure 10. Connecting the edges following the outline
So from there, I was able to create triangles/pizzas with the 2 vertices lying on the outline and the third on the centroid.
You might also notice that there is a discontinuity on the outline shown in Figure 10. If you inspect the Scilab code that I wrote, after summing over all the values of the pixel coordinates (ends at line 41), I also added a triangular area with the outside vertices connecting the discontinuity (line 53) to complete the entire area.
Yeah!