【问题标题】:OpenCV ROI Out-of-bounds: Fill with black?OpenCV ROI 越界:用黑色填充?
【发布时间】:2017-06-20 10:08:06
【问题描述】:

我正在使用 OpenCV 从大图像中获取小矩形 ROI 并将 ROI 保存到文件中。有时,ROI 会超出图像的范围。我需要一种方法来使生成的 Mat 显示大图像在边界内的部分,并在其余部分显示黑色。

为了帮助解释,请想象您拥有一张区域地图的图像。我知道一个人在地图上的位置,并想在地图上截取一个 500x500 像素的部分,他们的位置在中心。但是当用户到达地图边缘时,这个 500x500 部分的一部分将需要“离开地图”。所以我希望它用黑色填充。

最好,OpenCV 将能够通过填充黑色(就像使用 warpAffine 旋转图像时一样)来优雅地处理越界 ROI(例如负左上角值),但事实并非如此似乎是这样。关于如何实现这一目标的任何建议?

【问题讨论】:

  • 你能用样本输入和预期输出来支持你的问题吗?

标签: c++ opencv roi


【解决方案1】:

所有其他答案对我来说似乎有点太复杂了。简单地说:

// Create rects representing the image and the ROI
auto image_rect = cv::Rect({}, image.size());
auto roi = cv::Rect(-50, 50, 200, 100)

// Find intersection, i.e. valid crop region
auto intersection = image_rect & roi;

// Move intersection to the result coordinate space
auto inter_roi = intersection - roi.tl();

// Create black image and copy intersection
cv::Mat crop = cv::Mat::zeros(roi.size(), image.type());
image(intersection).copyTo(crop(inter_roi));

图片供参考:

【讨论】:

  • 很好的答案。或许应该提一下,这里的roi也是一个Rect,可以通过Rect(ord_y, ord_x, width_y, width_x)构造;
【解决方案2】:

我发现执行此操作的最佳方法是获取范围内的 ROI 部分,然后计算 ROI 的每一侧(顶部/底部/左侧/右侧)有多少超出范围,然后使用copyMakeBorder 函数在每一侧填充那么多黑色边框。结果非常好。现在看起来像这样:

Mat getPaddedROI(const Mat &input, int top_left_x, int top_left_y, int width, int height, Scalar paddingColor) {
    int bottom_right_x = top_left_x + width;
    int bottom_right_y = top_left_y + height;

    Mat output;
    if (top_left_x < 0 || top_left_y < 0 || bottom_right_x > input.cols || bottom_right_y > input.rows) {
        // border padding will be required
        int border_left = 0, border_right = 0, border_top = 0, border_bottom = 0;

        if (top_left_x < 0) {
            width = width + top_left_x;
            border_left = -1 * top_left_x;
            top_left_x = 0;
        }
        if (top_left_y < 0) {
            height = height + top_left_y;
            border_top = -1 * top_left_y;
            top_left_y = 0;
        }
        if (bottom_right_x > input.cols) {
            width = width - (bottom_right_x - input.cols);
            border_right = bottom_right_x - input.cols;
        }
        if (bottom_right_y > input.rows) {
            height = height - (bottom_right_y - input.rows);
            border_bottom = bottom_right_y - input.rows;
        }

        Rect R(top_left_x, top_left_y, width, height);
        copyMakeBorder(input(R), output, border_top, border_bottom, border_left, border_right, BORDER_CONSTANT, paddingColor);
    }
    else {
        // no border padding required
        Rect R(top_left_x, top_left_y, width, height);
        output = input(R);
    }
    return output;
}

而且您可以轻松地将填充设置为您喜欢的任何颜色,这很好。

【讨论】:

    【解决方案3】:

    我不确定是否有一个函数可以为您执行此操作,但您自己执行此操作非常简单 - 我制作了一个类似的函数来限制 ROI。您只需将 ROI 的 topLeft 位置与图像边框进行比较。

    例如检查

    if(roi.bottomRight.x > image.bottomRight.x) 
        constrain.x = image.bottomRight.x - roi.topLeft.x
    

    这是您的 ROI 矩阵中的访问点,包含跟踪的图像。您需要为每个边界执行此操作。现在您可以访问这些边界内的 ROI 矩阵并将像素值设置为 (0,0,0)。

    另一种解决方法是创建第二个矩形(按图像大小)并使用矩形运算符进行交集(rect = rect1 &amp; rect2)。然后,通过减去跟踪矩形和相交矩形的宽度和高度,您立即获得了约束,并且您可以执行与我上面提到的相同的矩阵访问。如果这是一个可能的替代解决方案 - 您可以只使用没有黑色区域的相交矩形 - 那么您只需复制相交矩形大小范围内的值。

    【讨论】:

    • >我不确定是否有一个函数可以为您执行此操作,OpenCV 绝对不会处理任何越界,即尝试写入不存在的矩阵的一部分。
    • "试图写入一个不存在的矩阵的一部分。" 你的意思是什么矩阵?我的意思是跟踪的 roi,它包含原始图像的子矩阵,外面的部分是不可见的,但确实存在。
    • 我很赞同你,说 OpenCV 内部非常乐意尝试在矩阵之外写入,因此由于内存问题而崩溃
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多