Use floats for energy
This commit is contained in:
parent
3984257c45
commit
1d28489c11
@ -23,16 +23,17 @@ void export_image(const char* filename, const void* data, int width, int height,
|
||||
if (!silent) std::cout << "Exporting to \"" << filename << "\".." << std::endl;
|
||||
int errcode = stbi_write_png(filename, width, height, nbChannels, data, nbChannels*width);
|
||||
if (!errcode) {
|
||||
std::cout<<"Error while exporting the resulting image."<<std::endl;
|
||||
std::cerr << "Error while exporting the resulting image." << std::endl;
|
||||
exit(errcode);
|
||||
}
|
||||
}
|
||||
|
||||
/** e_1 energy */
|
||||
std::vector<unsigned char> energy_e1(std::vector<unsigned char> source, int width, int height, int nbChannels) {
|
||||
std::vector<unsigned char> energy(width*height);
|
||||
/** e_1 energy, energy is always normalized between 0 and 1 */
|
||||
std::vector<float> energy_e1(std::vector<unsigned char> source, int width, int height, int nbChannels) {
|
||||
std::vector<float> energy(width*height);
|
||||
|
||||
for(auto i=0 ; i < width ; ++i) {
|
||||
float max_energy = 0;
|
||||
for(auto i=0 ; i < width; ++i) {
|
||||
for(auto j=0; j < height; ++j) {
|
||||
auto indexPixel = nbChannels*(width*j+i);
|
||||
auto indexPixel_up = (j-1 > 0) ? nbChannels*(width*(j-1)+i) : indexPixel;
|
||||
@ -47,17 +48,23 @@ std::vector<unsigned char> energy_e1(std::vector<unsigned char> source, int widt
|
||||
+fabs((float)source[indexPixel_down+ch] - source[indexPixel+ch])
|
||||
+fabs((float)source[indexPixel_left+ch] - source[indexPixel+ch])
|
||||
+fabs((float)source[indexPixel_right+ch] - source[indexPixel+ch])
|
||||
)/(nbChannels*4);
|
||||
);
|
||||
}
|
||||
max_energy = fmax(max_energy, energy[width*j+i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (max_energy == 0) { return energy; }
|
||||
for (auto k=0; k < width*height; k++) {
|
||||
energy[k] = energy[k]/max_energy;
|
||||
}
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
/** Given the energy value, returns the optimal vertical seam */
|
||||
std::vector<int> optimal_vertical_seam(std::vector<unsigned char> energy, int width, int height) {
|
||||
std::vector<unsigned char> dyn_energy(width*height);
|
||||
std::vector<int> optimal_vertical_seam(std::vector<float> energy, int width, int height) {
|
||||
std::vector<float> dyn_energy(width*height);
|
||||
|
||||
//* Find an end of the minimal connected vertical/horizontal seam
|
||||
for (auto i=1; i < height; i++) {
|
||||
@ -66,13 +73,13 @@ std::vector<int> optimal_vertical_seam(std::vector<unsigned char> energy, int wi
|
||||
|
||||
for (auto j=1; j < width; j++) {
|
||||
for (auto i=0; i < height; i++) {
|
||||
int bot_center = (i > 0) ? dyn_energy[width*(i-1)+j] : INT_MAX;
|
||||
int bot_left = (i > 0 && j > 0) ? dyn_energy[width*(i-1)+(j-1)] : INT_MAX;
|
||||
int bot_right = (i > 0 && j+1 < width) ? dyn_energy[width*(i-1)+(j+1)] : INT_MAX;
|
||||
float bot_center = (i > 0) ? dyn_energy[width*(i-1)+j] : __FLT_MAX__;
|
||||
float bot_left = (i > 0 && j > 0) ? dyn_energy[width*(i-1)+(j-1)] : __FLT_MAX__;
|
||||
float bot_right = (i > 0 && j+1 < width) ? dyn_energy[width*(i-1)+(j+1)] : __FLT_MAX__;
|
||||
|
||||
dyn_energy[width*i+j] = min(
|
||||
dyn_energy[width*i+j] = fmin(
|
||||
bot_center,
|
||||
min(
|
||||
fmin(
|
||||
bot_left,
|
||||
bot_right
|
||||
)
|
||||
@ -83,7 +90,7 @@ std::vector<int> optimal_vertical_seam(std::vector<unsigned char> energy, int wi
|
||||
std::vector<int> result(height);
|
||||
// Find the seam end
|
||||
int min_idx = -1;
|
||||
int min_val = INT_MAX;
|
||||
float min_val = __FLT_MAX__;
|
||||
for (auto j=0; j < width; j++) {
|
||||
if (min_val > dyn_energy[width*(height-1)+j]) {
|
||||
min_idx = j;
|
||||
@ -95,17 +102,20 @@ std::vector<int> optimal_vertical_seam(std::vector<unsigned char> energy, int wi
|
||||
//* Backtracking to find the path
|
||||
for (auto i=height-1; i > 0; i--) {
|
||||
// We want to find either (bot_l, bot_c, bot_r) with dyn_energy[.] = min_val - energy[cur]
|
||||
int objective_energy = min_val - energy[i*width+min_idx];
|
||||
float objective_energy = min_val - energy[i*width+min_idx]; //! With float, do we always have x + y - y = x ?
|
||||
|
||||
if (dyn_energy[(i-1)+height*min_idx] == objective_energy) {
|
||||
// min_idx does not change
|
||||
min_val = dyn_energy[(i-1)+height*min_idx];
|
||||
} else if (min_idx > 0 && dyn_energy[(i-1)+height*(min_idx-1)] == objective_energy) {
|
||||
min_val = dyn_energy[(i-1)+height*(min_idx - 1)];
|
||||
if (dyn_energy[(i-1)+height*min_idx] == objective_energy) {
|
||||
// min_idx does not change
|
||||
min_val = dyn_energy[(i-1)+height*min_idx];
|
||||
} else if (min_idx > 0 && dyn_energy[(i-1)+height*(min_idx-1)] == objective_energy) {
|
||||
min_val = dyn_energy[(i-1)+height*(min_idx - 1)];
|
||||
min_idx = min_idx - 1;
|
||||
} else if (min_idx+1 < width && dyn_energy[(i-1)+height*(min_idx+1)] == objective_energy) {
|
||||
min_val = dyn_energy[(i-1)+height*(min_idx + 1)];
|
||||
min_idx = min_idx + 1;
|
||||
} else {
|
||||
std::cerr << "Unable to backtrack path !" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
result[i-1] = min_idx;
|
||||
}
|
||||
@ -116,7 +126,7 @@ std::vector<int> optimal_vertical_seam(std::vector<unsigned char> energy, int wi
|
||||
/** Carves an image by one vertical seam. Returns the optimal seam used */
|
||||
std::vector<int> carving_step_vertical(const std::vector<unsigned char> source, std::vector<unsigned char> &output, int width, int height, int nbChannels) {
|
||||
|
||||
std::vector<unsigned char> energy = energy_e1(source, width, height, nbChannels);
|
||||
std::vector<float> energy = energy_e1(source, width, height, nbChannels);
|
||||
std::vector<int> opt_seam = optimal_vertical_seam(energy, width, height);
|
||||
std::vector<bool> blacklist(width*height);
|
||||
|
||||
@ -175,16 +185,16 @@ int main(int argc, char **argv) {
|
||||
for (auto k=0; k < width*height; k++) { complete_blacklist[k] = false; }
|
||||
for (auto i=0; i < width*height*nbChannels; i++) { source_img[i] = source[i]; }
|
||||
|
||||
std::vector<unsigned char> ini_energy = energy_e1(source_img, width, height, nbChannels);
|
||||
std::vector<float> ini_energy = energy_e1(source_img, width, height, nbChannels);
|
||||
|
||||
//* Prepare final output
|
||||
for (auto k=0; k < width*height; k++) {
|
||||
//output[3*k] = source_img[3*k]/3; //* Uncomment if you prefer to see darkened source image
|
||||
//output[3*k+1] = source_img[3*k+1]/3;
|
||||
//output[3*k+2] = source_img[3*k+2]/3;
|
||||
output[3*k] = ini_energy[k];
|
||||
output[3*k+1] = ini_energy[k];
|
||||
output[3*k+2] = ini_energy[k];
|
||||
output[3*k] = ini_energy[k]*255;
|
||||
output[3*k+1] = ini_energy[k]*255;
|
||||
output[3*k+2] = ini_energy[k]*255;
|
||||
}
|
||||
|
||||
int curWidth = width;
|
||||
|
Loading…
x
Reference in New Issue
Block a user