Fast content-aware image resizing
A simple content-aware image resizer, quite small, readable and fast: over 6 times faster than the LiquidRescale GIMP plugin, which is written in C.
Implemented object removal and preservation.
Seam carving is a recently presented method to resize images "intelligently", by removing pixels of the image that carry little information. It can do things like turning this image into this one Go watch the video for more examples.
I quickly reimplemented it in OCaml, obtaining an unexpected two-order-of-magnitude speed increase. This was slightly surprising because the Python version uses optimized extensions written in C, and Psyco should have brought the parts written in Python to at least one tenth of the native speed. In this case, the key, it turns out, was not the implementation language but the algorithm itself.
Seam carving is performed in three steps, executed iteratively (each run shrinks the image by one pixel):
- compute an energy map, where high energy regions correspond to detailed parts of the image that are to be retained
- find a minimum energy seam, i.e., a connected path which traverses regions of low energy. If you're resizing the image horizontally, you have to find a path that goes from the top of the image to the bottom.
- remove the pixels contained in the minimum energy seam. This tends to erase parts of the image with few details (low energy) and of little importance.
The authors of the original paper examined several image energy functions and found that simple ones, based on the gradient of the image intensity, work well. Both the Python implementation and mine used thus a Sobel filter *1. The difference lies in the way the energy map is updated after a seam has been carved. Whereas the Python version uses a fast C routine to apply the Sobel filter to the whole resized image (which has seen either its width or its height reduced by one pixel after the deletion of the seam), my code selectively updates the energy map only for the parts of the image that have been modified.
It is only very recently that I found the GIMP LiquidRescaling Plug-in. Even though it uses a simpler edge detector (one that could run up to three times faster than Sobel in theory), it is over 6 times slower than my implementation. After a cursory read of the 2200 lines of code devoted to the render code, I believe the culprit is the heavyweight data structure used to represent the image. To be fair, some of the extra info is used for things my implementation doesn't do yet, such as energy biasing (this allows you to use another pixmap to indicate which regions are to be preserved). Still, I'm quite sure I can implement energy biasing on top of the normal energy computation without modifying the underlying image representation (a mere matrix of rgb pixels), with a very small effect on performance, and most importantly without making the common case (no biasing) any slower. My seam carving code is abstracted over the energy computation (it's a functor), so it shouldn't be difficult.
great job, Mauricio !!
Allow me to quote from README.txt:
There's nothing particularly impressive about this implementation, and basically no claims to fame. There's however some value in it because it is quite small, readable and fast. Indeed, it is over 6 times faster than the GIMP LiquidRescale Plug-in on my machine.
This is quite straightforward code, but it avoids the mistake involving energy updates from the Python version, and performs much better than the GIMP plugin by virtue of the simpler data structure used for the energy map.
I have a slight problem... the scale of the images now look different the 2nd image doesnt have the same scale :/
The scales are supposed to be different. See the video or the papers for more details.
You can resize the image vertically in a second pass with the -vert option if you want to preserve the X:Y dimension ratio.
The cmdline can obviously be improved, but I didn't think anybody would really care.
Can this program make images bigger w/out pixelating them?
Not yet, I'm probably coding that soon.
Nice work again!
If you'd like to see a funny result, compare to
hah a long legged dog
This is the sort of images that need energy biasing for object preservation.
*1 my code also includes a histogram of gradients (HoG) energy function, which didn't seem to perform better than the Sobel filter
- 1278 http://programming.reddit.com
- 328 http://en.wikipedia.org/wiki/Seam_carving
- 90 http://del.icio.us/popular
- 69 http://programming.reddit.com/info/2vcbe/comments
- 68 http://programming.reddit.com/new
- 45 http://anarchaia.org
- 38 http://ja.reddit.com
- 38 http://planetruby.0x42.net
- 34 http://programming.reddit.com/?offset=25
- 20 http://www.planetrubyonrails.com