在 OpenCV 中选择图像的非矩形 ROI 的最有效方法是啥?

Posted

技术标签:

【中文标题】在 OpenCV 中选择图像的非矩形 ROI 的最有效方法是啥?【英文标题】:What's the most efficient way to select a non-rectangular ROI of an Image in OpenCV?在 OpenCV 中选择图像的非矩形 ROI 的最有效方法是什么? 【发布时间】:2016-06-03 22:48:26 【问题描述】:

我想创建一个二进制图像掩码,在 python 中只包含 1 和 0。感兴趣区域(白色)是非矩形的,由 4 个角点定义,如下所示:

在我的方法中,我首先计算上下 ROI 边界的线方程,然后检查每个掩码元素是否小于或大于边界。该代码正在运行,但速度很慢。一个 2000x1000 的面罩最多需要 4 秒来处理我的机器。

from matplotlib import pyplot as plt 
import cv2
import numpy as np
import time

def line_eq(line):
    """input:
            2 points of a line
       returns: 
            slope and intersection of the line
    """
    (x1, y1), (x2, y2) = line
    slope = (y2 - y1) / float((x2 - x1))
    intersect = int(slope * (-x1) + y1)

    return slope,intersect

def maskByROI(mask,ROI):
    """
        input: 
            ROI: with 4 corner points e.g. ((x0,y0),(x1,y1),(x2,y2),(x3,y3))
            mask: 
        output: 
            mask with roi set to 1, rest to 0

    """


    line1 = line_eq((ROI[0],ROI[1]))
    line2 = line_eq((ROI[2],ROI[3]))

    slope1 = line1[0] 
    intersect1 = line1[1]

    #upper line
    if slope1>0:
        for (x,y), value in np.ndenumerate(mask):
                if y > slope1*x +intersect1:
                    mask[x,y] = 0
    else:   
        for (x,y), value in np.ndenumerate(mask):
                if y < slope1*x +intersect1:
                    mask[x,y] = 0
    #lower line
    slope2 = line2[0]
    intersect2 = line2[1]
    if slope2<0:
        for (x,y), value in np.ndenumerate(mask):
                if y > slope2*x +intersect2:
                    mask[x,y] = 0
    else:   
        for (x,y), value in np.ndenumerate(mask):
                if y < slope2*x +intersect2:
                    mask[x,y] = 0

    return mask



mask = np.ones((2000,1000))

myROI = ((750,0),(900,1000),(1000,1000),(1500,0))

t1 = time.time()
mask = maskByROI(mask,myROI)
t2 = time.time()

print "execution time: ", t2-t1


plt.imshow(mask,cmap='Greys_r')
plt.show()

有什么更有效的方法来创建这样的蒙版?

对于非矩形形状有没有类似的解决方案 numpy、OpenCV 还是类似的库?

【问题讨论】:

codereview.stackexchange.com 看看Extreme Points 查看我在***.com/questions/12638790/… 的回答,了解如何使用 Pillow 绘制填充多边形的示例。 【参考方案1】:

fillPoly绘制蒙版:

mask = np.ones((1000, 2000))                              # (height, width)
myROI = [(750, 0), (900, 1000), (1000, 1000), (1500, 0)]  # (x, y)
cv2.fillPoly(mask, [np.array(myROI)], 0)

这大约需要 1 毫秒。

【讨论】:

壮丽的。 OpenCV 似乎以相反的方式索引矩阵。如果您交换 ROI 坐标以重现我发布的图像,我会接受您的回答。 我更新了答案以阐明 OpenCV 索引(x,y)和 numpy 索引(行主要)之间的区别。您的 sn-ps 中的 cmets 表示 ROI 作为 (x, y) 的数组提供,因此您索引 mask[x, y] 的方式与 numpy 的行主要索引不一致。 如果 roi 是凸的,您应该使用cv2.fillConvexPoly 以获得更好的性能。

以上是关于在 OpenCV 中选择图像的非矩形 ROI 的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 OpenCV c++ 中从图像中裁剪特定的矩形部分(ROI)

opencv 实现 ROI 框选功能

请问大虾们,opencv如何只对图像选择区域提取特征点

OpenCV中的错误ROI图像

OpenCV-C++选择提取感兴趣区域(ROI区域)附用鼠标选取ROI区域的代码

OpenCV 人脸检测 ROI 断言失败