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

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

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

几个星期前,我在互联网上的其他地方看到的function做了一些更改,以便能够:

  • 传递两个输入图像: 背景为BGR前景为BGRA ;
  • 根据简单的透明度规则将它们混合在一起;

(我不记得大部分代码来自哪里,对不起……但不管你是谁,都要感谢你!)

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; } } } } 

您将在下面找到用于测试的输入图像: 左边背景右边的图像是前景

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

 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%透明度的副本:

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

结果如下:

此实现不是用于生产目的的防弹,因此使用它需要您自担风险。

感谢所有试图回答我问题的人。 最后,我采用了列举背景图像条件的路径并将其转换为相同的通道编号,然后使用加权和。 不知道这个是否是正确的处理方式,但它似乎对我有用,除了透明背景PNG。 有什么建议么?

 private boolean convertToSameChannels() { if (_overlayImage.channels() != _image.channels()) { if (_image.channels() == 1) { if (_overlayImage.channels() == 3) { Imgproc.cvtColor(_overlayImage, _overlayImage, Imgproc.COLOR_BGR2GRAY); } else if (_overlayImage.channels() == 4) { Imgproc.cvtColor(_overlayImage, _overlayImage, Imgproc.COLOR_BGRA2GRAY); } } else if (_image.channels() == 3) { if (_overlayImage.channels() == 1) { Imgproc.cvtColor(_overlayImage, _overlayImage, Imgproc.COLOR_GRAY2BGR); } else if (_overlayImage.channels() == 4) { Imgproc.cvtColor(_overlayImage, _overlayImage, Imgproc.COLOR_BGRA2BGR); } } else if (_image.channels() == 4) { if (_overlayImage.channels() == 3) { Imgproc.cvtColor(_overlayImage, _overlayImage, Imgproc.COLOR_BGR2BGRA); } else if (_overlayImage.channels() == 1) { Imgproc.cvtColor(_overlayImage, _overlayImage, Imgproc.COLOR_GRAY2BGRA); } } else { System.out.println("overlay image not suppoerted error"); return false; } } return true; }