Documentation For Homework 2
Documentation For Homework 2
As the second homework did not have a specific framework within which it was
supposed to work my objective was to make my programs as general-purpose as possible. I set
up very unusual circumstances with various problems that may break the program and found
ways (or at least attempted) to go around those obstacles.
The first task I tackled was of course the concatenation problem. This was pretty
straightforward as all I had to do was determine the size of the resultant image and draw it pixel
by pixel utilizing two sets of doubly nested for loops, one for each image to be concatenated. As
it stands the program works in the aforementioned obvious way.
if direction=="h":
width = w1 + w2
if h1 > h2:
height = h1
else:
height = h2
else:
height = h1 + h2
if w1 > w2:
width = w1
else:
width = w2
if direction=="h":
for x in range(w1):
for y in range(h1):
concat_img.set(x,y,img1.get(x,y))
for x in range(w2):
for y in range(h2):
concat_img.set(x+w1,y,img2.get(x,y))
else:
for y in range(h1):
for x in range(w1):
concat_img.set(x,y,img1.get(x,y))
for y in range(h2):
for x in range(w2):
concat_img.set(x,y+h1,img2.get(x,y))
The results of the program are as obvious as the coding itself. It is clear that the
algorithm is working as intended.
-------------------------
| CS101 Image Processor |
-------------------------
| 1. Concatenate |
| 2. Detect |
| 3. Segment |
| 4. Quit |
-------------------------
Select : 1
Enter the 1st image name to concatenate : iu.jpg
Enter the 2nd image name to concatenate : kara.jpg
Enter the direction of concatenation (h or v) : v
-------------------------
| CS101 Image Processor |
-------------------------
| 1. Concatenate |
| 2. Detect |
| 3. Segment |
| 4. Quit |
-------------------------
Select : 1
Enter the 1st image name to concatenate : Circus_Live_london.jpg
Enter the 2nd image name to concatenate : Circus_Boston.jpg
Enter the direction of concatenation (h or v) : h
A superb specimen of the female human form, courtesy of Mrs. Britney Spears (divorced).
And yes, I agree her singing is NOT superb, but her body is, right?
Next stop is the detect task. The first thought that came to my mind when looking at
this problem was to simply for-loop the search space and whenever I hit a pixel identical to
obj_img.get(0,0) run a function checking I did indeed hit the mother lode; however I realized that
doing this would be hellishly inefficient if there were many cases of identical pixels (if this was so
the multiple instances of checks happening would slow the program down to a crawl) so I wrote
two functions- a light one that would run first and check the four corners of the ‘hit area’, and a
heavier one that follows the first and checks the entire region for identity.
Now that a region containing the detect object has been pinpointed, we need to frame it
in green. I decided on using two for-loops, one for each axis, and coloring the inner two pixels of
the region in green.
for cx in range(objimg_w):
inimg.set(x+cx,y,green)
inimg.set(x+cx,y+1,green)
inimg.set(x+cx,y+objimg_h-1,green)
inimg.set(x+cx,y+objimg_h-2,green)
for cy in range(objimg_h):
inimg.set(x,y+cy,green)
inimg.set(x+1,y+cy,green)
inimg.set(x+objimg_w-1,y+cy,green)
inimg.set(x+objimg_w-2,y+cy,green)
return inimg
All this comes together in the detect() method.
for tx in range(img_w):
for ty in range(img_h):
if det_img.get(tx,ty)==obj_img.get(0,0):
if detect_chkinit(det_img,obj_img,tx,ty):
if detect_chk(det_img,obj_img,tx,ty):
det_img = detect_gotcha(det_img,obj_img,tx,ty)
-------------------------
| CS101 Image Processor |
-------------------------
| 1. Concatenate |
| 2. Detect |
| 3. Segment |
| 4. Quit |
-------------------------
Select : 2
Enter a search space image name : ta_faces.bmp
Enter an object image name : ta_face4.bmp
And there you are! Gotcha! (… ahem)
The third and last task, segmentation, was quite troublesome for me. I hit stone walls
several times while trying to figure this out, but luckily with the help of the online python library
and a few moments of inspiration I came up with something which is, I hope, versatile enough to
get through most of the stranger inputs someone might throw at it. It did withstand things I
threw at it, even rotten tomatoes loaded with extra doses of ass.
My segment() method does not look so straightforward as the above two methods. Why
oh my, the method’s contents are simply a collection of function calls nested inside a single while
loop! I did this to make sure my program could handle queerer inputs, and so I’ll explain one-by-
one why a certain part looks like this and why that code had to be written down instead of
what’s-it-you-call-it.
##############################################################################################
# (4) Do something on here to segment the faces inside the green rectangles !
seg_img = segenlarge( seg_img )
seg_comparison = copy( seg_img )
fillqueue=[(0,0)]
while len(fillqueue)>0:
fx,fy = fillqueue[0]
seg_img,fillqueue = floodfill( seg_img, fx, fy, green, fillqueue )
fillqueue = fillqueue[1:]
seg_img = segblackout( seg_img, seg_comparison, green )
##############################################################################################
return seg_img
The first function called is the segenlarge(). This goes hand-in-hand with the last function,
segshrink(), so I’ll describe those two together. Here is the code for the two.
The next function in line is… is that a while loop we see? Yes, it is. What is this doing
here? The answer to that question can be given by looking at the floodfill() function sitting inside
the loop.
This is the crème de la crème of the entire program, the central achievement, the
crowning glory that everything else pales in comparison to… and a complete headache to
implement. The logic itself was pretty simple, but I had to spend a full hour debugging and
scratching my head because this just wouldn’t work as I told it to. However all that toil finally paid
off and this is now working as designed. Sigh
The floodfill() function is a recursive method; it is supposed to call itself when certain
conditions are met. It works like this: First, it checks the color of the pixel it is standing on and
colors it if it doesn’t match the one it received as input. Second, it checks its neighboring pixels
and sees if their colors are any different; if one of them also isn’t the object color it colors it
green and calls itself on that coordinate. The result is that when a single pixel that isn’t green is
chosen and floodfill(green) is called on it, the function will color the entire contiguously non-green
region in green.
“Okay,” you might ask, “I see that floodfill() is recursive, but why the queue? Why not
simply call floodfill() from within the floodfill()?” Oh, I think you know perfectly why, sir. I actually
did write it as such at the beginning, only to receive an error message from Wing IDE saying
‘maximum recursion level reached’. I couldn’t call that many recursive functions with python! So I
made a queue and then whenever floodfill() decides it needs to clone itself (ala Agent Smith in
the Matrix series) it can add the target coordinate in the queue.
On a side note, the above was not the only bug I encountered while programming
floodfill(). For one, the program would just simply freeze whenever I tried to run the segment()
method. This was because the queue was filling up with endless instances of the same
coordinates, which was in turn because two pixels neighboring the same non-green pixel would
BOTH call that coordinate and put it in the queue, and when THAT coordinate was reached it
would do the same with its neighboring coordinates (and do that multiple times because itself
happens multiple times), ad infinatum. This was solved by introducing the img.set(x,y,color) line to
each queue-adding sequence so that multiple appends of the same pixel would not happen.
Alright, now we have a green-filled image ready for displaying. Wait, did I say green?
Yes, I said green. The problem asked for a black image, so then why have I gone into all that
trouble just to paint the whole thing green? This is, again, to counter another ‘strange and
devilish input’ I thought up: what if, for whatever reasons, there is a big wall of black surrounding
a green rectangle? If I did floodfill(black) it would stop when it encounters black, so if such a wall
existed then it wouldn’t touch the area enclosed inside, which I AM supposed to fill up as it is still
outside any GREEN rectangles. I knew that checking for outside-green-ness was too haphazard so
I opted for a destructively creative solution: do floodfill(green) and worry about color afterwards.
This way I can safely assume that any area not colored is inside a green rectangle.
Thus naturally follows the next function: segblackout().
def segblackout( img, compare, color ):
if not img.size() == compare.size():
return img
imgw,imgh = img.size()
for x in range(imgw):
for y in range(imgh):
if img.get(x,y)==color:
if not compare.get(x,y)==color:
img.set(x,y,black)
return img
This function compares the green-filled result of floodfill(green) with the original input
image and decides which green pixel is a green rectangle and which isn’t. After that is done it
colors all green pixels that aren’t part of a rectangle in black. It looks extremely simple(and blunt)
but I had to go through 20 additional minutes of debugging since this, too, wouldn’t work. When
I finally found out that compare_img = seg_img doesn’t work and has to be rewritten as compare_img =
copy(seg_img) I crawled on the ground crying. Metaphorically Speaking, that is.