diff --git a/modules/photo/doc/cloning.rst b/modules/photo/doc/cloning.rst new file mode 100644 index 0000000000..48c5b24ba1 --- /dev/null +++ b/modules/photo/doc/cloning.rst @@ -0,0 +1,99 @@ +Seamless Cloning +================ + +.. highlight:: cpp + +seamlessClone +------------- +Image editing tasks concern either global changes (color/intensity corrections, filters, deformations) or local changes concerned to a selection. +Here we are interested in achieving local changes, ones that are restricted to a region manually selected (ROI), in a seamless and effortless manner. +The extent of the changes ranges from slight distortions to complete replacement by novel content. + +.. ocv:function:: void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p, OutputArray blend, int flags) + + :param src: Input 8-bit 3-channel image. + + :param dst: Input 8-bit 3-channel image. + + :param mask: Input 8-bit 1 or 3-channel image. + + :param p: Point in dst image where object is placed. + + :param result: Output image with the same size and type as ``dst``. + + :param flags: Cloning method that could be one of the following: + + * **NORMAL_CLONE** The power of the method is fully expressed when inserting objects with complex outlines into a new background + + * **MIXED_CLONE** The classic method, color-based selection and alpha + masking might be time consuming and often leaves an undesirable halo. Seamless + cloning, even averaged with the original image, is not effective. Mixed seamless + cloning based on a loose selection proves effective. + + * **FEATURE_EXCHANGE** Feature exchange allows the user to replace easily certain + features of one object by alternative features. + + + +colorChange +----------- +Given an original color image, two differently colored versions of this image can be mixed seamlessly. + +.. ocv:function:: void colorChange( InputArray src, InputArray mask, OutputArray dst, float red_mul = 1.0, float green_mul = 1.0, float blue_mul = 1.0) + + :param src: Input 8-bit 3-channel image. + + :param mask: Input 8-bit 1 or 3-channel image. + + :param dst: Output image with the same size and type as ``src`` . + + :param red_mul: R-channel multiply factor. + + :param green_mul: G-channel multiply factor. + + :param blue_mul: B-channel multiply factor. + +Multiplication factor is between .5 to 2.5. + + +illuminationChange +------------------ +Applying an appropriate non-linear transformation to the gradient field inside the selection and then integrating back with a Poisson +solver, modifies locally the apparent illumination of an image. + +.. ocv:function:: void illuminationChange(InputArray src, InputArray mask, OutputArray dst, float alpha = 0.2, float beta = 0.4) + + :param src: Input 8-bit 3-channel image. + + :param mask: Input 8-bit 1 or 3-channel image. + + :param dst: Output image with the same size and type as ``src``. + + :param alpha: Value ranges between 0-2. + + :param beta: Value ranges between 0-2. + +This is useful to highlight under-exposed foreground objects or to reduce specular reflections. + +textureFlattening +----------------- +By retaining only the gradients at edge locations, before integrating with the Poisson solver, one washes out the texture of the selected +region, giving its contents a flat aspect. Here Canny Edge Detector is used. + +.. ocv:function:: void textureFlattening(InputArray src, InputArray mask, OutputArray dst, double low_threshold=30 , double high_threshold=45, int kernel_size=3) + + :param src: Input 8-bit 3-channel image. + + :param mask: Input 8-bit 1 or 3-channel image. + + :param dst: Output image with the same size and type as ``src``. + + :param low_threshold: Range from 0 to 100. + + :param high_threshold: Value > 100. + + :param kernel_size: The size of the Sobel kernel to be used. + +**NOTE:** + +The algorithm assumes that the color of the source image is close to that of the destination. This assumption means that when the colors don't match, the source image color gets tinted toward the color of the destination image. diff --git a/modules/photo/doc/decolor.rst b/modules/photo/doc/decolor.rst new file mode 100644 index 0000000000..cf7b9b9c4c --- /dev/null +++ b/modules/photo/doc/decolor.rst @@ -0,0 +1,19 @@ +Decolorization +============== + +.. highlight:: cpp + +decolor +------- + +Transforms a color image to a grayscale image. It is a basic tool in digital printing, stylized black-and-white photograph rendering, and in many single channel image processing applications. + +.. ocv:function:: void decolor( InputArray src, OutputArray grayscale, OutputArray color_boost ) + + :param src: Input 8-bit 3-channel image. + + :param grayscale: Output 8-bit 1-channel image. + + :param color_boost: Output 8-bit 3-channel image. + +This function is to be applied on color images. diff --git a/modules/photo/doc/npr.rst b/modules/photo/doc/npr.rst new file mode 100644 index 0000000000..48e2db2a7d --- /dev/null +++ b/modules/photo/doc/npr.rst @@ -0,0 +1,74 @@ +Non-Photorealistic Rendering +============================ + +.. highlight:: cpp + +edgePreservingFilter +-------------------- + +Filtering is the fundamental operation in image and video processing. Edge-preserving smoothing filters are used in many different applications. + +.. ocv:function:: void edgePreservingFilter(InputArray src, OutputArray dst, int flags = 1, float sigma_s = 60, float sigma_r = 0.4) + + :param src: Input 8-bit 3-channel image. + + :param dst: Output 8-bit 3-channel image. + + :param flags: Edge preserving filters: + + * **RECURS_FILTER** + + * **NORMCONV_FILTER** + + :param sigma_s: Range between 0 to 200. + + :param sigma_r: Range between 0 to 1. + + +detailEnhance +------------- +This filter enhances the details of a particular image. + +.. ocv:function:: void detailEnhance(InputArray src, OutputArray dst, float sigma_s = 10, float sigma_r = 0.15) + + :param src: Input 8-bit 3-channel image. + + :param dst: Output image with the same size and type as ``src``. + + :param sigma_s: Range between 0 to 200. + + :param sigma_r: Range between 0 to 1. + + +pencilSketch +------------ +Pencil-like non-photorealistic line drawing + +.. ocv:function:: void pencilSketch(InputArray src, OutputArray dst1, OutputArray dst2, float sigma_s = 60, float sigma_r = 0.07, float shade_factor = 0.02) + + :param src: Input 8-bit 3-channel image. + + :param dst1: Output 8-bit 1-channel image. + + :param dst2: Output image with the same size and type as ``src``. + + :param sigma_s: Range between 0 to 200. + + :param sigma_r: Range between 0 to 1. + + :param shade_factor: Range between 0 to 0.1. + + +stylization +----------- +Stylization aims to produce digital imagery with a wide variety of effects not focused on photorealism. Edge-aware filters are ideal for stylization, as they can abstract regions of low contrast while preserving, or enhancing, high-contrast features. + +.. ocv:function:: void stylization(InputArray src, OutputArray dst, float sigma_s = 60, float sigma_r = 0.45) + + :param src: Input 8-bit 3-channel image. + + :param dst: Output image with the same size and type as ``src``. + + :param sigma_s: Range between 0 to 200. + + :param sigma_r: Range between 0 to 1. diff --git a/modules/photo/doc/photo.rst b/modules/photo/doc/photo.rst index c8aefda99c..676f3e9d45 100644 --- a/modules/photo/doc/photo.rst +++ b/modules/photo/doc/photo.rst @@ -9,4 +9,7 @@ photo. Computational Photography inpainting denoising - hdr_imaging \ No newline at end of file + hdr_imaging + decolor + cloning + npr diff --git a/modules/photo/include/opencv2/photo.hpp b/modules/photo/include/opencv2/photo.hpp index beec929235..7ca933c3f6 100644 --- a/modules/photo/include/opencv2/photo.hpp +++ b/modules/photo/include/opencv2/photo.hpp @@ -47,7 +47,7 @@ #include "opencv2/imgproc.hpp" /*! \namespace cv - Namespace where all the C++ OpenCV functionality resides + Namespace where all the C++ OpenCV functionality resides */ namespace cv { @@ -59,26 +59,39 @@ enum INPAINT_TELEA = 1 // A. Telea algorithm }; +enum +{ + NORMAL_CLONE = 1, + MIXED_CLONE = 2, + MONOCHROME_TRANSFER = 3 +}; + +enum +{ + RECURS_FILTER = 1, + NORMCONV_FILTER = 2 +}; + //! restores the damaged image areas using one of the available intpainting algorithms CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMask, - OutputArray dst, double inpaintRadius, int flags ); + OutputArray dst, double inpaintRadius, int flags ); CV_EXPORTS_W void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3, - int templateWindowSize = 7, int searchWindowSize = 21); + int templateWindowSize = 7, int searchWindowSize = 21); CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, - float h = 3, float hColor = 3, - int templateWindowSize = 7, int searchWindowSize = 21); + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputArray dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, int templateWindowSize = 7, int searchWindowSize = 21); CV_EXPORTS_W void fastNlMeansDenoisingColoredMulti( InputArrayOfArrays srcImgs, OutputArray dst, - int imgToDenoiseIndex, int temporalWindowSize, - float h = 3, float hColor = 3, - int templateWindowSize = 7, int searchWindowSize = 21); + int imgToDenoiseIndex, int temporalWindowSize, + float h = 3, float hColor = 3, + int templateWindowSize = 7, int searchWindowSize = 21); enum { LDR_SIZE = 256 }; @@ -288,6 +301,33 @@ public: CV_EXPORTS_W Ptr createMergeRobertson(); +CV_EXPORTS_W void decolor( InputArray src, OutputArray grayscale, OutputArray color_boost); + +CV_EXPORTS_W void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p, + OutputArray blend, int flags); + +CV_EXPORTS_W void colorChange(InputArray src, InputArray mask, OutputArray dst, float red_mul = 1.0, + float green_mul = 1.0, float blue_mul = 1.0); + +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, InputArray mask, OutputArray dst, + double low_threshold = 30, double high_threshold = 45, + int kernel_size = 3); + +CV_EXPORTS_W void edgePreservingFilter(InputArray src, OutputArray dst, int flags = 1, + float sigma_s = 60, float sigma_r = 0.4); + +CV_EXPORTS_W void detailEnhance(InputArray src, OutputArray dst, float sigma_s = 10, + float sigma_r = 0.15); + +CV_EXPORTS_W void pencilSketch(InputArray src, OutputArray dst1, OutputArray dst2, + float sigma_s = 60, float sigma_r = 0.07, float shade_factor = 0.02); + +CV_EXPORTS_W void stylization(InputArray src, OutputArray dst, float sigma_s = 60, + float sigma_r = 0.45); + } // cv #endif diff --git a/modules/photo/src/contrast_preserve.cpp b/modules/photo/src/contrast_preserve.cpp new file mode 100644 index 0000000000..7794b3646d --- /dev/null +++ b/modules/photo/src/contrast_preserve.cpp @@ -0,0 +1,210 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + + +#include "precomp.hpp" +#include "opencv2/photo.hpp" +#include "math.h" +#include +#include +#include +#include "contrast_preserve.hpp" + +using namespace std; +using namespace cv; + +void cv::decolor(InputArray _src, OutputArray _dst, OutputArray _color_boost) +{ + Mat I = _src.getMat(); + _dst.create(I.size(), CV_8UC1); + Mat dst = _dst.getMat(); + + _color_boost.create(I.size(), CV_8UC3); + Mat color_boost = _color_boost.getMat(); + + if(!I.data ) + { + cout << "Could not open or find the image" << endl ; + return; + } + if(I.channels() !=3) + { + cout << "Input Color Image" << endl; + return; + } + + // Parameter Setting + int maxIter = 15; + int iterCount = 0; + double tol = .0001; + double E = 0; + double pre_E = std::numeric_limits::infinity(); + + Decolor obj; + + Mat img; + + img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + // Initialization + obj.init(); + + vector Cg; + vector < vector > polyGrad; + vector < vector < int > > comb; + + vector alf; + + obj.grad_system(img,polyGrad,Cg,comb); + obj.weak_order(img,alf); + + // Solver + Mat Mt = Mat(polyGrad.size(),polyGrad[0].size(), CV_32FC1); + obj.wei_update_matrix(polyGrad,Cg,Mt); + + vector wei; + obj.wei_inti(comb,wei); + + //////////////////////////////// main loop starting //////////////////////////////////////// + + while(sqrt(pow(E-pre_E,2)) > tol) + { + iterCount +=1; + pre_E = E; + + vector G_pos; + vector G_neg; + + vector temp; + vector temp1; + + double val = 0.0; + for(unsigned int i=0;i< polyGrad[0].size();i++) + { + val = 0.0; + for(unsigned int j =0;j EXPsum; + vector EXPterm; + + for(unsigned int i = 0;i temp2; + + for(unsigned int i=0;i wei1; + + for(unsigned int i=0;i< polyGrad.size();i++) + { + val1 = 0.0; + for(unsigned int j =0;j(i,j) * EXPterm[j]); + } + wei1.push_back(val1); + } + + for(unsigned int i =0;i maxIter) + break; + + G_pos.clear(); + G_neg.clear(); + temp.clear(); + temp1.clear(); + EXPsum.clear(); + EXPterm.clear(); + temp2.clear(); + wei1.clear(); + } + + Mat Gray = Mat::zeros(img.size(),CV_32FC1); + obj.grayImContruct(wei, img, Gray); + + Gray.convertTo(dst,CV_8UC1,255); + + /////////////////////////////////// Contrast Boosting ///////////////////////////////// + + Mat lab = Mat(img.size(),CV_8UC3); + Mat color = Mat(img.size(),CV_8UC3); + + cvtColor(I,lab,COLOR_BGR2Lab); + + vector lab_channel; + split(lab,lab_channel); + + dst.copyTo(lab_channel[0]); + + merge(lab_channel,lab); + + cvtColor(lab,color_boost,COLOR_Lab2BGR); +} diff --git a/modules/photo/src/contrast_preserve.hpp b/modules/photo/src/contrast_preserve.hpp new file mode 100644 index 0000000000..8a95170e32 --- /dev/null +++ b/modules/photo/src/contrast_preserve.hpp @@ -0,0 +1,432 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/photo.hpp" +#include "math.h" +#include +#include + +using namespace std; +using namespace cv; + +class Decolor +{ + private: + Mat kernelx; + Mat kernely; + int order; + + public: + float sigma; + void init(); + vector product(vector < vector > &comb, vector &initRGB); + double energyCalcu(vector &Cg, vector < vector > &polyGrad, vector &wei); + void singleChannelGradx(const Mat &img, Mat& dest); + void singleChannelGrady(const Mat &img, Mat& dest); + void gradvector(const Mat &img, vector &grad); + void colorGrad(Mat img, vector &Cg); + void add_vector(vector < vector > &comb, int r,int g,int b); + void add_to_vector_poly(vector < vector > &polyGrad, vector &curGrad); + void weak_order(Mat img, vector &alf); + void grad_system(Mat img, vector < vector < double > > &polyGrad, + vector < double > &Cg, vector < vector >& comb); + void wei_update_matrix(vector < vector > &poly, vector &Cg, Mat &X); + void wei_inti(vector < vector > &comb, vector &wei); + void grayImContruct(vector &wei, Mat img, Mat &Gray); +}; + +int round_num(double a); + +int round_num(double a) +{ + return int(a + 0.5); +} + +double Decolor::energyCalcu(vector &Cg, vector < vector > &polyGrad, vector &wei) +{ + vector energy; + vector temp; + vector temp1; + + double val = 0.0; + for(unsigned int i=0;i< polyGrad[0].size();i++) + { + val = 0.0; + for(unsigned int j =0;j(0,0)=1.0; + kernelx.at(0,1)=-1.0; + kernely.at(0,0)=1.0; + kernely.at(1,0)=-1.0; + order = 2; + sigma = .02; +} + +vector Decolor::product(vector < vector > &comb, vector &initRGB) +{ + vector res; + double dp; + for (unsigned int i=0;i(i,w-1)=0.0; +} + +void Decolor::singleChannelGrady(const Mat &img, Mat& dest) +{ + int w=img.size().width; + int h=img.size().height; + Point anchor(kernely.cols - kernely.cols/2 - 1, kernely.rows - kernely.rows/2 - 1); + filter2D(img, dest, -1, kernely, anchor, 0.0, BORDER_CONSTANT); + for(int j=0;j(h-1,j)=0.0; +} + +void Decolor::gradvector(const Mat &img, vector &grad) +{ + Mat dest= Mat(img.size().height,img.size().width, CV_32FC1); + Mat dest1= Mat(img.size().height,img.size().width, CV_32FC1); + singleChannelGradx(img,dest); + singleChannelGrady(img,dest1); + + Mat d_trans=dest.t(); + Mat d1_trans=dest1.t(); + + int height = d_trans.size().height; + int width = d_trans.size().width; + + for(int i=0;i(i,j)); + + for(int i=0;i(i,j)); + dest.release(); + dest1.release(); +} + +void Decolor::colorGrad(Mat img, vector &Cg) +{ + + Mat lab = Mat(img.size(),CV_32FC3); + + cvtColor(img,lab,COLOR_BGR2Lab); + + vector lab_channel; + split(lab,lab_channel); + + vector ImL; + vector Ima; + vector Imb; + + gradvector(lab_channel[0],ImL); + gradvector(lab_channel[1],Ima); + gradvector(lab_channel[2],Imb); + + double res =0.0; + for(unsigned int i=0;i > &comb, int r,int g,int b) +{ + static int idx =0; + comb.push_back( vector () ); + comb.at(idx).push_back( r ); + comb.at(idx).push_back( g ); + comb.at(idx).push_back( b ); + idx++; +} + +void Decolor::add_to_vector_poly(vector < vector > &polyGrad, vector &curGrad) +{ + static int idx1 =0; + polyGrad.push_back( vector () ); + for(unsigned int i=0;i &alf) +{ + int h = img.size().height; + int w = img.size().width; + double sizefactor; + if((h + w) > 800) + { + sizefactor = (double)800/(h+w); + resize(img,img,Size(round_num(h*sizefactor),round_num(w*sizefactor))); + } + + Mat curIm = Mat(img.size(),CV_32FC1); + vector rgb_channel; + split(img,rgb_channel); + + vector Rg, Gg, Bg; + vector t1, t2, t3; + vector tmp1, tmp2, tmp3; + + gradvector(rgb_channel[2],Rg); + gradvector(rgb_channel[1],Gg); + gradvector(rgb_channel[0],Bg); + + double level = .05; + + for(unsigned int i=0;i level) + t1.push_back(1.0); + else + t1.push_back(0.0); + + if(Gg[i] > level) + t2.push_back(1.0); + else + t2.push_back(0.0); + + if(Bg[i] > level) + t3.push_back(1.0); + else + t3.push_back(0.0); + + if(Rg[i] < -1.0*level) + tmp1.push_back(1.0); + else + tmp1.push_back(0.0); + + if(Gg[i] < -1.0*level) + tmp2.push_back(1.0); + else + tmp2.push_back(0.0); + + if(Bg[i] < -1.0*level) + tmp3.push_back(1.0); + else + tmp3.push_back(0.0); + } + for(unsigned int i =0 ;i < Rg.size();i++) + alf.push_back(t1[i] * t2[i] * t3[i]); + + for(unsigned int i =0 ;i < Rg.size();i++) + alf[i] -= tmp1[i] * tmp2[i] * tmp3[i]; + + double sum =0.0; + for(unsigned int i=0;i > &polyGrad, + vector < double > &Cg, vector < vector >& comb) +{ + int h = img.size().height; + int w = img.size().width; + + double sizefactor; + if((h + w) > 800) + { + sizefactor = (double)800/(h+w); + resize(img,img,Size(round_num(h*sizefactor),round_num(w*sizefactor))); + } + + h = img.size().height; + w = img.size().width; + colorGrad(img,Cg); + + Mat curIm = Mat(img.size(),CV_32FC1); + vector rgb_channel; + split(img,rgb_channel); + + for(int r=0 ;r <=order; r++) + for(int g=0; g<=order;g++) + for(int b =0; b <=order;b++) + { + if((r+g+b)<=order && (r+g+b) > 0) + { + add_vector(comb,r,g,b); + for(int i = 0;i(i,j)= + pow(rgb_channel[2].at(i,j),r)*pow(rgb_channel[1].at(i,j),g)* + pow(rgb_channel[0].at(i,j),b); + vector curGrad; + gradvector(curIm,curGrad); + add_to_vector_poly(polyGrad,curGrad); + } + } +} + +void Decolor::wei_update_matrix(vector < vector > &poly, vector &Cg, Mat &X) +{ + Mat P = Mat(poly.size(),poly[0].size(), CV_32FC1); + Mat A = Mat(poly.size(),poly.size(), CV_32FC1); + + for(unsigned int i =0;i(i,j) = (float) poly[i][j]; + + Mat P_trans = P.t(); + Mat B = Mat(poly.size(),poly[0].size(), CV_32FC1); + for(unsigned int i =0;i < poly.size();i++) + { + for(unsigned int j=0;j(i,j) = (float) (poly[i][j] * Cg[j]); + } + + A = P*P_trans; + solve(A, B, X, DECOMP_NORMAL); + +} + +void Decolor::wei_inti(vector < vector > &comb, vector &wei) +{ + vector initRGB; + + initRGB.push_back( .33 ); + initRGB.push_back( .33 ); + initRGB.push_back( .33 ); + wei = product(comb,initRGB); + + vector sum; + + for(unsigned int i=0;i &wei, Mat img, Mat &Gray) +{ + int h=img.size().height; + int w=img.size().width; + + vector rgb_channel; + split(img,rgb_channel); + + int kk =0; + + for(int r =0;r<=order;r++) + for(int g=0;g<=order;g++) + for(int b=0;b<=order;b++) + if((r + g + b) <=order && (r+g+b) > 0) + { + for(int i = 0;i(i,j)=Gray.at(i,j) + + (float) wei[kk]*pow(rgb_channel[2].at(i,j),r)*pow(rgb_channel[1].at(i,j),g)* + pow(rgb_channel[0].at(i,j),b); + + kk=kk+1; + } + + float minval = INT_MAX; + float maxval = INT_MIN; + + for(int i=0;i(i,j) < minval) + minval = Gray.at(i,j); + + if(Gray.at(i,j) > maxval) + maxval = Gray.at(i,j); + } + + Gray -= minval; + Gray /= maxval - minval; +} diff --git a/modules/photo/src/npr.cpp b/modules/photo/src/npr.cpp new file mode 100644 index 0000000000..3f0be9ba9f --- /dev/null +++ b/modules/photo/src/npr.cpp @@ -0,0 +1,173 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/photo.hpp" +#include +#include + +#include "npr.hpp" + +using namespace std; +using namespace cv; + +void cv::edgePreservingFilter(InputArray _src, OutputArray _dst, int flags, float sigma_s, float sigma_r) +{ + Mat I = _src.getMat(); + _dst.create(I.size(), CV_8UC3); + Mat dst = _dst.getMat(); + + int h = I.size().height; + int w = I.size().width; + + Mat res = Mat(h,w,CV_32FC3); + dst.convertTo(res,CV_32FC3,1.0/255.0); + + Domain_Filter obj; + + Mat img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + obj.filter(img, res, sigma_s, sigma_r, flags); + + convertScaleAbs(res, dst, 255,0); +} + +void cv::detailEnhance(InputArray _src, OutputArray _dst, float sigma_s, float sigma_r) +{ + Mat I = _src.getMat(); + _dst.create(I.size(), CV_8UC3); + Mat dst = _dst.getMat(); + + int h = I.size().height; + int w = I.size().width; + float factor = 3.0; + + Mat img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + Mat res = Mat(h,w,CV_32FC1); + dst.convertTo(res,CV_32FC3,1.0/255.0); + + Mat result = Mat(img.size(),CV_32FC3); + Mat lab = Mat(img.size(),CV_32FC3); + vector lab_channel; + + cvtColor(img,lab,COLOR_BGR2Lab); + split(lab,lab_channel); + + Mat L = Mat(img.size(),CV_32FC1); + + lab_channel[0].convertTo(L,CV_32FC1,1.0/255.0); + + Domain_Filter obj; + + obj.filter(L, res, sigma_s, sigma_r, 1); + + Mat detail = Mat(h,w,CV_32FC1); + + detail = L - res; + multiply(detail,factor,detail); + L = res + detail; + + L.convertTo(lab_channel[0],CV_32FC1,255); + + merge(lab_channel,lab); + + cvtColor(lab,result,COLOR_Lab2BGR); + result.convertTo(dst,CV_8UC3,255); +} + +void cv::pencilSketch(InputArray _src, OutputArray _dst1, OutputArray _dst2, float sigma_s, float sigma_r, float shade_factor) +{ + Mat I = _src.getMat(); + _dst1.create(I.size(), CV_8UC1); + Mat dst1 = _dst1.getMat(); + + _dst2.create(I.size(), CV_8UC3); + Mat dst2 = _dst2.getMat(); + + Mat img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + Domain_Filter obj; + + Mat sketch = Mat(I.size(),CV_32FC1); + Mat color_sketch = Mat(I.size(),CV_32FC3); + + obj.pencil_sketch(img, sketch, color_sketch, sigma_s, sigma_r, shade_factor); + + sketch.convertTo(dst1,CV_8UC1,255); + color_sketch.convertTo(dst2,CV_8UC3,255); + +} + +void cv::stylization(InputArray _src, OutputArray _dst, float sigma_s, float sigma_r) +{ + Mat I = _src.getMat(); + _dst.create(I.size(), CV_8UC3); + Mat dst = _dst.getMat(); + + Mat img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + + int h = img.size().height; + int w = img.size().width; + + Mat res = Mat(h,w,CV_32FC3); + Mat magnitude = Mat(h,w,CV_32FC1); + + Domain_Filter obj; + obj.filter(img, res, sigma_s, sigma_r, NORMCONV_FILTER); + + obj.find_magnitude(res,magnitude); + + Mat stylized = Mat(h,w,CV_32FC3); + + vector temp; + split(res,temp); + multiply(temp[0],magnitude,temp[0]); + multiply(temp[1],magnitude,temp[1]); + multiply(temp[2],magnitude,temp[2]); + merge(temp,stylized); + + stylized.convertTo(dst,CV_8UC3,255); +} diff --git a/modules/photo/src/npr.hpp b/modules/photo/src/npr.hpp new file mode 100644 index 0000000000..744b2bdfbb --- /dev/null +++ b/modules/photo/src/npr.hpp @@ -0,0 +1,582 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/photo.hpp" +#include +#include +#include +#include "math.h" + + +using namespace std; +using namespace cv; + +double myinf = std::numeric_limits::infinity(); + +class Domain_Filter +{ + public: + Mat ct_H, ct_V, horiz, vert, O, O_t, lower_idx, upper_idx; + void init(const Mat &img, int flags, float sigma_s, float sigma_r); + void getGradientx( const Mat &img, Mat &gx); + void getGradienty( const Mat &img, Mat &gy); + void diffx(const Mat &img, Mat &temp); + void diffy(const Mat &img, Mat &temp); + void find_magnitude(Mat &img, Mat &mag); + void compute_boxfilter(Mat &output, Mat &hz, Mat &psketch, float radius); + void compute_Rfilter(Mat &O, Mat &horiz, float sigma_h); + void compute_NCfilter(Mat &O, Mat &horiz, Mat &psketch, float radius); + void filter(const Mat &img, Mat &res, float sigma_s, float sigma_r, int flags); + void pencil_sketch(const Mat &img, Mat &sketch, Mat &color_res, float sigma_s, float sigma_r, float shade_factor); + void Depth_of_field(const Mat &img, Mat &img1, float sigma_s, float sigma_r); +}; + +void Domain_Filter::diffx(const Mat &img, Mat &temp) +{ + int channel = img.channels(); + + for(int i = 0; i < img.size().height; i++) + for(int j = 0; j < img.size().width-1; j++) + { + for(int c =0; c < channel; c++) + { + temp.at(i,j*channel+c) = + img.at(i,(j+1)*channel+c) - img.at(i,j*channel+c); + } + } +} + +void Domain_Filter::diffy(const Mat &img, Mat &temp) +{ + int channel = img.channels(); + + for(int i = 0; i < img.size().height-1; i++) + for(int j = 0; j < img.size().width; j++) + { + for(int c =0; c < channel; c++) + { + temp.at(i,j*channel+c) = + img.at((i+1),j*channel+c) - img.at(i,j*channel+c); + } + } +} + +void Domain_Filter::getGradientx( const Mat &img, Mat &gx) +{ + int w = img.cols; + int h = img.rows; + int channel = img.channels(); + + for(int i=0;i(i,j*channel+c) = + img.at(i,(j+1)*channel+c) - img.at(i,j*channel+c); + } +} + +void Domain_Filter::getGradienty( const Mat &img, Mat &gy) +{ + int w = img.cols; + int h = img.rows; + int channel = img.channels(); + + for(int i=0;i(i,j*channel+c) = + img.at(i+1,j*channel+c) - img.at(i,j*channel+c); + + } +} + +void Domain_Filter::find_magnitude(Mat &img, Mat &mag) +{ + int h = img.rows; + int w = img.cols; + + vector planes; + split(img, planes); + + Mat magXR = Mat(h, w, CV_32FC1); + Mat magYR = Mat(h, w, CV_32FC1); + + Mat magXG = Mat(h, w, CV_32FC1); + Mat magYG = Mat(h, w, CV_32FC1); + + Mat magXB = Mat(h, w, CV_32FC1); + Mat magYB = Mat(h, w, CV_32FC1); + + Sobel(planes[0], magXR, CV_32FC1, 1, 0, 3); + Sobel(planes[0], magYR, CV_32FC1, 0, 1, 3); + + Sobel(planes[1], magXG, CV_32FC1, 1, 0, 3); + Sobel(planes[1], magYG, CV_32FC1, 0, 1, 3); + + Sobel(planes[2], magXB, CV_32FC1, 1, 0, 3); + Sobel(planes[2], magYB, CV_32FC1, 0, 1, 3); + + Mat mag1 = Mat(h,w,CV_32FC1); + Mat mag2 = Mat(h,w,CV_32FC1); + Mat mag3 = Mat(h,w,CV_32FC1); + + magnitude(magXR,magYR,mag1); + magnitude(magXG,magYG,mag2); + magnitude(magXB,magYB,mag3); + + mag = mag1 + mag2 + mag3; + mag = 1.0f - mag; +} + +void Domain_Filter::compute_Rfilter(Mat &output, Mat &hz, float sigma_h) +{ + int h = output.rows; + int w = output.cols; + + float a = (float) exp((-1.0 * sqrt(2.0)) / sigma_h); + + Mat temp = Mat(h,w,CV_32FC3); + + output.copyTo(temp); + Mat V = Mat(h,w,CV_32FC1); + + for(int i=0;i(i,j) = pow(a,hz.at(i,j)); + + for(int i=0; i(i,j) = temp.at(i,j) + (temp.at(i,j-1) - temp.at(i,j)) * V.at(i,j); + } + } + + for(int i=0; i= 0; j--) + { + temp.at(i,j) = temp.at(i,j) + (temp.at(i,j+1) - temp.at(i,j)) * V.at(i,j+1); + } + } + + temp.copyTo(output); +} + +void Domain_Filter::compute_boxfilter(Mat &output, Mat &hz, Mat &psketch, float radius) +{ + int h = output.rows; + int w = output.cols; + Mat lower_pos = Mat(h,w,CV_32FC1); + Mat upper_pos = Mat(h,w,CV_32FC1); + + lower_pos = hz - radius; + upper_pos = hz + radius; + + lower_idx = Mat::zeros(h,w,CV_32FC1); + upper_idx = Mat::zeros(h,w,CV_32FC1); + + Mat domain_row = Mat::zeros(1,w+1,CV_32FC1); + + for(int i=0;i(0,j) = hz.at(i,j); + domain_row.at(0,w) = (float) myinf; + + Mat lower_pos_row = Mat::zeros(1,w,CV_32FC1); + Mat upper_pos_row = Mat::zeros(1,w,CV_32FC1); + + for(int j=0;j(0,j) = lower_pos.at(i,j); + upper_pos_row.at(0,j) = upper_pos.at(i,j); + } + + Mat temp_lower_idx = Mat::zeros(1,w,CV_32FC1); + Mat temp_upper_idx = Mat::zeros(1,w,CV_32FC1); + + for(int j=0;j(0,j) > lower_pos_row.at(0,0)) + { + temp_lower_idx.at(0,0) = (float) j; + break; + } + } + for(int j=0;j(0,j) > upper_pos_row.at(0,0)) + { + temp_upper_idx.at(0,0) = (float) j; + break; + } + } + + int temp = 0; + for(int j=1;j(0,j-1);k(0,k) > lower_pos_row.at(0,j)) + { + temp = count; + break; + } + count++; + } + + temp_lower_idx.at(0,j) = temp_lower_idx.at(0,j-1) + temp; + + count = 0; + for(int k=(int) temp_upper_idx.at(0,j-1);k(0,k) > upper_pos_row.at(0,j)) + { + temp = count; + break; + } + count++; + } + + temp_upper_idx.at(0,j) = temp_upper_idx.at(0,j-1) + temp; + } + + for(int j=0;j(i,j) = temp_lower_idx.at(0,j) + 1; + upper_idx.at(i,j) = temp_upper_idx.at(0,j) + 1; + } + + } + psketch = upper_idx - lower_idx; +} +void Domain_Filter::compute_NCfilter(Mat &output, Mat &hz, Mat &psketch, float radius) +{ + int h = output.rows; + int w = output.cols; + int channel = output.channels(); + + compute_boxfilter(output,hz,psketch,radius); + + Mat box_filter = Mat::zeros(h,w+1,CV_32FC3); + + for(int i = 0; i < h; i++) + { + box_filter.at(i,1*channel+0) = output.at(i,0*channel+0); + box_filter.at(i,1*channel+1) = output.at(i,0*channel+1); + box_filter.at(i,1*channel+2) = output.at(i,0*channel+2); + for(int j = 2; j < w+1; j++) + { + for(int c=0;c(i,j*channel+c) = output.at(i,(j-1)*channel+c) + box_filter.at(i,(j-1)*channel+c); + } + } + + Mat indices = Mat::zeros(h,w,CV_32FC1); + Mat final = Mat::zeros(h,w,CV_32FC3); + + for(int i=0;i(i,j) = (float) i+1; + + Mat a = Mat::zeros(h,w,CV_32FC1); + Mat b = Mat::zeros(h,w,CV_32FC1); + + // Compute the box filter using a summed area table. + for(int c=0;c(i,j)/(h*(w+1)); + rem = (int) b.at(i,j) - r*h*(w+1); + q = rem/h; + p = rem - q*h; + if(q==0) + { + p=h; + q=w; + r=r-1; + } + if(p==0) + { + p=h; + q=q-1; + } + + r1 = (int) a.at(i,j)/(h*(w+1)); + rem1 = (int) a.at(i,j) - r1*h*(w+1); + q1 = rem1/h; + p1 = rem1 - q1*h; + if(p1==0) + { + p1=h; + q1=q1-1; + } + + final.at(i,j*channel+2-c) = (box_filter.at(p-1,q*channel+(2-r)) - box_filter.at(p1-1,q1*channel+(2-r1))) + /(upper_idx.at(i,j) - lower_idx.at(i,j)); + } + } + } + + final.copyTo(output); +} +void Domain_Filter::init(const Mat &img, int flags, float sigma_s, float sigma_r) +{ + int h = img.size().height; + int w = img.size().width; + int channel = img.channels(); + + //////////////////////////////////// horizontal and vertical partial derivatives ///////////////////////////////// + + Mat derivx = Mat::zeros(h,w-1,CV_32FC3); + Mat derivy = Mat::zeros(h-1,w,CV_32FC3); + + diffx(img,derivx); + diffy(img,derivy); + + Mat distx = Mat::zeros(h,w,CV_32FC1); + Mat disty = Mat::zeros(h,w,CV_32FC1); + + //////////////////////// Compute the l1-norm distance of neighbor pixels //////////////////////////////////////////////// + + for(int i = 0; i < h; i++) + for(int j = 0,k=1; j < w-1; j++,k++) + for(int c = 0; c < channel; c++) + { + distx.at(i,k) = + distx.at(i,k) + abs(derivx.at(i,j*channel+c)); + } + + for(int i = 0,k=1; i < h-1; i++,k++) + for(int j = 0; j < w; j++) + for(int c = 0; c < channel; c++) + { + disty.at(k,j) = + disty.at(k,j) + abs(derivy.at(i,j*channel+c)); + } + + ////////////////////// Compute the derivatives of the horizontal and vertical domain transforms. ///////////////////////////// + + horiz = Mat(h,w,CV_32FC1); + vert = Mat(h,w,CV_32FC1); + + Mat final = Mat(h,w,CV_32FC3); + + Mat tempx,tempy; + multiply(distx,sigma_s/sigma_r,tempx); + multiply(disty,sigma_s/sigma_r,tempy); + + horiz = 1.0f + tempx; + vert = 1.0f + tempy; + + O = Mat(h,w,CV_32FC3); + img.copyTo(O); + + O_t = Mat(w,h,CV_32FC3); + + if(flags == 2) + { + + ct_H = Mat(h,w,CV_32FC1); + ct_V = Mat(h,w,CV_32FC1); + + for(int i = 0; i < h; i++) + { + ct_H.at(i,0) = horiz.at(i,0); + for(int j = 1; j < w; j++) + { + ct_H.at(i,j) = horiz.at(i,j) + ct_H.at(i,j-1); + } + } + + for(int j = 0; j < w; j++) + { + ct_V.at(0,j) = vert.at(0,j); + for(int i = 1; i < h; i++) + { + ct_V.at(i,j) = vert.at(i,j) + ct_V.at(i-1,j); + } + } + } + +} + +void Domain_Filter::filter(const Mat &img, Mat &res, float sigma_s = 60, float sigma_r = 0.4, int flags = 1) +{ + int no_of_iter = 3; + int h = img.size().height; + int w = img.size().width; + float sigma_h = sigma_s; + + init(img,flags,sigma_s,sigma_r); + + if(flags == 1) + { + Mat vert_t = vert.t(); + + for(int i=0;i YUV_channel; + Mat vert_t = ct_V.t(); + + float sigma_h = sigma_s; + + Mat penx = Mat(h,w,CV_32FC1); + + Mat pen_res = Mat::zeros(h,w,CV_32FC1); + Mat peny = Mat(w,h,CV_32FC1); + + Mat peny_t; + + float radius; + + for(int i=0;i(k,j) = (shade_factor * (penx.at(k,j) + peny_t.at(k,j))); + + if(i==0) + { + sketch = pen_res.clone(); + split(color_sketch,YUV_channel); + pen_res.copyTo(YUV_channel[0]); + merge(YUV_channel,color_sketch); + cvtColor(color_sketch,color_res,COLOR_YCrCb2BGR); + } + + } +} diff --git a/modules/photo/src/seamless_cloning.cpp b/modules/photo/src/seamless_cloning.cpp new file mode 100644 index 0000000000..63f4530477 --- /dev/null +++ b/modules/photo/src/seamless_cloning.cpp @@ -0,0 +1,193 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/photo.hpp" +#include +#include + +#include "seamless_cloning.hpp" + +using namespace std; +using namespace cv; + +void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point p, OutputArray _blend, int flags) +{ + Mat src = _src.getMat(); + Mat dest = _dst.getMat(); + Mat mask = _mask.getMat(); + _blend.create(dest.size(), CV_8UC3); + Mat blend = _blend.getMat(); + + int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN; + int h = mask.size().height; + int w = mask.size().width; + + Mat gray = Mat(mask.size(),CV_8UC1); + Mat dst_mask = Mat::zeros(dest.size(),CV_8UC1); + Mat cs_mask = Mat::zeros(src.size(),CV_8UC3); + Mat cd_mask = Mat::zeros(dest.size(),CV_8UC3); + + if(mask.channels() == 3) + cvtColor(mask, gray, COLOR_BGR2GRAY ); + else + gray = mask; + + for(int i=0;i(i,j) == 255) + { + minx = std::min(minx,i); + maxx = std::max(maxx,i); + miny = std::min(miny,j); + maxy = std::max(maxy,j); + } + } + } + + int lenx = maxx - minx; + int leny = maxy - miny; + + int minxd = p.y - lenx/2; + int maxxd = p.y + lenx/2; + int minyd = p.x - leny/2; + int maxyd = p.x + leny/2; + + if(minxd < 0 || minyd < 0 || maxxd > dest.size().height || maxyd > dest.size().width) + { + cout << "Index out of range" << endl; + exit(0); + } + + Rect roi_d(minyd,minxd,leny,lenx); + Rect roi_s(miny,minx,leny,lenx); + + Mat destinationROI = dst_mask(roi_d); + Mat sourceROI = cs_mask(roi_s); + + gray(roi_s).copyTo(destinationROI); + src(roi_s).copyTo(sourceROI,gray(roi_s)); + + destinationROI = cd_mask(roi_d); + cs_mask(roi_s).copyTo(destinationROI); + + Cloning obj; + obj.normal_clone(dest,cd_mask,dst_mask,blend,flags); +} + +void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float r, float g, float b) +{ + Mat src = _src.getMat(); + Mat mask = _mask.getMat(); + _dst.create(src.size(), src.type()); + Mat blend = _dst.getMat(); + + float red = r; + float green = g; + float blue = b; + + 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); + + src.copyTo(cs_mask,gray); + + Cloning obj; + obj.local_color_change(src,cs_mask,gray,blend,red,green,blue); +} + + +void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float a, float b) +{ + + Mat src = _src.getMat(); + Mat mask = _mask.getMat(); + _dst.create(src.size(), src.type()); + Mat blend = _dst.getMat(); + float alpha = a; + float beta = b; + + 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); + + src.copyTo(cs_mask,gray); + + Cloning obj; + obj.illum_change(src,cs_mask,gray,blend,alpha,beta); + +} + +void cv::textureFlattening(InputArray _src, InputArray _mask, OutputArray _dst, + double low_threshold, double high_threshold, int kernel_size) +{ + + Mat src = _src.getMat(); + Mat mask = _mask.getMat(); + _dst.create(src.size(), src.type()); + Mat blend = _dst.getMat(); + + 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); + + src.copyTo(cs_mask,gray); + + Cloning obj; + obj.texture_flatten(src,cs_mask,gray,low_threshold,high_threshold,kernel_size,blend); +} diff --git a/modules/photo/src/seamless_cloning.hpp b/modules/photo/src/seamless_cloning.hpp new file mode 100644 index 0000000000..73d719c1ba --- /dev/null +++ b/modules/photo/src/seamless_cloning.hpp @@ -0,0 +1,594 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" +#include "opencv2/photo.hpp" +#include +#include +#include +#include "math.h" + +using namespace std; +using namespace cv; + +class Cloning +{ + + public: + + vector rgb_channel, rgbx_channel, rgby_channel, output; + Mat grx, gry, sgx, sgy, srx32, sry32, grx32, gry32, smask, smask1; + void init_var(Mat &I, Mat &wmask); + void initialization(Mat &I, Mat &mask, Mat &wmask); + void scalar_product(Mat mat, float r, float g, float b); + void array_product(Mat mat1, Mat mat2, Mat mat3); + void poisson(Mat &I, Mat &gx, Mat &gy, Mat &sx, Mat &sy); + void evaluate(Mat &I, Mat &wmask, Mat &cloned); + void getGradientx(const Mat &img, Mat &gx); + void getGradienty(const Mat &img, Mat &gy); + void lapx(const Mat &img, Mat &gxx); + void lapy(const Mat &img, Mat &gyy); + void dst(double *mod_diff, double *sineTransform,int h,int w); + void idst(double *mod_diff, double *sineTransform,int h,int w); + void transpose(double *mat, double *mat_t,int h,int w); + void solve(const Mat &img, double *mod_diff, Mat &result); + void poisson_solver(const Mat &img, Mat &gxx , Mat &gyy, Mat &result); + void normal_clone(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, int num); + void local_color_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float red_mul, float green_mul, float blue_mul); + void illum_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float alpha, float beta); + void texture_flatten(Mat &I, Mat &mask, Mat &wmask, double low_threshold, double high_threhold, int kernel_size, Mat &cloned); +}; + +void Cloning::getGradientx( const Mat &img, Mat &gx) +{ + int w = img.size().width; + int h = img.size().height; + int channel = img.channels(); + for(int i=0;i(i,j*channel+c) = + (float)img.at(i,(j+1)*channel+c) - (float)img.at(i,j*channel+c); + } + +} + +void Cloning::getGradienty( const Mat &img, Mat &gy) +{ + int w = img.size().width; + int h = img.size().height; + int channel = img.channels(); + for(int i=0;i(i,j*channel+c) = + (float)img.at((i+1),j*channel+c) - (float)img.at(i,j*channel+c); + + } +} + +void Cloning::lapx( const Mat &img, Mat &gxx) +{ + int w = img.size().width; + int h = img.size().height; + int channel = img.channels(); + for(int i=0;i(i,(j+1)*channel+c) = + (float)img.at(i,(j+1)*channel+c) - (float)img.at(i,j*channel+c); + } +} + +void Cloning::lapy( const Mat &img, Mat &gyy) +{ + int w = img.size().width; + int h = img.size().height; + int channel = img.channels(); + for(int i=0;i(i+1,j*channel+c) = + (float)img.at((i+1),j*channel+c) - (float)img.at(i,j*channel+c); + + } +} + +void Cloning::dst(double *mod_diff, double *sineTransform,int h,int w) +{ + + unsigned long int idx; + + Mat temp = Mat(2*h+2,1,CV_32F); + Mat res = Mat(h,1,CV_32F); + + Mat planes[] = {Mat_(temp), Mat::zeros(temp.size(), CV_32F)}; + + Mat result; + int p=0; + for(int i=0;i(0,0) = 0.0; + + for(int j=0,r=1;j(r,0) = (float) mod_diff[idx]; + } + + temp.at(h+1,0)=0.0; + + for(int j=h-1, r=h+2;j>=0;j--,r++) + { + idx = j*w+i; + temp.at(r,0) = (float) (-1.0 * mod_diff[idx]); + } + + merge(planes, 2, result); + + dft(result,result,0,0); + + Mat planes1[] = {Mat::zeros(result.size(), CV_32F), Mat::zeros(result.size(), CV_32F)}; + + split(result, planes1); + + std::complex two_i = std::sqrt(std::complex(-1)); + + double factor = -2*imag(two_i); + + for(int c=1,z=0;c(z,0) = (float) (planes1[1].at(c,0)/factor); + } + + for(int q=0,z=0;q(z,0); + } + p++; + } +} + +void Cloning::idst(double *mod_diff, double *sineTransform,int h,int w) +{ + int nn = h+1; + unsigned long int idx; + dst(mod_diff,sineTransform,h,w); + for(int i= 0;i(i,j) = (float) mat[idx]; + } + } + Mat tmp_t = tmp.t(); + + for(int i = 0;i < tmp_t.size().height; i++) + for(int j=0;j(i,j); + } +} + +void Cloning::solve(const Mat &img, double *mod_diff, Mat &result) +{ + int w = img.size().width; + int h = img.size().height; + + unsigned long int idx,idx1; + + double *sineTransform = new double[(h-2)*(w-2)]; + double *sineTransform_t = new double[(h-2)*(w-2)]; + double *denom = new double[(h-2)*(w-2)]; + double *invsineTransform = new double[(h-2)*(w-2)]; + double *invsineTransform_t = new double[(h-2)*(w-2)]; + double *img_d = new double[(h)*(w)]; + + dst(mod_diff,sineTransform,h-2,w-2); + + transpose(sineTransform,sineTransform_t,h-2,w-2); + + dst(sineTransform_t,sineTransform,w-2,h-2); + + transpose(sineTransform,sineTransform_t,w-2,h-2); + + int cy = 1; + + for(int i = 0 ; i < w-2;i++,cy++) + { + for(int j = 0,cx = 1; j < h-2; j++,cx++) + { + idx = j*(w-2) + i; + denom[idx] = (float) 2*cos(CV_PI*cy/( (double) (w-1))) - 2 + 2*cos(CV_PI*cx/((double) (h-1))) - 2; + + } + } + + for(idx = 0 ; idx < (unsigned)(w-2)*(h-2) ;idx++) + { + sineTransform_t[idx] = sineTransform_t[idx]/denom[idx]; + } + + idst(sineTransform_t,invsineTransform,h-2,w-2); + + transpose(invsineTransform,invsineTransform_t,h-2,w-2); + + idst(invsineTransform_t,invsineTransform,w-2,h-2); + + transpose(invsineTransform,invsineTransform_t,w-2,h-2); + + for(int i = 0 ; i < h;i++) + { + for(int j = 0 ; j < w; j++) + { + idx = i*w + j; + img_d[idx] = (double)img.at(i,j); + } + } + for(int i = 1 ; i < h-1;i++) + { + for(int j = 1 ; j < w-1; j++) + { + idx = i*w + j; + img_d[idx] = 0.0; + } + } + for(int i = 1,id1=0 ; i < h-1;i++,id1++) + { + for(int j = 1,id2=0 ; j < w-1; j++,id2++) + { + idx = i*w + j; + idx1= id1*(w-2) + id2; + img_d[idx] = invsineTransform_t[idx1]; + } + } + + for(int i = 0 ; i < h;i++) + { + for(int j = 0 ; j < w; j++) + { + idx = i*w + j; + if(img_d[idx] < 0.0) + result.at(i,j) = 0; + else if(img_d[idx] > 255.0) + result.at(i,j) = 255; + else + result.at(i,j) = (uchar) img_d[idx]; + } + } + + delete [] sineTransform; + delete [] sineTransform_t; + delete [] denom; + delete [] invsineTransform; + delete [] invsineTransform_t; + delete [] img_d; +} + +void Cloning::poisson_solver(const Mat &img, Mat &gxx , Mat &gyy, Mat &result) +{ + + int w = img.size().width; + int h = img.size().height; + + unsigned long int idx; + + Mat lap = Mat(img.size(),CV_32FC1); + + lap = gxx + gyy; + + Mat bound = img.clone(); + + rectangle(bound, Point(1, 1), Point(img.cols-2, img.rows-2), Scalar::all(0), -1); + + double *boundary_point = new double[h*w]; + + for(int i =1;i(i,j) + (int)bound.at(i,(j+1)) + (int)bound.at(i,(j-1)) + + (int)bound.at(i-1,j) + (int)bound.at(i+1,j); + } + + Mat diff = Mat(h,w,CV_32FC1); + for(int i =0;i(i,j) = (float) (lap.at(i,j) - boundary_point[idx]); + } + } + + double *mod_diff = new double[(h-2)*(w-2)]; + for(int i = 0 ; i < h-2;i++) + { + for(int j = 0 ; j < w-2; j++) + { + idx = i*(w-2) + j; + mod_diff[idx] = diff.at(i+1,j+1); + + } + } + ///////////////////////////////////////////////////// Find DST ///////////////////////////////////////////////////// + + solve(img,mod_diff,result); + + delete [] mod_diff; + delete [] boundary_point; +} + +void Cloning::init_var(Mat &I, Mat &wmask) +{ + grx = Mat(I.size(),CV_32FC3); + gry = Mat(I.size(),CV_32FC3); + sgx = Mat(I.size(),CV_32FC3); + sgy = Mat(I.size(),CV_32FC3); + + split(I,rgb_channel); + + smask = Mat(wmask.size(),CV_32FC1); + srx32 = Mat(I.size(),CV_32FC3); + sry32 = Mat(I.size(),CV_32FC3); + smask1 = Mat(wmask.size(),CV_32FC1); + grx32 = Mat(I.size(),CV_32FC3); + gry32 = Mat(I.size(),CV_32FC3); +} + +void Cloning::initialization(Mat &I, Mat &mask, Mat &wmask) +{ + init_var(I,wmask); + + getGradientx(I,grx); + getGradienty(I,gry); + + getGradientx(mask,sgx); + getGradienty(mask,sgy); + + Mat Kernel(Size(3, 3), CV_8UC1); + Kernel.setTo(Scalar(1)); + + erode(wmask, wmask, Kernel, Point(-1,-1), 3); + + wmask.convertTo(smask,CV_32FC1,1.0/255.0); + I.convertTo(srx32,CV_32FC3,1.0/255.0); + I.convertTo(sry32,CV_32FC3,1.0/255.0); +} + +void Cloning::scalar_product(Mat mat, float r, float g, float b) +{ + vector channels; + split(mat,channels); + multiply(channels[2],r,channels[2]); + multiply(channels[1],g,channels[1]); + multiply(channels[0],b,channels[0]); + merge(channels,mat); +} + +void Cloning::array_product(Mat mat1, Mat mat2, Mat mat3) +{ + vector channels_temp1; + vector channels_temp2; + split(mat1,channels_temp1); + split(mat2,channels_temp2); + multiply(channels_temp2[2],mat3,channels_temp1[2]); + multiply(channels_temp2[1],mat3,channels_temp1[1]); + multiply(channels_temp2[0],mat3,channels_temp1[0]); + merge(channels_temp1,mat1); +} + +void Cloning::poisson(Mat &I, Mat &gx, Mat &gy, Mat &sx, Mat &sy) +{ + Mat fx = Mat(I.size(),CV_32FC3); + Mat fy = Mat(I.size(),CV_32FC3); + + fx = gx + sx; + fy = gy + sy; + + Mat gxx = Mat(I.size(),CV_32FC3); + Mat gyy = Mat(I.size(),CV_32FC3); + + lapx(fx,gxx); + lapy(fy,gyy); + + split(gxx,rgbx_channel); + split(gyy,rgby_channel); + + split(I,output); + + poisson_solver(rgb_channel[2],rgbx_channel[2], rgby_channel[2],output[2]); + poisson_solver(rgb_channel[1],rgbx_channel[1], rgby_channel[1],output[1]); + poisson_solver(rgb_channel[0],rgbx_channel[0], rgby_channel[0],output[0]); +} + +void Cloning::evaluate(Mat &I, Mat &wmask, Mat &cloned) +{ + bitwise_not(wmask,wmask); + + 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); + + array_product(grx32,grx,smask1); + array_product(gry32,gry,smask1); + + poisson(I,grx32,gry32,srx32,sry32); + + merge(output,cloned); +} + +void Cloning::normal_clone(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, int num) +{ + int w = I.size().width; + int h = I.size().height; + + initialization(I,mask,wmask); + + if(num == 1) + { + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + + } + else if(num == 2) + { + for(int i=0;i < h; i++) + for(int j=0; j < w; j++) + { + if(abs(sgx.at(i,j) - sgy.at(i,j)) > abs(grx.at(i,j) - gry.at(i,j))) + { + srx32.at(i,j) = sgx.at(i,j) * smask.at(i,j); + sry32.at(i,j) = sgy.at(i,j) * smask.at(i,j); + } + else + { + srx32.at(i,j) = grx.at(i,j) * smask.at(i,j); + sry32.at(i,j) = gry.at(i,j) * smask.at(i,j); + } + } + } + else if(num == 3) + { + Mat gray = Mat(mask.size(),CV_8UC1); + Mat gray8 = Mat(mask.size(),CV_8UC3); + cvtColor(mask, gray, COLOR_BGR2GRAY ); + vector temp; + split(I,temp); + gray.copyTo(temp[2]); + gray.copyTo(temp[1]); + gray.copyTo(temp[0]); + + merge(temp,gray8); + + getGradientx(gray8,sgx); + getGradienty(gray8,sgy); + + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + + } + + evaluate(I,wmask,cloned); +} + +void Cloning::local_color_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float red_mul=1.0, + float green_mul=1.0, float blue_mul=1.0) +{ + initialization(I,mask,wmask); + + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + scalar_product(srx32,red_mul,green_mul,blue_mul); + scalar_product(sry32,red_mul,green_mul,blue_mul); + + evaluate(I,wmask,cloned); +} + +void Cloning::illum_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float alpha, float beta) +{ + initialization(I,mask,wmask); + + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + + Mat mag = Mat(I.size(),CV_32FC3); + magnitude(srx32,sry32,mag); + + Mat multX, multY, multx_temp, multy_temp; + + multiply(srx32,pow(alpha,beta),multX); + pow(mag,-1*beta, multx_temp); + multiply(multX,multx_temp,srx32); + + multiply(sry32,pow(alpha,beta),multY); + pow(mag,-1*beta, multy_temp); + multiply(multY,multy_temp,sry32); + + Mat zeroMask = (srx32 != 0); + + srx32.copyTo(srx32, zeroMask); + sry32.copyTo(sry32, zeroMask); + + evaluate(I,wmask,cloned); +} + +void Cloning::texture_flatten(Mat &I, Mat &mask, Mat &wmask, double low_threshold, + double high_threshold, int kernel_size, Mat &cloned) +{ + initialization(I,mask,wmask); + + Mat out = Mat(mask.size(),CV_8UC1); + Canny(mask,out,low_threshold,high_threshold,kernel_size); + + Mat zeros(sgx.size(), CV_32FC3); + zeros.setTo(0); + Mat zerosMask = (out != 255); + zeros.copyTo(sgx, zerosMask); + zeros.copyTo(sgy, zerosMask); + + array_product(srx32,sgx,smask); + array_product(sry32,sgy,smask); + + evaluate(I,wmask,cloned); +} diff --git a/modules/photo/test/test_cloning.cpp b/modules/photo/test/test_cloning.cpp new file mode 100644 index 0000000000..761b6e0d70 --- /dev/null +++ b/modules/photo/test/test_cloning.cpp @@ -0,0 +1,181 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + + +#include "test_precomp.hpp" +#include "opencv2/photo.hpp" +#include + +using namespace cv; +using namespace std; + + +TEST(Photo_SeamlessClone_normal, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Normal_Cloning/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(destination.empty()) << "Could not load destination image " << original_path2; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path3; + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + seamlessClone(source, destination, mask, p, result, 1); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_mixed, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Mixed_Cloning/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(destination.empty()) << "Could not load destination image " << original_path2; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path3; + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + seamlessClone(source, destination, mask, p, result, 2); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_featureExchange, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Monochrome_Transfer/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(destination.empty()) << "Could not load destination image " << original_path2; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path3; + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + seamlessClone(source, destination, mask, p, result, 3); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_colorChange, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/color_change/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path2; + + Mat result; + colorChange(source, mask, result, 1.5, .5, .5); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_illuminationChange, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Illumination_Change/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load source image " << original_path1; + ASSERT_FALSE(mask.empty()) << "Could not load mask image " << original_path2; + + Mat result; + illuminationChange(source, mask, result, .2, .4); + + imwrite(folder + "cloned.png", result); + +} + +TEST(Photo_SeamlessClone_textureFlattening, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "cloning/Texture_Flattening/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + 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, mask, result, 30, 45, 3); + + imwrite(folder + "cloned.png", result); + +} diff --git a/modules/photo/test/test_decolor.cpp b/modules/photo/test/test_decolor.cpp new file mode 100644 index 0000000000..bf21f37384 --- /dev/null +++ b/modules/photo/test/test_decolor.cpp @@ -0,0 +1,67 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + + +#include "test_precomp.hpp" +#include "opencv2/photo.hpp" +#include + +using namespace cv; +using namespace std; + + +TEST(Photo_Decolor, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "decolor/"; + string original_path = folder + "color_image_1.png"; + + Mat original = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; + ASSERT_FALSE(original.channels()!=3) << "Load color input image " << original_path; + + Mat grayscale, color_boost; + decolor(original, grayscale, color_boost); + + imwrite(folder + "grayscale.png",grayscale); + imwrite(folder + "color_boost.png",color_boost); + +} diff --git a/modules/photo/test/test_npr.cpp b/modules/photo/test/test_npr.cpp new file mode 100755 index 0000000000..993f6c390f --- /dev/null +++ b/modules/photo/test/test_npr.cpp @@ -0,0 +1,130 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + + +#include "test_precomp.hpp" +#include "opencv2/photo.hpp" +#include + +using namespace cv; +using namespace std; + + +TEST(Photo_NPR_EdgePreserveSmoothing_RecursiveFilter, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result; + edgePreservingFilter(source,result,1); + + imwrite(folder + "smoothened_RF.png", result); + +} + +TEST(Photo_NPR_EdgePreserveSmoothing_NormConvFilter, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result; + edgePreservingFilter(source,result,2); + + imwrite(folder + "smoothened_NCF.png", result); + +} + +TEST(Photo_NPR_DetailEnhance, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result; + detailEnhance(source,result); + + imwrite(folder + "detail_enhanced.png", result); + +} + +TEST(Photo_NPR_PencilSketch, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result,result1; + pencilSketch(source,result,result1,10,.1,.03); + + imwrite(folder + "pencil_sketch.png", result); + imwrite(folder + "color_pencil_sketch.png", result1); + +} + +TEST(Photo_NPR_Stylization, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "npr/"; + string original_path = folder + "test1.png"; + + Mat source = imread(original_path, IMREAD_COLOR); + + ASSERT_FALSE(source.empty()) << "Could not load input image " << original_path; + + Mat result; + stylization(source,result); + + imwrite(folder + "stylized.png", result); + +} diff --git a/samples/cpp/cloning_demo.cpp b/samples/cpp/cloning_demo.cpp new file mode 100644 index 0000000000..65a57f1497 --- /dev/null +++ b/samples/cpp/cloning_demo.cpp @@ -0,0 +1,246 @@ +/* +* cloning_demo.cpp +* +* Author: +* Siddharth Kherada +* +* This tutorial demonstrates how to use OpenCV seamless cloning +* module without GUI. +* +* 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 (for 1-3 methods) +* and ouputs the cloned image. +* +* Download test images from opencv_extra folder @github. +* +*/ + +#include "opencv2/photo.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/core.hpp" +#include +#include + +using namespace std; +using namespace cv; + +int main() +{ + cout << endl; + cout << "Cloning Module" << 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: "; + int num = 1; + cin >> num; + cout << endl; + + if(num == 1) + { + string folder = "cloning/Normal_Cloning/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(destination.empty()) + { + cout << "Could not load destination image " << original_path2 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path3 << endl; + exit(0); + } + + Mat result; + Point p; + p.x = 400; + p.y = 100; + + seamlessClone(source, destination, mask, p, result, 1); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 2) + { + string folder = "cloning/Mixed_Cloning/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(destination.empty()) + { + cout << "Could not load destination image " << original_path2 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path3 << endl; + exit(0); + } + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + + seamlessClone(source, destination, mask, p, result, 2); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 3) + { + string folder = "cloning/Monochrome_Transfer/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "destination1.png"; + string original_path3 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat destination = imread(original_path2, IMREAD_COLOR); + Mat mask = imread(original_path3, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(destination.empty()) + { + cout << "Could not load destination image " << original_path2 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path3 << endl; + exit(0); + } + + Mat result; + Point p; + p.x = destination.size().width/2; + p.y = destination.size().height/2; + + seamlessClone(source, destination, mask, p, result, 3); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 4) + { + string folder = "cloning/Color_Change/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path2 << endl; + exit(0); + } + + Mat result; + + colorChange(source, mask, result, 1.5, .5, .5); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 5) + { + string folder = "cloning/Illumination_Change/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path2 << endl; + exit(0); + } + + Mat result; + + illuminationChange(source, mask, result, .2, .4); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + else if(num == 6) + { + string folder = "cloning/Texture_Flattening/"; + string original_path1 = folder + "source1.png"; + string original_path2 = folder + "mask.png"; + + Mat source = imread(original_path1, IMREAD_COLOR); + Mat mask = imread(original_path2, IMREAD_COLOR); + + if(source.empty()) + { + cout << "Could not load source image " << original_path1 << endl; + exit(0); + } + if(mask.empty()) + { + cout << "Could not load mask image " << original_path2 << endl; + exit(0); + } + + Mat result; + + textureFlattening(source, mask, result, 30, 45, 3); + + imshow("Output",result); + imwrite(folder + "cloned.png", result); + } + waitKey(0); +} diff --git a/samples/cpp/cloning_gui.cpp b/samples/cpp/cloning_gui.cpp new file mode 100644 index 0000000000..2457b12154 --- /dev/null +++ b/samples/cpp/cloning_gui.cpp @@ -0,0 +1,546 @@ +/* +* cloning.cpp +* +* Author: +* Siddharth Kherada +* +* This tutorial demonstrates how to use OpenCV seamless cloning +* module. +* +* 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 (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 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 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" +#include "opencv2/core.hpp" +#include +#include + +using namespace std; +using namespace cv; + +Mat img0, img1, img2, res, res1, final, final1, blend; + +Point point; +int drag = 0; +int destx, desty; + +int numpts = 100; +Point* pts = new Point[100]; +Point* pts2 = new Point[100]; +Point* pts_diff = new Point[100]; + +int var = 0; +int flag = 0, flag1 = 0, flag4 = 0; + +int minx, miny, maxx, maxy, lenx, leny; +int minxd, minyd, maxxd, maxyd, lenxd, lenyd; + +int channel, num, kernel_size; + +float alpha,beta; + +float red, green, blue; + +double low_t, high_t; + +void source(int, int, int, int, void*); +void destination(int, int, int, int, void*); +void checkfile(char*); + +void source(int event, int x, int y, int, void*) +{ + + if (event == EVENT_LBUTTONDOWN && !drag) + { + if(flag1 == 0) + { + if(var==0) + img1 = img0.clone(); + point = Point(x, y); + circle(img1,point,2,Scalar(0, 0, 255),-1, 8, 0); + pts[var] = point; + var++; + drag = 1; + if(var>1) + line(img1,pts[var-2], point, Scalar(0, 0, 255), 2, 8, 0); + + imshow("Source", img1); + } + } + + if (event == EVENT_LBUTTONUP && drag) + { + imshow("Source", img1); + + drag = 0; + } + if (event == EVENT_RBUTTONDOWN) + { + 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 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); + + } + } + + const Point* pts6[1] = {&pts2[0]}; + fillPoly(res, pts6, &numpts, 1, Scalar(255, 255, 255), 8, 0); + + if(num == 1 || num == 2 || num == 3) + { + seamlessClone(img0,img2,res1,point,blend,num); + imshow("Cloned Image", blend); + imwrite("cloned.png",blend); + waitKey(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; + } + + im1.release(); +} + +int main() +{ + 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; + + 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; + + minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN; + + minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN; + + int flag3 = 0; + + if(num == 1 || num == 2 || num == 3) + { + + string src,dest; + cout << "Enter Source Image: "; + cin >> src; + + cout << "Enter Destination Image: "; + cin >> dest; + + img0 = imread(src); + + img2 = imread(dest); + + if(!img0.data) + { + cout << "Source Image does not exist" << endl; + exit(0); + } + if(!img2.data) + { + cout << "Destination Image does not exist" << endl; + exit(0); + } + + 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) + { + string src; + cout << "Enter Source Image: "; + cin >> src; + + cout << "Enter RGB values: " << endl; + cout << "Red: "; + cin >> red; + + cout << "Green: "; + cin >> green; + + cout << "Blue: "; + cin >> blue; + + img0 = imread(src); + + if(!img0.data) + { + cout << "Source Image does not exist" << endl; + exit(0); + } + + 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) + { + string src; + cout << "Enter Source Image: "; + cin >> src; + + cout << "alpha: "; + cin >> alpha; + + cout << "beta: "; + cin >> beta; + + img0 = imread(src); + + if(!img0.data) + { + cout << "Source Image does not exist" << endl; + exit(0); + } + + 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) + { + string src; + cout << "Enter Source Image: "; + cin >> src; + + cout << "low_threshold: "; + cin >> low_t; + + cout << "high_threshold: "; + cin >> high_t; + + cout << "kernel_size: "; + cin >> kernel_size; + + img0 = imread(src); + + if(!img0.data) + { + cout << "Source Image does not exist" << endl; + exit(0); + } + + 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 + { + cout << "Wrong Option Choosen" << endl; + exit(0); + } + + for(;;) + { + char key = (char) waitKey(0); + + if(key == 'd' && flag3 == 0) + { + flag1 = 1; + flag3 = 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 +* +* This tutorial demonstrates how to make mask image (black and white). +* The program takes as input a source image and ouputs its corresponding +* mask image. +*/ + +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/core.hpp" +#include +#include + +using namespace std; +using namespace cv; + +Mat img0, img1, res1, final; + +Point point; +int drag = 0; + +int numpts = 100; +Point* pts = new Point[100]; + +int var = 0; +int flag = 0; +int flag1 = 0; + +int minx,miny,maxx,maxy,lenx,leny; + +int channel; + +void mouseHandler(int, int, int, int, void*); + +void mouseHandler(int event, int x, int y, int, void*) +{ + + if (event == EVENT_LBUTTONDOWN && !drag) + { + if(flag1 == 0) + { + if(var==0) + img1 = img0.clone(); + point = Point(x, y); + circle(img1,point,2,Scalar(0, 0, 255),-1, 8, 0); + pts[var] = point; + var++; + drag = 1; + if(var>1) + line(img1,pts[var-2], point, Scalar(0, 0, 255), 2, 8, 0); + + imshow("Source", img1); + } + } + + if (event == EVENT_LBUTTONUP && drag) + { + imshow("Source", img1); + + drag = 0; + } + if (event == EVENT_RBUTTONDOWN) + { + 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" << endl; + exit(1); + } + + Mat src = imread(argv[1]); + + minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN; + + img0 = src; + + channel = img0.channels(); + + res1 = Mat::zeros(img0.size(),CV_8UC1); + final = Mat::zeros(img0.size(),CV_8UC3); + //////////// source image /////////////////// + + namedWindow("Source", 1); + setMouseCallback("Source", mouseHandler, NULL); + imshow("Source", img0); + waitKey(0); + + img0.release(); + img1.release(); +} diff --git a/samples/cpp/npr_demo.cpp b/samples/cpp/npr_demo.cpp new file mode 100644 index 0000000000..30d30cba9f --- /dev/null +++ b/samples/cpp/npr_demo.cpp @@ -0,0 +1,96 @@ +/* +* npr_demo.cpp +* +* Author: +* Siddharth Kherada +* +* This tutorial demonstrates how to use OpenCV Non-Photorealistic Rendering Module. +* 1) Edge Preserve Smoothing +* -> Using Normalized convolution Filter +* -> Using Recursive Filter +* 2) Detail Enhancement +* 3) Pencil sketch/Color Pencil Drawing +* 4) Stylization +* +*/ + +#include +#include "opencv2/photo.hpp" +#include "opencv2/imgproc.hpp" +#include "opencv2/highgui.hpp" +#include "opencv2/core.hpp" +#include +#include + +using namespace std; +using namespace cv; + +int main(int argc, char* argv[]) +{ + if(argc < 2) + { + cout << "usage: " << argv[0] << " " << endl; + exit(0); + } + + int num,type; + + Mat I = imread(argv[1]); + + if(!I.data) + { + cout << "Image not found" << endl; + exit(0); + } + + cout << endl; + cout << " Edge Preserve Filter" << endl; + cout << "----------------------" << endl; + + cout << "Options: " << endl; + cout << endl; + + cout << "1) Edge Preserve Smoothing" << endl; + cout << " -> Using Normalized convolution Filter" << endl; + cout << " -> Using Recursive Filter" << endl; + cout << "2) Detail Enhancement" << endl; + cout << "3) Pencil sketch/Color Pencil Drawing" << endl; + cout << "4) Stylization" << endl; + cout << endl; + + cout << "Press number 1-4 to choose from above techniques: "; + + cin >> num; + + Mat img; + + if(num == 1) + { + cout << endl; + cout << "Press 1 for Normalized Convolution Filter and 2 for Recursive Filter: "; + + cin >> type; + + edgePreservingFilter(I,img,type); + imshow("Edge Preserve Smoothing",img); + + } + else if(num == 2) + { + detailEnhance(I,img); + imshow("Detail Enhanced",img); + } + else if(num == 3) + { + Mat img1; + pencilSketch(I,img1, img, 10 ,.1,.03); + imshow("Pencil Sketch",img1); + imshow("Color Pencil Sketch",img); + } + else if(num == 4) + { + stylization(I,img); + imshow("Stylization",img); + } + waitKey(0); +}