在python中使用opencv剪切图像的特定部分

Posted

技术标签:

【中文标题】在python中使用opencv剪切图像的特定部分【英文标题】:cut out a specific part of an image with opencv in python 【发布时间】:2020-04-29 09:00:38 【问题描述】:

我有一张 IC 芯片的图像,我想剪掉中心的标记。标记始终位于左下角圆圈上方的特定位置。 这个想法是首先找到我已经通过霍夫圆变换完成的圆位置。现在我想剪掉标记所在的部分。理想情况下,它应该不是正方形或矩形,而是更像图像中的东西:

这是我的代码的一部分:

        cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        circles = cv2.HoughCircles(morph_image, cv2.HOUGH_GRADIENT, 1.3, 20, param1=50, param2=25, minRadius=15,
                                   maxRadius=19)

        if circles is not None:
            circles = np.uint16(np.around(circles))
            for i in circles[0, :]:
                # Zeichne äußeren Kreis
                cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)
                # Zeichne Kreiszentrum
                cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 3)
                # Tupel mit x- und y-Koordinaten des Kreiszentrums
                circle_center = (i[0], i[1])
                print('Die Koordinaten des Kreiszentrums lauten: ', circle_center)
                """cv2.imshow('Kreis', cimg)
                cv2.waitKey(0)
                cv2.destroyAllWindows()"""
        else:
            circle_center = None
            print('Kein Kreis gefunden')
            """cv2.imshow('Kein Kreis', cimg)
            cv2.waitKey(0)
            cv2.destroyAllWindows()"""

所以我的cicle center 具有我圈子的中心位置(例如(124, 370))。如何自动剪切图像的这一部分?我可以以某种方式裁剪出来吗?理想情况下,我想将标记裁剪到另一张图像中以单独检查,但我猜marking_img = img[y:y+h, x:x+w] 的正常裁剪方法行不通。

编辑: 这是原图:

输出应该和第一张图片一样,如果可能的话:

所以最后我想要两张图像:一张只有模具没有标记的图像和一张只有标记的图像

【问题讨论】:

你能附上预期的输出吗? 我添加了原始图像和预期输出 为什么不在阈值化后使用 tesseract 读取文本并使用形态学进行清理。或者提取所有字符并使用轮廓边界框仅保留中间的字符。如果文本比您的顶部和底部符号更宽(在 x 方向上),那么您可以阈值并使用形态学来连接 3 行文本并提取 3 个较大的边界框。 @fmw42 因为有些图像由于激光不良或某种划痕而无法读取字符。但无论如何,我都想剪掉这 3 行。对我来说有趣的部分是模具的表面,我只想要表面。对于可以使用 tessaract 的进一步任务,需要将标记裁剪成新图像。 但是这 3 行会比你的顶部和底部图标宽吗?如果是这样,可以这样做以将它们裁剪掉。是否总是有 3 行且只有 3 行? 3 行中每一行中的字符数是否总是相同的长度(6、3 和 5)? 【参考方案1】:

这是 Python/OpenCV 中的一种方式。

阅读图片 阅读蒙版(与您的另一张图片分开创建一次) 将蒙版转换为灰色并将其阈值化为二进制,将其反转并使其成为 3 个通道 从您自己的代码中获取圆心。 (我只是手动测量的) 设置文本区域底部与圆心的预期 x,y 偏移量 从圆心计算蒙版的预期左上角、蒙版图像的偏移量和高度 将蒙版放入与该位置输入大小相同的黑色图像中 将新蒙版应用于图像以使图像的其余部分变黑 从左上角裁剪出感兴趣区域和原始蒙版的大小 (可选)裁剪原始图像 保存结果

输入图片:

准备好的蒙版图片:

import cv2
import numpy as np

# read image
img = cv2.imread('die.jpg')
ht, wd, cc = img.shape

# read mask as grayscale
mask = cv2.imread('die_mask.png', cv2.IMREAD_GRAYSCALE)

# threshold mask and invert
mask = cv2.threshold(mask,0,255,cv2.THRESH_BINARY)[1]
mask = 255 - mask
hh, ww = mask.shape

# make mask 3 channel
mask = cv2.merge([mask,mask,mask])

# set circle center
cx = 62
cy = 336

# offsets from circle center to bottom of region
dx = -20
dy = -27

# compute top left corner of mask using size of mask and center and offsets
left = cx + dx
top = cy + dy - hh

# put mask into black background image
mask2 = np.zeros_like(img)
mask2[top:top+hh, left:left+ww] = mask

# apply mask to image
img_masked = cv2.bitwise_and(img, mask2)

# crop region
img_masked_cropped = img_masked[top:top+hh, left:left+ww]

# ALTERNATE just crop input
img_cropped = img[top:top+hh, left:left+ww]

cv2.imshow('image', img)
cv2.imshow('mask', mask)
cv2.imshow('mask2', mask2)
cv2.imshow('masked image', img_masked)
cv2.imshow('masked cropped image', img_masked_cropped)
cv2.imshow('cropped image', img_cropped)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save results
cv2.imwrite('die_mask_inserted.jpg', mask2)
cv2.imwrite('die_masked_image.jpg', img_masked)
cv2.imwrite('die_masked_cropped.jpg', img_masked_cropped)
cv2.imwrite('die_cropped.jpg', img_cropped)

插入黑色图像的蒙版:

蒙面图片:

蒙版图像的裁剪:

(可选)输入图像的裁剪:

【讨论】:

谢谢!该示例有效:) 但是当我将它添加到我现有的代码中时,它显示ValueError: could not broadcast input array from shape (175,226,3) into shape (0,44) 所以一个图像通道存在问题。我作为原始输入提供的图像已预先进行了预处理。它最初是一个较大的图像,有时会旋转,所以我裁剪它并旋转它以获得我提供的输入图像。但我会查查这个问题。再次感谢!

以上是关于在python中使用opencv剪切图像的特定部分的主要内容,如果未能解决你的问题,请参考以下文章

如何在openCV Python中选择统一着色图的特定部分?

如何使用python OpenCV在单通道图像中找到与特定值匹配的最大连通分量?

如何在Python中使用OpenCV以特定顺序显示图像?

Python从图像opencv中提取多个对象

如何使用python opencv删除文件夹中的特定图像

opencv从噪声很大的图像中剪切出字母(java)