cloning_gui.cpp 14 KB

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