{"article":{"slug":"making-hybrid-images","title":"Making Hybrid Images","subtitle":null,"summary":"Jeremy Kun explains hybrid images, pictures that read differently up close and from afar, using Fourier analysis: an intuitive tour of the discrete Fourier transform, low- and high-pass Gaussian filtering, and Python code that blends Marilyn Monroe and Albert Einstein into one image, with ideas for further experiments.","content_type":"tutorial","language":"en","canonical_url":"https://www.jeremykun.com/2014/09/29/hybrid-images/","author":{"name":"Jeremy Kun","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"Math ∩ Programming","url":"https://www.jeremykun.com/","listing_slug":null,"listing":null},"topics":[{"name":"Mathematics","slug":"mathematics","url":"https://listedarticles.com/topics/mathematics"},{"name":"Python","slug":"python","url":"https://listedarticles.com/topics/python"},{"name":"Graphics","slug":"graphics","url":"https://listedarticles.com/topics/graphics"},{"name":"Algorithms","slug":"algorithms","url":"https://listedarticles.com/topics/algorithms"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":2292,"reading_minutes":10,"published_at":"2014-09-29T10:00:06.000Z","added_at":"2026-10-18T11:13:07.975Z","updated_at":"2026-10-18T11:13:07.975Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/making-hybrid-images","markdown_url":"https://listedarticles.com/articles/making-hybrid-images.md","example":false,"citation":"Jeremy Kun, Math ∩ Programming. \"Making Hybrid Images.\" 29 Sept 2014. https://www.jeremykun.com/2014/09/29/hybrid-images/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://www.jeremykun.com/2014/09/29/hybrid-images/"},"body_markdown":"#### The Mona Lisa\n\nLeonardo da Vinci’s Mona Lisa is one of the most famous paintings of all time. And there has always been a discussion around her enigmatic smile. He used a trademark Renaissance technique called *sfumato,* which involves many thin layers of glaze mixed with subtle pigments. The striking result is that when you look directly at Mona Lisa’s smile, it seems to disappear. But when you look at the background your peripherals see a smiling face.\n\nOne could spend decades studying the works of these masters from various perspectives, but if we want to hone in on the disappearing nature of that smile, mathematics can provide valuable insights. Indeed, though he may not have known the relationship between his work and da Vinci’s, hundreds of years later Salvador Dali did the artist’s equivalent of mathematically isolating the problem with his painting, “Gala Contemplating the Mediterranean Sea.”\n\n[![](https://www.jeremykun.com/img/2014/gala-dali.jpg)](https://www.jeremykun.com/img/2014/gala-dali.jpg)\n\n#### Gala Contemplating the Mediterranean Sea which at a distance of 20 meters is transformed into the portrait of Abraham Lincoln (Homage to Rothko) - Salvador Dali, 1974\n\nHere you see a woman in the foreground, but step back quite far from the picture and there is a (more or less) clear image of Abraham Lincoln. Here the question of gaze is the blaring focus of the work. Now of course Dali and da Vinci weren’t scribbling down equations and computing integrals; their artistic expression was much less well-defined. But we the artistically challenged have tools of our own: mathematics, science, and programming.\n\nIn 2006 Aude Oliva, Antonio Torralba, and Philippe. G. Schyns used those tools to merge the distance of Dali and the faded smiles of da Vinci into one cohesive idea. In [their 2006 paper](http://web.archive.org/web/20191231032911/http://cvcl.mit.edu:80/publications/OlivaTorralb_Hybrid_Siggraph06.pdf) they presented the notion of a “hybrid image,” presented below.\n\n[![](https://www.jeremykun.com/img/2014/monalisas1.png)](https://www.jeremykun.com/img/2014/monalisas1.png)\n\n#### The Mona Lisas of Science\n\nIf you look closely, you’ll see three women, each of which looks the teensiest bit strange, like they might be trying to suppress a smile, but none of them are smiling. Blur your eyes or step back a few meters, and they clearly look happy. The effect is quite dramatic. At the risk of being overly dramatic, these three women are literally modern day versions of Mona Lisa, the “Mona Lisas of Science,” if you will.\n\nAnother, perhaps more famous version of their technique, since it was more widely publicized, is their “Marilyn Einstein,” which up close is Albert Einstein and from far away is Marilyn Monroe.\n\n[![](https://www.jeremykun.com/img/2014/marilyn-einstein.png)](https://www.jeremykun.com/img/2014/marilyn-einstein.png)\n\n#### Marilyn Einstein\n\nThis one gets to the heart of the question of what the eye sees at close range versus long range. And it turns out that you can address this question (and create brilliant works of art like the ones above) with some basic Fourier analysis.\n\n## Intuitive Fourier analysis (and references)\n\nThe basic idea of Fourier analysis is the idea that smooth functions are hard to understand, and realization of how great it would be if we could decompose them into simpler pieces. Decomposing complex things into simpler parts is one of the main tools in all of mathematics, and Fourier analysis is one of the clearest examples of its application.\n\nIn particular, the things we care about are functions $ f(x)$ with specific properties I won’t detail here like “smoothness” and “finiteness.” And the building blocks are the complex exponential functions\n\n$$\\displaystyle e^{2 \\pi i kx}$$\n\nwhere $ k$ can be any integer. If you have done some linear algebra (and ignore this if you haven’t), then I can summarize the idea succinctly by saying the complex exponentials form an orthonormal basis for the vector space of square-integrable functions.\n\nBack in colloquial language, what the Fourier theorem says is that *any* function of the kind we care about can be broken down into (perhaps infinitely many) pieces of this form called *Fourier coefficients* (I’m abusing the word “coefficient” here). The way it’s breaking down is also pleasingly simple: it’s a linear combination. Informally that means you’re just adding up all the complex exponentials with specific weights for each one. Mathematically, the conversion from the function to its Fourier coefficients is called the *Fourier transform,* and the set of all Fourier coefficients together is called the *Fourier spectrum*. So if you want to learn about your function $ f$, or more importantly *modify* it in some way, you can inspect and modify its spectrum instead. The reason this is useful is that Fourier coefficients have very natural interpretations in sound and images, as we’ll see for the latter.\n\nWe wrote $ f(x)$ and the complex exponential as a function of *one* real variable, but you can do the same thing for two variables (or a hundred!). And, if you’re willing to do some abusing and ignore the complexness of complex numbers, then you can visualize “complex exponentials in two variables” as images of stripes whose orientation and thickness correspond to two parameters (i.e., the $ k$ in the offset equation becomes two coefficients). The video below shows how such complex exponentials can be used to build up an image of striking detail. The left frame shows which complex exponential is currently being added, and the right frame shows the layers all put together. I think the result is quite beautiful.\n\nThis just goes to show how powerful da Vinci’s idea of fine layering is: it’s as powerful as possible because it can create *any image!*\n\nNow for digital images like the one above, everything is finite. So rather than have an infinitely precise function and a corresponding infinite set of Fourier coefficients, you get a finite list of sampled values (pixels) and a corresponding grid of Fourier coefficients. But the important and beautiful theorem is, and I want to emphasize how groundbreakingly important this is:\n\nIf you give me an image (or any function!) I can *compute* the decomposition very efficiently.\n\nAnd the same theorem lets you go the other way: if you give me the decomposition, I can compute the original function’s samples quite easily. The algorithm to do this is called the Fast Fourier transform, and if *any* piece of mathematics or computer science has a legitimate claim to changing the world, it’s the Fast Fourier transform. It’s hard to [pinpoint specific applications](http://dsp.stackexchange.com/questions/69/why-is-the-fourier-transform-so-important), because the transform is so ubiquitous across science and engineering, but we definitely would not have cell phones, satellites, internet, or electronics anywhere near as small as we do without the Fourier transform and the ability to compute it quickly.\n\nConstructing hybrid images is one particularly nice example of manipulating the Fourier spectrum of two images, and then combining them back into a single image. That’s what we’ll do now.\n\nAs a side note, by the nature of brevity, the discussion above is a big disservice to the mathematics involved. I summarized and abused in ways that mathematicians would object to. If you want to see a much better treatment of the material, this blog has a long series of posts developing Fourier transforms and their discrete analogues from scratch. See our four [primers](https://www.jeremykun.com/primers/), which lead into the main content posts where we [implement the Fast Fourier transform](https://www.jeremykun.com/2012/07/18/the-fast-fourier-transform/ \"The Fast Fourier Transform\") in Python and use it to [apply digital watermarks to an image](https://www.jeremykun.com/2013/12/30/the-two-dimensional-fourier-transform-and-digital-watermarking/ \"The Two-Dimensional Fourier Transform and Digital Watermarking\"). Note that in those posts, as in this one, all of the materials and code used are posted on [this blog’s Github page](https://github.com/j2kun/).\n\n## High and low frequencies\n\nFor images, interpreting ranges of Fourier coefficients is easy to do. You can imagine the coefficients lying on a grid in the plane like so:\n\n[![](https://www.jeremykun.com/img/2013/sherlock-spectrum.png)](https://www.jeremykun.com/img/2013/sherlock-spectrum.png)\n\n#### An example of a Fourier spectrum\n\nEach dot in this grid corresponds to how “intense” the Fourier coefficient is. That is, it’s the magnitude of the (complex) coefficient of the corresponding complex exponential. Now the points that are closer to the origin correspond informally to the broad, smooth changes in the image. These are called “low frequency” coefficients. And points that are further away correspond to sharp changes and edges, and are likewise called “high frequency” components. So the if you wanted to “hybridize” two images, you’d pick ones with complementary intensities in these regions. That’s why Einstein (with all his wiry hair and wrinkles) and Monroe (with smooth features) are such good candidates. That’s also why, when we layered the Fourier components one by one in the video from earlier, we see the fuzzy shapes emerge before the fine details.\n\nMoreover, we can “extract” the high frequency Fourier components by simply removing the low frequency ones. It’s a bit more complicated than that, since you want the transition from “something” to “nothing” to be smooth in sone sense. A proper discussion of this would go into sampling and the Nyquist frequency, but that’s beyond the scope of this post. Rather, we’ll just define a family of “filtering functions” without motivation and observe that they work well.\n\n**Definition:** The *Gaussian filter function* with variance $ \\sigma$ and center $ (a, b)$ is the function\n\n$$\\displaystyle g(x,y) = e^{-\\frac{(x – a)^2 + (y – b)^2}{2 \\sigma^2}}$$\n\nIt looks like this\n\n[![](https://www.jeremykun.com/img/2014/gaussian2d.png)](https://www.jeremykun.com/img/2014/gaussian2d.png)\n\n#### A Gaussian, image credit Wikipedia\n\nIn particular, at zero the function is 1 and it gradually drops to zero as you get farther away. The parameter $ \\sigma$ controls the rate at which it vanishes, and in the picture above the center is set to $ (0,0)$.\n\nNow what we’ll do is take our image, compute its spectrum, and multiply coordinatewise with a certain Gaussian function. If we’re trying to get rid of high-frequency components (called a “low-pass filter” because it lets the low frequencies through), we can just multiply the Fourier coefficients directly by the filter values $ g(x,y)$, and if we’re doing a “high-pass filter” we multiply by $ 1 – g(x,y)$.\n\nBefore we get to the code, here’s an example of a low-pass filter. First, take this image of Marilyn Monroe\n\n[![](https://www.jeremykun.com/img/2014/marilyn1.png)](https://www.jeremykun.com/img/2014/marilyn1.png)\n\n#### Marilyn Monroe\n\nNow compute its Fourier transform\n\n[![](https://www.jeremykun.com/img/2014/dft.png)](https://www.jeremykun.com/img/2014/dft.png)\n\n#### Marilyn's DFT\n\nApply the low-pass filter\n\n[![](https://www.jeremykun.com/img/2014/filtered-dft1.png)](https://www.jeremykun.com/img/2014/filtered-dft1.png)\n\n#### Marilyn's Filtered DFT\n\nAnd reverse the Fourier transform to get an image\n\n[![](https://www.jeremykun.com/img/2014/low-passed-marilyn1.png)](https://www.jeremykun.com/img/2014/low-passed-marilyn1.png)\n\n#### Low-passed Marilyn\n\nIn fact, this is a common operation in programs like photoshop for blurring an image (it’s called a *Gaussian blur* for obvious reasons). Here’s the python code to do this. You can [download it](https://github.com/j2kun/hybrid-images) along with all of the other resources used in making this post on [this blog’s Github page](https://github.com/j2kun/).\n\n```\nimport numpy\nfrom numpy.fft import fft2, ifft2, fftshift, ifftshift\nfrom scipy import misc\nfrom scipy import ndimage\nimport math\n\ndef makeGaussianFilter(numRows, numCols, sigma, highPass=True):\n   centerI = int(numRows/2) + 1 if numRows % 2 == 1 else int(numRows/2)\n   centerJ = int(numCols/2) + 1 if numCols % 2 == 1 else int(numCols/2)\n\n   def gaussian(i,j):\n      coefficient = math.exp(-1.0 * ((i - centerI)**2 + (j - centerJ)**2) / (2 * sigma**2))\n      return 1 - coefficient if highPass else coefficient\n\n   return numpy.array([[gaussian(i,j) for j in range(numCols)] for i in range(numRows)])\n\ndef filterDFT(imageMatrix, filterMatrix):\n   shiftedDFT = fftshift(fft2(imageMatrix))\n   filteredDFT = shiftedDFT * filterMatrix\n   return ifft2(ifftshift(filteredDFT))\n\ndef lowPass(imageMatrix, sigma):\n   n,m = imageMatrix.shape\n   return filterDFT(imageMatrix, makeGaussianFilter(n, m, sigma, highPass=False))\n\ndef highPass(imageMatrix, sigma):\n   n,m = imageMatrix.shape\n   return filterDFT(imageMatrix, makeGaussianFilter(n, m, sigma, highPass=True))\n\nif __name__ == \"__main__\":\n   marilyn = ndimage.imread(\"marilyn.png\", flatten=True)\n   lowPassedMarilyn = lowPass(marilyn, 20)\n   misc.imsave(\"low-passed-marilyn.png\", numpy.real(lowPassedMarilyn))\n```\n\nThe first function samples the values from a Gaussian function with the specified parameters, discretizing the function and storing the values in a matrix. Then the `filterDFT` function applies the filter by doing coordinatewise multiplication (note these are all numpy arrays). We can do the same thing with a high-pass filter, producing the edgy image below\n\n[![](https://www.jeremykun.com/img/2014/high-passed-marilyn1.png)](https://www.jeremykun.com/img/2014/high-passed-marilyn1.png)\n\n#### High-passed Marilyn\n\nAnd if we compute the average of these two images, we basically get back to the original.\n\n[![](https://www.jeremykun.com/img/2014/sum-of-marilyns1.png)](https://www.jeremykun.com/img/2014/sum-of-marilyns1.png)\n\n#### Sum of two Marilyns\n\nSo the only difference between this and a hybrid image is that you take the low-passed part of one image and the high-passed part of another. Then the art is in balancing the parameters so as to make the averaged image look right. Indeed, with the following picture of Einstein and the above shot of Monroe, we can get a pretty good recreation of the Oliva-Torralba-Schyns piece. I think with more tinkering it could be even better (I did barely any centering/aligning/resizing to the original images).\n\n[![](https://www.jeremykun.com/img/2014/marilyn-einstein-hybrid-collage.png)](https://www.jeremykun.com/img/2014/marilyn-einstein-hybrid-collage.png)\n\n#### Albert Einstein, Marilyn Monroe, and their hybridization.\n\nAnd here’s the code for it\n\n```\ndef hybridImage(highFreqImg, lowFreqImg, sigmaHigh, sigmaLow):\n   highPassed = highPass(highFreqImg, sigmaHigh)\n   lowPassed = lowPass(lowFreqImg, sigmaLow)\n\n   return highPassed + lowPassed\n```\n\nInterestingly enough, doing it in reverse doesn’t give quite as pleasing results, but it still technically works. So there’s something particularly important that the high-passed image does have a lot of high-frequency components, and vice versa for the low pass.\n\n[![](https://www.jeremykun.com/img/2014/backwards.png)](https://www.jeremykun.com/img/2014/backwards.png)\n\n#### The reverse high/low pass\n\nYou can see some of the other hybrid images Oliva et al constructed over at their [web gallery](https://web.archive.org/web/20180311064128/http://cvcl.mit.edu/hybrid_gallery/gallery.html).\n\n## Next Steps\n\nHow can we take this idea further? There are a few avenues I can think of. The most obvious one would be to see how this extends to video. Could one come up with generic parameters so that when two videos are hybridized (frame by frame, using this technique) it is only easy to see one at close distance? Or else, could we apply a three-dimensional transform to a video and modify that in some principled way? I think one would not likely find anything astounding, but who knows?\n\nSecond would be to look at the [many other transforms](http://en.wikipedia.org/wiki/List_of_transforms) we have at our disposal. How does manipulating the spectra of these transforms affect the original image, and can you make images that are hybridized in senses other than this one?\n\nAnd finally, can we bring this idea down in dimension to work with one-dimensional signals? In particular, can we hybridize music? It could usher in a new generation of mashup songs that sound different depending on whether you wear earmuffs 🙂\n\nUntil next time!\n","body_html":"<h4 id=\"the-mona-lisa\">The Mona Lisa</h4>\n<p>Leonardo da Vinci’s Mona Lisa is one of the most famous paintings of all time. And there has always been a discussion around her enigmatic smile. He used a trademark Renaissance technique called <em>sfumato,</em> which involves many thin layers of glaze mixed with subtle pigments. The striking result is that when you look directly at Mona Lisa’s smile, it seems to disappear. But when you look at the background your peripherals see a smiling face.</p>\n<p>One could spend decades studying the works of these masters from various perspectives, but if we want to hone in on the disappearing nature of that smile, mathematics can provide valuable insights. Indeed, though he may not have known the relationship between his work and da Vinci’s, hundreds of years later Salvador Dali did the artist’s equivalent of mathematically isolating the problem with his painting, “Gala Contemplating the Mediterranean Sea.”</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/gala-dali.jpg\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/gala-dali.jpg\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"gala-contemplating-the-mediterranean-sea-which-at-a-distance-of-\">Gala Contemplating the Mediterranean Sea which at a distance of 20 meters is transformed into the portrait of Abraham Lincoln (Homage to Rothko) - Salvador Dali, 1974</h4>\n<p>Here you see a woman in the foreground, but step back quite far from the picture and there is a (more or less) clear image of Abraham Lincoln. Here the question of gaze is the blaring focus of the work. Now of course Dali and da Vinci weren’t scribbling down equations and computing integrals; their artistic expression was much less well-defined. But we the artistically challenged have tools of our own: mathematics, science, and programming.</p>\n<p>In 2006 Aude Oliva, Antonio Torralba, and Philippe. G. Schyns used those tools to merge the distance of Dali and the faded smiles of da Vinci into one cohesive idea. In <a href=\"http://web.archive.org/web/20191231032911/http://cvcl.mit.edu:80/publications/OlivaTorralb_Hybrid_Siggraph06.pdf\" rel=\"nofollow ugc noopener\">their 2006 paper</a> they presented the notion of a “hybrid image,” presented below.</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/monalisas1.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/monalisas1.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"the-mona-lisas-of-science\">The Mona Lisas of Science</h4>\n<p>If you look closely, you’ll see three women, each of which looks the teensiest bit strange, like they might be trying to suppress a smile, but none of them are smiling. Blur your eyes or step back a few meters, and they clearly look happy. The effect is quite dramatic. At the risk of being overly dramatic, these three women are literally modern day versions of Mona Lisa, the “Mona Lisas of Science,” if you will.</p>\n<p>Another, perhaps more famous version of their technique, since it was more widely publicized, is their “Marilyn Einstein,” which up close is Albert Einstein and from far away is Marilyn Monroe.</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/marilyn-einstein.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/marilyn-einstein.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"marilyn-einstein\">Marilyn Einstein</h4>\n<p>This one gets to the heart of the question of what the eye sees at close range versus long range. And it turns out that you can address this question (and create brilliant works of art like the ones above) with some basic Fourier analysis.</p>\n<h2 id=\"intuitive-fourier-analysis-and-references\">Intuitive Fourier analysis (and references)</h2>\n<p>The basic idea of Fourier analysis is the idea that smooth functions are hard to understand, and realization of how great it would be if we could decompose them into simpler pieces. Decomposing complex things into simpler parts is one of the main tools in all of mathematics, and Fourier analysis is one of the clearest examples of its application.</p>\n<p>In particular, the things we care about are functions $ f(x)$ with specific properties I won’t detail here like “smoothness” and “finiteness.” And the building blocks are the complex exponential functions</p>\n<p>$$\\displaystyle e^{2 \\pi i kx}$$</p>\n<p>where $ k$ can be any integer. If you have done some linear algebra (and ignore this if you haven’t), then I can summarize the idea succinctly by saying the complex exponentials form an orthonormal basis for the vector space of square-integrable functions.</p>\n<p>Back in colloquial language, what the Fourier theorem says is that <em>any</em> function of the kind we care about can be broken down into (perhaps infinitely many) pieces of this form called <em>Fourier coefficients</em> (I’m abusing the word “coefficient” here). The way it’s breaking down is also pleasingly simple: it’s a linear combination. Informally that means you’re just adding up all the complex exponentials with specific weights for each one. Mathematically, the conversion from the function to its Fourier coefficients is called the <em>Fourier transform,</em> and the set of all Fourier coefficients together is called the <em>Fourier spectrum</em>. So if you want to learn about your function $ f$, or more importantly <em>modify</em> it in some way, you can inspect and modify its spectrum instead. The reason this is useful is that Fourier coefficients have very natural interpretations in sound and images, as we’ll see for the latter.</p>\n<p>We wrote $ f(x)$ and the complex exponential as a function of <em>one</em> real variable, but you can do the same thing for two variables (or a hundred!). And, if you’re willing to do some abusing and ignore the complexness of complex numbers, then you can visualize “complex exponentials in two variables” as images of stripes whose orientation and thickness correspond to two parameters (i.e., the $ k$ in the offset equation becomes two coefficients). The video below shows how such complex exponentials can be used to build up an image of striking detail. The left frame shows which complex exponential is currently being added, and the right frame shows the layers all put together. I think the result is quite beautiful.</p>\n<p>This just goes to show how powerful da Vinci’s idea of fine layering is: it’s as powerful as possible because it can create <em>any image!</em></p>\n<p>Now for digital images like the one above, everything is finite. So rather than have an infinitely precise function and a corresponding infinite set of Fourier coefficients, you get a finite list of sampled values (pixels) and a corresponding grid of Fourier coefficients. But the important and beautiful theorem is, and I want to emphasize how groundbreakingly important this is:</p>\n<p>If you give me an image (or any function!) I can <em>compute</em> the decomposition very efficiently.</p>\n<p>And the same theorem lets you go the other way: if you give me the decomposition, I can compute the original function’s samples quite easily. The algorithm to do this is called the Fast Fourier transform, and if <em>any</em> piece of mathematics or computer science has a legitimate claim to changing the world, it’s the Fast Fourier transform. It’s hard to <a href=\"http://dsp.stackexchange.com/questions/69/why-is-the-fourier-transform-so-important\" rel=\"nofollow ugc noopener\">pinpoint specific applications</a>, because the transform is so ubiquitous across science and engineering, but we definitely would not have cell phones, satellites, internet, or electronics anywhere near as small as we do without the Fourier transform and the ability to compute it quickly.</p>\n<p>Constructing hybrid images is one particularly nice example of manipulating the Fourier spectrum of two images, and then combining them back into a single image. That’s what we’ll do now.</p>\n<p>As a side note, by the nature of brevity, the discussion above is a big disservice to the mathematics involved. I summarized and abused in ways that mathematicians would object to. If you want to see a much better treatment of the material, this blog has a long series of posts developing Fourier transforms and their discrete analogues from scratch. See our four <a href=\"https://www.jeremykun.com/primers/\" rel=\"nofollow ugc noopener\">primers</a>, which lead into the main content posts where we <a href=\"https://www.jeremykun.com/2012/07/18/the-fast-fourier-transform/\" title=\"The Fast Fourier Transform\" rel=\"nofollow ugc noopener\">implement the Fast Fourier transform</a> in Python and use it to <a href=\"https://www.jeremykun.com/2013/12/30/the-two-dimensional-fourier-transform-and-digital-watermarking/\" title=\"The Two-Dimensional Fourier Transform and Digital Watermarking\" rel=\"nofollow ugc noopener\">apply digital watermarks to an image</a>. Note that in those posts, as in this one, all of the materials and code used are posted on <a href=\"https://github.com/j2kun/\" rel=\"nofollow ugc noopener\">this blog’s Github page</a>.</p>\n<h2 id=\"high-and-low-frequencies\">High and low frequencies</h2>\n<p>For images, interpreting ranges of Fourier coefficients is easy to do. You can imagine the coefficients lying on a grid in the plane like so:</p>\n<p><a href=\"https://www.jeremykun.com/img/2013/sherlock-spectrum.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2013/sherlock-spectrum.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"an-example-of-a-fourier-spectrum\">An example of a Fourier spectrum</h4>\n<p>Each dot in this grid corresponds to how “intense” the Fourier coefficient is. That is, it’s the magnitude of the (complex) coefficient of the corresponding complex exponential. Now the points that are closer to the origin correspond informally to the broad, smooth changes in the image. These are called “low frequency” coefficients. And points that are further away correspond to sharp changes and edges, and are likewise called “high frequency” components. So the if you wanted to “hybridize” two images, you’d pick ones with complementary intensities in these regions. That’s why Einstein (with all his wiry hair and wrinkles) and Monroe (with smooth features) are such good candidates. That’s also why, when we layered the Fourier components one by one in the video from earlier, we see the fuzzy shapes emerge before the fine details.</p>\n<p>Moreover, we can “extract” the high frequency Fourier components by simply removing the low frequency ones. It’s a bit more complicated than that, since you want the transition from “something” to “nothing” to be smooth in sone sense. A proper discussion of this would go into sampling and the Nyquist frequency, but that’s beyond the scope of this post. Rather, we’ll just define a family of “filtering functions” without motivation and observe that they work well.</p>\n<p><strong>Definition:</strong> The <em>Gaussian filter function</em> with variance $ \\sigma$ and center $ (a, b)$ is the function</p>\n<p>$$\\displaystyle g(x,y) = e^{-\\frac{(x – a)^2 + (y – b)^2}{2 \\sigma^2}}$$</p>\n<p>It looks like this</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/gaussian2d.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/gaussian2d.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"a-gaussian-image-credit-wikipedia\">A Gaussian, image credit Wikipedia</h4>\n<p>In particular, at zero the function is 1 and it gradually drops to zero as you get farther away. The parameter $ \\sigma$ controls the rate at which it vanishes, and in the picture above the center is set to $ (0,0)$.</p>\n<p>Now what we’ll do is take our image, compute its spectrum, and multiply coordinatewise with a certain Gaussian function. If we’re trying to get rid of high-frequency components (called a “low-pass filter” because it lets the low frequencies through), we can just multiply the Fourier coefficients directly by the filter values $ g(x,y)$, and if we’re doing a “high-pass filter” we multiply by $ 1 – g(x,y)$.</p>\n<p>Before we get to the code, here’s an example of a low-pass filter. First, take this image of Marilyn Monroe</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/marilyn1.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/marilyn1.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"marilyn-monroe\">Marilyn Monroe</h4>\n<p>Now compute its Fourier transform</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/dft.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/dft.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"marilyn-s-dft\">Marilyn&#39;s DFT</h4>\n<p>Apply the low-pass filter</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/filtered-dft1.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/filtered-dft1.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"marilyn-s-filtered-dft\">Marilyn&#39;s Filtered DFT</h4>\n<p>And reverse the Fourier transform to get an image</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/low-passed-marilyn1.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/low-passed-marilyn1.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"low-passed-marilyn\">Low-passed Marilyn</h4>\n<p>In fact, this is a common operation in programs like photoshop for blurring an image (it’s called a <em>Gaussian blur</em> for obvious reasons). Here’s the python code to do this. You can <a href=\"https://github.com/j2kun/hybrid-images\" rel=\"nofollow ugc noopener\">download it</a> along with all of the other resources used in making this post on <a href=\"https://github.com/j2kun/\" rel=\"nofollow ugc noopener\">this blog’s Github page</a>.</p>\n<pre><code>import numpy\nfrom numpy.fft import fft2, ifft2, fftshift, ifftshift\nfrom scipy import misc\nfrom scipy import ndimage\nimport math\n\ndef makeGaussianFilter(numRows, numCols, sigma, highPass=True):\n   centerI = int(numRows/2) + 1 if numRows % 2 == 1 else int(numRows/2)\n   centerJ = int(numCols/2) + 1 if numCols % 2 == 1 else int(numCols/2)\n\n   def gaussian(i,j):\n      coefficient = math.exp(-1.0 * ((i - centerI)**2 + (j - centerJ)**2) / (2 * sigma**2))\n      return 1 - coefficient if highPass else coefficient\n\n   return numpy.array([[gaussian(i,j) for j in range(numCols)] for i in range(numRows)])\n\ndef filterDFT(imageMatrix, filterMatrix):\n   shiftedDFT = fftshift(fft2(imageMatrix))\n   filteredDFT = shiftedDFT * filterMatrix\n   return ifft2(ifftshift(filteredDFT))\n\ndef lowPass(imageMatrix, sigma):\n   n,m = imageMatrix.shape\n   return filterDFT(imageMatrix, makeGaussianFilter(n, m, sigma, highPass=False))\n\ndef highPass(imageMatrix, sigma):\n   n,m = imageMatrix.shape\n   return filterDFT(imageMatrix, makeGaussianFilter(n, m, sigma, highPass=True))\n\nif __name__ == &quot;__main__&quot;:\n   marilyn = ndimage.imread(&quot;marilyn.png&quot;, flatten=True)\n   lowPassedMarilyn = lowPass(marilyn, 20)\n   misc.imsave(&quot;low-passed-marilyn.png&quot;, numpy.real(lowPassedMarilyn))</code></pre>\n<p>The first function samples the values from a Gaussian function with the specified parameters, discretizing the function and storing the values in a matrix. Then the <code>filterDFT</code> function applies the filter by doing coordinatewise multiplication (note these are all numpy arrays). We can do the same thing with a high-pass filter, producing the edgy image below</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/high-passed-marilyn1.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/high-passed-marilyn1.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"high-passed-marilyn\">High-passed Marilyn</h4>\n<p>And if we compute the average of these two images, we basically get back to the original.</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/sum-of-marilyns1.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/sum-of-marilyns1.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"sum-of-two-marilyns\">Sum of two Marilyns</h4>\n<p>So the only difference between this and a hybrid image is that you take the low-passed part of one image and the high-passed part of another. Then the art is in balancing the parameters so as to make the averaged image look right. Indeed, with the following picture of Einstein and the above shot of Monroe, we can get a pretty good recreation of the Oliva-Torralba-Schyns piece. I think with more tinkering it could be even better (I did barely any centering/aligning/resizing to the original images).</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/marilyn-einstein-hybrid-collage.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/marilyn-einstein-hybrid-collage.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"albert-einstein-marilyn-monroe-and-their-hybridization\">Albert Einstein, Marilyn Monroe, and their hybridization.</h4>\n<p>And here’s the code for it</p>\n<pre><code>def hybridImage(highFreqImg, lowFreqImg, sigmaHigh, sigmaLow):\n   highPassed = highPass(highFreqImg, sigmaHigh)\n   lowPassed = lowPass(lowFreqImg, sigmaLow)\n\n   return highPassed + lowPassed</code></pre>\n<p>Interestingly enough, doing it in reverse doesn’t give quite as pleasing results, but it still technically works. So there’s something particularly important that the high-passed image does have a lot of high-frequency components, and vice versa for the low pass.</p>\n<p><a href=\"https://www.jeremykun.com/img/2014/backwards.png\" rel=\"nofollow ugc noopener\"><img src=\"https://www.jeremykun.com/img/2014/backwards.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"the-reverse-high-low-pass\">The reverse high/low pass</h4>\n<p>You can see some of the other hybrid images Oliva et al constructed over at their <a href=\"https://web.archive.org/web/20180311064128/http://cvcl.mit.edu/hybrid_gallery/gallery.html\" rel=\"nofollow ugc noopener\">web gallery</a>.</p>\n<h2 id=\"next-steps\">Next Steps</h2>\n<p>How can we take this idea further? There are a few avenues I can think of. The most obvious one would be to see how this extends to video. Could one come up with generic parameters so that when two videos are hybridized (frame by frame, using this technique) it is only easy to see one at close distance? Or else, could we apply a three-dimensional transform to a video and modify that in some principled way? I think one would not likely find anything astounding, but who knows?</p>\n<p>Second would be to look at the <a href=\"http://en.wikipedia.org/wiki/List_of_transforms\" rel=\"nofollow ugc noopener\">many other transforms</a> we have at our disposal. How does manipulating the spectra of these transforms affect the original image, and can you make images that are hybridized in senses other than this one?</p>\n<p>And finally, can we bring this idea down in dimension to work with one-dimensional signals? In particular, can we hybridize music? It could usher in a new generation of mashup songs that sound different depending on whether you wear earmuffs 🙂</p>\n<p>Until next time!</p>","headings":[{"level":2,"text":"Intuitive Fourier analysis (and references)","id":"intuitive-fourier-analysis-and-references"},{"level":2,"text":"High and low frequencies","id":"high-and-low-frequencies"},{"level":2,"text":"Next Steps","id":"next-steps"}]}}