import cImage import math def deformedImage(image, newWidth, newHeight, deformer): """Deforms the given image and returns the new image. The inputs are an image, a width and height for the new image, and a deformer function. By a deformer function, I mean a function that takes in pairs of numbers between 0.0 and 1.0, and outputs pairs of numbers between 0.0 and 1.0.""" width = image.getWidth() height = image.getHeight() newImage = cImage.EmptyImage(newWidth, newHeight) # Loop over all pixels in the new image. for newRow in range(newHeight): for newCol in range(newWidth): # Convert (col, row) in the new image to (x, y) in the new image. newX = (newCol + 0.5) / newWidth newY = (newRow + 0.5) / newHeight # Apply deformer to get the corresponding (x, y) in the old image. xy = deformer((newX, newY)) # Convert (x, y) in the old image to (col, row) in the old image. col = round(xy[0] * width - 0.5) row = round(xy[1] * height - 0.5) # Make sure the column and row are safe. col = min(width - 1, max(0, col)) row = min(height - 1, max(0, row)) # Copy the pixel from the old image to the new image. pixel = image.getPixel(col, row) newImage.setPixel(newCol, newRow, pixel) return newImage def identityDeformer(xy): """Deformer function that doesn't deform at all. Useful for resizing images without deforming them.""" return xy def verticalFlipDeformer(xy): """Deformer function that flips about a vertical axis.""" return (1.0 - xy[0], xy[1]) def horizontalFlipDeformer(xy): """Deformer function that flips about a horizontal axis.""" return (xy[0], 1.0 - xy[1]) def halfRotationDeformer(xy): """Deformer function that rotates the image 180 degrees.""" return (1.0 - xy[0], 1.0 - xy[1]) def verticalMirrorDeformer(xy): """Deformer function that causes the right side of the image to mirror the left.""" if xy[0] > 0.5: return (1.0 - xy[0], xy[1]) else: return xy def horizontalMirrorDeformer(xy): """Deformer function that causes the bottom of the image to mirror the top.""" if xy[1] > 0.5: return (xy[0], 1.0 - xy[1]) else: return xy def cubicDeformer(xy): """Deformer function that interpolates nonlinearly in both directions (using the cubic function with slope zero at both endpoints).""" return (-2.0 * xy[0]**3 + 3.0 * xy[0]**2, -2.0 * xy[1]**3 + 3.0 * xy[1]**2) def cosDeformer(xy): """Similar to cubicDeformer(), but interpolates using a cosine curve.""" return (0.5 * (1.0 - math.cos(math.pi * xy[0])), 0.5 * (1.0 - math.cos(math.pi * xy[1]))) def acosDeformer(xy): """Uses the inverse of the function that cosDeformer() uses.""" return (math.acos(1.0 - 2.0 * xy[0]) / math.pi, math.acos(1.0 - 2.0 * xy[1]) / math.pi) # Global variables here!! xCenter = 0.5 yCenter = 0.5 radius = 0.25 def bubbleDeformer(xy): """Deformer function that nonlinearly deforms the image by magnifying the region of the image around (xCenter, yCenter).""" global xCenter, yCenter, radius v = (xy[0] - xCenter, xy[1] - yCenter) r = math.sqrt(v[0]**2 + v[1]**2) fraction = min(r, radius) / radius scale = -2.0 * fraction**3 + 3.0 * fraction**2 return (xCenter + scale * v[0], yCenter + scale * v[1]) # If the user ran (rather than imported) this file, then run this demo code. if __name__ == "__main__": # Draw the image. path = "bobama.jpg" image = cImage.FileImage(path) width = image.getWidth() height = image.getHeight() window = cImage.ImageWin(path, width + 16, height) image = cImage.FileImage(path) image.draw(window) # Let the user bubble-deform the image. xy = window.getMouse() x = xy[0] - 3 y = xy[1] - 3 while x < width and y < height: print "Deforming image..." xCenter = float(x) / width yCenter = float(y) / height newImage = deformedImage(image, width, height, bubbleDeformer) newImage.draw(window) # Get the next mouse input. xy = window.getMouse() x = xy[0] - 3 y = xy[1] - 3