Home | History | Annotate | Download | only in cpp
      1 /*
      2 * cloning.cpp
      3 *
      4 * Author:
      5 * Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
      6 *
      7 * This tutorial demonstrates how to use OpenCV seamless cloning
      8 * module.
      9 *
     10 * 1- Normal Cloning
     11 * 2- Mixed Cloning
     12 * 3- Monochrome Transfer
     13 * 4- Color Change
     14 * 5- Illumination change
     15 * 6- Texture Flattening
     16 
     17 * The program takes as input a source and a destination image (for 1-3 methods)
     18 * and ouputs the cloned image.
     19 
     20 * Step 1:
     21 * -> In the source image, select the region of interest by left click mouse button. A Polygon ROI will be created by left clicking mouse button.
     22 * -> To set the Polygon ROI, click the right mouse button or 'd' key.
     23 * -> To reset the region selected, click the middle mouse button or 'r' key.
     24 
     25 * Step 2:
     26 * -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button.
     27 * -> To get the cloned result, click the right mouse button or 'c' key.
     28 * -> To quit the program, use 'q' key.
     29 *
     30 * Result: The cloned image will be displayed.
     31 */
     32 
     33 #include <signal.h>
     34 #include "opencv2/photo.hpp"
     35 #include "opencv2/imgproc.hpp"
     36 #include "opencv2/imgcodecs.hpp"
     37 #include "opencv2/highgui.hpp"
     38 #include "opencv2/core.hpp"
     39 #include <iostream>
     40 #include <stdlib.h>
     41 
     42 using namespace std;
     43 using namespace cv;
     44 
     45 Mat img0, img1, img2, res, res1, final, final1, blend;
     46 
     47 Point point;
     48 int drag = 0;
     49 int destx, desty;
     50 
     51 int numpts = 100;
     52 Point* pts = new Point[100];
     53 Point* pts2 = new Point[100];
     54 Point* pts_diff = new Point[100];
     55 
     56 int var = 0;
     57 int flag = 0, flag1 = 0, flag4 = 0;
     58 
     59 int minx, miny, maxx, maxy, lenx, leny;
     60 int minxd, minyd, maxxd, maxyd, lenxd, lenyd;
     61 
     62 int channel, num, kernel_size;
     63 
     64 float alpha,beta;
     65 
     66 float red, green, blue;
     67 
     68 float low_t, high_t;
     69 
     70 void source(int, int, int, int, void*);
     71 void destination(int, int, int, int, void*);
     72 void checkfile(char*);
     73 
     74 void source(int event, int x, int y, int, void*)
     75 {
     76 
     77     if (event == EVENT_LBUTTONDOWN && !drag)
     78     {
     79         if(flag1 == 0)
     80         {
     81             if(var==0)
     82                 img1 = img0.clone();
     83             point = Point(x, y);
     84             circle(img1,point,2,Scalar(0, 0, 255),-1, 8, 0);
     85             pts[var] = point;
     86             var++;
     87             drag  = 1;
     88             if(var>1)
     89                 line(img1,pts[var-2], point, Scalar(0, 0, 255), 2, 8, 0);
     90 
     91             imshow("Source", img1);
     92         }
     93     }
     94 
     95     if (event == EVENT_LBUTTONUP && drag)
     96     {
     97         imshow("Source", img1);
     98 
     99         drag = 0;
    100     }
    101     if (event == EVENT_RBUTTONDOWN)
    102     {
    103         flag1 = 1;
    104         img1 = img0.clone();
    105         for(int i = var; i < numpts ; i++)
    106             pts[i] = point;
    107 
    108         if(var!=0)
    109         {
    110             const Point* pts3[1] = {&pts[0]};
    111             polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0);
    112         }
    113 
    114         for(int i=0;i<var;i++)
    115         {
    116             minx = min(minx,pts[i].x);
    117             maxx = max(maxx,pts[i].x);
    118             miny = min(miny,pts[i].y);
    119             maxy = max(maxy,pts[i].y);
    120         }
    121         lenx = maxx - minx;
    122         leny = maxy - miny;
    123 
    124         int mid_pointx = minx + lenx/2;
    125         int mid_pointy = miny + leny/2;
    126 
    127         for(int i=0;i<var;i++)
    128         {
    129             pts_diff[i].x = pts[i].x - mid_pointx;
    130             pts_diff[i].y = pts[i].y - mid_pointy;
    131         }
    132 
    133         imshow("Source", img1);
    134     }
    135 
    136     if (event == EVENT_RBUTTONUP)
    137     {
    138         flag = var;
    139 
    140         final = Mat::zeros(img0.size(),CV_8UC3);
    141         res1 = Mat::zeros(img0.size(),CV_8UC1);
    142         const Point* pts4[1] = {&pts[0]};
    143 
    144         fillPoly(res1, pts4,&numpts, 1, Scalar(255, 255, 255), 8, 0);
    145         bitwise_and(img0, img0, final,res1);
    146 
    147         imshow("Source", img1);
    148 
    149         if(num == 4)
    150         {
    151             colorChange(img0,res1,blend,red,green,blue);
    152             imshow("Color Change Image", blend);
    153             waitKey(0);
    154 
    155         }
    156         else if(num == 5)
    157         {
    158             illuminationChange(img0,res1,blend,alpha,beta);
    159             imshow("Illum Change Image", blend);
    160             waitKey(0);
    161         }
    162         else if(num == 6)
    163         {
    164             textureFlattening(img0,res1,blend,low_t,high_t,kernel_size);
    165             imshow("Texture Flattened", blend);
    166             waitKey(0);
    167         }
    168 
    169     }
    170     if (event == EVENT_MBUTTONDOWN)
    171     {
    172         for(int i = 0; i < numpts ; i++)
    173         {
    174             pts[i].x=0;
    175             pts[i].y=0;
    176         }
    177         var = 0;
    178         flag1 = 0;
    179         minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN;
    180         imshow("Source", img0);
    181         if(num == 1 || num == 2 || num == 3)
    182             imshow("Destination",img2);
    183         drag = 0;
    184     }
    185 }
    186 
    187 void destination(int event, int x, int y, int, void*)
    188 {
    189 
    190     Mat im1;
    191     minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN;
    192     im1 = img2.clone();
    193     if (event == EVENT_LBUTTONDOWN)
    194     {
    195         flag4 = 1;
    196         if(flag1 == 1)
    197         {
    198             point = Point(x, y);
    199 
    200             for(int i=0;i<var;i++)
    201             {
    202                 pts2[i].x = point.x + pts_diff[i].x;
    203                 pts2[i].y = point.y + pts_diff[i].y;
    204             }
    205 
    206             for(int i=var;i<numpts;i++)
    207             {
    208                 pts2[i].x = point.x + pts_diff[0].x;
    209                 pts2[i].y = point.y + pts_diff[0].y;
    210             }
    211 
    212             const Point* pts5[1] = {&pts2[0]};
    213             polylines( im1, pts5, &numpts,1, 1, Scalar(0,0,255), 2, 8, 0);
    214 
    215             destx = x;
    216             desty = y;
    217 
    218             imshow("Destination", im1);
    219         }
    220     }
    221     if (event == EVENT_RBUTTONUP)
    222     {
    223         for(int i=0;i<flag;i++)
    224         {
    225             minxd = min(minxd,pts2[i].x);
    226             maxxd = max(maxxd,pts2[i].x);
    227             minyd = min(minyd,pts2[i].y);
    228             maxyd = max(maxyd,pts2[i].y);
    229         }
    230 
    231         if(maxxd > im1.size().width || maxyd > im1.size().height || minxd < 0 || minyd < 0)
    232         {
    233             cout << "Index out of range" << endl;
    234             exit(0);
    235         }
    236 
    237         final1 = Mat::zeros(img2.size(),CV_8UC3);
    238         res = Mat::zeros(img2.size(),CV_8UC1);
    239         for(int i=miny, k=minyd;i<(miny+leny);i++,k++)
    240             for(int j=minx,l=minxd ;j<(minx+lenx);j++,l++)
    241             {
    242                 for(int c=0;c<channel;c++)
    243                 {
    244                     final1.at<uchar>(k,l*channel+c) = final.at<uchar>(i,j*channel+c);
    245 
    246                 }
    247             }
    248 
    249         const Point* pts6[1] = {&pts2[0]};
    250         fillPoly(res, pts6, &numpts, 1, Scalar(255, 255, 255), 8, 0);
    251 
    252         if(num == 1 || num == 2 || num == 3)
    253         {
    254             seamlessClone(img0,img2,res1,point,blend,num);
    255             imshow("Cloned Image", blend);
    256             imwrite("cloned.png",blend);
    257             waitKey(0);
    258         }
    259 
    260         for(int i = 0; i < flag ; i++)
    261         {
    262             pts2[i].x=0;
    263             pts2[i].y=0;
    264         }
    265 
    266         minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN;
    267     }
    268 
    269     im1.release();
    270 }
    271 
    272 int main()
    273 {
    274     cout << endl;
    275     cout << "Cloning Module" << endl;
    276     cout << "---------------" << endl;
    277     cout << "Step 1:" << endl;
    278     cout << " -> In the source image, select the region of interest by left click mouse button. A Polygon ROI will be created by left clicking mouse button." << endl;
    279     cout << " -> To set the Polygon ROI, click the right mouse button or use 'd' key" << endl;
    280     cout << " -> To reset the region selected, click the middle mouse button or use 'r' key." << endl;
    281 
    282     cout << "Step 2:" << endl;
    283     cout << " -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button." << endl;
    284     cout << " -> To get the cloned result, click the right mouse button or use 'c' key." << endl;
    285     cout << " -> To quit the program, use 'q' key." << endl;
    286     cout << endl;
    287     cout << "Options: " << endl;
    288     cout << endl;
    289     cout << "1) Normal Cloning " << endl;
    290     cout << "2) Mixed Cloning " << endl;
    291     cout << "3) Monochrome Transfer " << endl;
    292     cout << "4) Local Color Change " << endl;
    293     cout << "5) Local Illumination Change " << endl;
    294     cout << "6) Texture Flattening " << endl;
    295 
    296     cout << endl;
    297 
    298     cout << "Press number 1-6 to choose from above techniques: ";
    299     cin >> num;
    300     cout << endl;
    301 
    302     minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN;
    303 
    304     minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN;
    305 
    306     int flag3 = 0;
    307 
    308     if(num == 1 || num == 2 || num == 3)
    309     {
    310 
    311         string src,dest;
    312         cout << "Enter Source Image: ";
    313         cin >> src;
    314 
    315         cout << "Enter Destination Image: ";
    316         cin >> dest;
    317 
    318         img0 = imread(src);
    319 
    320         img2 = imread(dest);
    321 
    322         if(img0.empty())
    323         {
    324             cout << "Source Image does not exist" << endl;
    325             exit(0);
    326         }
    327         if(img2.empty())
    328         {
    329             cout << "Destination Image does not exist" << endl;
    330             exit(0);
    331         }
    332 
    333         channel = img0.channels();
    334 
    335         res = Mat::zeros(img2.size(),CV_8UC1);
    336         res1 = Mat::zeros(img0.size(),CV_8UC1);
    337         final = Mat::zeros(img0.size(),CV_8UC3);
    338         final1 = Mat::zeros(img2.size(),CV_8UC3);
    339         //////////// source image ///////////////////
    340 
    341         namedWindow("Source", 1);
    342         setMouseCallback("Source", source, NULL);
    343         imshow("Source", img0);
    344 
    345         /////////// destination image ///////////////
    346 
    347         namedWindow("Destination", 1);
    348         setMouseCallback("Destination", destination, NULL);
    349         imshow("Destination",img2);
    350 
    351     }
    352     else if(num == 4)
    353     {
    354         string src;
    355         cout << "Enter Source Image: ";
    356         cin >> src;
    357 
    358         cout << "Enter RGB values: " << endl;
    359         cout << "Red: ";
    360         cin >> red;
    361 
    362         cout << "Green: ";
    363         cin >> green;
    364 
    365         cout << "Blue: ";
    366         cin >> blue;
    367 
    368         img0 = imread(src);
    369 
    370         if(img0.empty())
    371         {
    372             cout << "Source Image does not exist" << endl;
    373             exit(0);
    374         }
    375 
    376         res1 = Mat::zeros(img0.size(),CV_8UC1);
    377         final = Mat::zeros(img0.size(),CV_8UC3);
    378 
    379         //////////// source image ///////////////////
    380 
    381         namedWindow("Source", 1);
    382         setMouseCallback("Source", source, NULL);
    383         imshow("Source", img0);
    384 
    385     }
    386     else if(num == 5)
    387     {
    388         string src;
    389         cout << "Enter Source Image: ";
    390         cin >> src;
    391 
    392         cout << "alpha: ";
    393         cin >> alpha;
    394 
    395         cout << "beta: ";
    396         cin >> beta;
    397 
    398         img0 = imread(src);
    399 
    400         if(img0.empty())
    401         {
    402             cout << "Source Image does not exist" << endl;
    403             exit(0);
    404         }
    405 
    406         res1 = Mat::zeros(img0.size(),CV_8UC1);
    407         final = Mat::zeros(img0.size(),CV_8UC3);
    408 
    409         //////////// source image ///////////////////
    410 
    411         namedWindow("Source", 1);
    412         setMouseCallback("Source", source, NULL);
    413         imshow("Source", img0);
    414 
    415     }
    416     else if(num == 6)
    417     {
    418         string src;
    419         cout << "Enter Source Image: ";
    420         cin >> src;
    421 
    422         cout << "low_threshold: ";
    423         cin >> low_t;
    424 
    425         cout << "high_threshold: ";
    426         cin >> high_t;
    427 
    428         cout << "kernel_size: ";
    429         cin >> kernel_size;
    430 
    431         img0 = imread(src);
    432 
    433         if(img0.empty())
    434         {
    435             cout << "Source Image does not exist" << endl;
    436             exit(0);
    437         }
    438 
    439         res1 = Mat::zeros(img0.size(),CV_8UC1);
    440         final = Mat::zeros(img0.size(),CV_8UC3);
    441 
    442         //////////// source image ///////////////////
    443 
    444         namedWindow("Source", 1);
    445         setMouseCallback("Source", source, NULL);
    446         imshow("Source", img0);
    447     }
    448     else
    449     {
    450         cout << "Wrong Option Choosen" << endl;
    451         exit(0);
    452     }
    453 
    454     for(;;)
    455     {
    456         char key = (char) waitKey(0);
    457 
    458         if(key == 'd' && flag3 == 0)
    459         {
    460             flag1 = 1;
    461             flag3 = 1;
    462             img1 = img0.clone();
    463             for(int i = var; i < numpts ; i++)
    464                 pts[i] = point;
    465 
    466             if(var!=0)
    467             {
    468                 const Point* pts3[1] = {&pts[0]};
    469                 polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0);
    470             }
    471 
    472             for(int i=0;i<var;i++)
    473             {
    474                 minx = min(minx,pts[i].x);
    475                 maxx = max(maxx,pts[i].x);
    476                 miny = min(miny,pts[i].y);
    477                 maxy = max(maxy,pts[i].y);
    478             }
    479             lenx = maxx - minx;
    480             leny = maxy - miny;
    481 
    482             int mid_pointx = minx + lenx/2;
    483             int mid_pointy = miny + leny/2;
    484 
    485             for(int i=0;i<var;i++)
    486             {
    487                 pts_diff[i].x = pts[i].x - mid_pointx;
    488                 pts_diff[i].y = pts[i].y - mid_pointy;
    489             }
    490 
    491             flag = var;
    492 
    493             final = Mat::zeros(img0.size(),CV_8UC3);
    494             res1 = Mat::zeros(img0.size(),CV_8UC1);
    495             const Point* pts4[1] = {&pts[0]};
    496 
    497             fillPoly(res1, pts4,&numpts, 1, Scalar(255, 255, 255), 8, 0);
    498             bitwise_and(img0, img0, final,res1);
    499 
    500             imshow("Source", img1);
    501         }
    502         else if(key == 'r')
    503         {
    504             for(int i = 0; i < numpts ; i++)
    505             {
    506                 pts[i].x=0;
    507                 pts[i].y=0;
    508             }
    509             var = 0;
    510             flag1 = 0;
    511             flag3 = 0;
    512             flag4 = 0;
    513             minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN;
    514             imshow("Source", img0);
    515             if(num == 1 || num == 2 || num == 3)
    516                 imshow("Destination",img2);
    517             drag = 0;
    518         }
    519         else if ((num == 1 || num == 2 || num == 3) && key == 'c' && flag1 == 1 && flag4 == 1)
    520         {
    521             seamlessClone(img0,img2,res1,point,blend,num);
    522             imshow("Cloned Image", blend);
    523             imwrite("cloned.png",blend);
    524         }
    525         else if (num == 4 && key == 'c' && flag1 == 1)
    526         {
    527             colorChange(img0,res1,blend,red,green,blue);
    528             imshow("Color Change Image", blend);
    529             imwrite("cloned.png",blend);
    530         }
    531         else if (num == 5 && key == 'c' && flag1 == 1)
    532         {
    533             illuminationChange(img0,res1,blend,alpha,beta);
    534             imshow("Illum Change Image", blend);
    535             imwrite("cloned.png",blend);
    536         }
    537         else if (num == 6 && key == 'c' && flag1 == 1)
    538         {
    539             textureFlattening(img0,res1,blend,low_t,high_t,kernel_size);
    540             imshow("Texture Flattened", blend);
    541             imwrite("cloned.png",blend);
    542         }
    543         else if(key == 'q')
    544             exit(0);
    545     }
    546     waitKey(0);
    547 }
    548