/*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; int channel = output.channels(); 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*channel+c) = temp.at(i,j*channel+c) + (temp.at(i,(j-1)*channel+c) - temp.at(i,j*channel+c)) * V.at(i,j); } } } for(int i=0; i= 0; j--) { for(int c = 0; c(i,j*channel+c) = temp.at(i,j*channel+c) + (temp.at(i,(j+1)*channel+c) - temp.at(i,j*channel+c))*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); } } }