如何检测形状的轮廓然后从图像中裁剪形状?
How to detect the outline of a shape and then crop the shape from image?
- 我试图只保留图像的一部分 由批次 #17 中的 orange/greenish 行 界定。
如您所见,形状相当不标准,而且我是图像处理的新手,所以到目前为止我的方法都是蛮力的并且容易出错。
我需要执行此操作的每张图像在我要裁剪的形状中心都有一个黑点(rgb
of (77,77,77))我的主播
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)
- 我的代码仅适用于右侧朝上的矩形(其中大部分是),但是当涉及到示例中的内容时它会失败。
- 我考虑过使用到目前为止编写的代码 'walk the line' 从通过 9x9 像素阵列提供的像素位置开始,并且只选择那些:
- 之前没有选择
- 匹配预先记录的颜色值
- 最接近锚点像素位置
但是在这个例子中有更多的 rgb
颜色值,甚至在我感兴趣的行中有一些空洞。
有没有办法获取中心黑点边界线的坐标,然后在记录所有坐标后裁剪图像?
提前致谢。
首先:如果您有权访问这些图像的生成,请将它们保存为无损 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
----------------------------------------
- 我试图只保留图像的一部分 由批次 #17 中的 orange/greenish 行 界定。
如您所见,形状相当不标准,而且我是图像处理的新手,所以到目前为止我的方法都是蛮力的并且容易出错。
我需要执行此操作的每张图像在我要裁剪的形状中心都有一个黑点(
rgb
of (77,77,77))我的主播
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)
- 我的代码仅适用于右侧朝上的矩形(其中大部分是),但是当涉及到示例中的内容时它会失败。
- 我考虑过使用到目前为止编写的代码 'walk the line' 从通过 9x9 像素阵列提供的像素位置开始,并且只选择那些:
- 之前没有选择
- 匹配预先记录的颜色值
- 最接近锚点像素位置
但是在这个例子中有更多的
rgb
颜色值,甚至在我感兴趣的行中有一些空洞。有没有办法获取中心黑点边界线的坐标,然后在记录所有坐标后裁剪图像?
提前致谢。
首先:如果您有权访问这些图像的生成,请将它们保存为无损 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
----------------------------------------