如何检测形状的轮廓然后从图像中裁剪形状?

How to detect the outline of a shape and then crop the shape from image?

import PIL
import pandas as pd

image = PIL.Image.open(file)
rgb_im = image.convert('RGB')

color = (77,77,77)
colorindex = pd.DataFrame(data = None,columns = ['X','Y'])
for x in range(image.size[0]):
 for y in range(image.size[1]):
    r, g, b = rgb_im.getpixel((x, y))
    if (r,g,b) == color:
        append = [x,y]
        append = pd.Series(append,index = colorindex.columns)
        colorindex = colorindex.append(append,ignore_index = True)
center = [colorindex.mode()['X'][0],colorindex.mode()['Y'][0]] 

line = pd.read_excel('C:/Users/lines RGb.xlsx') ##Prerecorded RGB Values

def findparcelline(CenterX,CenterY,direction):

if direction == 'left':
    for x in range(CenterX):
        r,g,b = rgb_im.getpixel((CenterX-x,CenterY))
        for i in range(len(line)):
            if (r,g,b) == (line.loc[i][0],line.loc[i][1],line.loc[i][2]):
                pixelsave = CenterX-x
                return pixelsave

elif direction == 'right':
    for x in range(CenterX):
        r,g,b = rgb_im.getpixel((CenterX+x,CenterY))
        for i in range(len(line)):
            if (r,g,b) == (line.loc[i][0],line.loc[i][1],line.loc[i][2]):
                pixelsave = CenterX+x
                return pixelsave

elif direction == 'down':
    for y in range(CenterY):
        r,g,b = rgb_im.getpixel((CenterX,CenterY + y))
        for i in range(len(line)):
            if (r,g,b) == (line.loc[i][0],line.loc[i][1],line.loc[i][2]):
                pixelsave = CenterY + y
                return pixelsave

elif direction == 'up':
    for y in range(CenterY):
        r,g,b = rgb_im.getpixel((CenterX,CenterY - y))
        for i in range(len(line)):
            if (r,g,b) == (line.loc[i][0],line.loc[i][1],line.loc[i][2]):
                pixelsave = CenterY - y
                return pixelsave

directions = ['left','down','right','up']
coords =[]
for direction in directions:
 coords.append(findparcelline(center[0],center[1],direction))       
im1 = image.crop(coords)
  1. 之前没有选择
  2. 匹配预先记录的颜色值
  3. 最接近锚点像素位置

提前致谢。

首先:如果您有权访问这些图像的生成,请将它们保存为无损 PNG!这些 JPG 伪影使得获得正确结果变得更加困难。例如,您的“黑”点只有一个像素实际上具有 (77, 77, 77) 的 RGB 值。因此,我省略了以编程方式查找“黑”点,并假定图像中心为点位置。

因为你有一些带有一些黄色点的红色线条,我通过减去绿色通道的一部分来修正红色通道以去除黄色。在进一步强调之后(红色线在红色通道中具有高值),新的红色通道如下所示:

在那个新的红色通道上,我使用某种 Laplace operator 来检测(红色)线。经过进一步处理后,结果是:

从那里开始,它只是使用 Otsu 的方法进行一些阈值处理以获得合适的二进制图像:

最后,我找到所有轮廓,并迭代它们。如果我找到一个内部(!)轮廓——请参阅 以获得对轮廓层次结构的广泛解释——其中包含“黑”点的位置,那一定是感兴趣的形状。因为你可能会从周围得到一些奇怪的、开放的轮廓,所以你需要坚持内部轮廓。此外,这里假设感兴趣的形状是闭合的。

提取出合适的轮廓后,您只需要设置合适的遮罩,例如将背景涂黑,或使用该遮罩的边界矩形裁剪图像:

完整代码如下:

import cv2
import numpy as np

# Read image, split color channels
img = cv2.imread('5aY7A.jpg')
b, g, r = cv2.split(img)

# Rectify red-ish lines (get rid of yellow-ish dots) by subtracting
# green channel from red channel
r = r - 0.5 * g
r[r < 0] = 0

# Emphasize red-ish lines
r **= 2
r = cv2.normalize(r, 0, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)

# Detection of red-ish lines by Laplace operator
r = cv2.Laplacian(r, cv2.CV_64F)
r = cv2.erode(r, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)))
r = cv2.GaussianBlur(r, (5, 5), 0)
r = cv2.normalize(r, 0, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)

# Mask red-ish lines
r = cv2.threshold(r, 10, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
r = cv2.morphologyEx(r, cv2.MORPH_CLOSE,
                     cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)))

# Detection of "black" dot location omitted here due to JPG artifacts...
dot = (916, 389)

# Find contours from masked red-ish lines
cnts, hier = cv2.findContours(r, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

# Find some inner(!) contour containing the "black dot"
cnt = None
for i, c in enumerate(cnts):
    if cv2.pointPolygonTest(c, dot, True) > 0 and hier[0, i, 3] != -1:
        cnt = c
        break

if cnt is None:
    print('Something went wrong, no contour found.')
else:
    mask = cv2.drawContours(np.zeros_like(r), [cnt], -1, 255, cv2.FILLED)
    output = cv2.bitwise_xor(img, np.zeros_like(img), mask=mask)
    cv2.imshow('Output', output)
    cv2.waitKey(0)

cv2.destroyAllWindows()
----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.19041-SP0
Python:        3.9.1
PyCharm:       2021.1.2
NumPy:         1.20.3
OpenCV:        4.5.2
----------------------------------------