查找包含内容的区域并获取其边界矩形
Find area with content and get its bouding rect
我正在使用 OpenCV 4 - python 3 - 在黑白图像中查找特定区域。
此区域不是 100% 填充的形状。白线之间可能会有一些空隙。
这是我开始处理的基础图像:
这是我期望的矩形 - 用 photoshop 制作 -:
我用 hough 变换线得到的结果 - 不准确 -
基本上,我从第一张图片开始,希望能找到您在第二张图片中看到的内容。
知道如何获取第二张图片的矩形吗?
在Python/OpenCV中,您可以使用形态学将图像的所有白色部分连接起来,然后得到外部轮廓。请注意,我已经修改了您的图片,以从您的屏幕快照中删除顶部和底部的部分。
import cv2
import numpy as np
# read image as grayscale
img = cv2.imread('blackbox.png')
# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# threshold
_,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)
# apply close to connect the white areas
kernel = np.ones((75,75), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# get contours (presumably just one around the outside)
result = img.copy()
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
x,y,w,h = cv2.boundingRect(cntr)
cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 2)
# show thresh and result
cv2.imshow("thresh", thresh)
cv2.imshow("Bounding Box", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
# save resulting images
cv2.imwrite('blackbox_thresh.png',thresh)
cv2.imwrite('blackbox_result.png',result)
输入:
形态学后的图像:
结果:
我想介绍一种可能比 only using NumPy's nonzero
函数中的解决方案计算成本更低的方法。基本上,找到两个轴的所有非零索引,然后获得最小值和最大值。由于我们这里有二进制图像,所以这种方法效果很好。
我们来看看下面的代码:
import cv2
import numpy as np
# Read image as grayscale; threshold to get rid of artifacts
_, img = cv2.threshold(cv2.imread('images/LXSsV.png', cv2.IMREAD_GRAYSCALE), 0, 255, cv2.THRESH_BINARY)
# Get indices of all non-zero elements
nz = np.nonzero(img)
# Find minimum and maximum x and y indices
y_min = np.min(nz[0])
y_max = np.max(nz[0])
x_min = np.min(nz[1])
x_max = np.max(nz[1])
# Create some output
output = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.rectangle(output, (x_min, y_min), (x_max, y_max), (0, 0, 255), 2)
# Show results
cv2.imshow('img', img)
cv2.imshow('output', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
我从fmw42的答案中借用了裁剪后的图像作为输入,我的输出应该是相同的(或最相似的):
希望(也)有所帮助!
此处对 稍作修改。将所需区域连接成单个轮廓的想法非常相似,但是您可以直接找到边界矩形,因为只有一个对象。使用相同的裁剪输入图像,结果如下。
我们也可以选择提取 ROI
import cv2
# Grayscale, threshold, and dilate
image = cv2.imread('3.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Connect into a single contour and find rect
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations=1)
x,y,w,h = cv2.boundingRect(dilate)
ROI = original[y:y+h,x:x+w]
cv2.rectangle(image, (x, y), (x+w, y+h), (36, 255, 12), 2)
cv2.imshow('image', image)
cv2.imshow('ROI', ROI)
cv2.waitKey()
我正在使用 OpenCV 4 - python 3 - 在黑白图像中查找特定区域。
此区域不是 100% 填充的形状。白线之间可能会有一些空隙。
这是我开始处理的基础图像:
这是我期望的矩形 - 用 photoshop 制作 -:
我用 hough 变换线得到的结果 - 不准确 -
基本上,我从第一张图片开始,希望能找到您在第二张图片中看到的内容。
知道如何获取第二张图片的矩形吗?
在Python/OpenCV中,您可以使用形态学将图像的所有白色部分连接起来,然后得到外部轮廓。请注意,我已经修改了您的图片,以从您的屏幕快照中删除顶部和底部的部分。
import cv2
import numpy as np
# read image as grayscale
img = cv2.imread('blackbox.png')
# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# threshold
_,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)
# apply close to connect the white areas
kernel = np.ones((75,75), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# get contours (presumably just one around the outside)
result = img.copy()
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
x,y,w,h = cv2.boundingRect(cntr)
cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 2)
# show thresh and result
cv2.imshow("thresh", thresh)
cv2.imshow("Bounding Box", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
# save resulting images
cv2.imwrite('blackbox_thresh.png',thresh)
cv2.imwrite('blackbox_result.png',result)
输入:
形态学后的图像:
结果:
我想介绍一种可能比 nonzero
函数中的解决方案计算成本更低的方法。基本上,找到两个轴的所有非零索引,然后获得最小值和最大值。由于我们这里有二进制图像,所以这种方法效果很好。
我们来看看下面的代码:
import cv2
import numpy as np
# Read image as grayscale; threshold to get rid of artifacts
_, img = cv2.threshold(cv2.imread('images/LXSsV.png', cv2.IMREAD_GRAYSCALE), 0, 255, cv2.THRESH_BINARY)
# Get indices of all non-zero elements
nz = np.nonzero(img)
# Find minimum and maximum x and y indices
y_min = np.min(nz[0])
y_max = np.max(nz[0])
x_min = np.min(nz[1])
x_max = np.max(nz[1])
# Create some output
output = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.rectangle(output, (x_min, y_min), (x_max, y_max), (0, 0, 255), 2)
# Show results
cv2.imshow('img', img)
cv2.imshow('output', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
我从fmw42的答案中借用了裁剪后的图像作为输入,我的输出应该是相同的(或最相似的):
希望(也)有所帮助!
此处对
我们也可以选择提取 ROI
import cv2
# Grayscale, threshold, and dilate
image = cv2.imread('3.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Connect into a single contour and find rect
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations=1)
x,y,w,h = cv2.boundingRect(dilate)
ROI = original[y:y+h,x:x+w]
cv2.rectangle(image, (x, y), (x+w, y+h), (36, 255, 12), 2)
cv2.imshow('image', image)
cv2.imshow('ROI', ROI)
cv2.waitKey()