8

我正在使用 Emgu.CV 执行一些基本的图像处理和合成。我的图像加载为Image<Bgra,Byte>.

问题 #1:当我使用该Image<,>.Add()方法时,无论 alpha 值如何,图像总是混合在一起。相反,我希望它们一个接一个地合成,并使用包含的 alpha 通道来确定应该如何混合图像。因此,如果我调用image1.Add(image2)image2 中的任何完全不透明像素将完全覆盖 image1 中的像素,而半透明像素将基于 alpha 值进行混合。

这就是我试图以视觉形式做的事情。有一个城市形象,剪掉了一些“透明的洞”,后面是一只青蛙。这应该是这样的:

在此处输入图像描述

这就是 openCV 产生的。

这就是我打电话时 OpenCV (Emgu.CV) 产生的结果

如何使用 OpenCV 获得这种效果?它会像打电话一样快Add()吗?

问题 #2:有没有办法就地执行此合成,而不是在每次调用时创建一个新图像Add()?(例如image1.AddImageInPlace(image2)修改 image1? 的字节)

注意:在 Emgu.CV 中寻找答案,我使用它是因为它处理透视变形的能力。

4

4 回答 4

6

在 OpenCV 2.4 之前,不支持带有 alpha 通道的 PNG。

要验证您当前的版本是否支持它,请在加载您确定为 RGBA 的图像后打印通道数。如果支持,应用程序将输出数字 4,否则将输出数字 3 (RGB)。使用 C API,您可以:

IplImage* t_img = cvLoadImage(argv[1], CV_LOAD_IMAGE_UNCHANGED);
if (!t_img)
{
    printf("!!! Unable to load transparent image.\n");
    return -1;
}
printf("Channels: %d\n", t_img->nChannels);

如果您无法更新 OpenCV

  • 一些帖子试图绕过这个限制,但我自己没有测试过;
  • 最简单的解决方案是使用另一个 API 来加载图像并混合它,检查blImageBlending
  • 另一种不是轻量级的替代方法是使用 Qt

如果您的版本已经支持带有 RGBA 的 PNG

编辑:

我最近不得不处理这个问题,并且我已经在这个答案上演示了如何处理它。

于 2012-08-22T18:58:10.930 回答
2

您必须遍历每个像素。我假设图像 1 是青蛙图像,图像 2 是城市图像,图像 1 总是大于图像 2。

//to simulate image1.AddInPlace(image2)
 int image2w = image2.Width;
 int image2h = image2.Height;
 int i,j;
 var alpha;
 for (i = 0; i < w; i++)
 {
     for (j = 0; j < h; j++)
     {
           //alpha=255 is opaque > image2 should be used
           alpha = image2[3][j,i].Intensity;
           image1[j, i] 
               = new Bgra(
               image2[j, i].Blue * alpha + (image1[j, i].Blue * (255-alpha)),
               image2[j, i].Green * alpha + (image1[j, i].Green * (255-alpha)),
               image2[j, i].Red * alpha + (image1[j, i].Red * (255-alpha)));
      }
 }
于 2012-08-21T07:00:04.777 回答
0

我在互联网上发现了一篇有趣的博客文章,我认为这与您正在尝试做的事情有关。

请查看创建叠加层方法archive.org 链接)。您可以使用这个想法来实现自己的功能,以上述方式添加两个图像,使图像中的某些特定区域透明,而其余部分保持不变。

于 2012-08-18T17:19:50.847 回答
0

以 Osiris 的建议为起点,并在 Wikipedia 上查看了 alpha compositing,我最终得到了以下内容,这对我的目的非常有效。

这与 Emgucv 一起使用。我希望在 Emgucv 中可以使用 opencv gpu::AlphaComposite 方法,我相信它会为我完成以下工作,但可惜我使用的版本似乎没有实现它们。

static public Image<Bgra, Byte> Overlay( Image<Bgra, Byte> image1, Image<Bgra, Byte> image2 )
        {

            Image<Bgra, Byte> result = image1.Copy();
            Image<Bgra, Byte> src = image2;
            Image<Bgra, Byte> dst = image1;

            int rows = result.Rows;
            int cols = result.Cols;
            for (int y = 0; y < rows; ++y)
            {
                for (int x = 0; x < cols; ++x)
                {
                    // http://en.wikipedia.org/wiki/Alpha_compositing
                    double  srcA = 1.0/255 * src.Data[y, x, 3];
                    double dstA = 1.0/255 * dst.Data[y, x, 3];
                    double outA = (srcA + (dstA - dstA * srcA));
                    result.Data[y, x, 0] = (Byte)(((src.Data[y, x, 0] * srcA) + (dst.Data[y, x, 0] * (1 - srcA))) / outA);  // Blue
                    result.Data[y, x, 1] = (Byte)(((src.Data[y, x, 1] * srcA) + (dst.Data[y, x, 1] * (1 - srcA))) / outA);  // Green
                    result.Data[y, x, 2] = (Byte)(((src.Data[y, x, 2] * srcA) + (dst.Data[y, x, 2] * (1 - srcA))) / outA); // Red
                    result.Data[y, x, 3] = (Byte)(outA*255);
                }
            }
            return result;
        }

较新的版本,使用 emgucv 方法。而不是一个循环。不确定它会提高性能。双单位 = 1.0 / 255.0;图像[] dstS = dst.Split(); 图像[] srcS = src.Split(); 图像[] rs = 结果.Split();

        Image<Gray, double> srcA = srcS[3] * unit;
        Image<Gray, double> dstA = dstS[3] * unit;
        Image<Gray, double> outA = srcA.Add(dstA.Sub(dstA.Mul(srcA)));// (srcA + (dstA - dstA * srcA));

        // Red.
        rs[0] = srcS[0].Mul(srcA).Add(dstS[0].Mul(1 - srcA)).Mul(outA.Pow(-1.0)); // Mul.Pow is divide.
        rs[1] = srcS[1].Mul(srcA).Add(dstS[1].Mul(1 - srcA)).Mul(outA.Pow(-1.0));
        rs[2] = srcS[2].Mul(srcA).Add(dstS[2].Mul(1 - srcA)).Mul(outA.Pow(-1.0));
        rs[3] = outA.Mul(255);

        // Merge image back together.
        CvInvoke.cvMerge(rs[0], rs[1], rs[2], rs[3], result);
        return result.Convert<Bgra, Byte>();
于 2013-10-14T14:46:46.577 回答