// calculate gradients for the pyramid // lum_temp gets overwritten! static void pyramid_calculate_gradient(pyramid_t* pyramid, float* lum_temp) { float* temp = matrix_alloc((pyramid->rows/2)*(pyramid->cols/2)); float* const temp_saved = temp; calculate_gradient(pyramid->cols, pyramid->rows, lum_temp, pyramid->Gx, pyramid->Gy); pyramid = pyramid->next; // int l = 1; while(pyramid) { matrix_downsample(pyramid->prev->cols, pyramid->prev->rows, lum_temp, temp); // fprintf( stderr, "%d x %d -> %d x %d\n", pyramid->cols, pyramid->rows, // prev_pp->cols, prev_pp->rows ); // char name[40]; // sprintf( name, "ds_%d.pfs", l++ ); // dump_matrix_to_file( pyramid->cols, pyramid->rows, temp, name ); calculate_gradient(pyramid->cols, pyramid->rows, temp, pyramid->Gx, pyramid->Gy); float* const dummy = lum_temp; lum_temp = temp; temp = dummy; pyramid = pyramid->next; } matrix_free(temp_saved); }
PerformanceTerm::FirstOrderPerformance MeanSquaredError::calculate_first_order_performance(void) const { // Control sentence #ifndef NDEBUG check(); #endif FirstOrderPerformance first_order_performance; first_order_performance.performance = calculate_performance(); first_order_performance.gradient = calculate_gradient(); return (first_order_performance); }
PerformanceTerm::SecondOrderPerformance MeanSquaredError::calculate_second_order_performance(void) const { // Control sentence #ifndef NDEBUG check(); #endif SecondOrderPerformance second_order_performance; second_order_performance.performance = calculate_performance(); second_order_performance.gradient = calculate_gradient(); second_order_performance.Hessian = calculate_Hessian(); return (second_order_performance); }
static int read_png(const char *fname, image *image, gradient *g) { int result = 0; memset(&image->image, 0, sizeof image->image); image->image.version = PNG_IMAGE_VERSION; if (png_image_begin_read_from_file(&image->image, image->file_name)) { image->image.format = PNG_FORMAT_RGBA; image->stride = PNG_IMAGE_ROW_STRIDE(image->image); image->buffer = malloc(PNG_IMAGE_SIZE(image->image)); image->pixel_bytes = PNG_IMAGE_PIXEL_SIZE(image->image.format); if (image->buffer != NULL) { if(png_image_finish_read(&image->image, NULL /*background*/, image->buffer, (png_int_32)image->stride, image->colormap)) { if(calculate_gradient(image, g)) result = 1; else printf("pngtocss: Gradient type not supported\n"); } else { fprintf(stderr, "pngtocss: read %s: %s\n", fname, image->image.message); png_image_free(&image->image); } } else fprintf(stderr, "pngtocss: out of memory: %lu bytes\n", (unsigned long)PNG_IMAGE_SIZE(image->image)); } else /* Failed to read the argument: */ fprintf(stderr, "pngtocss: %s: %s\n", fname, image->image.message); return result; }
int main(int argc, char** argv) { if (argc < 2) { std::cout << "Not enough arguments, Usage: ./seamcarver <path_to_image> <number_of_seams_to_carve>" << "\n"; std::cout << "If number of seams to carve is left out, the necessary size for object removal will be used instead" << "\n"; return 1; } std::cout << "Loading image" << "\n"; std::string fname = argv[1]; cimg_library::CImg<unsigned char> image(fname.c_str()); cimg_library::CImg<unsigned char> draw_image(fname.c_str()); //TODO figure out if i can undo the draw without having second copy std::cout << "Calculating luminosity" << "\n"; std::vector<std::vector<double> > luminosity_map = calculate_luminosity(image); std::cout << "Setting energy of image" << "\n"; std::vector<std::vector<int> > energy_map(luminosity_map.size(), std::vector<int>(luminosity_map[0].size(), 0)); cimg_library::CImgDisplay energy(draw_image, "Manually set special energy"); char red[3] = { 255, 0, 0 }; char green[3] = { 0, 255, 0 }; int cursor_size = 1; while (!energy.is_closed()) { energy.wait(); if (energy.button()) { std::vector<char> current_color; int energy_val = 0; if (energy.button() & 1) { // left click if (energy.is_keySPACE()) { flood(draw_image, energy_map, red, -1, energy.mouse_y(), energy.mouse_x()); energy_val = -2; } else { current_color = std::vector<char>(red, red + 3); energy_val = -1; } } else if (energy.button() & 2) { // right click if (energy.is_keySPACE()) { flood(draw_image, energy_map, green, 1, energy.mouse_y(), energy.mouse_x()); energy_val = -2; } else { current_color = std::vector<char>(green, green + 3); energy_val = 1; } } if (energy_val != -2) { for (int i = -cursor_size; i <= cursor_size; i++) { for (int j = -cursor_size; j <= cursor_size; j++) { if (valid_coord(std::pair<int, int>(energy.mouse_y() + i, energy.mouse_x() + j), energy_map[0].size(), energy_map.size())) { energy_map[energy.mouse_y() + i][energy.mouse_x() + j] = energy_val; draw_image.draw_point(energy.mouse_x() + j, energy.mouse_y() + i, ¤t_color[0]); } } } } } draw_image.display(energy); } //TODO //change so im_vec stores only pairs of coords, then we copy directly from image to new image? std::vector<std::vector<std::vector<char> > > im_vec; for (int i = 0; i < image.height(); i++) { std::vector<std::vector<char> > row; for (int j = 0; j < image.width(); j++) { std::vector<char> color; color.push_back(image.atXY(j, i, 0, 0)); color.push_back(image.atXY(j, i, 0, 1)); color.push_back(image.atXY(j, i, 0, 2)); row.push_back(color); } im_vec.push_back(row); } int numseam = 0; if (argc < 3) { // calculate max of max range of x on all y coordinates int maxseam = -1; for (int i = 0; i < energy_map.size(); i++) { int left = 0; int right = energy_map[i].size() - 1; while (right > 0 && left < energy_map[i].size() && (energy_map[i][left] != -1 || energy_map[i][right] != -1)) { if (energy_map[i][left] != -1) left++; if (energy_map[i][right] != -1) right--; } int diff = right - left + 1; if (maxseam < diff) { maxseam = diff; } } numseam = maxseam; } else { numseam = atoi(argv[2]); } for (int master = 0; master < numseam; master++) { std::cout << "Computing and removing seam #" << master + 1 << "\r" << std::flush; std::vector<std::vector<std::pair<double, double> > > gradient_map = calculate_gradient(luminosity_map); //set all energies specified in energy_map to negative/positive on the gradient map for (int i = 0; i < energy_map.size(); i++) { for (int j = 0; j < energy_map[0].size(); j++) { if (energy_map[i][j] != 0) { gradient_map[i][j].second = energy_map[i][j] * 1000; } } } double min_seam = DBL_MAX; int loc = -1; for (int i = 0; i < gradient_map.back().size(); i++) { calculate_seam(gradient_map, gradient_map.size() - 1, i); if (gradient_map.back()[i].first < min_seam) { min_seam = gradient_map.back()[i].first; loc = i; } } //remove seams and the object manipulation map coordinates std::vector<std::pair<int, int> > toremove = trace_seam(gradient_map, loc); for (int i = 0; i < toremove.size(); i++) { int row = toremove[i].first; int col = toremove[i].second; im_vec[row].erase(im_vec[row].begin() + col); luminosity_map[row].erase(luminosity_map[row].begin() + col); energy_map[row].erase(energy_map[row].begin() + col); } } cimg_library::CImg<unsigned char> newimage(im_vec[0].size(), im_vec.size(), 1, 3); for (int i = 0; i < im_vec.size(); i++) { for (int j = 0; j < im_vec[i].size(); j++) { char color[3] = { im_vec[i][j][0], im_vec[i][j][1], im_vec[i][j][2] }; newimage.draw_point(j, i, color); } } std::cout << "\n" << "Computation finished, displaying image" << "\n"; cimg_library::CImgDisplay display(newimage, "Seam Carved Image"); while (!display.is_closed()) { display.wait(); newimage.display(display); } }