1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2013, OpenCV Foundation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 22 // * Redistribution's in binary form must reproduce the above copyright notice, 23 // this list of conditions and the following disclaimer in the documentation 24 // and/or other materials provided with the distribution. 25 // 26 // * The name of the copyright holders may not be used to endorse or promote products 27 // derived from this software without specific prior written permission. 28 // 29 // This software is provided by the copyright holders and contributors "as is" and 30 // any express or implied warranties, including, but not limited to, the implied 31 // warranties of merchantability and fitness for a particular purpose are disclaimed. 32 // In no event shall the Intel Corporation or contributors be liable for any direct, 33 // indirect, incidental, special, exemplary, or consequential damages 34 // (including, but not limited to, procurement of substitute goods or services; 35 // loss of use, data, or profits; or business interruption) however caused 36 // and on any theory of liability, whether in contract, strict liability, 37 // or tort (including negligence or otherwise) arising in any way out of 38 // the use of this software, even if advised of the possibility of such damage. 39 // 40 //M*/ 41 42 #include "precomp.hpp" 43 #include "opencv2/photo.hpp" 44 #include "math.h" 45 #include <vector> 46 #include <limits> 47 48 using namespace std; 49 using namespace cv; 50 51 class Decolor 52 { 53 private: 54 Mat kernelx; 55 Mat kernely; 56 int order; 57 58 public: 59 float sigma; 60 void init(); 61 vector<double> product(vector < vector<int> > &comb, vector <double> &initRGB); 62 double energyCalcu(vector <double> &Cg, vector < vector <double> > &polyGrad, vector <double> &wei); 63 void singleChannelGradx(const Mat &img, Mat& dest); 64 void singleChannelGrady(const Mat &img, Mat& dest); 65 void gradvector(const Mat &img, vector <double> &grad); 66 void colorGrad(Mat img, vector <double> &Cg); 67 void add_vector(vector < vector <int> > &comb, int &idx, int r,int g,int b); 68 void add_to_vector_poly(vector < vector <double> > &polyGrad, vector <double> &curGrad, int &idx1); 69 void weak_order(Mat img, vector <double> &alf); 70 void grad_system(Mat img, vector < vector < double > > &polyGrad, 71 vector < double > &Cg, vector < vector <int> >& comb); 72 void wei_update_matrix(vector < vector <double> > &poly, vector <double> &Cg, Mat &X); 73 void wei_inti(vector < vector <int> > &comb, vector <double> &wei); 74 void grayImContruct(vector <double> &wei, Mat img, Mat &Gray); 75 }; 76 77 int round_num(double a); 78 79 int round_num(double a) 80 { 81 return int(a + 0.5); 82 } 83 84 double Decolor::energyCalcu(vector <double> &Cg, vector < vector <double> > &polyGrad, vector <double> &wei) 85 { 86 vector <double> energy; 87 vector <double> temp; 88 vector <double> temp1; 89 90 double val = 0.0; 91 for(unsigned int i=0;i< polyGrad[0].size();i++) 92 { 93 val = 0.0; 94 for(unsigned int j =0;j<polyGrad.size();j++) 95 val = val + (polyGrad[j][i] * wei[j]); 96 temp.push_back(val - Cg[i]); 97 temp1.push_back(val + Cg[i]); 98 } 99 100 for(unsigned int i=0;i<polyGrad[0].size();i++) 101 energy.push_back(-1.0*log(exp(-1.0*pow(temp[i],2)/sigma) + exp(-1.0*pow(temp1[i],2)/sigma))); 102 103 double sum = 0.0; 104 for(unsigned int i=0;i<polyGrad[0].size();i++) 105 sum +=energy[i]; 106 107 return (sum/polyGrad[0].size()); 108 109 } 110 111 void Decolor::init() 112 { 113 kernelx = Mat(1,2, CV_32FC1); 114 kernely = Mat(2,1, CV_32FC1); 115 kernelx.at<float>(0,0)=1.0; 116 kernelx.at<float>(0,1)=-1.0; 117 kernely.at<float>(0,0)=1.0; 118 kernely.at<float>(1,0)=-1.0; 119 order = 2; 120 sigma = 0.02f; 121 } 122 123 vector<double> Decolor::product(vector < vector<int> > &comb, vector <double> &initRGB) 124 { 125 vector <double> res; 126 double dp; 127 for (unsigned int i=0;i<comb.size();i++) 128 { 129 dp = 0.0; 130 for(int j=0;j<3;j++) 131 dp = dp + (comb[i][j] * initRGB[j]); 132 res.push_back(dp); 133 } 134 return res; 135 } 136 137 void Decolor::singleChannelGradx(const Mat &img, Mat& dest) 138 { 139 int w=img.size().width; 140 int h=img.size().height; 141 Point anchor(kernelx.cols - kernelx.cols/2 - 1, kernelx.rows - kernelx.rows/2 - 1); 142 filter2D(img, dest, -1, kernelx, anchor, 0.0, BORDER_CONSTANT); 143 for(int i=0;i<h;i++) 144 dest.at<float>(i,w-1)=0.0; 145 } 146 147 void Decolor::singleChannelGrady(const Mat &img, Mat& dest) 148 { 149 int w=img.size().width; 150 int h=img.size().height; 151 Point anchor(kernely.cols - kernely.cols/2 - 1, kernely.rows - kernely.rows/2 - 1); 152 filter2D(img, dest, -1, kernely, anchor, 0.0, BORDER_CONSTANT); 153 for(int j=0;j<w;j++) 154 dest.at<float>(h-1,j)=0.0; 155 } 156 157 void Decolor::gradvector(const Mat &img, vector <double> &grad) 158 { 159 Mat dest= Mat(img.size().height,img.size().width, CV_32FC1); 160 Mat dest1= Mat(img.size().height,img.size().width, CV_32FC1); 161 singleChannelGradx(img,dest); 162 singleChannelGrady(img,dest1); 163 164 Mat d_trans=dest.t(); 165 Mat d1_trans=dest1.t(); 166 167 int height = d_trans.size().height; 168 int width = d_trans.size().width; 169 170 for(int i=0;i<height;i++) 171 for(int j=0;j<width;j++) 172 grad.push_back(d_trans.at<float>(i,j)); 173 174 for(int i=0;i<height;i++) 175 for(int j=0;j<width;j++) 176 grad.push_back(d1_trans.at<float>(i,j)); 177 dest.release(); 178 dest1.release(); 179 } 180 181 void Decolor::colorGrad(Mat img, vector <double> &Cg) 182 { 183 184 Mat lab = Mat(img.size(),CV_32FC3); 185 186 cvtColor(img,lab,COLOR_BGR2Lab); 187 188 vector <Mat> lab_channel; 189 split(lab,lab_channel); 190 191 vector <double> ImL; 192 vector <double> Ima; 193 vector <double> Imb; 194 195 gradvector(lab_channel[0],ImL); 196 gradvector(lab_channel[1],Ima); 197 gradvector(lab_channel[2],Imb); 198 199 double res =0.0; 200 for(unsigned int i=0;i<ImL.size();i++) 201 { 202 res=sqrt(pow(ImL[i],2) + pow(Ima[i],2) + pow(Imb[i],2))/100; 203 Cg.push_back(res); 204 } 205 206 ImL.clear(); 207 Ima.clear(); 208 Imb.clear(); 209 } 210 211 void Decolor::add_vector(vector < vector <int> > &comb, int &idx, int r,int g,int b) 212 { 213 comb.push_back( vector <int>() ); 214 comb.at(idx).push_back( r ); 215 comb.at(idx).push_back( g ); 216 comb.at(idx).push_back( b ); 217 idx++; 218 } 219 220 void Decolor::add_to_vector_poly(vector < vector <double> > &polyGrad, vector <double> &curGrad, int &idx1) 221 { 222 polyGrad.push_back( vector <double>() ); 223 for(unsigned int i=0;i<curGrad.size();i++) 224 polyGrad.at(idx1).push_back(curGrad[i]); 225 idx1++; 226 } 227 228 void Decolor::weak_order(Mat img, vector <double> &alf) 229 { 230 int h = img.size().height; 231 int w = img.size().width; 232 double sizefactor; 233 if((h + w) > 800) 234 { 235 sizefactor = (double)800/(h+w); 236 resize(img,img,Size(round_num(h*sizefactor),round_num(w*sizefactor))); 237 } 238 239 Mat curIm = Mat(img.size(),CV_32FC1); 240 vector <Mat> rgb_channel; 241 split(img,rgb_channel); 242 243 vector <double> Rg, Gg, Bg; 244 vector <double> t1, t2, t3; 245 vector <double> tmp1, tmp2, tmp3; 246 247 gradvector(rgb_channel[2],Rg); 248 gradvector(rgb_channel[1],Gg); 249 gradvector(rgb_channel[0],Bg); 250 251 double level = .05; 252 253 for(unsigned int i=0;i<Rg.size();i++) 254 { 255 if(Rg[i] > level) 256 t1.push_back(1.0); 257 else 258 t1.push_back(0.0); 259 260 if(Gg[i] > level) 261 t2.push_back(1.0); 262 else 263 t2.push_back(0.0); 264 265 if(Bg[i] > level) 266 t3.push_back(1.0); 267 else 268 t3.push_back(0.0); 269 270 if(Rg[i] < -1.0*level) 271 tmp1.push_back(1.0); 272 else 273 tmp1.push_back(0.0); 274 275 if(Gg[i] < -1.0*level) 276 tmp2.push_back(1.0); 277 else 278 tmp2.push_back(0.0); 279 280 if(Bg[i] < -1.0*level) 281 tmp3.push_back(1.0); 282 else 283 tmp3.push_back(0.0); 284 } 285 for(unsigned int i =0 ;i < Rg.size();i++) 286 alf.push_back(t1[i] * t2[i] * t3[i]); 287 288 for(unsigned int i =0 ;i < Rg.size();i++) 289 alf[i] -= tmp1[i] * tmp2[i] * tmp3[i]; 290 291 double sum =0.0; 292 for(unsigned int i=0;i<alf.size();i++) 293 sum += abs(alf[i]); 294 295 sum = (double)100*sum/alf.size(); 296 297 Rg.clear(); Gg.clear(); Bg.clear(); 298 t1.clear(); t2.clear(); t3.clear(); 299 tmp1.clear(); tmp2.clear(); tmp3.clear(); 300 } 301 302 void Decolor::grad_system(Mat img, vector < vector < double > > &polyGrad, 303 vector < double > &Cg, vector < vector <int> >& comb) 304 { 305 int h = img.size().height; 306 int w = img.size().width; 307 308 double sizefactor; 309 if((h + w) > 800) 310 { 311 sizefactor = (double)800/(h+w); 312 resize(img,img,Size(round_num(h*sizefactor),round_num(w*sizefactor))); 313 } 314 315 h = img.size().height; 316 w = img.size().width; 317 colorGrad(img,Cg); 318 319 Mat curIm = Mat(img.size(),CV_32FC1); 320 vector <Mat> rgb_channel; 321 split(img,rgb_channel); 322 323 int idx = 0, idx1 = 0; 324 for(int r=0 ;r <=order; r++) 325 for(int g=0; g<=order;g++) 326 for(int b =0; b <=order;b++) 327 { 328 if((r+g+b)<=order && (r+g+b) > 0) 329 { 330 add_vector(comb,idx,r,g,b); 331 for(int i = 0;i<h;i++) 332 for(int j=0;j<w;j++) 333 curIm.at<float>(i,j)= 334 pow(rgb_channel[2].at<float>(i,j),r)*pow(rgb_channel[1].at<float>(i,j),g)* 335 pow(rgb_channel[0].at<float>(i,j),b); 336 vector <double> curGrad; 337 gradvector(curIm,curGrad); 338 add_to_vector_poly(polyGrad,curGrad,idx1); 339 } 340 } 341 } 342 343 void Decolor::wei_update_matrix(vector < vector <double> > &poly, vector <double> &Cg, Mat &X) 344 { 345 int size = static_cast<int>(poly.size()), size0 = static_cast<int>(poly[0].size()); 346 Mat P = Mat(size, size0, CV_32FC1); 347 Mat A = Mat(size, size, CV_32FC1); 348 349 for (int i = 0; i < size; i++) 350 for (int j = 0; j < size0;j++) 351 P.at<float>(i,j) = (float) poly[i][j]; 352 353 Mat P_trans = P.t(); 354 Mat B = Mat(size, size0, CV_32FC1); 355 for(int i =0;i < size;i++) 356 { 357 for(int j = 0, end = (int)Cg.size(); j < end;j++) 358 B.at<float>(i,j) = (float) (poly[i][j] * Cg[j]); 359 } 360 361 A = P*P_trans; 362 solve(A, B, X, DECOMP_NORMAL); 363 364 } 365 366 void Decolor::wei_inti(vector < vector <int> > &comb, vector <double> &wei) 367 { 368 vector <double> initRGB; 369 370 initRGB.push_back( .33 ); 371 initRGB.push_back( .33 ); 372 initRGB.push_back( .33 ); 373 wei = product(comb,initRGB); 374 375 vector <int> sum; 376 377 for(unsigned int i=0;i<comb.size();i++) 378 sum.push_back(comb[i][0] + comb[i][1] + comb[i][2]); 379 380 for(unsigned int i=0;i<sum.size();i++) 381 { 382 if(sum[i] == 1) 383 wei[i] = wei[i] * double(1); 384 else 385 wei[i] = wei[i] * double(0); 386 } 387 388 initRGB.clear(); 389 sum.clear(); 390 391 } 392 393 void Decolor::grayImContruct(vector <double> &wei, Mat img, Mat &Gray) 394 { 395 int h=img.size().height; 396 int w=img.size().width; 397 398 vector <Mat> rgb_channel; 399 split(img,rgb_channel); 400 401 int kk =0; 402 403 for(int r =0;r<=order;r++) 404 for(int g=0;g<=order;g++) 405 for(int b=0;b<=order;b++) 406 if((r + g + b) <=order && (r+g+b) > 0) 407 { 408 for(int i = 0;i<h;i++) 409 for(int j=0;j<w;j++) 410 Gray.at<float>(i,j)=Gray.at<float>(i,j) + 411 (float) wei[kk]*pow(rgb_channel[2].at<float>(i,j),r)*pow(rgb_channel[1].at<float>(i,j),g)* 412 pow(rgb_channel[0].at<float>(i,j),b); 413 414 kk=kk+1; 415 } 416 417 float minval = FLT_MAX; 418 float maxval = -FLT_MAX; 419 420 for(int i=0;i<h;i++) 421 for(int j =0;j<w;j++) 422 { 423 if(Gray.at<float>(i,j) < minval) 424 minval = Gray.at<float>(i,j); 425 426 if(Gray.at<float>(i,j) > maxval) 427 maxval = Gray.at<float>(i,j); 428 } 429 430 Gray -= minval; 431 Gray /= maxval - minval; 432 } 433