From 1ed0e44090e0519c183c3867ef1f8ae7607dc2ca Mon Sep 17 00:00:00 2001 From: siddharth Date: Mon, 19 Aug 2013 13:16:04 +0530 Subject: [PATCH] added keyboard control --- modules/photo/include/opencv2/photo.hpp | 12 +- modules/photo/src/seamless_cloning.cpp | 43 ++- modules/photo/src/seamless_cloning.hpp | 122 +++---- modules/photo/test/test_cloning.cpp | 11 +- samples/cpp/cloning.cpp | 453 ++++++++++++++++++------ 5 files changed, 457 insertions(+), 184 deletions(-) diff --git a/modules/photo/include/opencv2/photo.hpp b/modules/photo/include/opencv2/photo.hpp index 673670354..d825c2489 100644 --- a/modules/photo/include/opencv2/photo.hpp +++ b/modules/photo/include/opencv2/photo.hpp @@ -63,7 +63,13 @@ enum { NORMAL_CLONE = 1, MIXED_CLONE = 2, - FEATURE_EXCHANGE = 3 + MONOCHROME_TRANSFER = 3 +}; + +enum +{ + RECURSIVE_FILTER = 1, + NC_FILTER = 2 }; //! restores the damaged image areas using one of the available intpainting algorithms @@ -303,7 +309,9 @@ CV_EXPORTS_W void colorChange(InputArray src, InputArray mask, OutputArray dst, CV_EXPORTS_W void illuminationChange(InputArray src, InputArray mask, OutputArray dst, float alpha = 0.2, float beta = 0.4); -CV_EXPORTS_W void textureFlattening(InputArray src, OutputArray dst); +CV_EXPORTS_W void textureFlattening(InputArray src, InputArray mask, OutputArray dst); + +CV_EXPORTS_W void edgepreservefilter(InputArray _src, OutputArray _dst, int flags = 1, float sigma_h = 60, float sigma_r = 0.4); } // cv diff --git a/modules/photo/src/seamless_cloning.cpp b/modules/photo/src/seamless_cloning.cpp index c2d6c59b9..92beb02fe 100644 --- a/modules/photo/src/seamless_cloning.cpp +++ b/modules/photo/src/seamless_cloning.cpp @@ -144,8 +144,12 @@ void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float float blue = b; Mat gray = Mat::zeros(mask.size(),CV_8UC1); - cvtColor(mask, gray, COLOR_BGR2GRAY); + if(mask.channels() == 3) + cvtColor(mask, gray, COLOR_BGR2GRAY ); + else + gray = mask; + Mat cs_mask = Mat::zeros(src.size(),CV_8UC3); int channel = 3; @@ -178,7 +182,11 @@ void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float beta = b; Mat gray = Mat::zeros(mask.size(),CV_8UC1); - cvtColor(mask, gray, COLOR_BGR2GRAY); + + if(mask.channels() == 3) + cvtColor(mask, gray, COLOR_BGR2GRAY ); + else + gray = mask; Mat cs_mask = Mat::zeros(src.size(),CV_8UC3); @@ -200,14 +208,39 @@ void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, obj.illum_change(src,cs_mask,gray,blend,alpha,beta); } -void cv::textureFlattening(InputArray _src, OutputArray _dst) + +void cv::textureFlattening(InputArray _src, InputArray _mask, OutputArray _dst) { Mat src = _src.getMat(); + Mat mask = _mask.getMat(); _dst.create(src.size(), src.type()); Mat blend = _dst.getMat(); - Cloning obj; - obj.texture_flatten(src,blend); + Mat gray = Mat::zeros(mask.size(),CV_8UC1); + + if(mask.channels() == 3) + cvtColor(mask, gray, COLOR_BGR2GRAY ); + else + gray = mask; + + Mat cs_mask = Mat::zeros(src.size(),CV_8UC3); + + int channel = 3; + for(int i=0;i(i,j) == 255) + { + for(int c=0;c(i,j*channel+c) = src.at(i,j*channel+c); + } + } + + } + + Cloning obj; + obj.texture_flatten(src,cs_mask,gray,blend); } diff --git a/modules/photo/src/seamless_cloning.hpp b/modules/photo/src/seamless_cloning.hpp index 61fdad9c5..a59cb5d16 100644 --- a/modules/photo/src/seamless_cloning.hpp +++ b/modules/photo/src/seamless_cloning.hpp @@ -76,7 +76,7 @@ class Cloning void normal_clone(Mat &I, Mat &mask, Mat &wmask, Mat &final, int num); void local_color_change(Mat &I, Mat &mask, Mat &wmask, Mat &final, float red, float green, float blue); void illum_change(Mat &I, Mat &mask, Mat &wmask, Mat &final, float alpha, float beta); - void texture_flatten(Mat &I, Mat &final); + void texture_flatten(Mat &I, Mat &mask, Mat &wmask, Mat &final); }; void Cloning::getGradientx( const Mat &img, Mat &gx) @@ -782,91 +782,79 @@ void Cloning::illum_change(Mat &I, Mat &mask, Mat &wmask, Mat &final, float alph } } -void Cloning::texture_flatten(Mat &I, Mat &final) + +void Cloning::texture_flatten(Mat &I, Mat &mask, Mat &wmask, Mat &final) { + init(I,wmask); - grx = Mat(I.size(),CV_32FC3); - gry = Mat(I.size(),CV_32FC3); + int w = I.size().width; + int h = I.size().height; - Mat out = Mat(I.size(),CV_8UC1); + getGradientx(I,grx); + getGradienty(I,gry); - getGradientx( I, grx); - getGradienty( I, gry); + getGradientx(mask,sgx); + getGradienty(mask,sgy); - Canny( I, out, 30, 45, 3 ); + Mat Kernel(Size(3, 3), CV_8UC1); + Kernel.setTo(Scalar(1)); - int channel = I.channels(); + erode(wmask, wmask, Kernel); + erode(wmask, wmask, Kernel); + erode(wmask, wmask, Kernel); - for(int i=0;i(i,j) != 255) { - grx.at(i,j*channel+c) = 0.0; - gry.at(i,j*channel+c) = 0.0; + sgx.at(i,j*channel+c) = 0.0; + sgy.at(i,j*channel+c) = 0.0; } } - r_channel = Mat::zeros(I.size(),CV_8UC1); - g_channel = Mat::zeros(I.size(),CV_8UC1); - b_channel = Mat::zeros(I.size(),CV_8UC1); + for(int i=0;i < h; i++) + for(int j=0; j < w; j++) + for(int c=0;c(i,j*channel+c) = + (sgx.at(i,j*channel+c)*smask.at(i,j)); + sry32.at(i,j*channel+c) = + (sgy.at(i,j*channel+c)*smask.at(i,j)); + } - for(int i=0;i(i,j) = I.at(i,j*3+0); - g_channel.at(i,j) = I.at(i,j*3+1); - b_channel.at(i,j) = I.at(i,j*3+2); - } + bitwise_not(wmask,wmask); - Mat gxx = Mat(I.size(),CV_32FC3); - Mat gyy = Mat(I.size(),CV_32FC3); + wmask.convertTo(smask1,CV_32FC1,1.0/255.0); + I.convertTo(grx32,CV_32FC3,1.0/255.0); + I.convertTo(gry32,CV_32FC3,1.0/255.0); - lapx(grx,gxx); - lapy(gry,gyy); + for(int i=0;i < h; i++) + for(int j=0; j < w; j++) + for(int c=0;c(i,j*channel+c) = + (grx.at(i,j*channel+c)*smask1.at(i,j)); + gry32.at(i,j*channel+c) = + (gry.at(i,j*channel+c)*smask1.at(i,j)); + } - rx_channel = Mat(I.size(),CV_32FC1); - gx_channel = Mat(I.size(),CV_32FC1); - bx_channel = Mat(I.size(),CV_32FC1); + calc(I,grx32,gry32,srx32,sry32); - for(int i=0;i(i,j) = gxx.at(i,j*3+0); - gx_channel.at(i,j) = gxx.at(i,j*3+1); - bx_channel.at(i,j) = gxx.at(i,j*3+2); - } - - ry_channel = Mat(I.size(),CV_32FC1); - gy_channel = Mat(I.size(),CV_32FC1); - by_channel = Mat(I.size(),CV_32FC1); - - for(int i=0;i(i,j) = gyy.at(i,j*3+0); - gy_channel.at(i,j) = gyy.at(i,j*3+1); - by_channel.at(i,j) = gyy.at(i,j*3+2); - } - - resultr = Mat(I.size(),CV_8UC1); - resultg = Mat(I.size(),CV_8UC1); - resultb = Mat(I.size(),CV_8UC1); - - clock_t tic = clock(); - - - poisson_solver(r_channel,rx_channel, ry_channel,resultr); - poisson_solver(g_channel,gx_channel, gy_channel,resultg); - poisson_solver(b_channel,bx_channel, by_channel,resultb); - - clock_t toc = clock(); - - printf("Execution time: %f seconds\n", (double)(toc - tic) / CLOCKS_PER_SEC); - - for(int i=0;i(i,j*3+0) = resultr.at(i,j); final.at(i,j*3+1) = resultg.at(i,j); diff --git a/modules/photo/test/test_cloning.cpp b/modules/photo/test/test_cloning.cpp index 583a069ae..bb62d874a 100644 --- a/modules/photo/test/test_cloning.cpp +++ b/modules/photo/test/test_cloning.cpp @@ -164,14 +164,17 @@ TEST(Photo_SeamlessClone_illuminationChange, regression) TEST(Photo_SeamlessClone_textureFlattening, regression) { string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Texture_Flattening/"; - string original_path = folder + "source1.png"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; - Mat source = imread(original_path, IMREAD_COLOR); + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); - ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path; + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path2; Mat result; - textureFlattening(source, result); + textureFlattening(source, mask, result); imwrite(folder + "cloned.png", result); diff --git a/samples/cpp/cloning.cpp b/samples/cpp/cloning.cpp index 70725d8e7..9a41ce229 100644 --- a/samples/cpp/cloning.cpp +++ b/samples/cpp/cloning.cpp @@ -6,26 +6,31 @@ * * This tutorial demonstrates how to use OpenCV seamless cloning * module. -* Flags: -* 1- NORMAL_CLONE -* 2- MIXED_CLONE -* 3- FEATURE_EXCHANGE +* +* 1- Normal Cloning +* 2- Mixed Cloning +* 3- Monochrome Transfer +* 4- Color Change +* 5- Illumination change +* 6- Texture Flattening -* The program takes as input a source and a destination image +* The program takes as input a source and a destination image (for 1-3 methods) * and ouputs the cloned image. * Step 1: * -> 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. -* -> To set the Polygon ROI, click the right mouse button. -* -> To reset the region selected, click the middle mouse button. +* -> To set the Polygon ROI, click the right mouse button or 'd' key. +* -> To reset the region selected, click the middle mouse button or 'r' key. * Step 2: * -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button. -* -> To get the cloned result, click the right mouse button. - +* -> To get the cloned result, click the right mouse button or 'c' key. +* -> To quit the program, use 'q' key. +* * Result: The cloned image will be displayed. */ +#include #include "opencv2/photo.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/highgui.hpp" @@ -47,6 +52,8 @@ Point* pts = new Point[100]; Point* pts2 = new Point[100]; Point* pts_diff = new Point[100]; +char src[50]; +char dest[50]; int var = 0; int flag = 0; @@ -57,6 +64,10 @@ int minxd,minyd,maxxd,maxyd,lenxd,lenyd; int channel,num; +float alpha,beta; + +float red, green, blue; + void source(int event, int x, int y, int, void*) { @@ -93,20 +104,20 @@ void source(int event, int x, int y, int, void*) pts[i] = point; if(var!=0) - { - const Point* pts3[1] = {&pts[0]}; - polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0); - } + { + const Point* pts3[1] = {&pts[0]}; + polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0); + } - for(int i=0;i im1.size().width || maxyd > im1.size().height || minxd < 0 || minyd < 0) - { - cout << "Index out of range" << endl; - exit(0); - } + if(maxxd > im1.size().width || maxyd > im1.size().height || minxd < 0 || minyd < 0) + { + cout << "Index out of range" << endl; + exit(0); + } - final1 = Mat::zeros(img2.size(),CV_8UC3); - res = Mat::zeros(img2.size(),CV_8UC1); - for(int i=miny, k=minyd;i<(miny+leny);i++,k++) - for(int j=minx,l=minxd ;j<(minx+lenx);j++,l++) - { - for(int c=0;c(k,l*channel+c) = final.at(i,j*channel+c); + final1 = Mat::zeros(img2.size(),CV_8UC3); + res = Mat::zeros(img2.size(),CV_8UC1); + for(int i=miny, k=minyd;i<(miny+leny);i++,k++) + for(int j=minx,l=minxd ;j<(minx+lenx);j++,l++) + { + for(int c=0;c(k,l*channel+c) = final.at(i,j*channel+c); - } - } + } + } - const Point* pts6[1] = {&pts2[0]}; - fillPoly(res, pts6, &numpts, 1, Scalar(255, 255, 255), 8, 0); + const Point* pts6[1] = {&pts2[0]}; + fillPoly(res, pts6, &numpts, 1, Scalar(255, 255, 255), 8, 0); - if(num == 1 || num == 2 || num == 3) - { + if(num == 1 || num == 2 || num == 3) + { seamlessClone(img0,img2,res1,point,blend,num); - imshow("Cloned Image", blend); + imshow("Cloned Image", blend); imwrite("cloned.png",blend); - waitKey(0); - } + waitKey(0); + } - for(int i = 0; i < flag ; i++) - { - pts2[i].x=0; - pts2[i].y=0; - } + for(int i = 0; i < flag ; i++) + { + pts2[i].x=0; + pts2[i].y=0; + } - minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN; - } + minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN; + } - im1.release(); + im1.release(); +} + +void checkfile(char *file) +{ + while(1) + { + printf("Enter %s Image: ",file); + if(!strcmp(file,"Source")) + { + cin >> src; + if(access( src, F_OK ) != -1 ) + { + break; + } + else + { + printf("Image doesn't exist\n"); + } + } + else if(!strcmp(file,"Destination")) + { + cin >> dest; + + if(access( dest, F_OK ) != -1 ) + { + break; + } + else + { + printf("Image doesn't exist\n"); + } + + } + } } int main(int argc, char **argv) { + cout << endl; + cout << "Cloning Module" << endl; + cout << "---------------" << endl; + cout << "Step 1:" << endl; + 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; + cout << " -> To set the Polygon ROI, click the right mouse button or use 'd' key" << endl; + cout << " -> To reset the region selected, click the middle mouse button or use 'r' key." << endl; - if (argc != 3) + cout << "Step 2:" << endl; + cout << " -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button." << endl; + cout << " -> To get the cloned result, click the right mouse button or use 'c' key." << endl; + cout << " -> To quit the program, use 'q' key." << endl; + cout << endl; + cout << "Options: " << endl; + cout << endl; + cout << "1) Normal Cloning " << endl; + cout << "2) Mixed Cloning " << endl; + cout << "3) Monochrome Transfer " << endl; + cout << "4) Local Color Change " << endl; + cout << "5) Local Illumination Change " << endl; + cout << "6) Texture Flattening " << endl; + + cout << endl; + + cout << "Press number 1-6 to choose from above techniques: "; + cin >> num; + cout << endl; + + char s[]="Source"; + char d[]="Destination"; + + minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN; + + minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN; + + if(num == 1 || num == 2 || num == 3) { - cout << "usage: " << argv[0] << " " << " " << endl; - exit(1); + + checkfile(s); + checkfile(d); + + img0 = imread(src); + + img2 = imread(dest); + + channel = img0.channels(); + + res = Mat::zeros(img2.size(),CV_8UC1); + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + final1 = Mat::zeros(img2.size(),CV_8UC3); + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", source, NULL); + imshow("Source", img0); + + /////////// destination image /////////////// + + namedWindow("Destination", 1); + setMouseCallback("Destination", destination, NULL); + imshow("Destination",img2); + + } + else if(num == 4) + { + checkfile(s); + + cout << "Enter RGB values: " << endl; + cout << "Red: "; + cin >> red; + + cout << "Green: "; + cin >> green; + + cout << "Blue: "; + cin >> blue; + + img0 = imread(src); + + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + + + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", source, NULL); + imshow("Source", img0); + + + } + else if(num == 5) + { + checkfile(s); + + cout << "alpha: "; + cin >> alpha; + + cout << "beta: "; + cin >> beta; + + img0 = imread(src); + + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", source, NULL); + imshow("Source", img0); + + + } + else if(num == 6) + { + checkfile(s); + + img0 = imread(src); + + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", source, NULL); + imshow("Source", img0); + } + + while(true) + { + char key = waitKey(0); + + if(key == 'd') + { + flag1 = 1; + img1 = img0.clone(); + for(int i = var; i < numpts ; i++) + pts[i] = point; + + if(var!=0) + { + const Point* pts3[1] = {&pts[0]}; + polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0); + } + + for(int i=0;i> num; - - minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN; - - minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN; - - img0 = src; - img2 = dest; - - channel = img0.channels(); - - res = Mat::zeros(img2.size(),CV_8UC1); - res1 = Mat::zeros(img0.size(),CV_8UC1); - final = Mat::zeros(img0.size(),CV_8UC3); - final1 = Mat::zeros(img2.size(),CV_8UC3); - //////////// source image /////////////////// - - namedWindow("Source", 1); - setMouseCallback("Source", source, NULL); - imshow("Source", img0); - - /////////// destination image /////////////// - - namedWindow("Destination", 1); - setMouseCallback("Destination", destination, NULL); - imshow("Destination",img2); - waitKey(0); - - img0.release(); - img1.release(); - img2.release(); + waitKey(0); }