我正在尝试在OpenCV中重现Photoshop的多重混合模式。与此相同的是您在GIMP中找到的,或者在Apple的CoreImage框架中使用CIMultiplyBlendMode时。
我在网上阅读的所有内容都表明,只需将两个输入图像的通道相乘(即Blend = AxB)即可实现多次混合。并且,这是有效的,除了α是<的情况。 1.0。
您可以在GIMP / PhotoShop / CoreImage中非常简单地测试,方法是创建两个图层/图像,每个图层填充不同的纯色,然后修改第一层的不透明度。 (顺便说一句,当您修改alpha时,由于某种原因,GIMP中的操作不再是可交换的。)
一个简单的例子:如果A =(0,0,0,0)且B =(0.4,0,0,1.0),而C = AxB,那么我希望C为(0,0,0) ,0)。这是简单的乘法。但这并不是这种混合在实践中的实施方式。在实践中,C =(0.4,0,0,1.0),或C = B.
底线是这样的:我需要找出乘法混合模式的公式(显然比AxB更多),然后在OpenCV中实现它(一旦我有公式,这应该是微不足道的。)
非常感谢任何见解。
另外,作为参考,这里有一些链接显示多个混合只是AxB:
答案 0 :(得分:2)
我设法解决了这个问题。如果有任何建议的改进,请随时发表评论。
首先,我发现了如何在这篇文章中实现乘法函数的线索:
这是C ++中一个快速的OpenCV实现。
{{1}}
答案 1 :(得分:2)
这是一个基于GIMP源代码的OpenCV解决方案,特别是函数gimp_operation_multiply_mode_process_pixels
。
注意
opacity
值,必须在[0,255] 代码:
#include <opencv2\opencv.hpp>
using namespace cv;
Mat blend_multiply(const Mat& level1, const Mat& level2, uchar opacity)
{
CV_Assert(level1.size() == level2.size());
CV_Assert(level1.type() == level2.type());
CV_Assert(level1.channels() == level2.channels());
// Get 4 channel float images
Mat4f src1, src2;
if (level1.channels() == 3)
{
Mat4b tmp1, tmp2;
cvtColor(level1, tmp1, COLOR_BGR2BGRA);
cvtColor(level2, tmp2, COLOR_BGR2BGRA);
tmp1.convertTo(src1, CV_32F, 1. / 255.);
tmp2.convertTo(src2, CV_32F, 1. / 255.);
}
else
{
level1.convertTo(src1, CV_32F, 1. / 255.);
level2.convertTo(src2, CV_32F, 1. / 255.);
}
Mat4f dst(src1.rows, src1.cols, Vec4f(0., 0., 0., 0.));
// Loop on every pixel
float fopacity = opacity / 255.f;
float comp_alpha, new_alpha;
for (int r = 0; r < src1.rows; ++r)
{
for (int c = 0; c < src2.cols; ++c)
{
const Vec4f& v1 = src1(r, c);
const Vec4f& v2 = src2(r, c);
Vec4f& out = dst(r, c);
comp_alpha = min(v1[3], v2[3]) * fopacity;
new_alpha = v1[3] + (1.f - v1[3]) * comp_alpha;
if ((comp_alpha > 0.) && (new_alpha > 0.))
{
float ratio = comp_alpha / new_alpha;
out[0] = max(0.f, min(v1[0] * v2[0], 1.f)) * ratio + (v1[0] * (1.f - ratio));
out[1] = max(0.f, min(v1[1] * v2[1], 1.f)) * ratio + (v1[1] * (1.f - ratio));
out[2] = max(0.f, min(v1[2] * v2[2], 1.f)) * ratio + (v1[2] * (1.f - ratio));
}
else
{
out[0] = v1[0];
out[1] = v1[1];
out[2] = v1[2];
}
out[3] = v1[3];
}
}
Mat3b dst3b;
Mat4b dst4b;
dst.convertTo(dst4b, CV_8U, 255.);
cvtColor(dst4b, dst3b, COLOR_BGRA2BGR);
return dst3b;
}
int main()
{
Mat3b layer1 = imread("path_to_image_1");
Mat3b layer2 = imread("path_to_image_2");
Mat blend = blend_multiply(layer1, layer2, 255);
return 0;
}