在OpenCV c ++中为相机创建透明叠加层

时间:2016-09-09 14:23:23

标签: c++ opencv

我正在尝试为相机Feed创建叠加层,我希望叠加层模糊,大约50%透明。解决此问题的一种方法是从相机复制每个帧,绘制到它上面,然后使用addWeighted将它们合并在一起。这对我不起作用,因为模糊效果占用了输出fps下降到10的大量资源。

我想到的另一个解决方案是创建叠加一次(毕竟它是静态的,为什么每帧重新创建它?)并将其与摄像机源合并。然而,当这样做时,得到的视频会明显变暗,因为叠加垫会拒绝透明。

(*cap) >> frameOriginal;

orientationBackground = cv::Mat(frameOriginal.rows, frameOriginal.cols,
    frameOriginal.type(), cv::Scalar(0,0,0,0));
cv::Mat headingBackground;
orientationBackground.copyTo(headingBackground);

cv::Point layerpt1(1800, 675);
cv::Point layerpt2(1850, 395);
cv::rectangle(orientationBackground, layerpt1, layerpt2,
    cv::Scalar(255,80,80), CV_FILLED, CV_AA);

cv::blur(orientationBackground, orientationBackground, cv::Size(7,30));

double alpha = 0.5;
addWeighted(orientationBackground, alpha, frameOriginal, 1-alpha, 0, frameOriginal);

添加叠加层的前(左)和后(右):overlay problem

我在Windows x64 btw上使用OpenCV 3.10

1 个答案:

答案 0 :(得分:2)

试试这个:

    cv::Mat input = cv::imread("C:/StackOverflow/Input/Lenna.png");

    // define your overlay position
    cv::Rect overlay = cv::Rect(400, 100, 50, 300);

    float maxFadeRange = 20;

    // precompute fading mask:
    cv::Size size = input.size();
    cv::Mat maskTmp = cv::Mat(size, CV_8UC1, cv::Scalar(255));

    // draw black area where overlay is placed, because distance transform will assume 0 = distance 0
    cv::rectangle(maskTmp, overlay, 0, -1);

    cv::Mat distances;
    cv::distanceTransform(maskTmp, distances, CV_DIST_L1, CV_DIST_MASK_PRECISE);

    cv::Mat blendingMask = cv::Mat(size, CV_8UC1);

    // create blending mask from 
    for (int j = 0; j < blendingMask.rows; ++j)
    for (int i = 0; i < blendingMask.cols; ++i)
    {
        float dist = distances.at<float>(j, i);

        float maskVal = (maxFadeRange - dist)/maxFadeRange * 255; // this will scale from 0 (maxFadeRange distance) to 255 (0 distance)
        if (maskVal < 0) maskVal = 0;

        blendingMask.at<unsigned char>(j, i) = maskVal;
    }

    cv::Scalar overlayColor = cv::Scalar(255, 0, 0);

    // color a whole image in overlay colors so that rect and blurred area are coverered by that color
    cv::Mat overlayImage = cv::Mat(size, CV_8UC3, overlayColor);

    // this has created all the stuff that is expensive and can be precomputed for a fixes roi overlay


    float transparency = 0.5f; // 50% transparency





    // now for each image: just do this:

    cv::Mat result = input.clone();


    for (int j = 0; j < blendingMask.rows; ++j)
    for (int i = 0; i < blendingMask.cols; ++i)
    {
        const unsigned char & blendingMaskVal = blendingMask.at<unsigned char>(j, i);

        if (blendingMaskVal) // only blend in areas where blending is necessary
        {
            float alpha = transparency * blendingMaskVal / 255.0f;

            result.at<cv::Vec3b>(j, i) = (alpha)*overlayImage.at<cv::Vec3b>(j, i) + (1.0f - alpha)*result.at<cv::Vec3b>(j, i);
        }

    }

给出50%透明度和20像素的渐弱范围的结果:

enter image description here

enter image description here

这是20%透明度(变量值= 0.2f)和100像素衰落:

enter image description here

enter image description here