Add max_step argument
This commit is contained in:
parent
b99ee153f0
commit
4049dc4510
@ -16,7 +16,6 @@
|
|||||||
bool silent;
|
bool silent;
|
||||||
bool test_energy;
|
bool test_energy;
|
||||||
|
|
||||||
#define min(a, b) { (a < b ? a : b) }
|
|
||||||
|
|
||||||
// Get index for any table indexed by [width*(i : height) + (j : width)], but a : dim_long, b : dim_large
|
// Get index for any table indexed by [width*(i : height) + (j : width)], but a : dim_long, b : dim_large
|
||||||
#define im_index(a, b) \
|
#define im_index(a, b) \
|
||||||
@ -60,7 +59,7 @@ std::vector<float> energy_e1(std::vector<unsigned char> source, int width, int h
|
|||||||
+fabs((float)source[indexPixel_right+ch] - source[indexPixel+ch])
|
+fabs((float)source[indexPixel_right+ch] - source[indexPixel+ch])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
max_energy = fmax(max_energy, energy[width*j+i]);
|
max_energy = std::max(max_energy, energy[width*j+i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +72,7 @@ std::vector<float> energy_e1(std::vector<unsigned char> source, int width, int h
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Given the energy value, returns the optimal seam */
|
/** Given the energy value, returns the optimal seam */
|
||||||
std::vector<int> optimal_seam(std::vector<float> energy, int width, int height, bool vertical) {
|
std::vector<int> optimal_seam(std::vector<float> energy, int width, int height, bool vertical, int max_step=1) {
|
||||||
// dyn_energy is indexed by [dim_large*(i : dim_long) + (j : dim_large)]
|
// dyn_energy is indexed by [dim_large*(i : dim_long) + (j : dim_large)]
|
||||||
std::vector<float> dyn_energy(width*height);
|
std::vector<float> dyn_energy(width*height);
|
||||||
|
|
||||||
@ -87,17 +86,18 @@ std::vector<int> optimal_seam(std::vector<float> energy, int width, int height,
|
|||||||
|
|
||||||
for (auto i=1; i < dim_long; i++) { // Propagate dyn_energy
|
for (auto i=1; i < dim_long; i++) { // Propagate dyn_energy
|
||||||
for (auto j=0; j < dim_large; j++) {
|
for (auto j=0; j < dim_large; j++) {
|
||||||
float bot_center = dyn_energy[dim_large*(i-1) + j];
|
dyn_energy[dim_large*i+j] = __FLT_MAX__;
|
||||||
float bot_left = (j > 0) ? dyn_energy[dim_large*(i-1) + (j-1)] : __FLT_MAX__;
|
|
||||||
float bot_right = (j+1 < dim_large) ? dyn_energy[dim_large*(i-1) + (j+1)] : __FLT_MAX__;
|
|
||||||
|
|
||||||
dyn_energy[dim_large*i+j] = fmin(
|
int lower_bound = std::max(j - max_step, 0);
|
||||||
bot_center,
|
int upper_bound = std::min(j+max_step, dim_large-1);
|
||||||
fmin(
|
|
||||||
bot_left,
|
for (auto k=lower_bound; k <= upper_bound; k++) { // Compute energy based on predecessors
|
||||||
bot_right
|
dyn_energy[dim_large*i+j] = std::min(
|
||||||
)
|
dyn_energy[dim_large*i+j],
|
||||||
) + energy[im_index(i, j)];
|
dyn_energy[dim_large*(i-1)+k]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dyn_energy[dim_large*i+j] += energy[im_index(i, j)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,16 +123,26 @@ std::vector<int> optimal_seam(std::vector<float> energy, int width, int height,
|
|||||||
#define is_next_idx(idx) \
|
#define is_next_idx(idx) \
|
||||||
(dyn_energy[(i-1)*dim_large + idx]+energy[im_index(i, min_idx)] == min_val)
|
(dyn_energy[(i-1)*dim_large + idx]+energy[im_index(i, min_idx)] == min_val)
|
||||||
|
|
||||||
|
// This is not the nicest way to do thiss but we want to check in priority at the center to have straight seams
|
||||||
|
bool found = false;
|
||||||
if (is_next_idx(min_idx)) {
|
if (is_next_idx(min_idx)) {
|
||||||
// min_idx does not change
|
min_val = dyn_energy[(i-1)*dim_large+min_idx];
|
||||||
min_val = dyn_energy[(i-1)*dim_large + min_idx];
|
found = true;
|
||||||
} else if (min_idx > 0 && is_next_idx(min_idx-1)) {
|
}
|
||||||
min_val = dyn_energy[(i-1)*dim_large + (min_idx-1)];
|
for (auto k=1; !found && k <= max_step; k++) {
|
||||||
min_idx = min_idx - 1;
|
if (min_idx+k < dim_large && is_next_idx(min_idx+k)) {
|
||||||
} else if (min_idx+1 < dim_large && is_next_idx(min_idx+1)) {
|
min_val = dyn_energy[(i-1)*dim_large+min_idx+k];
|
||||||
min_val = dyn_energy[(i-1)*dim_large + (min_idx+1)];
|
min_idx = min_idx+k;
|
||||||
min_idx = min_idx + 1;
|
|
||||||
} else {
|
found = true;
|
||||||
|
} else if (min_idx-k >= 0 && is_next_idx(min_idx-k)) {
|
||||||
|
min_val = dyn_energy[(i-1)*dim_large+min_idx-k];
|
||||||
|
min_idx = min_idx-k;
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
std::cerr << "Unable to backtrack path !" << std::endl;
|
std::cerr << "Unable to backtrack path !" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -143,9 +153,9 @@ std::vector<int> optimal_seam(std::vector<float> energy, int width, int height,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Carves an image by one seam. Returns the optimal seam used */
|
/** Carves an image by one seam. Returns the optimal seam used */
|
||||||
std::vector<int> carving_step(const std::vector<unsigned char> source, std::vector<unsigned char> &output, int width, int height, int nbChannels, bool vertical) {
|
std::vector<int> carving_step(const std::vector<unsigned char> source, std::vector<unsigned char> &output, int width, int height, int nbChannels, bool vertical, int max_step=1) {
|
||||||
std::vector<float> energy = energy_e1(source, width, height, nbChannels);
|
std::vector<float> energy = energy_e1(source, width, height, nbChannels);
|
||||||
std::vector<int> opt_seam = optimal_seam(energy, width, height, vertical);
|
std::vector<int> opt_seam = optimal_seam(energy, width, height, vertical, max_step=max_step);
|
||||||
std::vector<bool> blacklist(width*height);
|
std::vector<bool> blacklist(width*height);
|
||||||
|
|
||||||
int dim_large = vertical ? width : height;
|
int dim_large = vertical ? width : height;
|
||||||
@ -174,7 +184,7 @@ std::vector<int> carving_step(const std::vector<unsigned char> source, std::vect
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void seam_carving(unsigned char* source, int width, int height, int nbChannels, const char* out_filename, int nbSeams, bool vertical, bool test_energy=false) {
|
void seam_carving(unsigned char* source, int width, int height, int nbChannels, const char* out_filename, int nbSeams, bool vertical, bool test_energy=false, int max_step=1) {
|
||||||
int nbColorChannels = nbChannels > 3 ? 3 : nbChannels;
|
int nbColorChannels = nbChannels > 3 ? 3 : nbChannels;
|
||||||
int curWidth = width;
|
int curWidth = width;
|
||||||
int curHeight = height;
|
int curHeight = height;
|
||||||
@ -209,7 +219,7 @@ void seam_carving(unsigned char* source, int width, int height, int nbChannels,
|
|||||||
|
|
||||||
SimpleProgressBar::ProgressBar bar(nbSeams);
|
SimpleProgressBar::ProgressBar bar(nbSeams);
|
||||||
for (auto seam=0; seam < nbSeams; seam++) {
|
for (auto seam=0; seam < nbSeams; seam++) {
|
||||||
std::vector<int> opt_seam = carving_step(source_img, carve_output, curWidth, curHeight, nbChannels, vertical);
|
std::vector<int> opt_seam = carving_step(source_img, carve_output, curWidth, curHeight, nbChannels, vertical, max_step=max_step);
|
||||||
std::copy(carve_output.begin(), carve_output.end(), source_img.begin());
|
std::copy(carve_output.begin(), carve_output.end(), source_img.begin());
|
||||||
|
|
||||||
if (vertical) // We just reduced the dimension
|
if (vertical) // We just reduced the dimension
|
||||||
@ -250,6 +260,8 @@ int main(int argc, char **argv) {
|
|||||||
app.add_option("-o,--output", outputImage, "Output image")->required();
|
app.add_option("-o,--output", outputImage, "Output image")->required();
|
||||||
int nbSeams = 1;
|
int nbSeams = 1;
|
||||||
app.add_option("-n,--nb-seams", nbSeams, "Number of seams");
|
app.add_option("-n,--nb-seams", nbSeams, "Number of seams");
|
||||||
|
int max_step = 1;
|
||||||
|
app.add_option("--max-step", max_step, "Max width of step to find a seam");
|
||||||
bool vertical = false;
|
bool vertical = false;
|
||||||
app.add_flag("--vertical", vertical, "Vertical carving");
|
app.add_flag("--vertical", vertical, "Vertical carving");
|
||||||
silent = false;
|
silent = false;
|
||||||
@ -261,11 +273,11 @@ int main(int argc, char **argv) {
|
|||||||
//Image loading
|
//Image loading
|
||||||
int width, height, nbChannels;
|
int width, height, nbChannels;
|
||||||
unsigned char *source = stbi_load(sourceImage.c_str(), &width, &height, &nbChannels, 0);
|
unsigned char *source = stbi_load(sourceImage.c_str(), &width, &height, &nbChannels, 0);
|
||||||
nbSeams = min(nbSeams, width);
|
nbSeams = std::min(nbSeams, width);
|
||||||
|
|
||||||
//std::cout << "channels: " << nbChannels << std::endl;
|
//std::cout << "channels: " << nbChannels << std::endl;
|
||||||
|
|
||||||
seam_carving(source, width, height, nbChannels, outputImage.c_str(), nbSeams, vertical, test_energy=test_energy);
|
seam_carving(source, width, height, nbChannels, outputImage.c_str(), nbSeams, vertical, test_energy=test_energy, max_step=max_step);
|
||||||
|
|
||||||
stbi_image_free(source);
|
stbi_image_free(source);
|
||||||
exit(0);
|
exit(0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user