egami
C++ Image Processing program
|
00001 #include <memory> 00002 #include <array> 00003 #include <string> 00004 00005 #include <gtkmm/image.h> 00006 #include <gtkmm/dialog.h> 00007 #include <gtkmm/spinbutton.h> 00008 #include <gtkmm/messagedialog.h> 00009 #include <gtkmm/checkbutton.h> 00010 #include <gtkmm/label.h> 00011 #include <gtkmm/enums.h> 00012 #include <gtkmm/stock.h> 00013 00014 #include "../display_unit.hpp" 00015 #include "../processing_page.hpp" 00016 #include "../processing_unit.hpp" 00017 #include "../utils.hpp" 00018 #include "../progress.hpp" 00019 00020 namespace{ 00021 class Config: public Gtk::Dialog { 00022 public: 00023 Config(int w, int h): adjw(Gtk::Adjustment::create(w, 1, std::numeric_limits<int>::max(), 10, 100)), ttw("Width:"), btw(adjw), 00024 adjh(Gtk::Adjustment::create(h, 1, std::numeric_limits<int>::max(), 10, 100)), tth("Height:"), bth(adjh), 00025 bic("Bicubic interpolation"){ 00026 set_resizable(false); 00027 bic.set_active(true); 00028 00029 get_vbox()->pack_start(bic); 00030 get_vbox()->pack_start(ttw); 00031 get_vbox()->pack_start(btw); 00032 get_vbox()->pack_start(tth); 00033 get_vbox()->pack_start(bth); 00034 00035 add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); 00036 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); 00037 00038 show_all_children(); 00039 } 00040 00041 unsigned getw() const { return btw.get_value(); } 00042 unsigned geth() const { return bth.get_value(); } 00043 unsigned getbic() const { return bic.get_active(); } 00044 private: 00045 Glib::RefPtr<Gtk::Adjustment> adjw; 00046 Gtk::Label ttw; 00047 Gtk::SpinButton btw; 00048 Glib::RefPtr<Gtk::Adjustment> adjh; 00049 Gtk::Label tth; 00050 Gtk::SpinButton bth; 00051 Gtk::CheckButton bic; 00052 }; 00053 00054 double cubic_interpolate(const std::array<double, 4> &p, double x){ 00055 return p[1] + 0.5 * x*(p[2] - p[0] + x*(2.0*p[0] - 5.0*p[1] + 4.0*p[2] - p[3] + x*(3.0*(p[1] - p[2]) + p[3] - p[0]))); 00056 } 00057 00058 double bicubic_interpolate (const std::array<std::array<double, 4>, 4> &p, double y, double x) { 00059 std::array<double, 4> arr; 00060 arr[0] = cubic_interpolate(p[0], y); 00061 arr[1] = cubic_interpolate(p[1], y); 00062 arr[2] = cubic_interpolate(p[2], y); 00063 arr[3] = cubic_interpolate(p[3], y); 00064 return cubic_interpolate(arr, x); 00065 } 00066 00067 Display_unit *impl(const Image_unit *in){ 00068 if(in->has_roi()){ 00069 Gtk::MessageDialog d("Can not apply Resize to a region of interest."); 00070 d.run(); 00071 return nullptr; 00072 } 00073 00074 Config c(in->width(), in->height()); 00075 if(c.run()!=Gtk::RESPONSE_OK) 00076 return nullptr; 00077 c.hide(); 00078 00079 Image_unit *out(new Image_unit(in, c.geth(), c.getw())); 00080 00081 if(c.getbic()){ 00082 Progress prog; 00083 std::array<std::array<double, 4>, 4> red_neighbors, green_neighbors, blue_neighbors; 00084 for(unsigned y=0; y<out->height(); ++y){ 00085 prog.advance(static_cast<double>(y)/out->height()); 00086 for(unsigned x=0; x<out->width(); ++x){ 00087 double ny=y*in->height()/static_cast<double>(out->height()); 00088 double nx=x*in->width()/static_cast<double>(out->width()); 00089 00090 for(int dx=-1; dx<=2; ++dx) 00091 for(int dy=-1; dy<=2; ++dy){ 00092 red_neighbors[dy+1][dx+1]=in->m_red(ny+dy, nx+dx); 00093 green_neighbors[dy+1][dx+1]=in->m_green(ny+dy, nx+dx); 00094 blue_neighbors[dy+1][dx+1]=in->m_blue(ny+dy, nx+dx); 00095 } 00096 00097 double red=bicubic_interpolate(red_neighbors, nx-std::floor(nx), ny-std::floor(ny)); 00098 red=red>255?255:red<0?0:red; 00099 double green=bicubic_interpolate(green_neighbors, nx-std::floor(nx), ny-std::floor(ny)); 00100 green=green>255?255:green<0?0:green; 00101 double blue=bicubic_interpolate(blue_neighbors, nx-std::floor(nx), ny-std::floor(ny)); 00102 blue=blue>255?255:blue<0?0:blue; 00103 out->red(y, x, red); 00104 out->green(y, x, green); 00105 out->blue(y, x, blue); 00106 } 00107 } 00108 } else { 00109 for(unsigned y=0; y<out->height(); ++y) 00110 for(unsigned x=0; x<out->width(); ++x){ 00111 double ny=y*in->height()/static_cast<double>(out->height()); 00112 double nx=x*in->width()/static_cast<double>(out->width()); 00113 out->red(y, x, in->m_red(ny, nx)); 00114 out->green(y, x, in->m_green(ny, nx)); 00115 out->blue(y, x, in->m_blue(ny, nx)); 00116 } 00117 } 00118 return out; 00119 } 00120 } 00121 00122 namespace Processes{ 00123 void resize(){ 00124 Gtk::Image icon(cmake_install_prefix+std::string("/share/egami/icons/resize.png")); 00125 std::shared_ptr<Processing_unit> pu(new Processing_unit(Processing(&impl), "Resize", icon, false)); 00126 Processing_page::add_unit_to_page("Reshape", pu); 00127 } 00128 }