View
234
Download
0
Tags:
Embed Size (px)
Citation preview
Intro to Robots
Processing Pictures:
• Without the fluke board we can’t process pictures taken by the robot.
• However we can process regular .jpg files.• Caution: Processing can take a long time so keep your
pictures to 600 x 600 pixels. If you are just experimenting try to keep your pictures even smaller – 200x200 pixels.
Intro to Robots
Picture Functions:
from myro import *
picture = makePicture(“somefile.jpg”) # read from a .jpg fileshow(picture)
newPic = pictureCopy(picture)
picWidth = getWidth(picture); picHeight = getHeight(picture)
<list of pixels> = getPixels(picture)<some Pixel> = getPixel(picture,x,y)
setRed(pix, <n>) # 0 <= n <= 255, ‘red’ == 255setGreen(pix, <n>) # 0 <= n <= 255, ‘red’ == 0setBlue(pix, <n>) # 0 <= n <= 255, ‘red’ == 0
redValue = getRed(pix); greenValue = getGreen(pix); blueValue = getBlue(pix)x = getX(pix); y = getY(pix)
savePicture(picture,”anotherfile.jpg”) # save to a .jpg file
Intro to Robots
Robot Vision:
• Without the Fluke board, Scribbler can not take pictures.• However we can explore how we would process
photographs taken by Scribbler and to use results of that analysis.
Intro to Robots
Making your own Picture:
newPic = makePicture(100,100)show(newPic)
onePixel = getPixel(newPic,10,5)print getRed(onePixel) #initial red valuesetRed(onePixel,255)print getRed(onePixel) #new red valueshow(newPic)
.
black by default
Intro to Robots
Making your own Picture:
for yValue in range(0, getHeight(newPic)): aPixel = getPixel(newPic, 10, yValue) setRed(aPixel,255) setGreen(aPixel,0) setBlue(aPixel,0)show(newPic)
# or make it into a function
def drawVerticalRedLine( picture, xPos ): for yPos in range(0, getHeight(picture) ): aPixel = getPixel( picture, xPos, yPos) setRed(aPixel,255) setGreen(aPixel,0) setBlue(aPixel,0)
drawVerticalRedLine(newPic,10)show(newPic)
height of picture
Intro to Robots
Real Photograph
• Photo taken by Scribbler
applePic = takePicture() ORapplePic = loadPicture(‘apple.jpg’)
drawVerticalRedLine(applePic,10)show(applePic)
Intro to Robots
Scan Real Photograph
• If we draw the vertical red line continuously across the photo we will cover up the photo.
• We would rather have the following behaviour.• What we are doing is:
– drawing a red line, – waiting a fraction of a second,– putting back the original pixels and – drawing the line again further on.
run
Intro to Robots
Robot/Program Vision:
• The robot and our program don’t see purple, they each see a combination of red, green and blue.
• Colors with low values of red, green and blue are generally dark and with high values, generally light.
r,g,b = getColors(pixel)
width=height=500myCanvas = GraphWin("Circles", width, height)myCanvas.setBackground("white")for i in range(1,25): c = Circle(Point(randrange(0,width), randrange(0,height)),20) red = 10*i c.setFill(color_rgb(red, red/2, red/4)) c.draw(myCanvas) wait(1) wait(5)myCanvas.close()
run
Intro to Robots
Filtering Photographs:
• Have you ever heard the expression, “The world is not black and white, but various shades of gray”.
• Some times seeing things as black and white helps filter out other irrelevant or confusing messages.
• Go back to our original pictureand ask, “What parts of the photo are brightest?”
Intro to Robots
Brightness Filter:
• We know that higher red, green and blue values mean brighter object.
• Brightness: average color value > 175
myPicture = takePicture()show(myPicture)for pixel in getPixels(myPicture): rValue = getRed(pixel) gValue = getGreen(pixel) bValue = getBlue(pixel) avgValue = ( rValue + gValue + bValue) / 3.0 if avgValue > 175 : #Turn the pixel white setRed(pixel,255);setGreen(pixel,255) setBlue(pixel,255) else: #Otherwise, turn it black. setRed(pixel,0);setGreen(pixel,0) setBlue(pixel,0)show(myPicture)
before
after
Intro to Robots
Redness Filter:
• Suppose you want to find the reddest thing in a photo (and if the photo was taken by the robot, have the robot turn towards that thing).
• In the previous example most of the filtered apple was black, why?
• Redness: – high red value (> 175), – low green and blue values (< 175).
Intro to Robots
Redness Filter:
• Program for highlighting red
myPicture = takePicture()show(myPicture)def filterRed(picture): for pixel in getPixels(picture): rValue = getRed(pixel) if rValue > 175: #Turn the pixel white setRed(pixel,255) setGreen(pixel,255) setBlue(pixel,255) else: #Otherwise, turn it black. setRed(pixel,0) setGreen(pixel,0) setBlue(pixel,0)
filterRed(myPicture)show(myPicture)
an awful lot of red
Intro to Robots
Greenness Filter:
• Same program for green
myPicture = takePicture()show(myPicture)for pixel in getPixels(myPicture): gValue = getGreen(pixel) if gValue > 175: #Turn the pixel white setRed(pixel,255) setGreen(pixel,255) setBlue(pixel,255) else: #Otherwise, turn it black. setRed(pixel,0) setGreen(pixel,0) setBlue(pixel,0)
show(myPicture)
funny how a green filter makes a red apple stand out
Intro to Robots
Primarily Red Filter:
myPicture = takePicture()show(myPicture)Def findRedAreas(picture): for pixel in getPixels(myPicture): rValue = getRed(pixel) gValue = getGreen(pixel) bValue = getBlue(pixel) if rValue > 175 and gValue < 175 and bValue < 175: #Turn the pixel white setRed(pixel,255) setGreen(pixel,255) setBlue(pixel,255) else: #Otherwise, turn it black. setRed(pixel,0) setGreen(pixel,0) setBlue(pixel,0)
show(myPicture)more like it; just two red“hot spots”
Intro to Robots
Find the Center of Redness:
• Simple Technique: Find the average x-coordinate of all white pixels in the filtered picture.
• This will point to the center of redness, which may unfortunately be somewhere in between two major red (now white) areas
average x-coordinate
Intro to Robots
Center of Redness of our Photography
def AverageXofWhitePixels(picture): sumX = 0.0 # We use floating point values. counter = 0.0 # We use floating point values. for xPos in range(0, getWidth(picture) ): for yPos in range(0, getHeight(picture) ): pixel = getPixel(picture,xPos,yPos) value = getGreen(pixel) if value > 0 : # add x-coord of every white pixel sumX = sumX + xPos counter = counter + 1 averageX = sumX / counter return int(averageX) #Return an Integer
myPicture = takePicture()picture = copyPicture(myPicture)picture = findRedAreas(picture)XposAvg = AverageXofWhitePixels(picture)drawVerticalRedLine(myPicture,XposAvg)show(myPicture)
Vertical line to one side becauseredness of the apple shadow ispulling the red center to the right.
Intro to Robots
Processing Red Areas Individually:
• Call each red area “a blob”. • Our problem is:
– find a blob– count its pixels– calculate its x-coordinate center
• Easiest way to traverse the picture is for pix in getPixels(picCopy): . . .
two blobs one blob
Intro to Robots
Red Blobs one-at-a-time:
• Problem: Processing the pixels left-to-right, top-to-bottom we won’t know when we process the line indicated by the red arrow if the blobs are two or one.
• Solution: Keep a list of partially-built blobs and as we find that two blobs are really one, combine them into one.
two blobs one blob
processing a new blobcontinue on same blobno longer processing blobprocessing a new blob;or is it the same blob?
Intro to Robots
BlobList Data Structure:
• A BlobList is a data structure that contains a list of blobs and has many methods for accessing that list.
from blob import *
class BlobList: def __init__(self): self.contents = [ ]
def add(self,b): self.contents.append(b)
def findBlob(self,c): for b in self.contents: if b.inBlob(c): return b return None def getIndex(self,b): for i in range(len(self.contents)): if b == self.contents[i]: return i return -1
def dropBlob(self, b): i = self.getIndex(b) del self.contents[i]
def writeOut(self): for b in self.contents: b.writeOut() print ""
def getBiggestBlob(self): maxNdx = -1 maxSz = 0 for i in range(len(self.contents)): b = self.contents[i] size = b.getSize() if size > maxSz: maxSz = size maxNdx = i return self.contents[maxNdx]
Intro to Robots
Blob Data Structure:
• A Blob is a contiguous red section of a filtered photo. All pixels are connected either vertically or horizontally.
• A blob is built by finding a red point, not already part of another blob and adding it and all the connected red points on the same vertical line to the same blob.
.x
As the point, x, is addedto a new blob, we continueto add all the red pixels on the same vertical line asthe point, x, and connectedto x
Intro to Robots
Complicated Blobs
x . these points are part of theinitial blob containing x
these points are not part of the initial blob containing x because although on the same vertical line, the two lines are not connected by red pixels
once the line labeled A is part of the same blob as x, the extension of the vertical line containing x will also become part of the same blob
A
eventually the entire donut will bea single blob
Intro to Robots
How to Build a Blob:
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
total blob in picture
pixels addedto programblob
1st
2nd
Which is the last pixel to be added to the program blob?
Intro to Robots
Blob Strategy
• Each time we add a pixel to a blob we give it a color that is not red and not black and not used in any other blob.
select a red pixelcreate a new empty blob with new colorwhile pixel is red: add pixel to current blob (change color) if pixel to the left is already in another blob: combine the two blobs if pixel to the right is already in another blob: combine the two blobs get the pixel immediately above the previous pixelselect the pixel immediately below the original red pixelwhile pixel is red: add pixel to current blob (change color) if pixel to the left is already in another blob: combine the two blobs if pixel to the right is already in another blob: combine the two blobs get the pixel immediately below the previous pixel
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
previous blob new blobcombined blob
Intro to Robots
Blob Code:
from myro import *
class Blob:
def __init__(self, c=None,x=None): self.colors = [ ]; self.blobPixelSum = 0 ### blob consists of a list of colors in use self.verticalCounts = { }; self.midPoint = -1 ### and a dictionary of vertical counts if c != None: ### key = xCoord; value = number yPixels self.colors.append(c) if x != None: self.verticalCounts[x] = 0 def incPixelCount(self,xCoordinate,cnt): self.blobPixelSum = self.blobPixelSum + cnt if self.verticalCounts.has_key(xCoordinate): ### xCoord already belongs to blob self.verticalCounts[xCoordinate] = ### handles the donut case self.verticalCounts[xCoordinate] + cnt else: self.verticalCounts[xCoordinate] = cnt
def inBlob(self,c): return c in self.colors ### tests if a color is already in the blob; if the same color ### is found in two blobs, they are the same blob
. . . . .
. . . . .
. . . . .
. . . . .xCoordinates 12 13 14
vertcialCounts = {12:2, 13:3, 14:1}
Intro to Robots
Blob Code:
def mergeDictionaries(self,b): newD = { } d1 = self.verticalCounts ### {x1:c1, x2:c2, …, xn:cn} d2 = b.verticalCounts for d in d1.keys(): newD[d] = d1[d] if d2.has_key(d): newD[d] = newD[d] + d2[d] ### add vertical counts if xCoord in both blobs del d2[d] for d in d2.keys(): ### get the remaining xCoords not gotten in first loop newD[d] = d2[d] return newD
def combine(self,b): newB = Blob() newB.colors = self.colors + b.colors ### combine disjoint color lists newB.blobPixelSum = self.blobPixelSum + b.blobPixelSum newB.verticalCounts = self.mergeDictionaries(b) ### combine vertical counts return newB
Intro to Robots
Blob Code:
def calculateMidPoint(self): sum = 0 for x in self.verticalCounts.keys(): ### same calculation as the single blob problem sum = sum + x*self.verticalCounts[x] self.midPoint = sum/self.blobPixelSum
def getMidPoint(self): if self.midPoint == -1: self.calculateMidPoint() return self.midPoint
def getSize(self): return self.blobPixelSum
def writeOut(self): print self.colors print "sum of pixels: ", self.blobPixelSum self.calculateMidPoint() print 'midPoint ' , self.midPoint print 'color list', self.colors
Intro to Robots
Generate New Colors:
• Our filtered picture is all black (0,0,0) or red (255,0,0).• We have 224 – 2 other colors to choose from.• More than enough for the pictures we will process.
from myro import *
class AvailableColors: def __init__(self): self.g = 100; self.b = 0
def getNext(self): g = self.g; b = self.b self.b = self.b + 1 if self.b > 255: self.g = self.g+1 self.b = 0 return Color(0,g,b)
generates blue-green colorson the fly in the ranges: 100 <= green <= 255 0 <= blue <= 255approximately 37500 differentcolors
Intro to Robots
Alternate AvailableColors Implementation:
from myro import *
class AlternativeAvailableColors: def __init__(self): self.contents = [ ] self.index = 0 for i in range (100,256): for j in range(0,256): self.contents.append(Color(0,i,j))
def getNext(self): c = self.contents[self.index] index = index + 1 return c
creates a complete lost of colorsup front and then returns these colors one at a time as requested
Intro to Robots
Data/Code Comparisons:
• Both AvailableColors and AlternativeAvailableColors have exactly the same interface:
• But their implementations are very different.• AvailableColors has almost no data (variables g and b)
and a complicated algorithm for getNext().• AlternativeAvailableColors has a complicated data
structure (self.contents, a list of all available colors) but a very simple implementation of getNext().
• Lesson to Learn: There is a trade-off between data structure and algorithm; if one is simple the other is usually complex.
ac.getNext()
Intro to Robots
Main Program:
for each pixel if pixel is red: create a new empty blob and new color while pixel is red: add pixel to current blob (change color) if pixel to the left is already in another blob: combine the two blobs if pixel to the right is already in another blob: combine the two blobs get the pixel immediately above the previous pixel select the pixel immediately below the original red pixel while pixel is red: add pixel to current blob (change color) if pixel to the left is already in another blob: combine the two blobs if pixel to the right is already in another blob: combine the two blobs get the pixel immediately below the previous pixel add blob to blob list
ac= AvailableColors() bl = BlobList()
for pix in getPixels(pictureCopy): redValue = getRed(pix) if redValue > maxRed:
clr = ac.getNext()x = getX(pix)y = getY(pix)b = Blob(clr,x)pixel = pix
while yNdx >= 0 and getRed(pixel) > maxRed: setColor(pixel,clr)
leftPixel = getPixel(pictureCopy,x-1,yNdx)if getRed(leftPixel) == 0 and getGreen(leftPixel) > 0: leftColor = getColor(leftPixel) if not b.inBlob(leftColor): oldB = bl.findBlob(leftColor) b = b.combine(oldB) bl.dropBlob(oldB)
rightPixel = getPixel(pictureCopy,x+1,yNdx)if getRed(rightPixel) == 0 and getGreen(rightPixel) > 0: rightColor = getColor(rightPixel) if not b.inBlob(rightColor): oldB = bl.findBlob(rightColor) b = b.combine(oldB) bl.dropBlob(oldB)
yNdx = yNdx - 1pixel = getPixel(pictureCopy,x,yNdx)
yNdx = y+1picHeight = getHeight(pictureCopy)if yNdx < picHeight:
pixel = getPixel(pictureCopy,x,yNdx)
while yNdx < picHeight and getRed(pixel) > maxRed: setColor(pixel,clr)
leftPixel = getPixel(pictureCopy,x-1,yNdx)if getRed(leftPixel) == 0 and getGreen(leftPixel) > 0: leftColor = getColor(leftPixel) if not b.inBlob(leftColor): oldB = bl.findBlob(leftColor) b = b.combine(oldB) bl.dropBlob(oldB)
rightPixel = getPixel(pictureCopy,x+1,yNdx)if getRed(rightPixel) == 0 and getGreen(rightPixel) > 0: rightColor = getColor(rightPixel) if not b.inBlob(rightColor): oldB = bl.findBlob(rightColor) b = b.combine(oldB) bl.dropBlob(oldB)
yNdx = yNdx + 1pixel = getPixel(pictureCopy,x,yNdx)
yCount = yCount + yNdx - y -1b.incPixelCount(x,yCount)bl.add(b)