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