gpt4 book ai didi

python - 去除圆形蒙版周围的空白

转载 作者:行者123 更新时间:2023-12-02 16:14:30 25 4
gpt4 key购买 nike

我有一个圆形蒙版的图像,它基本上是黑色图像中的一个彩色圆圈。 mask
我要删除蒙版周围的所有空白区域,以使图像的边界与圆圈对齐,如下所示:original vs cropped
我已经编写了一个脚本,通过搜索每一列和每一行直到出现一个值大于0的像素来做到这一点。从左到右,从右到左,从上到下以及从下到上搜索可以使我获得蒙版边界,从而可以裁剪原始图像。这是代码:

ROWS, COLS, _ = img.shape

BORDER_RIGHT = (0,0)
BORDER_LEFT = (0,0)

right_found = False
left_found = False

# find borders of blank space for removal.
# left and right border
print('Searching for Right and Left corners')
for col in tqdm(range(COLS), position=0, leave=True):
for row in range(ROWS):
if left_found and right_found:
break

# searching from left to right
if not left_found and N.sum(img[row][col]) > 0:
BORDER_LEFT = (row, col)
left_found = True

# searching from right to left
if not right_found and N.sum(img[row][-col]) > 0:
BORDER_RIGHT = (row, img.shape[1] + (-col))
right_found = True

BORDER_TOP = (0,0)
BORDER_BOTTOM = (0,0)

top_found = False
bottom_found = False

# top and bottom borders
print('Searching for Top and Bottom corners')
for row in tqdm(range(ROWS), position=0, leave=True):
for col in range(COLS):
if top_found and bottom_found:
break

# searching top to bottom
if not top_found and N.sum(img[row][col]) > 0:
BORDER_TOP = (row, col)
top_found = True

# searching bottom to top
if not bottom_found and N.sum(img[-row][col]) > 0:
BORDER_BOTTOM = (img.shape[0] + (-row), col)
bottom_found = True

# crop left and right borders
new_img = img[:,BORDER_LEFT[1]: BORDER_RIGHT[1] ,:]

# crop top and bottom borders
new_img = new_img[BORDER_TOP[0] : BORDER_BOTTOM[0],:,:]
我想知道是否有更有效的方法来做到这一点。对于较大的图像,这可能会非常耗时,尤其是在蒙版相对于原始图像形状相对较小的情况下。谢谢!

最佳答案

假设图像中只有该对象,则有两种方法可以执行此操作:

  • 您可以对图像进行阈值处理,然后使用 numpy.where 查找非零的所有位置,然后在numpy.min产生的适当行和列位置上使用 numpy.max numpy.where 为边界矩形。
  • 使用 cv2.findContours 设置阈值后,您可以首先找到对象的轮廓点。这应该产生一个单一的轮廓,因此一旦有了这些点,就将其放置在 cv2.boundingRect 中,以返回矩形的左上角以及其范围的宽度和高度。

  • 如果只有一个对象,那么第一种方法将有效。如果有多个对象,则第二个将起作用,但是您必须知道感兴趣的对象位于哪个轮廓中,然后只需索引到 cv2.findContours的输出中,并将其通过 cv2.boundingRect进行管道传输即可获得对象的矩形尺寸利益。
    但是,可以得出的结论是,这两种方法都比您建议的方法效率更高,在该方法中,您手动遍历每一行和每一列并计算总和。

    前处理
    这些步骤对这两种方法都是通用的。总而言之,我们读入图像,然后将其转换为灰度,然后转换为阈值。我无权访问您的原始图像,因此我从Stack Overflow中读取了该图像并对其进行了裁剪,以使轴不显示。这也将适用于第二种方法。
    这是我拍摄快照后的图像重建图。
    Original
    首先,我将直接从Internet阅读图像,并导入完成工作所需的相关软件包:
    import skimage.io as io
    import numpy as np
    import cv2

    img = io.imread('/image/dj1a8.png')
    值得庆幸的是,Scikit图像具有一种直接从Internet读取图像的方法: skimage.io.imread
    之后,我将图像转换为灰度,然后对其进行阈值处理:
    img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    im = img_gray > 40
    我使用OpenCV的 cv2.cvtColor 将图像从彩色转换为灰度。之后,我对图像进行阈值处理,以便将高于40的任何强度设置为 True,其他所有设置为 False。我反复尝试选择的阈值40,直到我得到一个看起来像圆形的面具。看一下这张图片,我们得到:
    Threhsold

    方法1
    如上所示,在带阈值的图像上使用 numpy.where,然后使用 numpy.minnumpy.max找到适当的左上角和右下角并裁剪图像:
    (r, c) = np.where(im == 1)
    min_row, min_col = np.min(r), np.min(c)
    max_row, max_col = np.max(r), np.max(c)
    im_crop = img[min_row:max_row+1, min_col:max_col+1]
    2D数组的 numpy.where将返回行和列位置非零的元组。如果找到最小的行和列位置,则该位置对应于边界矩形的左上角。同样,最大的行和列的位置对应于边界矩形的右下角。好的是 numpy.minnumpy.max以矢量化方式工作,这意味着它可以在一次扫描中对整个NumPy数组进行操作。上面使用了此逻辑,然后我们索引到原始彩色图像中,以裁剪出包含感兴趣对象的行和列的范围。 im_crop包含该结果。请注意,当我们索引时,最大行和列需要加1,因为与末端索引的 slice 是互斥的,因此加1可以确保我们在矩形的右下角包括像素位置。
    因此,我们得到:
    Crop 1
    方法#2
    我们将使用 cv2.findContours查找图像中所有对象的所有轮廓点。因为只有一个对象,所以只能得到一个轮廓,因此我们使用该轮廓将其插入 cv2.boundingRect中,以找到对象边界矩形的左上角,并结合其宽度和高度来裁剪图像。
    cnt, _ = cv2.findContours(im.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    x, y, w, h = cv2.boundingRect(cnt[0])
    im_crop = img[y:y+h, x:x+w]
    请注意,我们必须将阈值图像转换为无符号的8位整数,因为这是函数期望的类型。此外,我们使用 cv2.RETR_EXTERNAL,因为我们只想检索图像中看到的任何对象的外围坐标。我们还使用 cv2.CHAIN_APPROX_NONE返回对象上所有可能的轮廓点。 cnt是在图像中找到的轮廓列表。该列表的大小应仅为1,因此我们直接对其进行索引并将其通过管道传递到 cv2.boundingRect中。然后,我们使用矩形的左上角,并结合其宽度和高度来裁剪出对象。
    因此,我们得到:
    Crop 2

    完整代码
    这是从头到尾的完整代码 list 。我在下面留下评论来描述方法1和方法2。目前,方法2已被注释掉,但是您可以通过简单地注释和取消注释相关代码来决定要使用的方法。
    import skimage.io as io
    import cv2
    import numpy as np

    img = io.imread('/image/dj1a8.png')

    img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    im = img_gray > 40

    # Method #1
    (r, c) = np.where(im == 1)
    min_row, min_col = np.min(r), np.min(c)
    max_row, max_col = np.max(r), np.max(c)
    im_crop = img[min_row:max_row+1, min_col:max_col+1]

    # Method #2
    #cnt, _ = cv2.findContours(im.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    #x, y, w, h = cv2.boundingRect(cnt[0])
    #im_crop = img[y:y+h, x:x+w]

    关于python - 去除圆形蒙版周围的空白,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62629743/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com