OpenCv overlay two Mat (drawings not images) with transparency

最后都变了- 提交于 2019-12-11 07:38:38

问题


Hi what I have is a couple of Mat that I want to overlay (in a custom order). The Mat holdes some opencv polygons (which means a lot transparency). This Mat I need to overlay/merge. But not with the classical alpha blending more like with a 100% opacity but with transparency.

This is a simple sample code of what I want to merge.

Mat m1, m2;
m1.create(Point{ 100,100 }, CV_8UC4);
m2.create(Point{ 100,100 }, CV_8UC4);

cv::polylines(m1, std::vector<Point>{ Point{ 2,20 },Point{ 20,40 } }, true, Scalar(6, 6, 255));
cv::polylines(m2, std::vector<Point>{Point{ 100,100 }, Point{ 0,0 } }, true, Scalar(192, 112, 0));

Please note, that I cannot draw the polygons directly in one Mat due to various reasons.

I thought that maybe m1.copyTo(m2); will work, but its overwriting everything (incl. the black background)

Any idea how to get it merged/overlayed without the background? May I construct the mat's wrong?


回答1:


I suspect you've had a problem looking for black in those images, as they were not initialized (it became apparent in debug mode). If we start with a zeroed out matrix, and draw using a 4-channel colour, so that the lines are visible, we get inputs such as this:

Input 1:

Input 2:

Now, we can use inRange to find all pixels set to (0,0,0,0). Since we want a mask of all non-black pixels, we just invert it by subtracting from 255. (i.e. mask = 255 - mask)

Mask:

Finally, use the mask as the second parameter of copyTo.

Result:

Code:

#include <opencv2/opencv.hpp>

int main()
{
    cv::Mat m1(100, 100, CV_8UC4, cv::Scalar(0, 0, 0, 0));
    cv::Mat m2(100, 100, CV_8UC4, cv::Scalar(0, 0, 0, 0));

    cv::polylines(m1
        , std::vector<cv::Point>{cv::Point{2, 20}, cv::Point{20, 40}}
        , true, cv::Scalar(6, 6, 255, 255));
    cv::polylines(m2
        , std::vector<cv::Point>{cv::Point{100, 100}, cv::Point{0, 0}}
        , true, cv::Scalar(192, 112, 0, 255));

    cv::Mat mask;
    cv::inRange(m2, cv::Scalar(0, 0, 0, 0), cv::Scalar(0, 0, 0, 0), mask);
    mask = 255 - mask; // invert the mask

    cv::Mat result(m1.clone());
    m2.copyTo(result, mask);

    cv::imwrite("transp_in_1.png", m1);
    cv::imwrite("transp_in_2.png", m2);
    cv::imwrite("transp_mask.png", mask);
    cv::imwrite("transp_res.png", result);

    return 0;
}

Instead of inverting the mask, you can invert the direction in which you copy. (i.e. overwrite everything black in m2 with stuff from m1)

cv::Mat mask;
cv::inRange(m2, cv::Scalar(0, 0, 0, 0), cv::Scalar(0, 0, 0, 0), mask);

cv::Mat result(m2.clone());
m1.copyTo(result, mask);


来源:https://stackoverflow.com/questions/45131216/opencv-overlay-two-mat-drawings-not-images-with-transparency

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!