diff --git a/modules/photo/include/opencv2/photo.hpp b/modules/photo/include/opencv2/photo.hpp index e656b93e8a..6f5868dd4c 100644 --- a/modules/photo/include/opencv2/photo.hpp +++ b/modules/photo/include/opencv2/photo.hpp @@ -288,7 +288,7 @@ public: CV_EXPORTS_W Ptr createMergeRobertson(); -CV_EXPORTS_W void decolor(InputArray src, OutputArray grayscale, OutputArray color_boost); +CV_EXPORTS_W void decolor(InputArray src, OutputArray grayscale); } // cv diff --git a/modules/photo/src/contrast_preserve.cpp b/modules/photo/src/contrast_preserve.cpp index 271afb5e7e..6d4a2d1313 100644 --- a/modules/photo/src/contrast_preserve.cpp +++ b/modules/photo/src/contrast_preserve.cpp @@ -5,72 +5,162 @@ #include #include #include - #include "contrast_preserve.hpp" using namespace std; using namespace cv; -int rounding(double); + +int rounding(double a); int rounding(double a) { - return int(a + 0.5); + return int(a + 0.5); } -void cv::decolor(InputArray _src, OutputArray _gray, OutputArray _boost) +void cv::decolor(InputArray _src, OutputArray _dst) { - Mat I = _src.getMat(); - _gray.create(I.size(), CV_8UC1); - Mat dst = _gray.getMat(); + Mat I = _src.getMat(); + _dst.create(I.size(), CV_8UC1); + Mat dst = _dst.getMat(); - _boost.create(I.size(), CV_8UC3); - Mat color_boost = _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; + } - if(!I.data ) - { - cout << "Could not open or find the image" << endl ; - return; - } - if(I.channels() !=3) - { - cout << "Input Color Image" << endl; - return; - } + float sigma = .02; + int maxIter = 8; + int iterCount = 0; - float sigma = .02; - int maxIter = 8; - int iterCount = 0; + int h = I.size().height; + int w = I.size().width; - int h = I.size().height; - int w = I.size().width; + Decolor obj; - Mat img; - Decolor obj; + Mat img; + + double sizefactor; - double sizefactor; + if((h + w) > 900) + { + sizefactor = (double)900/(h+w); + resize(I,I,Size(rounding(h*sizefactor),rounding(w*sizefactor))); + img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + } + else + { + img = Mat(I.size(),CV_32FC3); + I.convertTo(img,CV_32FC3,1.0/255.0); + } - if((h + w) > 900) - { - sizefactor = (double)900/(h+w); - resize(I,I,Size(rounding(h*sizefactor),rounding(w*sizefactor))); - img = Mat(I.size(),CV_32FC3); - I.convertTo(img,CV_32FC3,1.0/255.0); - } - else - { - img = Mat(I.size(),CV_32FC3); - I.convertTo(img,CV_32FC3,1.0/255.0); - } + obj.init(); - obj.init(); + vector Cg; + vector < vector > polyGrad; + vector < vector > bc; + vector < vector < int > > comb; - vector Cg; - vector < vector > polyGrad; - vector < vector > bc; - vector < vector < int > > comb; + vector alf; - vector alf; + obj.grad_system(img,polyGrad,Cg,comb); + obj.weak_order(img,alf); + + 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 (iterCount < maxIter) + { + iterCount +=1; + + 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 product(vector < vector > &comb, vector &initRGB); + 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); }; void Decolor::init() { - kernel = Mat(1,2, CV_32FC1); - kernel1 = Mat(2,1, CV_32FC1); - kernel.at(0,0)=1.0; - kernel.at(0,1)=-1.0; - kernel1.at(0,0)=1.0; - kernel1.at(1,0)=-1.0; - order = 2; + kernel = Mat(1,2, CV_32FC1); + kernel1 = Mat(2,1, CV_32FC1); + kernel.at(0,0)=1.0; + kernel.at(0,1)=-1.0; + kernel1.at(0,0)=1.0; + kernel1.at(1,0)=-1.0; + order = 2; } + +vector Decolor::product(vector < vector > &comb, vector &initRGB) +{ + vector res; + float 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(kernel1.cols - kernel1.cols/2 - 1, kernel1.rows - kernel1.rows/2 - 1); + filter2D(img, dest, -1, kernel1, 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); + Mat l_channel = Mat(img.size(),CV_32FC1); + Mat a_channel = Mat(img.size(),CV_32FC1); + Mat b_channel = Mat(img.size(),CV_32FC1); + + cvtColor(img,lab,COLOR_BGR2Lab); + for(int i=0;i(i,j) = lab.at(i,j*3+0); + a_channel.at(i,j) = lab.at(i,j*3+1); + b_channel.at(i,j) = lab.at(i,j*3+2); + } + + vector ImL; + vector Ima; + vector Imb; + gradvector(l_channel,ImL); + gradvector(a_channel,Ima); + gradvector(b_channel,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) +{ + Mat curIm = Mat(img.size(),CV_32FC1); + Mat red = Mat(img.size(),CV_32FC1); + Mat green = Mat(img.size(),CV_32FC1); + Mat blue = Mat(img.size(),CV_32FC1); + + for(int i=0;i(i,j) = img.at(i,j*3+2); + green.at(i,j) = img.at(i,j*3+1); + blue.at(i,j) = img.at(i,j*3+0); + } + + vector Rg; + vector Gg; + vector Bg; + + vector t1; + vector t2; + vector t3; + + vector tmp1; + vector tmp2; + vector tmp3; + + gradvector(red,Rg); + gradvector(green,Gg); + gradvector(blue,Bg); + double level = .05; + + for(unsigned int i=0;i level) + t1.push_back(1.0); + else + t1.push_back(0.0); + } + for(unsigned int i=0;i level) + t2.push_back(1.0); + else + t2.push_back(0.0); + } + for(unsigned int i=0;i level) + t3.push_back(1.0); + else + t3.push_back(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; + colorGrad(img,Cg); + + Mat curIm = Mat(img.size(),CV_32FC1); + Mat red = Mat(img.size(),CV_32FC1); + Mat green = Mat(img.size(),CV_32FC1); + Mat blue = Mat(img.size(),CV_32FC1); + + for(int i=0;i(i,j) = img.at(i,j*3+2); + green.at(i,j) = img.at(i,j*3+1); + blue.at(i,j) = img.at(i,j*3+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) + { + add_vector(comb,r,g,b); + for(int i = 0;i(i,j)= + pow(red.at(i,j),r)*pow(green.at(i,j),g)* + pow(blue.at(i,j),b); + vector curGrad; + gradvector(curIm,curGrad); + add_to_vector_poly(polyGrad,curGrad); + } + } + + red.release(); + green.release(); + blue.release(); + curIm.release(); +} + +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) = 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) = poly[i][j]*Cg[j]; + } + + A = P*P_trans; + solve(A, B, X, DECOMP_NORMAL); + + P.release(); + A.release(); + B.release(); + +} + +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; + + Mat red = Mat(img.size(),CV_32FC1); + Mat green = Mat(img.size(),CV_32FC1); + Mat blue = Mat(img.size(),CV_32FC1); + + for(int i=0;i(i,j) = img.at(i,j*3+2); + green.at(i,j) = img.at(i,j*3+1); + blue.at(i,j) = img.at(i,j*3+0); + } + + 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) + + wei[kk]*pow(red.at(i,j),r)*pow(green.at(i,j),g)* + pow(blue.at(i,j),b); + + kk=kk+1; + } + + double minval = INT_MAX; + double 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); + } + + for(int i=0;i(i,j) = (Gray.at(i,j) - minval)/(maxval - minval); + + red.release(); + green.release(); + blue.release(); +} diff --git a/modules/photo/test/test_decolor.cpp b/modules/photo/test/test_decolor.cpp new file mode 100644 index 0000000000..3edec908a8 --- /dev/null +++ b/modules/photo/test/test_decolor.cpp @@ -0,0 +1,34 @@ +#include "test_precomp.hpp" +#include "opencv2/photo.hpp" +#include + +using namespace cv; +using namespace std; + +#ifdef DUMP_RESULTS +# define DUMP(image, path) imwrite(path, image) +#else +# define DUMP(image, path) +#endif + + +TEST(Photo_Decolor, regression) +{ + string folder = string(cvtest::TS::ptr()->get_data_path()) + "decolor/"; + string original_path = folder + "color_image_1.png"; + string expected_path = folder + "grayscale_image_1.png"; + + Mat original = imread(original_path, IMREAD_COLOR); + Mat expected = imread(expected_path, IMREAD_GRAYSCALE); + + ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; + ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path; + + Mat result; + decolor(original, result); + + DUMP(result, expected_path + ".res.png"); + + ASSERT_EQ(0, norm(result != expected)); +} +