egami
C++ Image Processing program
/homes/esi30/DCS339/coursework/src/Processes/resize.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends