egami
C++ Image Processing program
|
00001 #include <string> 00002 #include <stdexcept> 00003 00004 #include <gdkmm/pixbuf.h> 00005 00006 #include "image.hpp" 00007 00008 // @todo clean const_iterator... inhertance ? 00009 00010 Image::Image(const std::string &filepath): data(Gdk::Pixbuf::create_from_file(filepath)), regionalised(false), 00011 clip_x(0), clip_y(0), clip_dx(data->get_width()), clip_dy(data->get_height()) { } 00012 00013 Image::Image(const Image &other): data(other.data->copy()), regionalised(other.regionalised), 00014 clip_x(other.clip_x), clip_y(other.clip_y), clip_dx(other.clip_dx), clip_dy(other.clip_dy) { 00016 } 00017 00018 Image::Image(unsigned height, unsigned width): data(Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, false, 8, width, height)), regionalised(false), 00019 clip_x(0), clip_y(0), clip_dx(width), clip_dy(height) { } 00020 00021 Image::Image(Image &&other) noexcept { 00022 swap(*this, other); 00023 } 00024 00025 Image& Image::operator=(Image other) noexcept { 00026 swap(*this, other); 00027 return *this; 00028 } 00029 00030 void swap(Image &lhs, Image &rhs) noexcept { 00031 using std::swap; // Enable ADL 00032 00033 swap(lhs.data, rhs.data); 00034 swap(lhs.regionalised, rhs.regionalised); 00035 swap(lhs.clip_x, rhs.clip_x); 00036 swap(lhs.clip_y, rhs.clip_y); 00037 swap(lhs.clip_dx, rhs.clip_dx); 00038 swap(lhs.clip_dy, rhs.clip_dy); 00039 } 00040 00041 void Image::save_img(const std::string &fp) const { 00042 std::string::const_reverse_iterator rdot=std::find(fp.rbegin(), fp.rend(), '.'); 00043 if(rdot==fp.rend()) 00044 throw std::runtime_error("No extension provided"); 00045 std::string::const_iterator dot=rdot.base(); 00046 std::string ext(dot, fp.end()); 00047 std::vector<Gdk::PixbufFormat> sup=Gdk::Pixbuf::get_formats(); 00048 for(Gdk::PixbufFormat format: sup) 00049 if(format.get_name()==ext && format.is_writable()){ 00050 data->save(fp, format.get_name()); 00051 return; 00052 } 00053 throw std::runtime_error("Unknow extension"); 00054 } 00055 00056 Pixel_proxy Image::at(unsigned y, unsigned x){ 00057 return Pixel_proxy(this, y+clip_y, x+clip_x); 00058 } 00059 00060 const_Pixel_proxy Image::at(unsigned y, unsigned x) const { 00061 return const_Pixel_proxy(this, y+clip_y, x+clip_x); 00062 } 00063 00064 Image::iterator Image::begin() noexcept { 00065 return iterator(this, 0, 0); 00066 } 00067 00068 Image::iterator Image::end() noexcept { 00069 return iterator(this, height(), 0); 00070 } 00071 00072 Image::const_iterator Image::begin() const noexcept { 00073 return const_iterator(this, 0, 0); 00074 } 00075 00076 Image::const_iterator Image::end() const noexcept { 00077 return const_iterator(this, height(), 0); 00078 } 00079 00080 unsigned Image::width() const noexcept { 00081 return clip_dx; 00082 } 00083 00084 unsigned Image::height() const noexcept { 00085 return clip_dy; 00086 } 00087 00088 unsigned Image::rowstride() const noexcept { 00089 return data->get_rowstride(); 00090 } 00091 00092 unsigned Image::n_channels() const noexcept { 00093 return data->get_n_channels(); 00094 } 00095 00096 void Image::red(unsigned y, unsigned x, unsigned char v){ 00097 *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x))=v; 00098 } 00099 00100 void Image::green(unsigned y, unsigned x, unsigned char v){ 00101 *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x)+1)=v; 00102 } 00103 00104 void Image::blue(unsigned y, unsigned x, unsigned char v){ 00105 *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x)+2)=v; 00106 } 00107 00108 unsigned char Image::red(unsigned y, unsigned x) const { 00109 return *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x)); 00110 } 00111 00112 unsigned char Image::green(unsigned y, unsigned x) const { 00113 return *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x)+1); 00114 } 00115 00116 unsigned char Image::blue(unsigned y, unsigned x) const { 00117 return *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x)+2); 00118 } 00119 00120 unsigned char Image::m_red(int y, int x) const { 00121 y+=clip_y; 00122 x+=clip_x; 00123 // We are not mirroring if we can take the input from the non-regionalised image. 00124 if(y>=static_cast<int>(data->get_height())) y=data->get_height()-y-1; 00125 if(x>=static_cast<int>(data->get_width())) x=data->get_width()-x-1; 00126 if(y<0) y=-y; 00127 if(x<0) x=-x; 00128 return *(data->get_pixels()+y*rowstride()+n_channels()*x); 00129 } 00130 00131 unsigned char Image::m_green(int y, int x) const { 00132 y+=clip_y; 00133 x+=clip_x; 00134 // We are not mirroring if we can take the input from the non-regionalised image. 00135 if(y>=static_cast<int>(data->get_height())) y=data->get_height()-y-1; 00136 if(x>=static_cast<int>(data->get_width())) x=data->get_width()-x-1; 00137 if(y<0) y=-y; 00138 if(x<0) x=-x; 00139 return *(data->get_pixels()+y*rowstride()+n_channels()*x+1); 00140 } 00141 00142 unsigned char Image::m_blue(int y, int x) const { 00143 y+=clip_y; 00144 x+=clip_x; 00145 // We are not mirroring if we can take the input from the non-regionalised image. 00146 if(y>=static_cast<int>(data->get_height())) y=data->get_height()-y-1; 00147 if(x>=static_cast<int>(data->get_width())) x=data->get_width()-x-1; 00148 if(y<0) y=-y; 00149 if(x<0) x=-x; 00150 return *(data->get_pixels()+y*rowstride()+n_channels()*x+2); 00151 } 00152 00153 unsigned Image::x_win() const { 00154 return clip_x; 00155 } 00156 00157 unsigned Image::y_win() const { 00158 return clip_y; 00159 } 00160 00161 bool Image::has_roi() const { 00162 return clip_y || clip_x || true_height()!=height() || true_width()!=width(); 00163 } 00164 00165 unsigned Image::true_height() const { 00166 return data->get_height(); 00167 } 00168 00169 unsigned Image::true_width() const { 00170 return data->get_width(); 00171 } 00172 00173 void Image::clip(unsigned y, unsigned x, unsigned dy, unsigned dx){ 00174 clip_y=y; 00175 clip_x=x; 00176 clip_dy=dy; 00177 clip_dx=dx; 00178 } 00179 00180 void Image::unclip(){ 00181 clip_y=clip_x=0; 00182 clip_dy=true_height(); 00183 clip_dx=true_width(); 00184 } 00185 00186 Row_proxy Image::operator[](unsigned y){ 00187 if(y>height()) 00188 throw std::runtime_error("Image out of bound access: trying to get the row "+std::to_string(y)+" on an image of height "+std::to_string(height())); 00189 return Row_proxy(this, y); 00190 } 00191 00192 const_Row_proxy Image::operator[](unsigned y) const { 00193 if(y>height()) 00194 throw std::runtime_error("Image out of bound access: trying to get the row "+std::to_string(y)+" on an image of height "+std::to_string(height())); 00195 return const_Row_proxy(this, y); 00196 } 00197 00198 Row_proxy::Row_proxy(Image *img, unsigned y) noexcept : img(img), y(y+img->y_win()) {} 00199 00200 Pixel_proxy Row_proxy::operator[](unsigned x){ 00201 if(x>img->width()) 00202 throw std::runtime_error("Image out of bound access: trying to get the column "+std::to_string(x)+" on an image of width "+std::to_string(img->width())); 00203 return Pixel_proxy(img, y, img->x_win()+x); 00204 } 00205 00206 const_Row_proxy::const_Row_proxy(const Image *img, unsigned y) noexcept : img(img), y(y+img->y_win()) {} 00207 00208 const_Pixel_proxy const_Row_proxy::operator[](unsigned x) const { 00209 if(x>img->width()) 00210 throw std::runtime_error("Image out of bound access: trying to get the column "+std::to_string(x)+" on an image of width "+std::to_string(img->width())); 00211 return const_Pixel_proxy(img, y, img->x_win()+x); 00212 } 00213 00214 Pixel_proxy::Pixel_proxy(Image *img, unsigned y, unsigned x) noexcept : 00215 r(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x))), 00216 g(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x)+1)), 00217 b(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x)+2)) {} 00218 00219 Pixel_proxy& Pixel_proxy::operator=(std::initializer_list<int> values){ 00220 switch(values.size()){ 00221 case 0: 00222 r=g=b=0; 00223 break; 00224 case 1: 00225 r=g=b=*values.begin(); 00226 break; 00227 case 3: 00228 r=values.begin()[0]; 00229 g=values.begin()[1]; 00230 b=values.begin()[2]; 00231 break; 00232 default: 00233 throw std::runtime_error("Dimension error in pixel assignment, got "+std::to_string(values.size())+" values instead of 0, 1 or 3"); 00234 } 00235 return *this; 00236 } 00237 00238 Pixel_proxy& Pixel_proxy::operator=(const const_Pixel_proxy &rhs){ 00239 r=rhs.r; 00240 g=rhs.g; 00241 b=rhs.b; 00242 return *this; 00243 } 00244 00245 Pixel::Pixel(unsigned char r, unsigned char g, unsigned char b): r(r), g(g), b(b) {} 00246 Pixel::Pixel(): r(), g(), b() {} 00247 00248 Image::iterator::iterator(Image *img, unsigned y, unsigned x): img(img), y(y), x(x), proxy(new Pixel_proxy(img, y, x)) { } 00249 00250 Image::iterator::iterator(const iterator &other): img(other.img), y(other.y), x(other.x), proxy(new Pixel_proxy(img, y, x)) {} 00251 00252 Image::iterator::iterator(iterator &&other) noexcept { 00253 swap(*this, other); 00254 } 00255 00256 void swap(Image::iterator &lhs, Image::iterator &rhs) noexcept { 00257 using std::swap; // Enable ADL 00258 00259 swap(lhs.img, rhs.img); 00260 swap(lhs.y, rhs.y); 00261 swap(lhs.x, rhs.x); 00262 swap(lhs.proxy, rhs.proxy); 00263 } 00264 00265 Image::iterator& Image::iterator::operator=(iterator other) noexcept { 00266 swap(*this, other); 00267 return *this; 00268 } 00269 00270 Image::iterator::operator Image::const_iterator() const noexcept { 00271 return Image::const_iterator(img, y, x); 00272 } 00273 00274 bool Image::iterator::valid() const { 00275 return x<img->width() && y<img->height(); 00276 } 00277 00278 Pixel Image::iterator::get_copy() const { 00279 return Pixel(proxy->r, proxy->g, proxy->b); 00280 } 00281 00282 Pixel_proxy* Image::iterator::operator->() noexcept { 00283 return proxy.get(); 00284 } 00285 00286 Pixel_proxy& Image::iterator::operator*() noexcept { 00287 return *proxy; 00288 } 00289 00290 Pixel_proxy* Image::iterator::operator->() const noexcept { 00291 return proxy.get(); 00292 } 00293 00294 Pixel_proxy& Image::iterator::operator*() const noexcept { 00295 return *proxy; 00296 } 00297 00298 unsigned char Image::iterator::red() const { 00299 return img->red(y, x); 00300 } 00301 00302 unsigned char Image::iterator::green() const { 00303 return img->blue(y, x); 00304 } 00305 00306 unsigned char Image::iterator::blue() const { 00307 return img->blue(y, x); 00308 } 00309 00310 void Image::iterator::red(unsigned char v){ 00311 img->red(y, x, v); 00312 } 00313 00314 void Image::iterator::green(unsigned char v){ 00315 img->green(y, x, v); 00316 } 00317 00318 void Image::iterator::blue(unsigned char v){ 00319 img->blue(y, x, v); 00320 } 00321 00322 void Image::iterator::rebuild(){ 00323 proxy.get()->~Pixel_proxy(); 00324 new (proxy.get()) Pixel_proxy(img, y+img->y_win(), x+img->x_win()); 00325 // proxy.reset(new Pixel_proxy(img, y, x)); 00326 } 00327 00328 Image::iterator& Image::iterator::operator++(){ 00329 ++x; 00330 if(x>=img->width()){ 00331 x=0; 00332 ++y; 00333 } 00334 00335 rebuild(); 00336 00337 return *this; 00338 } 00339 00340 Image::iterator Image::iterator::operator++(int){ 00341 Image::iterator old(*this); 00342 ++x; 00343 if(x>=img->width()){ 00344 x=0; 00345 ++y; 00346 } 00347 00348 rebuild(); 00349 00350 return old; 00351 } 00352 00353 Image::iterator& Image::iterator::operator--(){ 00354 if(!x--){ 00355 x=img->width()-1; 00356 --y; 00357 } 00358 00359 rebuild(); 00360 00361 return *this; 00362 } 00363 00364 Image::iterator Image::iterator::operator--(int){ 00365 Image::iterator old(*this); 00366 if(!x--){ 00367 x=img->width()-1; 00368 --y; 00369 } 00370 00371 rebuild(); 00372 00373 return old; 00374 } 00375 00376 Image::iterator& Image::iterator::operator+=(int rhs){ 00377 x+=rhs; 00378 y+=x/img->width(); 00379 x%=img->width(); 00380 rebuild(); 00381 return *this; 00382 } 00383 00384 Image::iterator& Image::iterator::operator-=(int rhs){ 00385 x+=rhs; 00386 y+=x/img->width(); 00387 x%=img->width(); 00388 rebuild(); 00389 return *this; 00390 } 00391 00392 Image::iterator operator+(Image::iterator lhs, int rhs){ 00393 return lhs+=rhs; 00394 } 00395 00396 Image::iterator operator+(int lhs, Image::iterator rhs){ 00397 return rhs+=lhs; 00398 } 00399 00400 Image::iterator operator-(Image::iterator lhs, int rhs){ 00401 return lhs-=rhs; 00402 } 00403 00404 int operator-(const Image::iterator &lhs, const Image::iterator &rhs){ 00405 return (lhs.y-rhs.y)*lhs.img->width()+(lhs.x-rhs.x); 00406 } 00407 00408 bool Image::iterator::operator==(const Image::iterator &o) const noexcept { 00409 return o.img==img && o.y==y && o.x==x; 00410 } 00411 00412 bool Image::iterator::operator!=(const Image::iterator &o) const noexcept { 00413 return o.img!=img || o.y!=y || o.x!=x; 00414 } 00415 00416 Image::const_iterator::const_iterator(const Image *img, unsigned y, unsigned x): img(img), y(y), x(x), proxy(new const_Pixel_proxy(img, y, x)) { } 00417 00418 Image::const_iterator::const_iterator(const const_iterator &other): img(other.img), y(other.y), x(other.x), proxy(new const_Pixel_proxy(img, y, x)) {} 00419 00420 Image::const_iterator::const_iterator(const_iterator &&other) noexcept { 00421 swap(*this, other); 00422 } 00423 00424 void swap(Image::const_iterator &lhs, Image::const_iterator &rhs) noexcept { 00425 using std::swap; // Enable ADL 00426 00427 swap(lhs.img, rhs.img); 00428 swap(lhs.y, rhs.y); 00429 swap(lhs.x, rhs.x); 00430 swap(lhs.proxy, rhs.proxy); 00431 } 00432 00433 Image::const_iterator& Image::const_iterator::operator=(const_iterator other) noexcept { 00434 swap(*this, other); 00435 return *this; 00436 } 00437 00438 bool Image::const_iterator::valid() const { 00439 return x<img->width() && y<img->height(); 00440 } 00441 00442 Pixel Image::const_iterator::get_copy() const { 00443 return Pixel(proxy->r, proxy->g, proxy->b); 00444 } 00445 00446 const_Pixel_proxy* Image::const_iterator::operator->() noexcept { 00447 return proxy.get(); 00448 } 00449 00450 const_Pixel_proxy& Image::const_iterator::operator*() noexcept { 00451 return *proxy; 00452 } 00453 00454 const_Pixel_proxy* Image::const_iterator::operator->() const noexcept { 00455 return proxy.get(); 00456 } 00457 00458 const_Pixel_proxy& Image::const_iterator::operator*() const noexcept { 00459 return *proxy; 00460 } 00461 00462 unsigned char Image::const_iterator::red() const { 00463 return img->red(y, x); 00464 } 00465 00466 unsigned char Image::const_iterator::green() const { 00467 return img->blue(y, x); 00468 } 00469 00470 unsigned char Image::const_iterator::blue() const { 00471 return img->blue(y, x); 00472 } 00473 00474 void Image::const_iterator::rebuild(){ 00475 proxy.get()->~const_Pixel_proxy(); 00476 new (proxy.get()) const_Pixel_proxy(img, y+img->y_win(), x+img->x_win()); 00477 } 00478 00479 Image::const_iterator& Image::const_iterator::operator++(){ 00480 ++x; 00481 if(x>=img->width()){ 00482 x=0; 00483 ++y; 00484 } 00485 00486 rebuild(); 00487 00488 return *this; 00489 } 00490 00491 Image::const_iterator Image::const_iterator::operator++(int){ 00492 Image::const_iterator old(*this); 00493 ++x; 00494 if(x>=img->width()){ 00495 x=0; 00496 ++y; 00497 } 00498 00499 rebuild(); 00500 00501 return old; 00502 } 00503 00504 Image::const_iterator& Image::const_iterator::operator--(){ 00505 if(!x--){ 00506 x=img->width()-1; 00507 --y; 00508 } 00509 00510 rebuild(); 00511 00512 return *this; 00513 } 00514 00515 Image::const_iterator Image::const_iterator::operator--(int){ 00516 Image::const_iterator old(*this); 00517 if(!x--){ 00518 x=img->width()-1; 00519 --y; 00520 } 00521 00522 rebuild(); 00523 00524 return old; 00525 } 00526 00527 Image::const_iterator& Image::const_iterator::operator+=(int rhs){ 00528 x+=rhs; 00529 y+=x/img->width(); 00530 x%=img->width(); 00531 rebuild(); 00532 return *this; 00533 } 00534 00535 Image::const_iterator& Image::const_iterator::operator-=(int rhs){ 00536 x+=rhs; 00537 y+=x/img->width(); 00538 x%=img->width(); 00539 rebuild(); 00540 return *this; 00541 } 00542 00543 Image::const_iterator operator+(Image::const_iterator lhs, int rhs){ 00544 return lhs+=rhs; 00545 } 00546 00547 Image::const_iterator operator+(int lhs, Image::const_iterator rhs){ 00548 return rhs+=lhs; 00549 } 00550 00551 Image::const_iterator operator-(Image::const_iterator lhs, int rhs){ 00552 return lhs-=rhs; 00553 } 00554 00555 int operator-(const Image::const_iterator &lhs, const Image::const_iterator &rhs){ 00556 return (lhs.y-rhs.y)*lhs.img->width()+(lhs.x-rhs.x); 00557 } 00558 00559 bool Image::const_iterator::operator==(const Image::const_iterator &o) const noexcept { 00560 return o.img==img && o.y==y && o.x==x; 00561 } 00562 00563 bool Image::const_iterator::operator!=(const Image::const_iterator &o) const noexcept { 00564 return o.img!=img || o.y!=y || o.x!=x; 00565 } 00566 00567 00568 const_Pixel_proxy::const_Pixel_proxy(const Image *img, unsigned y, unsigned x) noexcept : 00569 r(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x))), 00570 g(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x)+1)), 00571 b(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x)+2)) {}