OpenCV java alpha Blending



我正在尝试移植以下代码(从C++移植到 Java(以在我的图像之间进行良好的 alpha 混合,但它不起作用:

#include opencv2/opencv.hpp
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// Read the images
Mat foreground = imread("puppets.png");
Mat background = imread("ocean.png");
Mat alpha = imread("puppets_alpha.png");
// Convert Mat to float data type
foreground.convertTo(foreground, CV_32FC3);
background.convertTo(background, CV_32FC3);
// Normalize the alpha mask to keep intensity between 0 and 1
alpha.convertTo(alpha, CV_32FC3, 1.0/255); // 
// Storage for output image
Mat ouImage = Mat::zeros(foreground.size(), foreground.type());
// Multiply the foreground with the alpha matte
multiply(alpha, foreground, foreground); 
// Multiply the background with ( 1 - alpha )
multiply(Scalar::all(1.0)-alpha, background, background); 
// Add the masked foreground and background.
add(foreground, background, ouImage); 
// Display image
imshow("alpha blended image", ouImage/255);
waitKey(0);
return 0;
}

代码可以在这里找到:https://www.learnopencv.com/alpha-blending-using-opencv-cpp-python/还有我的Java版本:

public static Mat alphaBlend(Mat background, Mat foreground) {
Vector<Mat> rgba = new Vector<Mat>();
// split RBGA image for separate channels
Core.split(background, rgba);
// get alpha channel
Mat alpha = rgba.get(3);
// Convert Mat to float data type
foreground.convertTo(foreground, CvType.CV_32FC3);
background.convertTo(background, CvType.CV_32FC3);
// Normalize the alpha mask to keep intensity between 0 and 1
alpha.convertTo(alpha, CvType.CV_32FC3, 1.0/255); //
Imgproc.cvtColor(alpha,alpha, Imgproc.COLOR_GRAY2BGRA,4);
Mat outImage = Mat.zeros(foreground.size(),foreground.type());
// Multiply the foreground with the alpha matte
Core.multiply(alpha, foreground, foreground);
Mat kernel = new MatOfDouble(1.0);
Core.subtract(kernel, alpha, alpha);
// Multiply the background with ( 1 - alpha )
Core.multiply(alpha, background, background);
// Add the masked foreground and background.
Core.add(foreground, background, outImage);
Core.divide(new MatOfDouble(255), outImage,outImage);
return outImage;
}

我认为我的问题是在 java 中移植它:

multiply(Scalar::all(1.0)-alpha, background, background); 

任何帮助将不胜感激!

谢谢

编辑: 这里有一个工作版本,但边框不混合透明像素,导致图像交叉点边界处出现空白像素/线:

private static Mat merge(Mat background, Mat foreground) {
Vector<Mat> rgba = new Vector<Mat>();
// split RBGA image for separate channels
Core.split(background, rgba);
// get alpha channel
Mat alpha = rgba.get(3);
// Convert Mat to float data type
// Normalize the alpha mask to keep intensity between 0 and 1
alpha.convertTo(alpha, CvType.CV_32FC3, 1.0/255); //
Mat dst = new Mat(256,256,CvType.CV_8UC4);
alpha.convertTo(alpha,CvType.CV_8UC1);
Mat alphaInv = new Mat();
// invert the mask
Core.absdiff(new MatOfDouble(1.0), alpha, alphaInv);
foreground.copyTo(dst, alphaInv);
// case where foreground is full JPEG in BGR
if(dst.type() != CvType.CV_8UC4) {
Imgproc.cvtColor(dst, dst, Imgproc.COLOR_BGR2BGRA, 4);
}
background.copyTo(dst, alpha);
return dst;
}

我建议使用Core的addWeighted方法进行基本的alpha混合。

看起来您想要基于掩码的可变 alpha 混合,您需要按照 api 指定的顺序排列参数,以进行加法/减法/乘法等基本操作。 对于您的乘法,这意味着标量应该是第二个参数。 对于您的减法,这意味着标量应该再次是第二个参数(我发现自己将矩阵乘以负 1,然后添加到标量值(。

根据您共享的链接,看起来目标只是使用图像遮罩,我认为有一种更简单的方法,使用 copyTo 功能。 尝试将其放在您的主文件中,当它工作时,请移动到您的函数:

// Read the images
Mat foreground = Imgcodecs.imread("puppets.png");
Mat background = Imgcodecs.imread("ocean.png");
Mat mask = Imgcodecs.imread("puppets_alpha.png");
Mat notMask = new Mat();
Core.bitwise_not(mask, notMask);
Mat result = new Mat();
Core.copyTo(background, result, mask);
Core.copyTo(foreground, result, notMask);
Imgcodecs.imwrite("result.png", result);
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.UnityUtils;
using UnityEngine;
public class bitwiseNew : MonoBehaviour
{
Texture2D textureFace, textureMask, textureBG;
void Start()
{
Utils.setDebugMode(true);
textureFace = Resources.Load("Lena") as Texture2D;
textureMask = Resources.Load("circle") as Texture2D;
textureBG = Resources.Load("face") as Texture2D;
Mat matFace = new Mat(textureFace.height, textureFace.width, CvType.CV_8UC4);
Mat matMask = new Mat(textureMask.height, textureMask.width, CvType.CV_8UC4);
Mat matBG = new Mat(textureBG.height, textureBG.width, CvType.CV_8UC4);
Utils.texture2DToMat(textureFace, matFace);
Utils.texture2DToMat(textureMask, matMask);
Utils.texture2DToMat(textureBG, matBG);
Mat mask = new Mat(matFace.cols(), matFace.rows(), matFace.type());
Mat maskDst1 = new Mat(matFace.cols(), matFace.rows(), matFace.type());
Mat maskDst2 = new Mat(matFace.cols(), matFace.rows(), matFace.type());
Mat dst = new Mat(matFace.cols(), matFace.rows(), matFace.type());
Core.bitwise_not(matMask, mask);
Core.bitwise_not(matFace, matFace);
Core.bitwise_and(matBG, mask, maskDst1);
Core.bitwise_or(mask, matFace, maskDst2);
Core.bitwise_not(maskDst2, maskDst2);
Core.addWeighted(maskDst1, 1f, maskDst2, 1f, 0f, dst);
Debug.Log("dst: " + dst.channels());
Texture2D texture = new Texture2D(dst.cols(), dst.rows(), TextureFormat.RGBA32, false);
Utils.matToTexture2D(dst, texture);
gameObject.GetComponent<Renderer>().material.mainTexture = texture;
Utils.setDebugMode(false);
}
}

最新更新