opencv混合(叠加)具有不同通道的两个图像

问题描述:

我想用opencv覆盖两个图像(可能是不同格式(通道).最初我使用addWeighted,但是,它在两个具有不同通道的图像上失败了.opencv中有什么方法可以处理这种情况吗?谢谢>

I want to overlay two images (maybe different format (channels) with opencv. Originally I use addWeighted, however, it fails on two images with different channels. Is there any way in opencv that can handle this case? Thanks

,OpenCV中没有API本身提供此功能.另一方面,没有什么可以阻止您编写自己的代码来做到这一点.

No, there is no API in OpenCV that offers this feature nativelly. On the other hand, there's nothing stopping you from writing your own code to do that.

几个星期前,我对某项功能进行了一些更改,以便在Internet上其他地方看到该功能:

A few weeks ago a made some changes to a function I saw somewhere else on the Internet to be able to:

  • 传递两个输入图像:背景为BGR 前景为BGRA
  • 根据一个简单的透明度规则将它们混合在一起;
  • Pass two input images: the background as BGR and the foreground as BGRA;
  • Blend them together according to a simple transparency rule;

(我不记得这段代码的大部分来自哪里,对不起...但是谢谢你,无论你是谁!)

void overlayImage(const cv::Mat &background, const cv::Mat &foreground, cv::Mat &output, cv::Point2i location, double opacity = 1.0)
{
    background.copyTo(output);

    // start at the row indicated by location, or at row 0 if location.y is negative.
    for (int y = std::max(location.y , 0); y < background.rows; ++y) {
        int fY = y - location.y; // because of the translation

        // we are done of we have processed all rows of the foreground image.
        if (fY >= foreground.rows)
            break;

        // start at the column indicated by location, or at column 0 if location.x is negative.
        for (int x = std::max(location.x, 0); x < background.cols; ++x) {
            int fX = x - location.x; // because of the translation.

            // we are done with this row if the column is outside of the foreground image.
            if (fX >= foreground.cols)
                break;

            // determine the opacity of the foregrond pixel, using its fourth (alpha) channel.
            double opacity_level = ((double)foreground.data[fY * foreground.step + fX * foreground.channels() + 3]) / 255.;
            if (opacity >= 0.0 && opacity < 1.0)
                opacity_level *= opacity;

            // and now combine the background and foreground pixel, using the opacity, but only if opacity > 0.
            for (int c = 0; opacity_level > 0 && c < output.channels(); ++c) {
                unsigned char foregroundPx = foreground.data[fY * foreground.step + fX * foreground.channels() + c];
                unsigned char backgroundPx = background.data[y * background.step + x * background.channels() + c];
                output.data[y*output.step + output.channels()*x + c] = backgroundPx * (1.-opacity_level) + foregroundPx * opacity_level;
            }
        }
    }
}

在下面,您将找到用于测试的输入图像:背景,而上的图像是前景.

Below you will find the input images used for testing: the left is the background and the image on the right is the foreground.

要在背景上完全复制前景,只需执行以下操作:

To copy the foreground completely over the background, just do:

cv::Mat background = cv::imread("road.png");         // 3-chan BGR
cv::Mat foreground= cv::imread("tulip.png", -1);     // 4-chan BGRA
cv::Point location(0, 0);  

cv::Mat output;
overlayImage(input_bkg, input_target, output, location, 1.0);
cv::imwrite("output_alpha1.0.png", output);

并以50%的透明度进行复制:

and to perform a copy with 50% transparency:

overlayImage(input_bkg, input_target, output, location, 0.5);
cv::imwrite("output_alpha0.5.png", output);

以下是结果:

此实现并非出于生产目的而防弹,请自行承担风险.

This implementation is not bulletproof for production purposes, so use it at your own risk.