gpt4 book ai didi

java - 如何展平2个不同的图像层?

转载 作者:行者123 更新时间:2023-12-01 09:57:04 25 4
gpt4 key购买 nike

我有 2 个 Mat 对象,覆盖背景

如何将我的 overlay Mat 放在我的 background Mat 之上,以便只有 overlay Mat 的非透明像素完全显示遮挡背景垫?

我尝试过 addWeighted() ,它结合了 2 个 Mat,但两个“层”仍然可见。

  • 覆盖 Mat 具有透明 channel ,而背景 Mat 则没有。
  • overlay Mat 中的像素要么完全透明,要么完全模糊。
  • 两个垫子尺寸相同。

最佳答案

函数 addWeighted 将不起作用,因为它会对所有像素使用相同的 alpha 值。为了准确地执行您所说的操作,仅替换后台中的非透明值,您可以为此创建一个小函数,如下所示:

cv::Mat blending(cv::Mat& overlay, cv::Mat& background){
//must have same size for this to work
assert(overlay.cols == background.cols && overlay.rows == background.rows);
cv::Mat result = background.clone();
for (int i = 0; i < result.rows; i++){
for (int j = 0; j < result.cols; j++){
cv::Vec4b pix = overlay.at<cv::Vec4b>(i,j);
if (pix[3] == 0){
result.at<cv::Vec3b>(i,j) = cv::Vec3b(pix[0], pix[1], pix[2]);
}
}
}
return result;
}

我不确定opencv中的透明值是0还是255,所以相应地改变它......我认为0表示不透明,255表示完全透明。

如果您想使用 Alpha channel 的值作为混合速率,请将其稍微更改为:

cv::Mat blending(cv::Mat& overlay, cv::Mat& background){
//must have same size for this to work
assert(overlay.cols == background.cols && overlay.rows == background.rows);
cv::Mat result = background.clone();
for (int i = 0; i < result.rows; i++){
for (int j = 0; j < result.cols; j++){
cv::Vec4b pix = overlay.at<cv::Vec4b>(i,j);
double alphaRate = 1.0 - pix[3]/255.0;
result.at<cv::Vec3b>(i,j) = (1.0 - alphaRate) * cv::Vec3b(pix[0], pix[1], pix[2]) + result.at<cv::Vec3b>(i,j) * alphaRate;
}
}
return result;
}

抱歉,代码是用 C++ 编写的,而不是用 JAVA 编写的,但我认为您可以了解一下。基本上只是像素中的一个循环,如果背景副本中的像素不透明,则将其更改为覆盖层的像素。

* 编辑*

我将通过此编辑来回答您的评论,因为它可能会占用空间。问题是 OpenCV 矩阵如何工作。对于带有 alpha 的图像,数据被组织为一个数组,如 BGRA BGRA .... BGRA,并且像加法、乘法等基本操作在具有相同维度的矩阵中工作...... ..您始终可以尝试使用 split 来分离矩阵(这将重新写入矩阵,因此可能会很慢),然后将 alpha channel 更改为双倍(再次重写),然后进行矩阵的乘法和加法。它应该更快,因为 OpenCV 优化了这些函数....您也可以在 GPU 中执行此操作...

类似这样的事情:

cv::Mat blending(cv::Mat& overlay, cv::Mat& background){
std::vector<cv::Mat> channels;
cv::split(overlay, channels);
channels[3].convertTo(channels[3], CV_64F, 1.0/255.0);
cv::Mat newOverlay, result;
cv::merge(channels, newOverlay);
result = newOverlay * channels[3] + ((1 - channels[3]) * background);
return result;
}

不确定 OpenCV 是否允许 CV_8U 乘以 CV_64F,或者这是否会更快......但可能会。

此外,带有循环的线程在线程中没有问题,因此可以对其进行优化...在 Release模式下运行它也会大大提高速度,因为 OpenCV 的 .at 函数做了几个断言....在 Release模式下尚未完成。不确定这是否可以在 JAVA 中更改...

关于java - 如何展平2个不同的图像层?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37116687/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com