opencv3.0 photo 模块加入了seamless_cloning类。该类对应的论文是“Poisson Image Editing”
主要可以实现一下功能:
seamless clone:
纹理传输:
去除光噪:
等等。
本文主要以normal_clone为例, 从代码层面解释整个流程:
1. 在normal_clone 中需要准备三张图片,分别是source, mask, destination。 如最上面那张图,source就是熊,孩子那些要黏贴的图片,mask是这些前景的mask。 destination是背景,这里是水池。
2. 计算source和destination的x,y方向上的梯度
3. 计算lapx, lapy即对梯度再取梯度。得到lap
4. 取destination中非mask位置和source中mask位置lap,两者拼接得到最终lap
5. 用这个lap和原始图片,解决possion equation, 得到最终结果。(这部分不是很懂)
用到了Discrete sine transform,
参考:http://www.mathworks.com/help/pde/ug/dst.html
http://www.mathworks.com/help/pde/ug/fast-solution-of-poissons-equation.html
注释代码如下:(做了少量修改,与opencv不完全相同)
- #ifndef SEAMLESSCLONE_H_H
- #define SEAMLESSCLONE_H_H
- //#include "precomp.hpp"
- //#include "opencv2/photo.hpp"
- #include "opencv2/imgproc.hpp"
- #include "opencv2/core/core.hpp"
- #include <iostream>
- #include <stdlib.h>
- #include <complex>
- #include "math.h"
- using namespace std;
- using namespace cv;
- namespace customCV {
- class Cloning
- {
- public:
- //output: 每个通道的合成结果数组
- //rbgx_channel, rgby_channel是gxx, gyy 分通道结果
- vector <Mat> rgb_channel, rgbx_channel, rgby_channel, output;
- //smask是source图片的mask, smask1是smask取反的结果
- //grx, gry 是dst图片的梯度。 grx32, gry32是smask1区域的梯度
- //sgx, sgy 是source图片的梯度。 srx32, sry32是smask区域的梯度
- Mat grx, gry, sgx, sgy, srx32, sry32, grx32, gry32, smask, smask1;
- void init_var(Mat &I, Mat &wmask);
- void initialization(Mat &I, Mat &mask, Mat &wmask);
- void scalar_product(Mat mat, float r, float g, float b);
- void array_product(Mat mat1, Mat mat2, Mat mat3);
- void poisson(Mat &I, Mat &gx, Mat &gy, Mat &sx, Mat &sy);
- void evaluate(Mat &I, Mat &wmask, Mat &cloned);
- void getGradientx(const Mat &img, Mat &gx);
- void getGradienty(const Mat &img, Mat &gy);
- void lapx(const Mat &img, Mat &gxx);
- void lapy(const Mat &img, Mat &gyy);
- void dst(double *mod_diff, double *sineTransform, int h, int w);
- void idst(double *mod_diff, double *sineTransform, int h, int w);
- void transpose(double *mat, double *mat_t, int h, int w);
- void solve(const Mat &img, double *mod_diff, Mat &result);
- void poisson_solver(const Mat &img, Mat &gxx, Mat &gyy, Mat &result);
- void normal_clone(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, int num);
- void local_color_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float red_mul, float green_mul, float blue_mul);
- void illum_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float alpha, float beta);
- void texture_flatten(Mat &I, Mat &mask, Mat &wmask, double low_threshold, double high_threhold, int kernel_size, Mat &cloned);
- };
- void seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point p, OutputArray _blend, int flags);
- void colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float r, float g, float b);
- void illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float a, float b);
- void textureFlattening(InputArray _src, InputArray _mask, OutputArray _dst, double low_threshold, double high_threshold, int kernel_size);
- }
- #endif
- //#include "precomp.hpp"
- //#include "opencv2/photo.hpp"
- #include <stdlib.h>
- #include <opencv2/highgui/highgui.hpp>
- #include "seamless_cloning.hpp"
- using namespace std;
- using namespace cv;
- namespace customCV {
- void Cloning::getGradientx(const Mat &img, Mat &gx)
- {
- Mat kernel = Mat::zeros(1, 3, CV_8S);
- kernel.at<char>(0, 2) = 1;
- kernel.at<char>(0, 1) = -1;
- filter2D(img, gx, CV_32F, kernel);
- }
- void Cloning::getGradienty(const Mat &img, Mat &gy)
- {
- Mat kernel = Mat::zeros(3, 1, CV_8S);
- kernel.at<char>(2, 0) = 1;
- kernel.at<char>(1, 0) = -1;
- filter2D(img, gy, CV_32F, kernel);
- }
- //img是原始图像水平方向上的梯度。本函数是对梯度再求梯度
- void Cloning::lapx(const Mat &img, Mat &gxx)
- {
- Mat kernel = Mat::zeros(1, 3, CV_8S);
- kernel.at<char>(0, 0) = -1;
- kernel.at<char>(0, 1) = 1;
- filter2D(img, gxx, CV_32F, kernel);
- }
- void Cloning::lapy(const Mat &img, Mat &gyy)
- {
- Mat kernel = Mat::zeros(3, 1, CV_8S);
- kernel.at<char>(0, 0) = -1;
- kernel.at<char>(1, 0) = 1;
- filter2D(img, gyy, CV_32F, kernel);
- }
- //离散正弦变换
- //参考:http://www.mathworks.com/help/pde/ug/dst.html
- //参考:http://www.mathworks.com/help/pde/ug/fast-solution-of-poissons-equation.html
- void Cloning::dst(double *mod_diff, double *sineTransform, int h, int w)
- {
- unsigned long int idx;
- Mat temp = Mat(2 * h + 2, 1, CV_32F);
- Mat res = Mat(h, 1, CV_32F);
- Mat planes[] = { Mat_<float>(temp), Mat::zeros(temp.size(), CV_32F) };
- Mat result;
- int p = 0;
- for (int i = 0; i < w; i++)
- {
- temp.at<float>(0, 0) = 0.0;
- for (int j = 0, r = 1; j < h; j++, r++)
- {
- idx = j*w + i;
- temp.at<float>(r, 0) = (float)mod_diff[idx];
- }
- temp.at<float>(h + 1, 0) = 0.0;
- for (int j = h - 1, r = h + 2; j >= 0; j--, r++)
- {
- idx = j*w + i;
- temp.at<float>(r, 0) = (float)(-1.0 * mod_diff[idx]);
- }
- merge(planes, 2, result);
- dft(result, result, 0, 0);
- Mat planes1[] = { Mat::zeros(result.size(), CV_32F), Mat::zeros(result.size(), CV_32F) };
- split(result, planes1);
- std::complex<double> two_i = std::sqrt(std::complex<double>(-1));
- double factor = -2 * imag(two_i);
- for (int c = 1, z = 0; c < h + 1; c++, z++)
- {
- res.at<float>(z, 0) = (float)(planes1[1].at<float>(c, 0) / factor);
- }
- for (int q = 0, z = 0; q < h; q++, z++)
- {
- idx = q*w + p;
- sineTransform[idx] = res.at<float>(z, 0);
- }
- p++;
- }
- }
- void Cloning::idst(double *mod_diff, double *sineTransform, int h, int w)
- {
- int nn = h + 1;
- unsigned long int idx;
- dst(mod_diff, sineTransform, h, w);
- for (int i = 0; i < h; i++)
- for (int j = 0; j < w; j++)
- {
- idx = i*w + j;
- sineTransform[idx] = (double)(2 * sineTransform[idx]) / nn;
- }
- }
- void Cloning::transpose(double *mat, double *mat_t, int h, int w)
- {
- Mat tmp = Mat(h, w, CV_32FC1);
- unsigned long int idx;
- for (int i = 0; i < h; i++)
- {
- for (int j = 0; j < w; j++)
- {
- idx = i*(w)+j;
- tmp.at<float>(i, j) = (float)mat[idx];
- }
- }
- Mat tmp_t = tmp.t();
- for (int i = 0; i < tmp_t.size().height; i++)
- for (int j = 0; j < tmp_t.size().width; j++)
- {
- idx = i*tmp_t.size().width + j;
- mat_t[idx] = tmp_t.at<float>(i, j);
- }
- }
- void Cloning::solve(const Mat &img, double *mod_diff, Mat &result)
- {
- int w = img.size().width;
- int h = img.size().height;
- unsigned long int idx, idx1;
- double *sineTransform = new double[(h - 2)*(w - 2)];
- double *sineTransform_t = new double[(h - 2)*(w - 2)];
- double *denom = new double[(h - 2)*(w - 2)];
- double *invsineTransform = new double[(h - 2)*(w - 2)];
- double *invsineTransform_t = new double[(h - 2)*(w - 2)];
- double *img_d = new double[(h)*(w)];
- //结果存在img_d
- dst(mod_diff, sineTransform, h - 2, w - 2);
- transpose(sineTransform, sineTransform_t, h - 2, w - 2);
- dst(sineTransform_t, sineTransform, w - 2, h - 2);
- transpose(sineTransform, sineTransform_t, w - 2, h - 2);
- int cy = 1;
- for (int i = 0; i < w - 2; i++, cy++)
- {
- for (int j = 0, cx = 1; j < h - 2; j++, cx++)
- {
- idx = j*(w - 2) + i;
- denom[idx] = (float)2 * cos(CV_PI*cy / ((double)(w - 1))) - 2 + 2 * cos(CV_PI*cx / ((double)(h - 1))) - 2;
- }
- }
- for (idx = 0; idx < (unsigned)(w - 2)*(h - 2); idx++)
- {
- sineTransform_t[idx] = sineTransform_t[idx] / denom[idx];
- }
- idst(sineTransform_t, invsineTransform, h - 2, w - 2);
- transpose(invsineTransform, invsineTransform_t, h - 2, w - 2);
- idst(invsineTransform_t, invsineTransform, w - 2, h - 2);
- transpose(invsineTransform, invsineTransform_t, w - 2, h - 2);
- for (int i = 0; i < h; i++)
- {
- for (int j = 0; j < w; j++)
- {
- idx = i*w + j;
- img_d[idx] = (double)img.at<uchar>(i, j);
- }
- }
- for (int i = 1; i < h - 1; i++)
- {
- for (int j = 1; j < w - 1; j++)
- {
- idx = i*w + j;
- img_d[idx] = 0.0;
- }
- }
- for (int i = 1, id1 = 0; i < h - 1; i++, id1++)
- {
- for (int j = 1, id2 = 0; j < w - 1; j++, id2++)
- {
- idx = i*w + j;
- idx1 = id1*(w - 2) + id2;
- img_d[idx] = invsineTransform_t[idx1];
- }
- }
- for (int i = 0; i < h; i++)
- {
- for (int j = 0; j < w; j++)
- {
- idx = i*w + j;
- if (img_d[idx] < 0.0) {
- result.at<uchar>(i, j) = 0;
- }
- else if (img_d[idx] > 255.0)
- result.at<uchar>(i, j) = 255;
- else {
- result.at<uchar>(i, j) = (uchar)img_d[idx];
- }
- }
- }
- delete[] sineTransform;
- delete[] sineTransform_t;
- delete[] denom;
- delete[] invsineTransform;
- delete[] invsineTransform_t;
- delete[] img_d;
- }
- //由img和lap计算合成结果, 注意实际上lap有大量负数
- void Cloning::poisson_solver(const Mat &img, Mat &gxx, Mat &gyy, Mat &result)
- {
- int w = img.size().width;
- int h = img.size().height;
- unsigned long int idx;
- Mat lap = Mat(img.size(), CV_32FC1);
- lap = gxx + gyy;
- Mat bound = img.clone();
- //rectangle 外围保持原样,rect内部变为scalar
- rectangle(bound, Point(1, 1), Point(img.cols - 2, img.rows - 2), Scalar::all(0), -1);
- //rectangle(bound, Point(20, 20), Point(img.cols - 50, img.rows - 50), Scalar::all(0), -1);
- double *boundary_point = new double[h*w];
- Mat bound_map = cv::Mat(img.size(), CV_8UC1, cv::Scalar(0));
- for (int i = 1; i < h - 1; i++)
- for (int j = 1; j < w - 1; j++)
- {
- idx = i*w + j;
- boundary_point[idx] = -4 * (int)bound.at<uchar>(i, j) + (int)bound.at<uchar>(i, (j + 1)) + (int)bound.at<uchar>(i, (j - 1))
- + (int)bound.at<uchar>(i - 1, j) + (int)bound.at<uchar>(i + 1, j);
- bound_map.at<uchar>(i, j) = boundary_point[idx];
- }
- Mat diff = Mat(h, w, CV_32FC1);
- for (int i = 0; i < h; i++)
- {
- for (int j = 0; j < w; j++)
- {
- idx = i*w + j;
- diff.at<float>(i, j) = (float)(lap.at<float>(i, j) - boundary_point[idx]);
- }
- }
- //diff和lap几乎没什么区别
- double *mod_diff = new double[(h - 2)*(w - 2)];
- for (int i = 0; i < h - 2; i++)
- {
- for (int j = 0; j < w - 2; j++)
- {
- idx = i*(w - 2) + j;
- mod_diff[idx] = diff.at<float>(i + 1, j + 1);
- }
- }
- / Find DST /
- solve(img, mod_diff, result);
- delete[] mod_diff;
- delete[] boundary_point;
- }
- void Cloning::init_var(Mat &I, Mat &wmask)
- {
- grx = Mat(I.size(), CV_32FC3);
- gry = Mat(I.size(), CV_32FC3);
- sgx = Mat(I.size(), CV_32FC3);
- sgy = Mat(I.size(), CV_32FC3);
- split(I, rgb_channel);
- smask = Mat(wmask.size(), CV_32FC1);
- srx32 = Mat(I.size(), CV_32FC3);
- sry32 = Mat(I.size(), CV_32FC3);
- smask1 = Mat(wmask.size(), CV_32FC1);
- grx32 = Mat(I.size(), CV_32FC3);
- gry32 = Mat(I.size(), CV_32FC3);
- }
- void Cloning::initialization(Mat &I, Mat &mask, Mat &wmask)
- {
- //初始化各个mat
- init_var(I, wmask);
- //grx, gry 分别表示dest的x,y方向的梯度
- getGradientx(I, grx);
- getGradienty(I, gry);
- //sgx, sgy 分别表示在mask区域内的source图片在x,y方向的梯度
- getGradientx(mask, sgx);
- getGradienty(mask, sgy);
- Mat Kernel(Size(3, 3), CV_8UC1);
- Kernel.setTo(Scalar(1));
- //腐蚀
- erode(wmask, wmask, Kernel, Point(-1, -1), 3);
- wmask.convertTo(smask, CV_32FC1, 1.0 / 255.0);
- I.convertTo(srx32, CV_32FC3, 1.0 / 255.0);
- I.convertTo(sry32, CV_32FC3, 1.0 / 255.0);
- }
- void Cloning::scalar_product(Mat mat, float r, float g, float b)
- {
- vector <Mat> channels;
- split(mat, channels);
- multiply(channels[2], r, channels[2]);
- multiply(channels[1], g, channels[1]);
- multiply(channels[0], b, channels[0]);
- merge(channels, mat);
- }
- //mat1 = mat3.mul(mat2(:)) mat3为单通道,一般为mask
- void Cloning::array_product(Mat mat1, Mat mat2, Mat mat3)
- {
- vector <Mat> channels_temp1;
- vector <Mat> channels_temp2;
- split(mat1, channels_temp1);
- split(mat2, channels_temp2);
- multiply(channels_temp2[2], mat3, channels_temp1[2]);
- multiply(channels_temp2[1], mat3, channels_temp1[1]);
- multiply(channels_temp2[0], mat3, channels_temp1[0]);
- merge(channels_temp1, mat1);
- }
- void Cloning::poisson(Mat &I, Mat &gx, Mat &gy, Mat &sx, Mat &sy)
- {
- //fx, fy是两者组合的梯度
- Mat fx = Mat(I.size(), CV_32FC3);
- Mat fy = Mat(I.size(), CV_32FC3);
- fx = gx + sx;
- fy = gy + sy;
- Mat gxx = Mat(I.size(), CV_32FC3);
- Mat gyy = Mat(I.size(), CV_32FC3);
- //gxx, gyy 是在x,y方向的laplacian算子
- lapx(fx, gxx);
- lapy(fy, gyy);
- split(gxx, rgbx_channel);
- split(gyy, rgby_channel);
- split(I, output);
- poisson_solver(rgb_channel[2], rgbx_channel[2], rgby_channel[2], output[2]);
- poisson_solver(rgb_channel[1], rgbx_channel[1], rgby_channel[1], output[1]);
- poisson_solver(rgb_channel[0], rgbx_channel[0], rgby_channel[0], output[0]);
- }
- void Cloning::evaluate(Mat &I, Mat &wmask, Mat &cloned)
- {
- //mask取反
- bitwise_not(wmask, wmask);
- wmask.convertTo(smask1, CV_32FC1, 1.0 / 255.0);
- I.convertTo(grx32, CV_32FC3, 1.0 / 255.0);
- I.convertTo(gry32, CV_32FC3, 1.0 / 255.0);
- array_product(grx32, grx, smask1);
- array_product(gry32, gry, smask1);
- poisson(I, grx32, gry32, srx32, sry32);
- merge(output, cloned);
- }
- void Cloning::normal_clone(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, int num)
- {
- int w = I.size().width;
- int h = I.size().height;
- int channel = I.channels();
- //初始化各个存储参数的mat,并计算原图于目标图的x,y方向梯度,对mask腐蚀
- initialization(I, mask, wmask);
- if (num == 1) //NORMAL_CLONE
- {
- //srx32, sry32是sgx,sgy的mask区域
- array_product(srx32, sgx, smask);
- array_product(sry32, sgy, smask);
- }
- else if (num == 2) //MIXED_CLONE
- {
- for (int i = 0; i < h; i++)
- {
- for (int j = 0; j < w; j++)
- {
- for (int c = 0; c<channel; ++c)
- {
- if (abs(sgx.at<float>(i, j*channel + c) - sgy.at<float>(i, j*channel + c)) >
- abs(grx.at<float>(i, j*channel + c) - gry.at<float>(i, j*channel + c)))
- {
- srx32.at<float>(i, j*channel + c) = sgx.at<float>(i, j*channel + c)
- * smask.at<float>(i, j);
- sry32.at<float>(i, j*channel + c) = sgy.at<float>(i, j*channel + c)
- * smask.at<float>(i, j);
- }
- else
- {
- srx32.at<float>(i, j*channel + c) = grx.at<float>(i, j*channel + c)
- * smask.at<float>(i, j);
- sry32.at<float>(i, j*channel + c) = gry.at<float>(i, j*channel + c)
- * smask.at<float>(i, j);
- }
- }
- }
- }
- }
- else if (num == 3) //FEATURE_EXCHANGE
- {
- Mat gray = Mat(mask.size(), CV_8UC1);
- Mat gray8 = Mat(mask.size(), CV_8UC3);
- cvtColor(mask, gray, COLOR_BGR2GRAY);
- vector <Mat> temp;
- split(I, temp);
- gray.copyTo(temp[2]);
- gray.copyTo(temp[1]);
- gray.copyTo(temp[0]);
- merge(temp, gray8);
- getGradientx(gray8, sgx);
- getGradienty(gray8, sgy);
- array_product(srx32, sgx, smask);
- array_product(sry32, sgy, smask);
- }
- evaluate(I, wmask, cloned);
- }
- void Cloning::local_color_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float red_mul = 1.0,
- float green_mul = 1.0, float blue_mul = 1.0)
- {
- initialization(I, mask, wmask);
- array_product(srx32, sgx, smask);
- array_product(sry32, sgy, smask);
- scalar_product(srx32, red_mul, green_mul, blue_mul);
- scalar_product(sry32, red_mul, green_mul, blue_mul);
- evaluate(I, wmask, cloned);
- }
- void Cloning::illum_change(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float alpha, float beta)
- {
- initialization(I, mask, wmask);
- array_product(srx32, sgx, smask);
- array_product(sry32, sgy, smask);
- Mat mag = Mat(I.size(), CV_32FC3);
- magnitude(srx32, sry32, mag);
- //opencv3.0 alpha中有bug,需要加入一下代码才不能得到正确结果。已经提交bug
- for (int i = 0; i < mag.cols; i++)
- {
- for (int j = 0; j < mag.rows; j++)
- {
- if (mag.at<cv::Vec3f>(j, i)[0] == 0)
- mag.at<cv::Vec3f>(j, i)[0] = 1e-8;
- if (mag.at<cv::Vec3f>(j, i)[1] == 0)
- mag.at<cv::Vec3f>(j, i)[1] = 1e-8;
- if (mag.at<cv::Vec3f>(j, i)[2] == 0)
- mag.at<cv::Vec3f>(j, i)[2] = 1e-8;
- }
- }
- Mat multX, multY, multx_temp, multy_temp;
- multiply(srx32, pow(alpha, beta), multX);
- pow(mag, -1 * beta, multx_temp);
- multiply(multX, multx_temp, srx32);
- multiply(sry32, pow(alpha, beta), multY);
- pow(mag, -1 * beta, multy_temp);
- multiply(multY, multy_temp, sry32);
- Mat zeroMask = (srx32 != 0);
- srx32.copyTo(srx32, zeroMask);
- sry32.copyTo(sry32, zeroMask);
- evaluate(I, wmask, cloned);
- }
- void Cloning::texture_flatten(Mat &I, Mat &mask, Mat &wmask, double low_threshold,
- double high_threshold, int kernel_size, Mat &cloned)
- {
- initialization(I, mask, wmask);
- Mat out = Mat(mask.size(), CV_8UC1);
- Canny(mask, out, low_threshold, high_threshold, kernel_size);
- Mat zeros(sgx.size(), CV_32FC3);
- zeros.setTo(0);
- Mat zerosMask = (out != 255);
- zeros.copyTo(sgx, zerosMask);
- zeros.copyTo(sgy, zerosMask);
- array_product(srx32, sgx, smask);
- array_product(sry32, sgy, smask);
- evaluate(I, wmask, cloned);
- }
- void seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point p, OutputArray _blend, int flags)
- {
- Mat src = _src.getMat();
- Mat dest = _dst.getMat();
- Mat mask = _mask.getMat();
- _blend.create(dest.size(), CV_8UC3);
- Mat blend = _blend.getMat();
- int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN;
- int h = mask.size().height;
- int w = mask.size().width;
- Mat gray = Mat(mask.size(), CV_8UC1);
- Mat dst_mask = Mat::zeros(dest.size(), CV_8UC1);
- Mat cs_mask = Mat::zeros(src.size(), CV_8UC3);
- Mat cd_mask = Mat::zeros(dest.size(), CV_8UC3);
- if (mask.channels() == 3)
- cvtColor(mask, gray, COLOR_BGR2GRAY);
- else
- gray = mask;
- for (int i = 0; i < h; i++)
- {
- for (int j = 0; j < w; j++)
- {
- if (gray.at<uchar>(i, j) == 255)
- {
- minx = std::min(minx, i);
- maxx = std::max(maxx, i);
- miny = std::min(miny, j);
- maxy = std::max(maxy, j);
- }
- }
- }
- int lenx = maxx - minx;
- int leny = maxy - miny;
- int minxd = p.y - lenx / 2;
- int maxxd = p.y + lenx / 2;
- int minyd = p.x - leny / 2;
- int maxyd = p.x + leny / 2;
- CV_Assert(minxd >= 0 && minyd >= 0 && maxxd <= dest.rows && maxyd <= dest.cols);
- Rect roi_d(minyd, minxd, leny, lenx);
- Rect roi_s(miny, minx, leny, lenx);
- Mat destinationROI = dst_mask(roi_d);
- Mat sourceROI = cs_mask(roi_s);
- gray(roi_s).copyTo(destinationROI);
- src(roi_s).copyTo(sourceROI, gray(roi_s));
- destinationROI = cd_mask(roi_d);
- cs_mask(roi_s).copyTo(destinationROI);
- Cloning obj;
- obj.normal_clone(dest, cd_mask, dst_mask, blend, flags);
- }
- void colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float r, float g, float b)
- {
- Mat src = _src.getMat();
- Mat mask = _mask.getMat();
- _dst.create(src.size(), src.type());
- Mat blend = _dst.getMat();
- float red = r;
- float green = g;
- float blue = b;
- Mat gray = Mat::zeros(mask.size(), CV_8UC1);
- if (mask.channels() == 3)
- cvtColor(mask, gray, COLOR_BGR2GRAY);
- else
- gray = mask;
- Mat cs_mask = Mat::zeros(src.size(), CV_8UC3);
- src.copyTo(cs_mask, gray);
- Cloning obj;
- obj.local_color_change(src, cs_mask, gray, blend, red, green, blue);
- }
- void illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float a, float b)
- {
- Mat src = _src.getMat();
- Mat mask = _mask.getMat();
- _dst.create(src.size(), src.type());
- Mat blend = _dst.getMat();
- float alpha = a;
- float beta = b;
- Mat gray = Mat::zeros(mask.size(), CV_8UC1);
- if (mask.channels() == 3)
- cvtColor(mask, gray, COLOR_BGR2GRAY);
- else
- gray = mask;
- Mat cs_mask = Mat::zeros(src.size(), CV_8UC3);
- src.copyTo(cs_mask, gray);
- Cloning obj;
- obj.illum_change(src, cs_mask, gray, blend, alpha, beta);
- }
- void textureFlattening(InputArray _src, InputArray _mask, OutputArray _dst,
- double low_threshold, double high_threshold, int kernel_size)
- {
- Mat src = _src.getMat();
- Mat mask = _mask.getMat();
- _dst.create(src.size(), src.type());
- Mat blend = _dst.getMat();
- Mat gray = Mat::zeros(mask.size(), CV_8UC1);
- if (mask.channels() == 3)
- cvtColor(mask, gray, COLOR_BGR2GRAY);
- else
- gray = mask;
- Mat cs_mask = Mat::zeros(src.size(), CV_8UC3);
- src.copyTo(cs_mask, gray);
- Cloning obj;
- obj.texture_flatten(src, cs_mask, gray, low_threshold, high_threshold, kernel_size, blend);
- }
- }