简体   繁体   English

OpenCV ROI 越界:用黑色填充?

[英]OpenCV ROI Out-of-bounds: Fill with black?

I'm using OpenCV to get a small rectangular ROI from a large image and save the ROI to a file.我正在使用 OpenCV 从大图像中获取一个小的矩形 ROI,并将 ROI 保存到文件中。 Sometimes, the ROI goes out of bounds of the image.有时,ROI 超出图像范围。 I need a way to make the resulting Mat show the portion of the large image that is within bounds, and show black for the rest.我需要一种方法来使生成的 Mat 显示在边界内的大图像部分,并为其余部分显示黑色。

To help explain, image that you have an image that is a map of an area.为了帮助解释,想象你有一个区域地图的图像。 I know where a person is on the map, and want to take a 500x500 pixel section of the map with their location in the center.我知道一个人在地图上的位置,并想在地图上取一个 500x500 像素的部分,并将他们的位置放在中心。 But when the user gets to the edge of the map, part of this 500x500 section will need to be "off the map".但是当用户到达地图边缘时,这个 500x500 部分的一部分将需要“离开地图”。 So I would like it to fill it in with black.所以我想用黑色填充它。

Preferably, OpenCV would be able to gracefully handle out-of-bounds ROIs (eg negative top left corner values) by filling in with black (like it does when you rotate an image with warpAffine ) but that doesn't seem to be the case.最好,OpenCV 能够通过填充黑色(就像使用warpAffine旋转图像时warpAffine )来优雅地处理越界 ROI(例如负左上角值),但情况似乎并非如此. Any suggestions for how to accomplish this goal?有关如何实现这一目标的任何建议?

All other answers seem a little bit too complicated to me.所有其他答案对我来说似乎有点太复杂了。 Simply:简单地:

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

Image for reference:图片供参考:

在此处输入图片说明

I found that the best way to do this was to get the section of the ROI that was within bounds, then calculate how much on each side (top/bottom/left/right) of the ROI was out of bounds, then use the copyMakeBorder function to pad that much black border around each side.我发现执行此操作的最佳方法是获取边界内的 ROI 部分,然后计算 ROI 的每一侧(顶部/底部/左侧/右侧)有多少超出边界,然后使用copyMakeBorder功能是在每一侧填充那么多黑色边框。 It worked out very well.效果很好。 It looks something like this now:现在看起来像这样:

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;
}

And you can easily make the padding whatever colour you like, which is nice.而且您可以轻松地制作您喜欢的任何颜色的填充,这很好。

I am not sure about a function doing that for you, but it's quite simple to do this by your self - I made a similar function to constrain a ROI.我不确定是否有一个函数可以为您执行此操作,但是您自己执行此操作非常简单 - 我创建了一个类似的函数来限制 ROI。 You just need to compare the topLeft position of the ROI with the image borders.您只需将 ROI 的 topLeft 位置与图像边框进行比较。

eg check例如检查

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

This is your access point in your ROI matrix, containing the tracked image.这是您的 ROI 矩阵中的访问点,包含跟踪的图像。 You would need to do this for every border.您需要为每个边界执行此操作。 Now you can just access the ROI matrix inside these borders and set the pixel values to (0,0,0).现在您可以访问这些边界内的 ROI 矩阵并将像素值设置为 (0,0,0)。

Another workaround would be possible to create a second rectangle(in size of the image) and use the rectangle operators for intersection( rect = rect1 & rect2 ).另一种解决方法是创建第二个矩形(图像大小)并使用矩形运算符进行交集( rect = rect1 & rect2 )。 Then you've got the constraints right away by subtracting the width and height of the tracked rectangle and the intersection rectangle and you are able to perform the same matrix access like I mentioned above.然后,通过减去跟踪矩形和相交矩形的宽度和高度,您立即获得了约束,并且您可以像我上面提到的那样执行相同的矩阵访问。 If it's a possible alternative solution - you can just use the intersection rectangle without the black regions - then you just have to copy the values inside the range of the intersection rectangle's size.如果这是一个可能的替代解决方案 - 您可以只使用没有黑色区域的交叉矩形 - 那么您只需复制交叉矩形大小范围内的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM