decolor module updated
authorsiddharth <siddharthkherada27@gmail.com>
Mon, 17 Jun 2013 09:57:52 +0000 (15:27 +0530)
committersiddharth <siddharthkherada27@gmail.com>
Wed, 4 Dec 2013 13:47:58 +0000 (19:17 +0530)
update3

update4

update4

update5

added test data

modules/photo/include/opencv2/photo.hpp
modules/photo/src/contrast_preserve.cpp
modules/photo/src/contrast_preserve.hpp
modules/photo/test/test_decolor.cpp [new file with mode: 0644]

index e656b93..6f5868d 100644 (file)
@@ -288,7 +288,7 @@ public:
 
 CV_EXPORTS_W Ptr<MergeRobertson> createMergeRobertson();
 
-CV_EXPORTS_W void decolor(InputArray src, OutputArray grayscale, OutputArray color_boost);
+CV_EXPORTS_W void decolor(InputArray src, OutputArray grayscale);
 
 } // cv
 
index 271afb5..6d4a2d1 100644 (file)
 #include <vector>
 #include <limits>
 #include <iostream>
-
 #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();
-
-        _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;
-        }
-
-        float sigma = .02;
-        int maxIter = 8;
-        int iterCount = 0;
-
-        int h = I.size().height;
-        int w = I.size().width;
-
-        Mat img;
-        Decolor obj;
-
-        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);
-        }
-
-        obj.init();
-
-        vector <double> Cg;
-        vector < vector <double> > polyGrad;
-        vector < vector <double> > bc;
-        vector < vector < int > > comb;
-
-        vector <double> alf;
-
-
+       Mat I = _src.getMat();
+    _dst.create(I.size(), CV_8UC1);
+    Mat dst = _dst.getMat();
+
+    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;
+
+       int h = I.size().height;
+       int w = I.size().width;
+
+       Decolor obj;
+
+       Mat img;
+       
+       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);
+       }
+
+       obj.init();
+
+       vector <double> Cg;
+       vector < vector <double> > polyGrad;
+       vector < vector <double> > bc;
+       vector < vector < int > > comb;
+
+       vector <double> 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 <double> wei;
+       obj.wei_inti(comb,wei);
+
+       //////////////////////////////// main loop starting ////////////////////////////////////////
+
+       while (iterCount < maxIter)
+       {
+               iterCount +=1;
+
+               vector <double> G_pos;
+               vector <double> G_neg;
+
+               vector <double> temp;
+               vector <double> temp1;
+
+               double val = 0.0;
+               for(unsigned int i=0;i< polyGrad[0].size();i++)
+               {
+                       val = 0.0;
+                       for(unsigned int j =0;j<polyGrad.size();j++)
+                               val = val + (polyGrad[j][i] * wei[j]);
+                       temp.push_back(val - Cg[i]);
+                       temp1.push_back(val + Cg[i]);
+               }
+
+               double ans = 0.0;
+               double ans1 = 0.0;
+               for(unsigned int i =0;i<alf.size();i++)
+               {
+                       ans = ((1 + alf[i])/2) * exp((-1.0 * 0.5 * pow(temp[i],2))/pow(sigma,2));
+                       ans1 =((1 - alf[i])/2) * exp((-1.0 * 0.5 * pow(temp1[i],2))/pow(sigma,2));
+                       G_pos.push_back(ans);
+                       G_neg.push_back(ans1);
+               }
+
+               vector <double> EXPsum;
+               vector <double> EXPterm;
+
+               for(unsigned int i = 0;i<G_pos.size();i++)
+                       EXPsum.push_back(G_pos[i]+G_neg[i]);
+
+
+               vector <double> temp2;
+
+               for(unsigned int i=0;i<EXPsum.size();i++)
+               {
+                       if(EXPsum[i] == 0)
+                               temp2.push_back(1.0);
+                       else
+                               temp2.push_back(0.0);
+               }
+
+               for(unsigned int i =0; i < G_pos.size();i++)
+                       EXPterm.push_back((G_pos[i] - G_neg[i])/(EXPsum[i] + temp2[i]));
+
+               
+               double val1 = 0.0;
+               vector <double> wei1;
+
+               for(unsigned int i=0;i< polyGrad.size();i++)
+               {
+                       val1 = 0.0;
+                       for(unsigned int j =0;j<polyGrad[0].size();j++)
+                       {
+                               val1 = val1 + (Mt.at<float>(i,j) * EXPterm[j]);
+                       }
+                       wei1.push_back(val1);
+               }
+
+               for(unsigned int i =0;i<wei.size();i++)
+                       wei[i] = wei1[i];
+
+               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);
+
+       
 }
-
index 5c6cd50..440427f 100644 (file)
@@ -10,22 +10,411 @@ using namespace cv;
 
 class Decolor
 {
-        public:
+        private:
                 Mat kernel;
                 Mat kernel1;
                 int order;
+        
+        public:
                 void init();
+                vector<double> product(vector < vector<int> > &comb, vector <double> &initRGB);
+                void singleChannelGradx(const Mat &img, Mat& dest);
+                void singleChannelGrady(const Mat &img, Mat& dest);
+                void gradvector(const Mat &img, vector <double> &grad);
+                void colorGrad(Mat img, vector <double> &Cg);
+                void add_vector(vector < vector <int> > &comb, int r,int g,int b);
+                void add_to_vector_poly(vector < vector <double> > &polyGrad, vector <double> &curGrad);
+                void weak_order(Mat img, vector <double> &alf);
                 void grad_system(Mat img, vector < vector < double > > &polyGrad, vector < double > &Cg, vector < vector <int> >& comb);
+                void wei_update_matrix(vector < vector <double> > &poly, vector <double> &Cg, Mat &X);
+                void wei_inti(vector < vector <int> > &comb, vector <double> &wei);
+                void grayImContruct(vector <double> &wei, Mat img, Mat &Gray);
 };
 
 void Decolor::init()
 {
-        kernel = Mat(1,2, CV_32FC1);
-        kernel1 = Mat(2,1, CV_32FC1);
-        kernel.at<float>(0,0)=1.0;
-        kernel.at<float>(0,1)=-1.0;
-        kernel1.at<float>(0,0)=1.0;
-        kernel1.at<float>(1,0)=-1.0;
-        order = 2;
+       kernel = Mat(1,2, CV_32FC1);
+       kernel1 = Mat(2,1, CV_32FC1);
+       kernel.at<float>(0,0)=1.0;
+       kernel.at<float>(0,1)=-1.0;
+       kernel1.at<float>(0,0)=1.0;
+       kernel1.at<float>(1,0)=-1.0;
+       order = 2;
+
+}
+
+vector<double> Decolor::product(vector < vector<int> > &comb, vector <double> &initRGB)
+{
+       vector <double> res;
+       float dp;
+       for (unsigned int i=0;i<comb.size();i++)
+       {
+               dp = 0.0f;
+               for(int j=0;j<3;j++)
+                       dp += comb[i][j] * initRGB[j];
+               res.push_back(dp);
+       }
+       return res;
+}
+
+void Decolor::singleChannelGradx(const Mat &img, Mat& dest)
+{
+       int w=img.size().width;
+       int h=img.size().height;
+       Point anchor(kernel.cols - kernel.cols/2 - 1, kernel.rows - kernel.rows/2 - 1);
+       filter2D(img, dest, -1, kernel, anchor, 0.0, BORDER_CONSTANT);
+       for(int i=0;i<h;i++)
+               dest.at<float>(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<w;j++)
+               dest.at<float>(h-1,j)=0.0;
+}
+
+void Decolor::gradvector(const Mat &img, vector <double> &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<height;i++)
+               for(int j=0;j<width;j++)
+                       grad.push_back(d_trans.at<float>(i,j));
+
+       for(int i=0;i<height;i++)
+               for(int j=0;j<width;j++)
+                       grad.push_back(d1_trans.at<float>(i,j));
+       dest.release();
+       dest1.release();
+}
+        
+void Decolor::colorGrad(Mat img, vector <double> &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<img.size().height;i++)
+               for(int j=0;j<img.size().width;j++)
+               {
+                       l_channel.at<float>(i,j) = lab.at<float>(i,j*3+0);
+                       a_channel.at<float>(i,j) = lab.at<float>(i,j*3+1);
+                       b_channel.at<float>(i,j) = lab.at<float>(i,j*3+2);
+               }
+
+       vector <double> ImL;
+       vector <double> Ima;
+       vector <double> Imb;
+       gradvector(l_channel,ImL);
+       gradvector(a_channel,Ima);
+       gradvector(b_channel,Imb);
+
+       double res =0.0;
+       for(unsigned int i=0;i<ImL.size();i++)
+       {
+               res=sqrt(pow(ImL[i],2) + pow(Ima[i],2) + pow(Imb[i],2))/100;
+               Cg.push_back(res);
+       }
+       lab.release();
+       l_channel.release();
+       a_channel.release();
+       b_channel.release();
+
+       ImL.clear();
+       Ima.clear();
+       Imb.clear();
+       
+}
+
+void Decolor::add_vector(vector < vector <int> > &comb, int r,int g,int b)
+{
+       static int idx =0;
+       comb.push_back( vector <int>() );
+       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 <double> > &polyGrad, vector <double> &curGrad)
+{
+       static int idx1 =0;
+       polyGrad.push_back( vector <double>() );
+       for(unsigned int i=0;i<curGrad.size();i++)
+               polyGrad.at(idx1).push_back(curGrad[i]);
+       idx1++;
+}
+
+void Decolor::weak_order(Mat img, vector <double> &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<img.size().height;i++)
+               for(int j=0;j<img.size().width;j++)
+               {
+                       red.at<float>(i,j) = img.at<float>(i,j*3+2);
+                       green.at<float>(i,j) = img.at<float>(i,j*3+1);
+                       blue.at<float>(i,j) = img.at<float>(i,j*3+0);
+               }
+       
+       vector <double> Rg;
+       vector <double> Gg;
+       vector <double> Bg;
+
+       vector <double> t1;
+       vector <double> t2;
+       vector <double> t3;
+       
+       vector <double> tmp1;
+       vector <double> tmp2;
+       vector <double> tmp3;
+
+       gradvector(red,Rg);
+       gradvector(green,Gg);
+       gradvector(blue,Bg);
+       double level = .05;
+
+       for(unsigned int i=0;i<Rg.size();i++)
+       {
+               if(Rg[i] > level)
+                       t1.push_back(1.0);
+               else
+                       t1.push_back(0.0);
+       }
+       for(unsigned int i=0;i<Gg.size();i++)
+       {
+               if(Gg[i] > level)
+                       t2.push_back(1.0);
+               else
+                       t2.push_back(0.0);
+       }
+       for(unsigned int i=0;i<Bg.size();i++)
+       {
+               if(Bg[i] > level)
+                       t3.push_back(1.0);
+               else
+                       t3.push_back(0.0);
+       }
+       for(unsigned int i=0;i<Rg.size();i++)
+       {
+               if(Rg[i] < -1.0*level)
+                       tmp1.push_back(1.0);
+               else
+                       tmp1.push_back(0.0);
+       }
+       for(unsigned int i=0;i<Gg.size();i++)
+       {
+               if(Gg[i] < -1.0*level)
+                       tmp2.push_back(1.0);
+               else
+                       tmp2.push_back(0.0);
+       }
+       for(unsigned int i=0;i<Bg.size();i++)
+       {
+               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<alf.size();i++)
+               sum += abs(alf[i]);
+
+       sum = (double)100*sum/alf.size();
+
+       red.release();
+       green.release();
+       blue.release();
+       curIm.release();
+
+       Rg.clear();
+       Gg.clear();
+       Bg.clear();
+
+       t1.clear();
+       t2.clear();
+       t3.clear();
+
+       tmp1.clear();
+       tmp2.clear();
+       tmp3.clear();
+
+
+}
+
+void Decolor::grad_system(Mat img, vector < vector < double > > &polyGrad, vector < double > &Cg, vector < vector <int> >& 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<img.size().height;i++)
+               for(int j=0;j<img.size().width;j++)
+               {
+                       red.at<float>(i,j) = img.at<float>(i,j*3+2);
+                       green.at<float>(i,j) = img.at<float>(i,j*3+1);
+                       blue.at<float>(i,j) = img.at<float>(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<h;i++)
+                                               for(int j=0;j<w;j++)
+                                                       curIm.at<float>(i,j)=
+                                                               pow(red.at<float>(i,j),r)*pow(green.at<float>(i,j),g)*
+                                                                       pow(blue.at<float>(i,j),b);
+                                       vector <double> 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 <double> > &poly, vector <double> &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<poly.size();i++)
+               for(unsigned int j=0;j<poly[0].size();j++)
+                       P.at<float>(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<Cg.size();j++)
+                       B.at<float>(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 <int> > &comb, vector <double> &wei)
+{
+       vector <double> initRGB;
+
+       initRGB.push_back( .33 );
+       initRGB.push_back( .33 );
+       initRGB.push_back( .33 );
+       wei = product(comb,initRGB);
+
+       vector <int> sum;
+
+       for(unsigned int i=0;i<comb.size();i++)
+               sum.push_back(comb[i][0] + comb[i][1] + comb[i][2]);
+
+       for(unsigned int i=0;i<sum.size();i++)
+       {
+               if(sum[i] == 1)
+                       wei[i] = wei[i] * double(1);
+               else
+                       wei[i] = wei[i] * double(0);
+       }
+
+       initRGB.clear();
+       sum.clear();
+
+}
+
+void Decolor::grayImContruct(vector <double> &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<img.size().height;i++)
+               for(int j=0;j<img.size().width;j++)
+               {
+                       red.at<float>(i,j) = img.at<float>(i,j*3+2);
+                       green.at<float>(i,j) = img.at<float>(i,j*3+1);
+                       blue.at<float>(i,j) = img.at<float>(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<h;i++)
+                                               for(int j=0;j<w;j++)
+                                                       Gray.at<float>(i,j)=Gray.at<float>(i,j) +
+                                                               wei[kk]*pow(red.at<float>(i,j),r)*pow(green.at<float>(i,j),g)*
+                                                                       pow(blue.at<float>(i,j),b);
+
+                                       kk=kk+1;
+                               }
+
+       double minval = INT_MAX;
+       double maxval = INT_MIN;
+
+       for(int i=0;i<h;i++)
+               for(int j =0;j<w;j++)
+               {
+                       if(Gray.at<float>(i,j) < minval)
+                               minval = Gray.at<float>(i,j);
+                       
+                       if(Gray.at<float>(i,j) > maxval)
+                               maxval = Gray.at<float>(i,j);
+               }
+
+       for(int i=0;i<h;i++)
+               for(int j=0;j<w;j++)
+                       Gray.at<float>(i,j) = (Gray.at<float>(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 (file)
index 0000000..3edec90
--- /dev/null
@@ -0,0 +1,34 @@
+#include "test_precomp.hpp"
+#include "opencv2/photo.hpp"
+#include <string>
+
+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));
+}
+