虽然这是旧的,但这至少可以帮助任何其他有同样问题的人。除了 nathancy 的答案之外,这应该可以让您更准确地找到非常模糊的角落:
伪代码
- 根据需要调整大小,但没有必要
- 转换为灰度
- 应用模糊或双边过滤
- 应用 Otsu 阈值获得二值图像
- 找出构成矩形的轮廓
- 将轮廓近似为矩形
- 近似点是矩形的角!
执行此操作的代码
- 调整大小:
该函数采用新的宽度和高度,因此我只是将图像制作为当前尺寸的 5 倍。
img = cv2.resize(img,(img.shape[0] * 5,img.shape[1] * 5))
- 灰度转换:
只是从 OpenCV 的默认 BGR 色彩空间转换为灰度。
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- 模糊/双边过滤:
如果需要,您可以使用任意数量的技术进一步柔化此图像。也许是高斯模糊,或者如 nathancy 建议的那样,是双边滤波器,但两者都不需要。
# choose one,or a different function
blurred = cv2.GaussianBlur(gray,(5,5),0)
blurred = cv2.bilateralFilter(gray,9,75,75)
- 大津的门槛
使用阈值函数,传递 0
和 255
作为阈值和最大值的参数。我们传入 0
是因为我们使用了阈值技术 cv2.THRESH_OTSU
,它为我们确定了值。这与阈值本身一起返回,但我只是将其设置为 _
,因为我们不需要它。
_,thresh = cv2.threshold(blurred,255,cv2.THRESH_OTSU)
- 寻找轮廓
轮廓的内容比我在这里解释的要多得多,请随时查看 docs。
对我们来说重要的事情是它返回一个轮廓列表和一个层次结构。我们不需要层次结构所以它被设置为 _
,我们只需要它找到的单个轮廓,所以我们设置 contour = contours[0]
。
contours,_ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0]
- 近似轮廓为矩形
首先我们计算轮廓的周长。然后我们用cv2.approxPolyDP
函数对其进行近似,并用0.05 * perimeter
告诉它原始曲线与其近似值之间的最大距离。您可能需要使用小数点以获得更好的近似值。
approx
是一个形状为 (num_points,1,2)
的 numpy 数组,在本例中为 (4,2)
,因为它找到了矩形的 4 个角。
请在docs中阅读更多内容。
perimeter = cv2.arcLength(contour,True)
approx = cv2.approxPolyDP(contour,0.05 * perimeter,True)
- 找到你的倾斜矩形!
你已经完成了!这就是你如何绘制这些点。首先,我们通过循环绘制圆圈,然后获取 x 和 y 坐标,然后绘制矩形本身。
# drawing points
for point in approx:
x,y = point[0]
cv2.circle(img,(x,y),3,(0,0),-1)
# drawing skewed rectangle
cv2.drawContours(img,[approx],-1,0))
完成代码
import cv2
img = cv2.imread("rect.png")
img = cv2.resize(img,img.shape[1] * 5))
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blurred = cv2.bilateralFilter(gray,75)
_,cv2.THRESH_OTSU)
contours,cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0]
perimeter = cv2.arcLength(contour,True)
for point in approx:
x,-1)
cv2.drawContours(img,0))
,
要检测拐角,可以使用cv2.goodFeaturesToTrack()
。该函数有四个参数
corners = cv2.goodFeaturesToTrack(image,maxCorners,qualityLevel,minDistance)
-
image
-输入8位或浮点32位灰度单通道图像
-
maxCorners
-要返回的最大拐角数
-
qualityLevel
-0-1之间的最小可接受角点质量等级。低于质量级别的所有角落
-
minDistance
-拐角之间的最小欧几里得距离
现在我们知道如何找到角,我们必须找到旋转的矩形并应用该函数。这是一种方法:
我们首先放大图像,转换为灰度,应用双边滤镜,然后使用Otsu的阈值获得二进制图像
接下来,我们通过使用cv2.findContours()
查找轮廓来找到变形的矩形,然后获得以绿色突出显示的旋转边界框。我们将边界框绘制到蒙版上
现在有了遮罩,我们只需使用cv2.goodFeaturesToTrack()
在遮罩上找到角点
这是原始输入图像上的结果以及每个角的(x,y)
坐标
角点
(377.0,375.0)
(81.0,344.0)
(400.0,158.0)
(104.0,127.0)
代码
import cv2
import numpy as np
import imutils
# Resize image,blur,and Otsu's threshold
image = cv2.imread('1.png')
resize = imutils.resize(image,width=500)
mask = np.zeros(resize.shape,dtype=np.uint8)
gray = cv2.cvtColor(resize,cv2.COLOR_BGR2GRAY)
blur = cv2.bilateralFilter(gray,75)
thresh = cv2.threshold(blur,cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
# Find distorted rectangle contour and draw onto a mask
cnts = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
rect = cv2.minAreaRect(cnts[0])
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(resize,[box],(36,12),2)
cv2.fillPoly(mask,(255,255))
# Find corners on the mask
mask = cv2.cvtColor(mask,cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(mask,maxCorners=4,qualityLevel=0.5,minDistance=150)
for corner in corners:
x,y = corner.ravel()
cv2.circle(resize,8,(155,20,255),-1)
print("({},{})".format(x,y))
cv2.imshow('resize',resize)
cv2.imshow('thresh',thresh)
cv2.imshow('mask',mask)
cv2.waitKey()