|
Image magic
|
Sep 07th, 2007 (10PM)
|
|
No, I'm not going to appologize for lack of post. But I made a thing!
|
I'll probably post the source for this up in a little bit- it still needs a fair bit of work. But I just thought I'd show off a few examples of something that I've been working on for the past few days.
I also need to admit that this was not my idea. The original idea was sort of stolen. A coworker sent out this link with a message "Get on it man!" as a joke. I've been working on an integrated image editor for websites, and unfortunately I can't show any of that to you. But it's pretty rad for the most part.
Anyways, so this video, in case you don't want to watch, shows off a neat little image resize tool. It basically attempts to maintain context among the "important" parts of the image.
There are two main issues that are brought up. The obvious one, and the one they actually touch on, is how to determine what the important parts are. I'm not 100% sure what method they used, but I came up with an algorithm that would get the job done pretty well. It's a bit of edge detection, so I'm sure there's an official name for it- but I sort of just winged it.
Basically, I'm just taking each pixel, and figuring out the average RGB values that make up the surrounding pixels. It then takes the difference between those two sets of numbers, basically telling me how different any given pixel is from its neighbors. This yields a sort of "energy". The higher the energy, the more different the given pixel is from its buddies.
The second issue is a bit more obvious, once you actually start coding it up. It's simply one of efficiency, and trying to find a middle ground that actually runs at a good speed, and yields good results.
The issue is basically, to optimally do this, you need to do three things for every image. The first is calculate the energy of every pixel. The second is calculate an optimal path that will remove the lowest possible contiguous row (in terms of energy mentioned above), and the third is the calculation that determines the lowest possible contiguous column. The contiguity is a must- if you're just picking the lowest energy pixels, you see some crazy distortion and artifacts show up on the image.
Now, those steps might not sound so bad- but think of what the term "image" refers to. I'm not just talking about the source. Whenever you remove a row, you've just created an entirely new image of size (x,y-1). Which means, for optimal results, you'll need to do this on EVERY removal. It takes a while, that's for sure.
Anyways, those are the challenges. My current (the one that gen'ed these images) implementation is doing the following: First, it only calculates the energy at the beginning of the run. This causes for severe pixellation at around 33% or of original image size (x or y scaled), but before then, it works well for the most part. Also, it's not calculating every conceivable path from left to right to determine the absolute best path. For example, when remove a row (shortening the height), it first starts with each pixel on the x scale, then proceeds to check the pixels to the lower left of that pixel, below that pixel, and to the lower right of that pixel. It takes the smallest one and then adds that pixels energy to a tally. It then checks the same three pixels for that pixel with the smallest energy and so on, until it hits the edge of the image. Once this is calcuted for every pixel at the top of the image, it takes the starting pixel with the lowest energy row branching from it, and then proceeds to remove those lowest energy pixels from the image.
Same idea for the Y axis, or removing a column.
It sucks, and it takes a while.
Anyways, enough boring stuff, here are some examples. First, we have this source image:

Now, here is that image thinned up a bit along the X axis:

Notice how the image is much thinner, but the main focal point (our dear friend the antelope) has remained relatively untouched.
Now, for a vertical shrink, take this forest picture:

Now, here it is, only shorter:

There is a noticable pattern in this one that basically started removing the bottom rows- this makes sense, as they have the lowest general energy. All of those tree parts sort of look the same to the algorithm.
Now, for a final example, a horizontal/vertical shift. Here's the source:

Here it is scaled down a bit:

This example totally sucks, but it does go to show that it can be applied to both the X and Y axis at the same time. Although it really does looks like ass for the most part.
Well, that's about all I have for now. I plan on tweaking it out a bit, but it should show up on the code page within the next few weeks here.
Thanks for reading, comments are more than welcomed.
|
|
|
|
|