使用OpenCV在Python中裁剪图像的特定部分

3
我有一张芯片晶圆的图片,我想切掉中心的标记。该标记始终位于左下角圆形上方的特定位置。 首先要找到圆形的位置,我已经通过霍夫圆变换完成了。现在我想切掉标记所在的部分。最好不是正方形或矩形,而更像图片中的形状。

example

这是我的代码的一部分:

        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()"""

我的圆形中心位置是(例如(124, 370)),那么如何自动剪切出图像的这一部分呢?我能否以某种方式将其裁剪出来?理想情况下,我希望将标记裁剪成另一个图像以单独检查,但正常的裁剪方法marking_img = img[y:y+h, x:x+w]不起作用。
编辑: 以下是原始图像:

enter image description here

输出应该像第一张图片那样,如果可能的话,应该是这样的:

enter image description here

最终,我希望有两张图片:一张只有骰子而没有标记,另一张只有标记而没有骰子。

你能否同时附上预期输出? - ZdaR
我添加了原始图像和预期输出。 - NECben067
为什么不直接使用Tesseract来读取经过阈值处理和形态学清理后的文本呢?或者提取所有字符,只保留中间的字符,使用轮廓边界框。如果文本在x方向上比您的顶部和底部符号更宽,则可以进行阈值处理并使用形态学连接文本的3行,并提取3个较大的边界框。 - fmw42
@fmw42 因为有些图像由于激光刻录不良或某种划痕而无法读取字符。但是我想无论如何都要裁剪掉这三行。对我来说,有趣的部分是芯片的表面,我不想在那里看到其他东西。将标记裁剪成新图像对于后续可能使用tessaract的任务是必要的。 - NECben067
@fmw42 就像第一张图片中那样。如果我们假设 x 是圆心的 x 值,y 是圆心的 y 值,那么它应该从大约 (x-14) 和 y-30 开始。这样我们就可以得到位于圆心位置上方的区域底部。 - NECben067
显示剩余4条评论
1个回答

4

以下是Python/OpenCV中的一种方法。

  • 读取图像
  • 读取掩码(从另一个图像单独创建一次)
  • 将掩码转换为灰度,并对其进行二值化、反转并将其变为3通道
  • 从您自己的代码中获取圆的中心。(我只是手动测量了它)
  • 设置期望的x,y偏移,以使文本区域底部与圆的中心对齐
  • 根据圆心、偏移和掩码图像的高度计算掩码左上角的位置
  • 将掩码放入黑色输入图像的该位置
  • 将新掩码应用于图像,使图像其余部分变为黑色
  • 从左上角裁剪出感兴趣的区域,大小与原始掩码相同
  • 选择性地裁剪原始图像
  • 保存结果

输入图像:

enter image description here

准备好的掩膜图像:

enter image description here

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)


黑色图像中插入的掩码:

enter image description here

掩码图像:

enter image description here

掩蔽图像的裁剪:

enter image description here

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

enter image description here


谢谢!这个例子很好用 :) 但是当我把它加入到我的现有代码中时,它会显示ValueError: could not broadcast input array from shape (175,226,3) into shape (0,44) 所以其中一个图像通道存在问题。我提供的原始输入图像在预处理之前已经被裁剪和旋转过了。它最初是一张更大的图像,有时会被旋转,所以我要对其进行裁剪和旋转,以得到我提供的输入图像。但我会查找这个问题。再次感谢! - NECben067

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接