【问题标题】:Creating transparent overlay for camera in OpenCV c++在 OpenCV c++ 中为相机创建透明覆盖
【发布时间】:2016-09-09 14:23:22
【问题描述】:

我正在尝试为相机供稿创建叠加层,我希望叠加层变得模糊,并且大约 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);

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

我在 windows x64 btw 上使用 OpenCV 3.10

【问题讨论】:

  • 只需创建一个mask,即在没有覆盖的情况下为 0,在有覆盖的情况下为 255。然后执行以下操作:对于每个像素:if(mask(pixel) == 255) result(pixel) = alpha*background(pixel) + (1-alpha)*image(pixel) else result(pixel) = image(pixel); 如果您不想手动迭代所有像素,您可以使用(可能更慢):cv::Mat hardBackground = image.clone(); background.copyTo(hardBackground, mask); cv::addWeighted(hardBackground, alpha, image, 1-alpha, 0, result);
  • 写这个作为答案不是更好吗? :p
  • 没有时间也没有可能测试它=)如果他能够以这种方式实现它,我希望他会自己写答案。如果有问题我会在有时间的时候写一个详细的答案。
  • 我试试看。这个周末我没有时间(我可能应该等着打开这个问题,但是哦,好吧),但我会在周一解决问题 :)
  • 是否可以假设叠加层是矩形并且在每个方向上执行淡化?或者你能定义你想要达到的目标吗?

标签: c++ opencv


【解决方案1】:

试试这个:

    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 像素的淡化范围给出此结果:

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

【讨论】:

  • 对混合蒙版的圆形边缘区域使用`CV_D​​IST_L2`
  • 有时进行代码清理并不是一件坏事,你知道的。 =,D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-07
  • 2014-11-15
  • 2012-09-23
  • 2017-05-21
  • 1970-01-01
  • 1970-01-01
  • 2016-07-14
相关资源
最近更新 更多