OpenCV ROI越界:填充黑色?

时间:2017-02-03 05:31:59

标签: c++ opencv roi

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

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

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

3 个答案:

答案 0 :(得分:4)

我发现做到这一点的最好方法是获取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;
}

你可以轻松地填充你喜欢的颜色,这很不错。

答案 1 :(得分:3)

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

// Create rect representing the image
auto image_rect = cv::Rect({}, image.size());

// 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));

图片供参考:

enter image description here

答案 2 :(得分:1)

我不确定为你做这个功能,但是你自己做这个很简单 - 我做了类似的功能来约束ROI。您只需要将ROI的topLeft位置与图像边界进行比较。

e.g。检查

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

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

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