Python:如何从图像中切出具有特定颜色的区域(OpenCV,Numpy)
Posted
技术标签:
【中文标题】Python:如何从图像中切出具有特定颜色的区域(OpenCV,Numpy)【英文标题】:Python: How to cut out an area with specific color from image (OpenCV, Numpy) 【发布时间】:2020-07-01 23:37:26 【问题描述】:所以我一直在尝试编写一个 Python 脚本,该脚本将图像作为输入,然后用特定的背景颜色切出一个矩形。但是,对我的编码技能造成问题的是,矩形不是在每个图像中的固定位置(位置将是随机的)。
我不太了解如何管理 numpy 函数。我还阅读了一些关于 OpenCV 的内容,但我对它完全陌生。到目前为止,我只是通过“.crop”函数裁剪图像,但随后我将不得不使用固定值。
这就是输入图像的外观,现在我想检测黄色矩形的位置,然后将图像裁剪成它的大小。
非常感谢您的帮助,在此先感谢。
编辑:@MarkSetchell 的方法效果很好,但发现不同测试图片的问题。另一张图片的问题是图片的顶部和底部有2个颜色相同的小像素,这会导致错误或裁剪不好。
【问题讨论】:
我认为这对于 Stack Overflow 来说太宽泛了,而且很可能离题。请参阅How to Ask、help center。 我已经更新了我的答案 - 请再看看。 欣赏!非常感谢 【参考方案1】:在 opencv 中你可以使用 inRange。这基本上使您指定范围内的任何颜色为白色,其余为黑色。这样所有的黄色都会变成白色。
这里是文档:https://docs.opencv.org/3.4/da/d97/tutorial_threshold_inRange.html
【讨论】:
谢谢。不幸的是,我没有成功【参考方案2】:更新答案
我已经更新了我的答案,以应对与黄色框颜色相同的嘈杂异常像素点。这可以通过首先在图像上运行 3x3 中值滤波器来去除斑点:
#!/usr/bin/env python3
import numpy as np
from PIL import Image, ImageFilter
# Open image and make into Numpy array
im = Image.open('image.png').convert('RGB')
na = np.array(im)
orig = na.copy() # Save original
# Median filter to remove outliers
im = im.filter(ImageFilter.MedianFilter(3))
# Find X,Y coordinates of all yellow pixels
yellowY, yellowX = np.where(np.all(na==[247,213,83],axis=2))
top, bottom = yellowY[0], yellowY[-1]
left, right = yellowX[0], yellowX[-1]
print(top,bottom,left,right)
# Extract Region of Interest from unblurred original
ROI = orig[top:bottom, left:right]
Image.fromarray(ROI).save('result.png')
原答案
好的,你的黄色是rgb(247,213,83)
,所以我们要找到所有黄色像素的X,Y坐标:
#!/usr/bin/env python3
from PIL import Image
import numpy as np
# Open image and make into Numpy array
im = Image.open('image.png').convert('RGB')
na = np.array(im)
# Find X,Y coordinates of all yellow pixels
yellowY, yellowX = np.where(np.all(na==[247,213,83],axis=2))
# Find first and last row containing yellow pixels
top, bottom = yellowY[0], yellowY[-1]
# Find first and last column containing yellow pixels
left, right = yellowX[0], yellowX[-1]
# Extract Region of Interest
ROI=na[top:bottom, left:right]
Image.fromarray(ROI).save('result.png')
您可以使用 ImageMagick 在终端中执行完全相同的操作:
# Get trim box of yellow pixels
trim=$(magick image.png -fill black +opaque "rgb(247,213,83)" -format %@ info:)
# Check how it looks
echo $trim
251x109+101+220
# Crop image to trim box and save as "ROI.png"
magick image.png -crop "$trim" ROI.png
如果仍在使用 ImageMagick v6 而不是 v7,请将 magick
替换为 convert
。
【讨论】:
感谢您的帮助!试了一下,效果很好——至少对于我上传的示例图片。但我用其他图片对其进行了测试,由于某种原因,我得到了一个 "ValueError: tile cannot extend outside image" forImage.fromarray(ROI).save('result.png')
@Karlo 您永远不应该期望 Stack Overflow 中的答案涵盖您未发布的案例。问题应该是具体的而不是笼统的。您可以尝试发布更多图片,但请确保展示您为解决问题所做的努力(发布您的代码)。
真实的话,应该考虑一下 - 对不起。我目前正试图弄清楚问题到底出在哪里,因为来自@MarkSetchell 的代码确实适用于我的大多数测试图像,但有一些不起作用。我想是因为其他同色的小像素【参考方案3】:
我看到的是侧面和顶部的深灰色和浅灰色区域、一个白色区域和一个黄色矩形,白色区域内有灰色三角形。
我建议的第一阶段是将图像从 RGB 色彩空间转换为 HSV 色彩空间。 HSV空间中的S色彩通道,是“色彩饱和度通道”。 所有无色(灰色/黑色/白色)都是零,黄色像素在 S 通道中高于零。
下一阶段:
在 S 通道上应用阈值(将其转换为二值图像)。 黄色像素变为 255,其他像素变为 0。 在 thresh 中查找轮廓(仅查找外部轮廓 - 仅矩形)。 反转矩形内像素的极性。 灰色三角形变为 255,其他像素为零。 在 thresh 中查找轮廓 - 查找灰色三角形。代码如下:
import numpy as np
import cv2
# Read input image
img = cv2.imread('img.png')
# Convert from BGR to HSV color space
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Get the saturation plane - all black/white/gray pixels are zero, and colored pixels are above zero.
s = hsv[:, :, 1]
# Apply threshold on s - use automatic threshold algorithm (use THRESH_OTSU).
ret, thresh = cv2.threshold(s, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Find contours in thresh (find only the outer contour - only the rectangle).
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # [-2] indexing takes return value before last (due to OpenCV compatibility issues).
# Mark rectangle with green line
cv2.drawContours(img, contours, -1, (0, 255, 0), 2)
# Assume there is only one contour, get the bounding rectangle of the contour.
x, y, w, h = cv2.boundingRect(contours[0])
# Invert polarity of the pixels inside the rectangle (on thresh image).
thresh[y:y+h, x:x+w] = 255 - thresh[y:y+h, x:x+w]
# Find contours in thresh (find the triangles).
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2] # [-2] indexing takes return value before last (due to OpenCV compatibility issues).
# Iterate triangle contours
for c in contours:
if cv2.contourArea(c) > 4: # Ignore very small contours
# Mark triangle with blue line
cv2.drawContours(img, [c], -1, (255, 0, 0), 2)
# Show result (for testing).
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
HSV色彩空间中的S色彩通道:
thresh
- 阈值后的 S:
thresh
矩形极性反转后:
结果(矩形和三角形被标记):
更新:
如果背景上有一些彩色点,您可以裁剪最大的彩色轮廓:
import cv2
import imutils # https://pypi.org/project/imutils/
# Read input image
img = cv2.imread('img2.png')
# Convert from BGR to HSV color space
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Get the saturation plane - all black/white/gray pixels are zero, and colored pixels are above zero.
s = hsv[:, :, 1]
cv2.imwrite('s.png', s)
# Apply threshold on s - use automatic threshold algorithm (use THRESH_OTSU).
ret, thresh = cv2.threshold(s, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Find contours
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = imutils.grab_contours(cnts)
# Find the contour with the maximum area.
c = max(cnts, key=cv2.contourArea)
# Get bounding rectangle
x, y, w, h = cv2.boundingRect(c)
# Crop the bounding rectangle out of img
out = img[y:y+h, x:x+w, :].copy()
结果:
【讨论】:
感谢您的帮助!感谢您的努力 您可以裁剪最大的彩色轮廓。我更新了我的帖子以上是关于Python:如何从图像中切出具有特定颜色的区域(OpenCV,Numpy)的主要内容,如果未能解决你的问题,请参考以下文章