opencv - 广告牌角点检测
问题描述
我试图检测随机背景上的广告牌图像。我能够使用 SSD 定位广告牌,这给了我广告牌周围的近似边界框。现在我想为我的应用程序找到广告牌的确切角落。我尝试使用我遇到的不同策略,例如 Harris 角点检测(使用 Opencv),使用 Canny + 形态学操作 + 轮廓查找线的交点。下面给出了输出的详细信息。
哈里斯角点检测哈里斯角点检测 的伪代码如下:
img_patch_gray = np.float32(img_patch_gray)
harris_point = cv2.cornerHarris(img_patch_gray,2,3,0.04)
img_patch[harris_point>0.01*harris_point.max()]=[255,0,0]
plt.figure(figsize=IMAGE_SIZE)
plt.imshow(img_patch)
这里红点是Harris角点检测算法检测到的角点,兴趣点被绿色包围。
使用霍夫线检测 在这里我试图找到线的交点,然后选择点。类似于stackoverflow 链接的东西,但由于广告牌中有文本和图形,因此很难获得准确的线条。
基于轮廓 在这种方法中,我使用了精明的边缘检测器,然后是膨胀(3*3 内核),然后是轮廓。
bin_img = cv2.Canny(gray_img_patch,100,250)
bin_img = dilate(bin_img, 3)
plt.imshow(bin_img, cmap='gray')
(_,cnts, _) = cv2.findContours(bin_img.copy(),
cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:10]
cv2.drawContours(img_patch, [cnts[0]],0, (0,255,0), 1)
, . 我曾尝试使用 openCV 中的 approxPolyDp 函数,但它并不像预期的那样,因为它还可以通过四个点来近似更大或更小的轮廓,并且在某些图像中它可能不会在广告牌框架周围形成轮廓。
我已将 openCV 3.4 用于所有图像处理操作。可以在这里找到使用过的。请注意,此处讨论的图像仅用于说明目的,一般图像可以是任何广告牌。在此先感谢,任何帮助表示赞赏。
解决方案
这是一项非常困难的任务,因为图像包含大量噪声。您可以获得轮廓的近似值,但特定的角落会非常困难。我举了一个例子来说明我将如何做一个近似值。它可能不适用于其他图像。也许它会有所帮助或给你一个新的想法。干杯!
import cv2
import numpy as np
# Read the image
img = cv2.imread('billboard.png')
# Blur the image with a big kernel and then transform to gray colorspace
blur = cv2.GaussianBlur(img,(19,19),0)
gray = cv2.cvtColor(blur,cv2.COLOR_BGR2GRAY)
# Perform histogram equalization on the blur and then perform Otsu threshold
equ = cv2.equalizeHist(gray)
_, thresh = cv2.threshold(equ,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Perform opening on threshold with a big kernel (erosion followed by dilation)
kernel = np.ones((20,20),np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
# Search for contours and select the biggest one
_, contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
# Make a hull arround the contour and draw it on the original image
mask = np.zeros((img.shape[:2]), np.uint8)
hull = cv2.convexHull(cnt)
cv2.drawContours(mask, [hull], 0, (255,255,255),-1)
# Search for contours and select the biggest one again
_, thresh = cv2.threshold(mask,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
# Draw approxPolyDP on the image
epsilon = 0.008*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
cv2.drawContours(img, [cnt], 0, (0,255,0), 5)
# Display the image
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
推荐阅读
- android - 以编程方式执行 UI 事件,如 Android 应用程序中的点击事件
- .net - AzureDevops-.Net 项目分析与 sonarQube 错误
- java - 如何用两个分隔符拆分字符串并只保留其中一个?
- angular - Angular 5 - Angular 服务不在“模态”中显示数据
- python - 如果内容来自缓存,如何在烧瓶应用程序中查找
- c# - excel无法打开文件,因为文件格式或文件扩展名无效c#
- python - Python:删除除X之外的所有文件夹
- python - 用于 Python 应用程序的 Azure Application Insights 日志记录 - 显式设置异常属性
- c++ - 在单写多读的情况下,我们需要锁定 uint64_t 吗?
- javascript - 如何在父组件的多个位置渲染 React 组件的一部分(在另一个组件的中间渲染组件)