### Seam Carving using DP Hello together!

I'm currently working on an implementation of the Seam Carving Algorithm, using Dynamic Programming. But sadly my function that is supposed to get the Seam with the lowest Energy doesn't seem to choose the lowest-energy-seam. There is always an offset of about 3 to 4 points in the energy value. So for example the seam has energy of 8.17 when it is supposed to have an energy of 4.15.

This is my code so far:
 ``12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182`` `````` // the DP algorithm // compute and return the minimum energy vertical seam in an array // the returned vector contains at position y the x-coordinate to y std::vector GetMinSeam(const Array& array){ unsigned w = array.Width(); unsigned h = array.Height(); std::vector seam(h); Array e = energies(array); //Array containing all the energies Array dp (w-1,h-2); //dp-table double min = std::numeric_limits::max(); for(unsigned int j=0; j0; --k){ //reconstruct the way of lowest energy in dp-table if(p == w-2){ if(dp(p,k-1)

The Array is a class, that consists of two unsigned values, width and height, as well as the data the cells are holding. There are functions for accessing those values and an overloaded operator "=".

I've tried a lot, but I don't know where the problem is, so I really hope that someone here can take a look and maybe help find the fault.

Thanks a lot! Why don't you print out your dp() table to debug it? You can use a simple replacement energy function (linear or V shape perhaps) and keep width and height small.

Don't try to compute your seam until the dp() table is correct; otherwise you are conflating two separate problems and it's hard to debug

Print p and min after line 40.

Your dp() table "looks" correct (provided the energies are correct); however, I'm not convinced that your back-tracing of the seam is.

Can you give us some complete code to run? (Simplify the energy function as above). Apart from anything else, you can't guarantee that the error isn't in a different bit of code; (your energies() routine is the prime candidate - you need to do a unit test on that alone).

Please try to use the same counting variable in each direction (e.g. lines 15-17 would more naturally have used i than j).

` seam.at(h-2) = o;`
You've just found the minimum energy in row h-3. Why are you indexing the seam at h-2?
Last edited on Okay, so this is my energy function:

 ``123456789101112131415`` ``````double energy(const Array& array, unsigned x, unsigned y){ if ((x == 0 || x == array.Width() - 1) && (y == 0 || y == array.Height() - 1)) return 1; // max distance at the corners // otherwise: sum of all (available) surrounding pixels double result = 0; if (x > 0) result += distance(array(x, y), array(x - 1, y)); if (x < array.Width() - 1) result += distance(array(x, y), array(x + 1, y)); if (y > 0) result += distance(array(x, y), array(x, y - 1)); if (y < array.Height() - 1) result += distance(array(x, y), array(x, y + 1)); return result; }``````

It is using a distance-function, that just calculates std::abs() of two double values. The energies function i used before is just using this function above to compute the energy of a whole array.

I altered the problems you talked about in line 15-17 and line 41 and i added a print after line 40.

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384`` ``````class Array{ private: double* data = nullptr; unsigned int width; unsigned int height; void swap(Array& a); public: Array::Array(unsigned int w, unsigned int h): width{w}, height{h} { data = new double[width*height]; } Array::Array(const Array& a): width{a.width}, height{a.height}{ data = new double[width*height]; std::copy(a.data, a.data + width*height, data); } Array::~Array(){ assert(data != nullptr); delete[] data; } Array& operator=(const Array& a); double& Array::operator()(unsigned int x, unsigned int y){ assert(x < width); assert(y < height); return data[y*width+x]; } unsigned int Width() const; //returns width unsigned int Height() const; //returns height }; double GetSeamEnergy(const Array& array, const std::vector& seam){ double total = 0; for (unsigned y = 0; y < seam.size(); ++y){ total += energy(array,seam[y],y); } return total; } void cut_x(const Array& array, Array& copy, unsigned omit, unsigned y){ for (unsigned x = 0; x != omit; ++x){ copy(x,y) = array(x,y); } for (unsigned x = omit+1; x != array.Width(); ++x){ copy(x-1,y) = array(x,y); } } Array SeamCut(const Array& array, const std::vector& seam){ unsigned w = array.Width(); unsigned h = array.Height(); Array copy(w-1,h); for(std::size_t i = 0; i seam = GetMinSeam(result); energy = GetSeamEnergy(result, seam); result = SeamCut(result, seam); } std::cout << energy; } return 0; }``````

So here I added the class that I'm using as data structure plus a hopefully working easier main function. I left the Array img = empty, so that you can add whatever you want to use for reading the image.

The energies function is working just fine, so if you're saying the computing of my dp table looks fine, then the problem will be most likely in the backtracing of the seam.

Thanks a lot for your help! You already calculated the total energy of the seam in the last row of GetMinSeam:
 ``1234567`` `````` unsigned p,o; //search for lowest energy in last row of dp-table for(o=0; o

Why are you trying to do it again in
 ``1234567`` ``````double GetSeamEnergy(const Array& array, const std::vector& seam){ double total = 0; for (unsigned y = 0; y < seam.size(); ++y){ total += energy(array,seam[y],y); } return total; }``````

?

Also, in GetMinSeam(), which finds minimum summative energy in row h-3
` seam.at(h-2) = o;`
Did you mean
` seam.at(h-2) = p; <==== p, not o`
or even
` seam.at(h-3) = p; <==== h-3, not h-2`

If you want to check the minimum-energy summation CHECK THE ELEMENTS IN THE LAST ROW OF YOUR dp-table FIRST.
Last edited on The seam is a vector that stores in every cell the x value to the corresponding y value seam[y] while x < width and y < height. So in GetMinSeam I'm backtracing those values by looking for the path with the minimum energy in the dp-table, starting with traversing through the last row of the dp table to find the minimum value there and then looking at the values above that one.

GetSeamEnergy is a function to return the total energy of the seam, to check if the seam was calculated correctly or if it is not the minimal seam.

Yes, that's right, it has to be p and not o in line 41. I went through all the indices again and changed some. Now the energy value has gotten a bit better.

 ``12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182`` ``````std::vector GetMinSeam(const Array& array){ unsigned w = array.Width(); unsigned h = array.Height(); std::vector seam(h); Array e = energies(array); Array dp (w,h); double min = std::numeric_limits::max(); for(unsigned int i=0; i0; --k){ if(p == w-1){ if(dp(p,k-1)

How can I check the elements in the last row of my dp-table? Just print them out!

Pick a small example and do it by hand. Check your calculations: i.e. print out dp[][] and the seam.

Isn't your seam energy supposed to be the same as min? Which (if either) gives the correct answer? Yes that is right. I just used the GetSeamEnergy function to check if my Seam gets the same value. And i just realized, that I printed min and it is absolutely not the same value.

Seems like it is time to check the dp-table :) I found something strange. The min I get is 0, but there is no 0 in the last row of the dp-table.

And if I put (dp(o,h-1) <= min) I get 0 again, but this time there is another p. How can that happen, if i just calculate it after printing my dp-table?

Edit: It is working now, when I only remove one seam. I don't really know why there should be a problem for several seams, cause then it should only call on the function several times, but at least there is some progress :D
Or maybe it isn't removing the previous seam properly.
Last edited on Thanks a lot for the good help, i figured it out now :)))
Topic archived. No new replies allowed.