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 41using namespace std; 42using namespace cv; 43 44Mat img0, img1, img2, res, res1, final, final1, blend; 45 46Point point; 47int drag = 0; 48int destx, desty; 49 50int numpts = 100; 51Point* pts = new Point[100]; 52Point* pts2 = new Point[100]; 53Point* pts_diff = new Point[100]; 54 55int var = 0; 56int flag = 0, flag1 = 0, flag4 = 0; 57 58int minx, miny, maxx, maxy, lenx, leny; 59int minxd, minyd, maxxd, maxyd, lenxd, lenyd; 60 61int channel, num, kernel_size; 62 63float alpha,beta; 64 65float red, green, blue; 66 67float low_t, high_t; 68 69void source(int, int, int, int, void*); 70void destination(int, int, int, int, void*); 71void checkfile(char*); 72 73void 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 186void 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 271int 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