#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
/*
* 两个图像混合, 对应图像进行如下计算:
* mat = mat1 * alpha + mat * beta + gamma
* alpha 和 beta的值域区间[0, 1], 当alpha + beta = 1 时, 是线性混合, gamma 是每个像素要增加的常量
* 如果计算的结果超出元素范围则要做调整, 小于0则为0, 大于最大值则为最大值
*/
class BlendImage
{
public:
struct MatParam
{
int height = 0;
int width = 0;
int type = CV_8UC1;
int min = 0;
int max = 255;
cv::Mat mat = cv::Mat();
string str = "";
};
enum ImageOrder { first = 0, second };
public:
BlendImage(MatParam* param);
cv::Mat blendMatrixs(double alpha = 0.3, int beta = 0.5); // if beta == 1 - alpha, it's linear blending
void showMatrix(ImageOrder order = ImageOrder::first);
bool readImage(const string& path, ImageOrder name = ImageOrder::first);
void showImage(ImageOrder order = ImageOrder::first);
static cv::Mat diffMatrix(const cv::Mat& lhs, const cv::Mat& rhs);
static void showMatrix(const cv::Mat& mat, const string& str) { cout << str << " = " << endl << mat << endl; }
static void OpencvBlendImage(cv::Mat& res, BlendImage& blend, double alpha = 0.3, double beta = 0.5);
public:
const cv::Mat& GetMatrix(ImageOrder order = ImageOrder::first) const { return param[order].mat; }
private:
static cv::Mat random(MatParam& param);
private:
MatParam param[2];
};
BlendImage::BlendImage(MatParam* par)
{
param[0] = par[0], param[1] = par[1];
param[0].mat = random(param[0]);
param[1].mat = random(param[1]);
}
void BlendImage::showMatrix(ImageOrder order)
{
const cv::Mat mat = GetMatrix(order);
showMatrix(mat, param[order].str);
}
cv::Mat BlendImage::blendMatrixs(double alpha, int beta)
{
cv::Mat res(param[0].mat.rows, param[0].mat.cols, param[0].type);
if (res.empty())
{
cout << "Create matrix failed" << endl;
return cv::Mat();
}
for (int row = 0; row < res.rows; ++row)
{
cv::Vec3b* ptr1 = param[0].mat.ptr<cv::Vec3b>(row);
cv::Vec3b* ptr2 = param[1].mat.ptr<cv::Vec3b>(row);
cv::Vec3b* ptr = res.ptr<cv::Vec3b>(row);
for (int col = 0; col < res.cols; ++col)
{
double b = (double)ptr1[col][0] * alpha + (double)ptr2[col][0] * beta;
double g = (double)ptr1[col][1] * alpha + (double)ptr2[col][1] * beta;
double r = (double)ptr1[col][2] * alpha + (double)ptr2[col][2] * beta;
ptr[col][0] = cv::saturate_cast<uchar>(b);
ptr[col][1] = cv::saturate_cast<uchar>(g);
ptr[col][2] = cv::saturate_cast<uchar>(r);
}
}
return res;
}
void BlendImage::OpencvBlendImage(cv::Mat& res, BlendImage& blend, double alpha, double beta)
{
cv::addWeighted(blend.GetMatrix(BlendImage::first), alpha, blend.GetMatrix(BlendImage::second), beta, 0, res);
}
cv::Mat BlendImage::diffMatrix(const cv::Mat& lhs, const cv::Mat& rhs)
{
cv::Mat diff = lhs - rhs;
if (diff.empty())
return cv::Mat();
return diff;
}
cv::Mat BlendImage::random(MatParam& param)
{
assert(param.min >= 0 && param.min <= 255);
assert(param.max >= 0 && param.max <= 255);
cv::Mat mat(param.height, param.width, param.type);
if (mat.empty())
return cv::Mat();
cv::randu(mat, cv::Scalar::all(param.min), cv::Scalar::all(param.max));
return mat;
}
bool BlendImage::readImage(const string& path, ImageOrder order)
{
if(!param[order].mat.empty())
param[order].mat.release();
param[order].mat = cv::imread(path, cv::IMREAD_COLOR);
param[order].height = param[order].mat.rows;
param[order].width = param[order].mat.cols;
param[order].type = param[order].mat.type();
param[order].str = path;
if (param[order].mat.empty())
return false;
return true;
}
void BlendImage::showImage(ImageOrder order)
{
cv::imshow(param[order].str, param[order].mat);
}
int main()
{
BlendImage::MatParam par[2];
par[0] = { 8, 8, CV_8UC3, 0, 255, cv::Mat(), "matrix1" };
par[1] = { 8, 8, CV_8UC3, 0, 255, cv::Mat(), "matrix2" };
BlendImage blend(par);
blend.showMatrix(BlendImage::first);
blend.showMatrix(BlendImage::second);
cv::Mat res1;
double alpha = 0.3, beta = 0.5;
BlendImage::OpencvBlendImage(res1, blend, alpha, beta);
BlendImage::showMatrix(res1, "result1");
cv::Mat res2 = blend.blendMatrixs();
BlendImage::showMatrix(res2, "result2");
cv::Mat diff = BlendImage::diffMatrix(res1, res2);
BlendImage::showMatrix(diff, "difference");
return 0;
}