#---------------------------------------------------------------------- # Image Processing and Command Interface # Copyright (C) 2017 -- Dr. William T. Verts #---------------------------------------------------------------------- import string #---------------------------------------------------------------------- # Simple single-pixel functions # # This first group of functions are simple, but lengthy. Each one # does the "full job" of scanning all the rows and columns of an image, # picking up each pixel, processing the pixel, replacing the pixel's # value in the canvas, and repainting the screen. There's a LOT of # duplicated code in this group of functions. #---------------------------------------------------------------------- def Brighten (Canvas): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) R = getRed(PX) G = getGreen(PX) B = getBlue(PX) R = R + 20 G = G + 20 B = B + 20 setRed(PX,R) setGreen(PX,G) setBlue(PX,B) repaint(Canvas) return #---------------------------------------------------------------------- def Darken (Canvas): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) R = getRed(PX) G = getGreen(PX) B = getBlue(PX) R = R - 20 G = G - 20 B = B - 20 setRed(PX,R) setGreen(PX,G) setBlue(PX,B) repaint(Canvas) return #---------------------------------------------------------------------- def Monochrome (Canvas): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) R = getRed(PX) G = getGreen(PX) B = getBlue(PX) Brightness = (R + G + B) / 3 if Brightness > 128: R = 255 G = 255 B = 255 else: R = 0 G = 0 B = 0 setRed(PX,R) setGreen(PX,G) setBlue(PX,B) repaint(Canvas) return #---------------------------------------------------------------------- # This function is a "stub" that hasn't been finished yet. def RGB (Canvas): showInformation("RGB") return #---------------------------------------------------------------------- def Grayscale (Canvas): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) R = getRed(PX) G = getGreen(PX) B = getBlue(PX) Brightness = (R + G + B) / 3 R = Brightness G = Brightness B = Brightness setRed(PX,R) setGreen(PX,G) setBlue(PX,B) repaint(Canvas) return #---------------------------------------------------------------------- # Refer to the Companion, page 291, or the Guzdial book for a # discussion of sepia. def Sepia (Canvas): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): PX = getPixel(Canvas,X,Y) R = getRed(PX) G = getGreen(PX) B = getBlue(PX) NewR = int(R * 0.393 + G * 0.769 + B * 0.189) NewG = int(R * 0.349 + G * 0.686 + B * 0.168) NewB = int(R * 0.272 + G * 0.534 + B * 0.131) setRed(PX,NewR) setGreen(PX,NewG) setBlue(PX,NewB) repaint(Canvas) return #---------------------------------------------------------------------- # This is a different approach: split off the part that scans every # pixel and updates the screen into its own function (Process) and # make the pixel transformations their own individual (but smaller) # functions. This requires that the desired pixel function be PASSED # AS A PARAMETER to Process (which calls it FN internally). # # Earlier functions Sepia and GrayScale still need to be converted # into this form. Once done, all those earlier functions may be # deleted. #---------------------------------------------------------------------- def Pixel_Monochrome (PX): R = getRed(PX) G = getGreen(PX) B = getBlue(PX) Brightness = (R + G + B) / 3 Value = Brightness / 128 * 255 R = Value G = Value B = Value setRed(PX,R) setGreen(PX,G) setBlue(PX,B) return def Pixel_RGB (PX): setRed (PX, getRed(PX) / 128 * 255) setGreen(PX, getGreen(PX) / 128 * 255) setBlue (PX, getBlue(PX) / 128 * 255) return def Pixel_Darken (PX): setRed (PX, getRed(PX) - 20) setGreen(PX, getGreen(PX) - 20) setBlue (PX, getBlue(PX) - 20) return def Pixel_Brighten (PX): setRed (PX, getRed(PX) + 20) setGreen(PX, getGreen(PX) + 20) setBlue (PX, getBlue(PX) + 20) return def Process (Canvas, FN): for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): FN(getPixel(Canvas,X,Y)) repaint(Canvas) return #---------------------------------------------------------------------- # Dual-canvas functions require that a pixel and its neighborhood be # examined from a source canvas to determine its new color value, which # must be updated on a destination canvas to avoid interference with # the processing of subsequent pixels. EdgeDetect and Focus are stubs, # and Blur is done here. Can you make these into a single, general # function that is passed in information about what to do with each of # the neighbors? #---------------------------------------------------------------------- def EdgeDetect (Canvas): showInformation("EdgeDetect") return def Focus (Canvas): showInformation("Focus") return def Blur (Canvas): Size = requestIntegerInRange("Enter Neighborhood Size", 1, 7) NewCanvas = makeEmptyPicture(getWidth(Canvas),getHeight(Canvas)) for Y in range(getHeight(Canvas)): for X in range(getWidth(Canvas)): SumR = 0 SumG = 0 SumB = 0 Count = 0 for Y2 in range(max(0,Y-Size),min(getHeight(Canvas)-1,Y+Size+1)): for X2 in range(max(0,X-Size),min(getWidth(Canvas)-1,X+Size+1)): PX2 = getPixel(Canvas,X2,Y2) SumR = SumR + getRed(PX2) SumG = SumG + getGreen(PX2) SumB = SumB + getBlue(PX2) Count = Count + 1 NewR = SumR / Count NewG = SumG / Count NewB = SumB / Count MyColor = makeColor(NewR,NewG,NewB) PX = getPixel(NewCanvas, X, Y) setColor(PX,MyColor) repaint(NewCanvas) return NewCanvas #---------------------------------------------------------------------- # Mirror and Flip are single canvas functions, but they deal with two # pixels at a time (so they cannot use the Process function). #---------------------------------------------------------------------- def SwapPixels (PX1,PX2): Temp1 = getColor(PX1) Temp2 = getColor(PX2) setColor(PX1,Temp2) setColor(PX2,Temp1) return def Mirror (Canvas): for Y in range(getHeight(Canvas)): for X1 in range(getWidth(Canvas)/2): # what happens to the middle pixel? X2 = getWidth(Canvas) - 1 - X1 SwapPixels(getPixel(Canvas, X1, Y),getPixel(Canvas, X2, Y)) repaint(Canvas) return def Flip (Canvas): for X in range(getWidth(Canvas)): for Y1 in range(getHeight(Canvas)/2): # what happens to the middle pixel? Y2 = getHeight(Canvas) - 1 - Y1 SwapPixels(getPixel(Canvas, X, Y1),getPixel(Canvas, X, Y2)) repaint(Canvas) return #---------------------------------------------------------------------- # Command processor #---------------------------------------------------------------------- def Main(): Canvas = makeEmptyPicture(50,50) show(Canvas) # The triple-double quotes define a string that can span multiple # lines, including the line-breaks in the string. Message = """BLUR FOCUS BRIGHTEN DARKEN GRAYSCALE MONOCHROME SEPIA RGB EDGEDETECT FLIP MIRROR OPEN QUIT Enter a Command: """ MoreToDo = True while (MoreToDo): repaint(Canvas) Command = string.upper(requestString(Message)) if (Command == "FOCUS"): Focus(Canvas) elif (Command == "BRIGHTEN"): Process(Canvas, Pixel_Brighten) elif (Command == "DARKEN"): Process(Canvas, Pixel_Darken) elif (Command == "BLUR"): Canvas = Blur(Canvas) elif (Command == "GRAYSCALE"): Grayscale(Canvas) elif (Command == "MONOCHROME"): Process(Canvas, Pixel_Monochrome) elif (Command == "SEPIA"): Sepia(Canvas) elif (Command == "RGB"): Process(Canvas, Pixel_RGB) elif (Command == "EDGEDETECT"): EdgeDetect(Canvas) elif (Command == "FLIP"): Flip(Canvas) elif (Command == "MIRROR"): Mirror(Canvas) elif (Command == "OPEN"): Filename = pickAFile() Canvas = makePicture(Filename) elif (Command == "QUIT"): MoreToDo = False else: showError("Illegal Command") return