Path: blob/master/modules/photo/src/contrast_preserve.hpp
16356 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2013, OpenCV Foundation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of the copyright holders may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/4041#include "precomp.hpp"42#include "opencv2/photo.hpp"43#include <cmath>44#include <vector>4546using namespace std;47using namespace cv;4849class Decolor50{51private:52Mat kernelx;53Mat kernely;54int order;5556public:57float sigma;5859Decolor();60static vector<double> product(const vector <Vec3i> &comb, const double initRGB[3]);61double energyCalcu(const vector <double> &Cg, const vector < vector <double> > &polyGrad, const vector <double> &wei) const;62void singleChannelGradx(const Mat &img, Mat& dest) const;63void singleChannelGrady(const Mat &img, Mat& dest) const;64void gradvector(const Mat &img, vector <double> &grad) const;65void colorGrad(const Mat &img, vector <double> &Cg) const;66static void add_vector(vector <Vec3i> &comb, int &idx, int r,int g,int b);67static void add_to_vector_poly(vector < vector <double> > &polyGrad, const vector <double> &curGrad, int &idx1);68void weak_order(const Mat &img, vector <double> &alf) const;69void grad_system(const Mat &img, vector < vector < double > > &polyGrad,70vector < double > &Cg, vector <Vec3i>& comb) const;71static void wei_update_matrix(const vector < vector <double> > &poly, const vector <double> &Cg, Mat &X);72static void wei_inti(const vector <Vec3i> &comb, vector <double> &wei);73void grayImContruct(vector <double> &wei, const Mat &img, Mat &Gray) const;74};7576double Decolor::energyCalcu(const vector <double> &Cg, const vector < vector <double> > &polyGrad, const vector <double> &wei) const77{78const size_t size = polyGrad[0].size();79vector <double> energy(size);80vector <double> temp(size);81vector <double> temp1(size);8283for(size_t i=0;i< polyGrad[0].size();i++)84{85double val = 0.0;86for(size_t j =0;j<polyGrad.size();j++)87val = val + (polyGrad[j][i] * wei[j]);88temp[i] = val - Cg[i];89temp1[i] = val + Cg[i];90}9192for(size_t i=0;i<polyGrad[0].size();i++)93energy[i] = -1.0*log(exp(-1.0*pow(temp[i],2)/sigma) + exp(-1.0*pow(temp1[i],2)/sigma));9495double sum = 0.0;96for(size_t i=0;i<polyGrad[0].size();i++)97sum +=energy[i];9899return (sum/polyGrad[0].size());100101}102103Decolor::Decolor()104{105kernelx = Mat(1,2, CV_32FC1);106kernely = Mat(2,1, CV_32FC1);107kernelx.at<float>(0,0)=1.0;108kernelx.at<float>(0,1)=-1.0;109kernely.at<float>(0,0)=1.0;110kernely.at<float>(1,0)=-1.0;111order = 2;112sigma = 0.02f;113}114115vector<double> Decolor::product(const vector <Vec3i> &comb, const double initRGB[3])116{117vector <double> res(comb.size());118for (size_t i=0;i<comb.size();i++)119{120double dp = 0.0;121for(int j=0;j<3;j++)122dp = dp + (comb[i][j] * initRGB[j]);123res[i] = dp;124}125return res;126}127128void Decolor::singleChannelGradx(const Mat &img, Mat& dest) const129{130const int w = img.size().width;131const Point anchor(kernelx.cols - kernelx.cols/2 - 1, kernelx.rows - kernelx.rows/2 - 1);132filter2D(img, dest, -1, kernelx, anchor, 0.0, BORDER_CONSTANT);133dest.col(w - 1) = 0.0;134}135136void Decolor::singleChannelGrady(const Mat &img, Mat& dest) const137{138const int h = img.size().height;139const Point anchor(kernely.cols - kernely.cols/2 - 1, kernely.rows - kernely.rows/2 - 1);140filter2D(img, dest, -1, kernely, anchor, 0.0, BORDER_CONSTANT);141dest.row(h - 1) = 0.0;142}143144void Decolor::gradvector(const Mat &img, vector <double> &grad) const145{146Mat dest;147Mat dest1;148singleChannelGradx(img,dest);149singleChannelGrady(img,dest1);150151Mat d_trans=dest.t();152Mat d1_trans=dest1.t();153154const int height = d_trans.size().height;155const int width = d_trans.size().width;156157grad.resize(width * height * 2);158159for(int i=0;i<height;i++)160for(int j=0;j<width;j++)161grad[i*width + j] = d_trans.at<float>(i, j);162163const int offset = width * height;164for(int i=0;i<height;i++)165for(int j=0;j<width;j++)166grad[offset + i * width + j] = d1_trans.at<float>(i, j);167}168169void Decolor::colorGrad(const Mat &img, vector <double> &Cg) const170{171Mat lab;172173cvtColor(img,lab,COLOR_BGR2Lab);174175vector <Mat> lab_channel;176split(lab,lab_channel);177178vector <double> ImL;179vector <double> Ima;180vector <double> Imb;181182gradvector(lab_channel[0],ImL);183gradvector(lab_channel[1],Ima);184gradvector(lab_channel[2],Imb);185186Cg.resize(ImL.size());187for(size_t i=0;i<ImL.size();i++)188{189const double res = sqrt(pow(ImL[i],2) + pow(Ima[i],2) + pow(Imb[i],2))/100;190Cg[i] = res;191}192}193194void Decolor::add_vector(vector <Vec3i> &comb, int &idx, int r,int g,int b)195{196comb.push_back(Vec3i(r, g, b));197idx++;198}199200void Decolor::add_to_vector_poly(vector < vector <double> > &polyGrad, const vector <double> &curGrad, int &idx1)201{202polyGrad.push_back(curGrad);203idx1++;204}205206void Decolor::weak_order(const Mat &im, vector <double> &alf) const207{208Mat img;209const int h = im.size().height;210const int w = im.size().width;211if((h + w) > 800)212{213const double sizefactor = double(800)/(h+w);214resize(im, img, Size(cvRound(w*sizefactor), cvRound(h*sizefactor)));215}216else217{218img = im;219}220221Mat curIm = Mat(img.size(),CV_32FC1);222vector <Mat> rgb_channel;223split(img,rgb_channel);224225vector <double> Rg, Gg, Bg;226gradvector(rgb_channel[2],Rg);227gradvector(rgb_channel[1],Gg);228gradvector(rgb_channel[0],Bg);229230vector <double> t1(Rg.size()), t2(Rg.size()), t3(Rg.size());231vector <double> tmp1(Rg.size()), tmp2(Rg.size()), tmp3(Rg.size());232233const double level = .05;234235for(size_t i=0;i<Rg.size();i++)236{237t1[i] = (Rg[i] > level) ? 1.0 : 0.0;238t2[i] = (Gg[i] > level) ? 1.0 : 0.0;239t3[i] = (Bg[i] > level) ? 1.0 : 0.0;240tmp1[i] = (Rg[i] < -1.0*level) ? 1.0 : 0.0;241tmp2[i] = (Gg[i] < -1.0*level) ? 1.0 : 0.0;242tmp3[i] = (Bg[i] < -1.0*level) ? 1.0 : 0.0;243}244245alf.resize(Rg.size());246for(size_t i =0 ;i < Rg.size();i++)247alf[i] = (t1[i] * t2[i] * t3[i]);248249for(size_t i =0 ;i < Rg.size();i++)250alf[i] -= tmp1[i] * tmp2[i] * tmp3[i];251}252253void Decolor::grad_system(const Mat &im, vector < vector < double > > &polyGrad,254vector < double > &Cg, vector <Vec3i>& comb) const255{256Mat img;257int h = im.size().height;258int w = im.size().width;259if((h + w) > 800)260{261const double sizefactor = double(800)/(h+w);262resize(im, img, Size(cvRound(w*sizefactor), cvRound(h*sizefactor)));263}264else265{266img = im;267}268269h = img.size().height;270w = img.size().width;271colorGrad(img,Cg);272273Mat curIm = Mat(img.size(),CV_32FC1);274vector <Mat> rgb_channel;275split(img,rgb_channel);276277int idx = 0, idx1 = 0;278for(int r=0 ;r <=order; r++)279for(int g=0; g<=order;g++)280for(int b =0; b <=order;b++)281{282if((r+g+b)<=order && (r+g+b) > 0)283{284add_vector(comb,idx,r,g,b);285for(int i = 0;i<h;i++)286for(int j=0;j<w;j++)287curIm.at<float>(i,j)=288pow(rgb_channel[2].at<float>(i,j),r)*pow(rgb_channel[1].at<float>(i,j),g)*289pow(rgb_channel[0].at<float>(i,j),b);290vector <double> curGrad;291gradvector(curIm,curGrad);292add_to_vector_poly(polyGrad,curGrad,idx1);293}294}295}296297void Decolor::wei_update_matrix(const vector < vector <double> > &poly, const vector <double> &Cg, Mat &X)298{299const int size = static_cast<int>(poly.size());300const int size0 = static_cast<int>(poly[0].size());301Mat P = Mat(size, size0, CV_32FC1);302303for (int i = 0; i < size; i++)304for (int j = 0; j < size0;j++)305P.at<float>(i,j) = static_cast<float>(poly[i][j]);306307const Mat P_trans = P.t();308Mat B = Mat(size, size0, CV_32FC1);309for(int i =0;i < size;i++)310{311for(int j = 0, end = int(Cg.size()); j < end;j++)312B.at<float>(i,j) = static_cast<float>(poly[i][j] * Cg[j]);313}314315Mat A = P*P_trans;316solve(A, B, X, DECOMP_NORMAL);317318}319320void Decolor::wei_inti(const vector <Vec3i> &comb, vector <double> &wei)321{322double initRGB[3] = { .33, .33, .33 };323324wei = product(comb,initRGB);325326vector <int> sum(comb.size());327328for(size_t i=0;i<comb.size();i++)329sum[i] = (comb[i][0] + comb[i][1] + comb[i][2]);330331for(size_t i=0;i<sum.size();i++)332{333if(sum[i] == 1)334wei[i] = wei[i] * double(1);335else336wei[i] = wei[i] * double(0);337}338339sum.clear();340341}342343void Decolor::grayImContruct(vector <double> &wei, const Mat &img, Mat &Gray) const344{345const int h = img.size().height;346const int w = img.size().width;347348vector <Mat> rgb_channel;349split(img,rgb_channel);350351int kk =0;352353for(int r =0;r<=order;r++)354for(int g=0;g<=order;g++)355for(int b=0;b<=order;b++)356if((r + g + b) <=order && (r+g+b) > 0)357{358for(int i = 0;i<h;i++)359for(int j=0;j<w;j++)360Gray.at<float>(i,j)=Gray.at<float>(i,j) +361static_cast<float>(wei[kk])*pow(rgb_channel[2].at<float>(i,j),r)*pow(rgb_channel[1].at<float>(i,j),g)*362pow(rgb_channel[0].at<float>(i,j),b);363364kk=kk+1;365}366367double minval, maxval;368minMaxLoc(Gray, &minval, &maxval);369370Gray -= minval;371Gray /= maxval - minval;372}373374375