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