GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing inventwithpython.com — Chapter 14 - Droste Maker Check out other books by Al Sweigart, free online or available for purchase: ...and other books as well! Or register for the online video course. You can also donate to support the author directly.
The Droste effect is a recursive art technique named after a 1904 illustration on a tin of Droste’s Cacao, a Dutch brand of cocoa. Shown in Figure 14-1, the tin features an image of a nurse holding a meal tray containing a tin of Droste cocoa, which itself bears the illustration. In this chapter we’ll create a Droste Maker program that can generate similar recursive images from any photograph or drawing you have, whether it be a museum patron looking at an exhibit of themself, a cat in front of a computer monitor of a cat in front of a computer monitor, or something else entirely.
Figure 14-1: The recursive illustration on a tin of Droste’s Cacao Using a graphics program such as Microsoft Paint or Adobe Photoshop, you’ll prepare the image by covering an area of it with a pure magenta color, indicating where to place the recursive image. The Python program uses the Pillow image library to read this image data and produce a recursive image. First, we’ll cover how to install the Pillow library and how the Droste Maker algorithm works. Next, we’ll present the Python source code for the program with accompanying explanation of the code. Installing the Pillow Python LibraryThis chapter’s project requires the Pillow image library. This library allows your Python programs to create and modify image files including PNGs, JPEGs, and GIFs. It has several functions to perform resizing, copying, cropping, and other common actions on images. To install this library on Windows, open a command prompt window and run To verify that the installation worked, open a Python terminal and run The official documentation for Pillow can be found at https://pillow.readthedocs.io. Painting Your ImageThe next step is to prepare an image by setting a portion of it to the RGB (red, green, blue) color value (255, 0, 255). Computer graphics often use magenta to mark which pixels of an image should be rendered as transparent. Our program will treat these magenta pixels like a green screen in video production, replacing them with a resized version of the initial image. Of course, this resized image will have its own smaller magenta area, which the program will replace with another resized image. The base case occurs when the final image has no more magenta pixels, at which point the algorithm is done. Figure 14-2 shows the progression of images created as the resized image is recursively applied to the magenta pixels. In this example, a model stands in front of an art museum exhibit that has been replaced with magenta pixels, turning the photograph itself into the exhibit. You can download this base image from https://inventwithpython.com/museum.png. Be sure you use only the pure (255, 0, 255) magenta color for painting the magenta area in your image. Some tools may have a fading effect that produces a more natural look. For example, Photoshop’s Brush tool will produce faded magenta pixels on the outline of the painted area, so you will need to use the Pencil tool instead, which paints using only the precise pure magenta color you’ve selected. If your graphics program doesn’t allow you to specify the precise RGB color for drawing, you can copy and paste the colors from the PNG image at https://inventwithpython.com/magenta.png. The magenta area in the image can be of any size or shape; it does not have to be an exact, contiguous rectangle. You can see that in Figure 14-2, the museum visitor cuts into the magenta rectangle, placing them in front of the recursive image. If you make your own images with Droste Maker, you should use the PNG image file format instead of JPEG. JPEG images use lossy compression techniques to keep the file size small that introduce slight imperfections. These are usually imperceptible to the human eye and don’t affect overall image quality. However, this lossy compression will replace the pure (255, 0, 255) magenta pixels with slightly different shades of magenta. The lossless image compression of PNG images ensures this won’t happen.
Figure 14-2: Recursive applications of the image to the magenta pixels. If you are viewing the black-and-white image printed in this book, the magenta area is the rectangle in front of the museum visitor. The Complete Droste Maker ProgramThe following is the source code for drostemaker.py; because this program relies on the Python-only Pillow library, there is no JavaScript equivalent for this project in this book:
Before you run this program, place your image file in the same folder as drostemaker.py. The program will save the recursive image as museum-recursive.png and then open an image viewer to display it. If you want to run the program on your own image that you’ve added a magenta area to, replace Setting UpThe Droste Maker program has only one function, Python
The program begins by importing the Next, we check whether the Python
The For example, passing This parameter prevents the function from recursing until it causes a stack overflow in cases when the magenta area is particularly large. It also lets us pass a smaller argument than Next, we check the color mode of the base image. This can be either Python
The Droste Maker needs to know the color mode so that it can find magenta pixels. The values for each channel range from Finding the Magenta AreaBefore the program can recursively insert the image into the magenta area, it must find the boundaries of the magenta area in the image. This involves finding the leftmost, rightmost, topmost, and bottommost magenta pixels in the image. While the magenta area itself doesn’t need to be a perfect rectangle, the program needs to know the rectangular boundaries of the magenta in order to properly resize the image for insertion. For example, Figure 14-3 shows a base image of the Mona Lisa with the magenta area outlined in white. The magenta pixels are replaced to produce the recursive image.
Figure 14-3: The base image with a magenta area outlined in white (left) and the recursive image it produces (right) To calculate the resizing and placement of the resized image, the program retrieves the width and height of the base image from the Python
These edge variable values are replaced by integer Python
These nested By the time the nested Python
If Resizing the Base ImageWe need to resize the base image to cover the entire magenta area and no more. Figure 14-4 shows the complete resized image overlayed transparently on the original base image. This resized image is cropped so that only the parts over magenta pixels are copied over to the final image.
Figure 14-4: The base image with the magenta area in the monitor (top), the resized image over the base image (middle), and the final recursive image that replaces only the magenta pixels (bottom) We cannot simply resize the base image to the dimensions of the magenta area because it’s unlikely the two share the same aspect ratio, or proportion of the width divided by the height. Doing so results in a recursive image that looks stretched or squished, like Figure 14-5. Instead, we must make the resized image large enough to completely cover the magenta area but still retain the image’s original aspect ratio. This means either setting the width of the resized image to the width of the magenta area such that the height of the resized image is equal to or larger than the height of the magenta area, or setting the height of the resized image to the height of the magenta area such that the width of the resized image is equal to or larger than the width of the magenta area.
Figure 14-5: Resizing the image to the dimensions of the magenta area can result in a different aspect ratio, causing it to look stretched or squished. To calculate the correct resizing dimensions, the program needs to determine the aspect ratio of both the base image and the magenta area: Python
From Because the aspect ratio is the width divided by the height, images with small aspect ratios are taller than they are wide, and those with large aspect ratios are wider than they are tall. An aspect ratio of 1.0 describes a perfect square. The next lines set the dimensions of the resized image after comparing the aspect ratios of the base image and the magenta area:
If the base image’s aspect ratio is less than the magenta area’s aspect ratio, the resized image’s width should match the width of the magenta area. If the base image’s aspect ratio is greater, the resized image’s height should match the height of the magenta area. We then determine the other dimension by multiplying the base image’s height by the width ratio, or the base image’s width by the height ratio. This ensures that the resized image both completely covers the magenta area and remains proportional to its original aspect ratio. We call the We don’t want this, because it could blur the magenta pixels with neighboring non-magenta pixels in the resized image. Our Recursively Placing the Image Within the ImageOnce the base image has been resized, we can place the resized image over the base image. But the pixels from the resized image should be placed over only magenta pixels in the base image. The resized image will be placed such that the top-left corner of the resized image is at the top-left corner of the magenta area: Python
Two nested However, the resized image itself could have magenta pixels, and if so, these will now become part of the base image, as in the top-right image of Figure 14-2. We’ll need to pass the modified base image to a recursive Python
This line is the recursive call in our recursive algorithm, and it’s the last line of code in the Finally, the Droste Maker program begins by passing Python
You can change these filenames to whichever image on your computer you’d like to use with the program. Does the SummaryThis chapter’s project was a program that produces recursive Droste effect images, just like the illustration on old tins of Droste’s Cacao. The program works by using pure magenta pixels with RGB values of (255, 0, 255) to mark the parts of the image that should be replaced by a smaller version. Since this smaller version will also have its own smaller magenta area, the replacements will repeat until the magenta area is gone to produce a recursive image. The base case for our recursive algorithm occurs when no more magenta pixels remain in the image to place the smaller recursive image in, or when the You can modify your own photos to add magenta pixels and then run them through the Droste Maker. The museum patron looking at an exhibit of themself, the cat in front of a computer monitor of the cat in front of a computer monitor, and the faceless Mona Lisa images are just a few examples of the surreal possibilities you can create with this recursive program. Further ReadingThe Wikipedia article for the Droste effect at https://en.wikipedia.org/wiki/Droste_effect has examples of products other than Droste’s Cacao that use the Droste effect. Dutch artist M.C. Escher’s Print Gallery is a famous example of a scene that also contains itself, and you can learn more about it at https://en.wikipedia.org/wiki/Print_Gallery_(M._C._Escher). In a video titled “The Neverending Story (and Droste Effect)” on the Numberphile YouTube channel, Dr. Clifford Stoll discusses recursion and the Droste’s Cacao box art at https://youtu.be/EeuLDnOupCI. Chapter 19 of my book Automate the Boring Stuff with Python, 2nd edition (No Starch Press, 2019) provides a basic tutorial of the Pillow library at https://automatetheboringstuff.com/2e/chapter19. |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |