0% found this document useful (0 votes)
72 views9 pages

Documentation For Homework 2

This document summarizes the code for a homework assignment on image processing tasks. It discusses: 1) A method for concatenating images side-by-side or stacked that works by determining the output size and copying pixels over in nested loops. 2) A method for detecting an object image within a larger image that uses two functions - one to check pixel matches at the corners, and another to fully check the region. Matches are outlined in green. 3) A segmentation method that uses a series of nested functions to handle edge cases, including enlarging/shrinking the image, flooding filled regions with black, and addressing scenarios where the object touches the edge.

Uploaded by

Seungho Yang
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
72 views9 pages

Documentation For Homework 2

This document summarizes the code for a homework assignment on image processing tasks. It discusses: 1) A method for concatenating images side-by-side or stacked that works by determining the output size and copying pixels over in nested loops. 2) A method for detecting an object image within a larger image that uses two functions - one to check pixel matches at the corners, and another to fully check the region. Matches are outlined in green. 3) A segmentation method that uses a series of nested functions to handle edge cases, including enlarging/shrinking the image, flooding filled regions with black, and addressing scenarios where the object touches the edge.

Uploaded by

Seungho Yang
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 9

CS101

Documentation for Homework 2


20070454 Seung Ho Yang

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

concat_img = create_picture( width, height, white )

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.

def detect_chkinit( inimg, objimg, x, y ):


inimg_w, inimg_h = inimg.size()
objimg_w, objimg_h = objimg.size()
if (inimg_w-x)<objimg_w:
return False
elif (inimg_h-y)<objimg_h:
return False
else:
if not inimg.get(x+objimg_w-1,y)==objimg.get(objimg_w-1,0):
return False
elif not inimg.get(x,y+objimg_h-1)==objimg.get(0,objimg_h-1):
return False
elif not inimg.get(x+objimg_w-1,y+objimg_h-1)==objimg.get(objimg_w-1,objimg_h-1):
return False
else:
return True

def detect_chk( inimg, objimg, x, y ):


inimg_w, inimg_h = inimg.size()
objimg_w, objimg_h = objimg.size()
result=True
for bx in range(objimg_w):
for by in range(objimg_h):
if not inimg.get(x+bx,y+by)==objimg.get(bx,by):
result=False
break
return result

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.

def detect_gotcha( inimg, objimg, x, y):


inimg_w, inimg_h = inimg.size()
objimg_w, objimg_h = objimg.size()

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.

def segment( img ) :


seg_img = copy( img )

##############################################################################################
# (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 )

seg_img = segshrink( seg_img )

##############################################################################################

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.

def segenlarge( img ):


w,h = img.size()
w=w+2
h=h+2
largeimg = create_picture( w, h, white )
for x in range(w-2):
for y in range(h-2):
largeimg.set(x+1,y+1,img.get(x,y))
return largeimg

def segshrink( img ):


w,h = img.size()
w=w-2
h=h-2
smallimg = create_picture( w, h, white )
for x in range(w):
for y in range(h):
smallimg.set(x,y,img.get(x+1,y+1))
return smallimg
These two methods segenlarge() and segshrink() are there to handle the following question:
What if the pixel (0,0) contained green? That is, if one of the green rectangles began in the (0,0)
coordinate my method won’t be able to find where to start coloring things black, not without
making mistakes some of the time. I could have simply made the program keep going to
neighboring coordinates until a non-green square is found, but in the strange case where the
ENTIRE TOP ROW is green this approach fails: the first non-green pixel it would encounter would
be INSIDE a green rectangle. So I solved this by giving the image extra pixels, empty rows and
columns on all four sides, where I could start coloring things in comfort. This way, as long as the
ENTIRE edge is not green, my floodfill() function (explained later) will find ways to get into the
image, and if the ENTIRE edge is indeed green then I need not worry because then I don’t have
to color a single pixel(the entire image is encased in a green rectangle).

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.

def floodfill( img, x, y, color, queue ):


imgw, imgh = img.size()
if not img.get(x,y)==color:
img.set(x,y,color)
# this line was written for debugging
#print str(x)+","+str(y)
if x>0:
if not img.get(x-1,y)==color:
queue.append((x-1,y))
img.set(x-1,y,color)
if y>0:
if not img.get(x,y-1)==color:
queue.append((x,y-1))
img.set(x,y-1,color)
if x<(imgw-1):
if not img.get(x+1,y)==color:
queue.append((x+1,y))
img.set(x+1,y,color)
if y<(imgh-1):
if not img.get(x,y+1)==color:
queue.append((x,y+1))
img.set(x,y+1,color)
return img, queue

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.

Finally, we see the results.


-------------------------
| CS101 Image Processor |
-------------------------
| 1. Concatenate |
| 2. Detect |
| 3. Segment |
| 4. Quit |
-------------------------
Select : 3
Enter an image name to segment : ta_faces_found.bmp
Now that’s done I feel like a drink. Martini, please. Shaken, not stirred.
One last thing I’d like to note before concluding the documentation: perhaps because of
its recursive nature segmentation method takes a long time to compute. I’d like to point out
(with pride) that the recursive nature allows it to adapt to different cases of the problem: it is
even able to cope with non-rectangular green enclosures. I strongly protest that the long time
taken by recursion shouldn’t be a cause for a lower grade. By taking a few longer it does much
more! Yes, taking long is criminal in the context of today’s programming, but isn’t versatility a
great thing to have? You think so, right? So please do look upon me and my program kindly and
give it good grades, dear good sir(or madam). Por favor.

Yours truly, 20070454 양승호!

You might also like