posts - 81, comments - 262, trackbacks - 0

Seam Carving for Resizing using SEAMonster


I first saw seam carving, http://www.seamcarving.com/, about a year ago when it was so hot that just downloading the white paper was a challenge (see post). I immediately dug for code with no luck. A few months later I noted some python code, thought of translating that but the time just wasn't available. I did another check for seam carving code lately and found SEAMonster. The code runs well as is, though the algorithm was a bit slower than I had hoped. Resizing a 400x300 jpg image on my core2 laptop took a few seconds. While this is just great for applications, not quite where I want it for web use, say in a resize library for a web app.

 

One issue I did find with SEAMonster, a small 'bug' in the Carve method when it carves to a size. The algorithm will stop on the first constraint minimizing, and will not alternate carving directions automatically. I made a small change to it so that it will stop when both dimensions have been met and so that it will carve down both sizes. The redefined Carve() method is included below.

 

The SEAMonster library, once compiled can be referenced from a web app. I originally wanted to include the source code within the web app for convenience, but the unsafe code steered my away from that approach.

 

Some Thoughts:

  • I noticed that the source for the carving depends on unsafe code; I would like to look into this to see if it can be made 'safe' for web apps.
  • Hopefully profiling/tuning/cleaning the code can get carving images in the 600x600 range to less than a second.
  • Add seam insertion ability?
  • Wish I saw this earlier… and dang, I even missed this at Mix in Vegas.

 

Special Thanks to Mike Swanson

 

public void Carve(Direction direction, ComparisonMethod comparisonMethod, Size minimumSize)

{

if (modifiedWidth <= 0 || modifiedHeight <= 0)

{

return;

}

 

// Time this carve

HiPerfTimer timer = new HiPerfTimer();

timer.Start();

 

bmd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),

ImageLockMode.ReadWrite, bitmap.PixelFormat);

 

// Modified By CCook

// Changed it so that it continues until both constraints are met,

// not either one. (while x and y are greater stops on first...)

// Checks are also done on whether the Direction is capable of continuing.

while ((modifiedWidth > 0 && modifiedHeight > 0) && ((

((modifiedWidth > minimumSize.Width ||

modifiedHeight > minimumSize.Height)) && direction == Direction.Optimal) ||

(((modifiedWidth > minimumSize.Width &&

modifiedHeight > minimumSize.Height)) && direction != Direction.Optimal)))

{

// Find the lowest energy seam

Seam lowestEnergySeam;

if (direction == Direction.Vertical || direction == Direction.Horizontal)

{

lowestEnergySeam = seamFunction.FindLowestEnergy(direction, comparisonMethod, Size);

}

else

{

// Modified By CCook

// If a constraint is matched the direction is known so pick the appropriate direction.

// If however, either direction is possible, choose the optimal one.

if (minimumSize.Width == modifiedWidth)

lowestEnergySeam = seamFunction.FindLowestEnergy(Direction.Horizontal, comparisonMethod, Size);

else if (minimumSize.Height == modifiedHeight)

lowestEnergySeam = seamFunction.FindLowestEnergy(Direction.Vertical, comparisonMethod, Size);

else

{

 

// Find lowest energy across both horizontal and vertical directions

Seam isLowest1 = seamFunction.FindLowestEnergy(Direction.Vertical, comparisonMethod, Size);

Seam isLowest2 = seamFunction.FindLowestEnergy(Direction.Horizontal, comparisonMethod, Size);

 

// Use compareValue, since it's been run through the seam comparison method

if (isLowest1.compareValue < isLowest2.compareValue)

{

lowestEnergySeam = isLowest1;

}

else

{

lowestEnergySeam = isLowest2;

}

}

}

 

// Resume unchanged code ...

 

 


Print | posted on Thursday, June 5, 2008 9:06 PM | Filed Under [ Web Programming ]

Powered by:
Powered By Subtext Powered By ASP.NET