首页 > 编程问答 >如何在 OpenCV 中检测部分被遮挡的圆形标记?

如何在 OpenCV 中检测部分被遮挡的圆形标记?

时间:2024-07-28 16:54:26浏览次数:9  
标签:python opencv computer-vision detection

我正在开发一个项目,涉及使用 OpenCV 检测地图上的圆形标记(图钉)。标记有时部分连接到街道,这使得使用标准轮廓过滤方法很难检测到它们。

我尝试了几种方法来改进检测,包括:

  • 形态操作:我使用了 cv2.morphologyEx、cv2.erode和 cv2.dilate 具有不同的内核大小。然而,这些方法要么错过了标记,要么导致更多误报。
  • 模板匹配:我尝试了 cv2.matchTemplate,但结果更糟,并且对于部分模糊的标记来说不可靠。
  • 颜色分割:我实现了颜色分割,但我担心不同图像中街道地图颜色的变化,这可能会影响结果的一致性。
import cv2
import numpy as np
from matplotlib import pyplot as plt

# Read the image
image = cv2.imread('Capture.jpg')

# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Apply thresholding to create a binary image
ret, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((3,3), np.uint8)
eroded = cv2.erode(thresh, kernel, iterations=1)
dilated = cv2.dilate(eroded, kernel, iterations=1)
# dilated = cv2.morphologyEx(thresh, cv2.MORPH_HITMISS, np.ones((3,3), np.uint8))

# Find contours
contours, hierarchy = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Debug: Display all detected contours
image_with_contours = image.copy()
cv2.drawContours(image_with_contours, contours, -1, (0, 255, 0), 1)

plt.figure(figsize=(12, 6))
plt.imshow(cv2.cvtColor(image_with_contours, cv2.COLOR_BGR2RGB))
plt.title('All Contours')
plt.show()

# Function to check if a contour is likely a marker pin based on circularity
def is_marker_pin(contour):
    area = cv2.contourArea(contour)
    perimeter = cv2.arcLength(contour, True)
    if perimeter == 0:  # To avoid division by zero
        return False
    circularity = 4 * np.pi * (area / (perimeter * perimeter))
    x, y, w, h = cv2.boundingRect(contour)
    aspect_ratio = float(w) / h
    return 50 < area < 2500 and 0.5 < aspect_ratio < 2.5 and 0.6 < circularity < 1.5

# Filter contours based on shape characteristics
marker_contours = [cnt for cnt in contours if is_marker_pin(cnt)]

# Calculate and print the centroid of each marker contour
centroids = []
for cnt in marker_contours:
    M = cv2.moments(cnt)
    if M['m00'] != 0:
        cx = int(M['m10'] / M['m00'])
        cy = int(M['m01'] / M['m00'])
        centroids.append((cx, cy))
    else:
        centroids.append((0, 0))

# Debug: Display only marker contours and their centroids
image_with_marker_contours = image.copy()
cv2.drawContours(image_with_marker_contours, marker_contours, -1, (0, 255, 0), 1)
for (cx, cy) in centroids:
    cv2.circle(image_with_marker_contours, (cx, cy), 5, (255, 0, 0), -1)

plt.figure(figsize=(12, 6))
plt.imshow(cv2.cvtColor(image_with_marker_contours, cv2.COLOR_BGR2RGB))
plt.title('Marker Contours with Centroids')
plt.show()

# Create a mask for the marker pins
mask = np.zeros_like(gray)
cv2.drawContours(mask, marker_contours, -1, (255), thickness=cv2.FILLED)

# Apply the mask to the original image
result = cv2.bitwise_and(image, image, mask=mask)

# Display the result
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.imshow(mask, cmap='gray')
plt.title('Mask')
plt.subplot(1, 2, 2)
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.title('Markers Isolated')
plt.show()

# Print the number of detected markers and their centroids
print(f"Number of detected markers: {len(marker_contours)}")
print("Centroids of the detected markers:")
for i, (cx, cy) in enumerate(centroids):
    print(f"Marker {i + 1}: ({cx}, {cy})")

Image i used in this project (Capture.jpg)

Image with the contours

我当前的问题是:

  • 部分连接到街道的标记没有被可靠地检测到.

如何修改我的方法或轮廓过滤标准以可靠地检测这些部分模糊的标记?我是否应该考虑任何其他技术或参数来提高检测精度?

任何建议或改进将不胜感激!


走在正确的轨道上,但需要对方法进行一些调整才能可靠地检测部分遮挡的圆形标记。形态操作和轮廓过滤的组合可以很好地解决这个问题,但关键在于微调和正确的技术组合。

以下是一些改进的方法,以及对现有代码的更改建议:

  1. 预处理:

  2. 自适应阈值化: 由于地图的不同部分可能具有不同的照明条件,因此请考虑使用自适应阈值化(如 cv2.adaptiveThreshold )而不是全局 cv2.threshold 。这将创建针对局部光照变化更稳健的二值图像。

  3. 形态学操作的顺序: 首先应用膨胀然后腐蚀(闭合操作)可以帮助关闭标记内的间隙,使其更像圆形。实验内核大小和迭代次数。 python kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

  4. 轮廓过滤:

  5. 圆度检查: 的圆度检查是一个很好的功能。为了使其对轻微变形更稳健,请考虑放宽圆度阈值。

  6. 纵横比检查: 纵横比检查也有帮助。但是,由于标记可能是部分遮挡的,因此放宽纵横比条件以允许更大范围的值可能会有用。
  7. 最小面积: 过滤掉小于一定阈值的轮廓,以消除噪声和小的误报。的代码中已经包含此内容。
  8. 轮廓逼近: 可以使用 cv2.approxPolyDP 用更少的顶点逼近轮廓。这可以帮助平滑由于部分遮挡而导致的任何凹凸不平的边缘。

  9. 霍夫圆变换:

  10. cv2.HoughCircles 除了基于轮廓的方法之外,还可以考虑使用霍夫圆变换 ( cv2.HoughCircles ) 直接检测圆。此方法对部分遮挡具有鲁棒性。但是,需要根据图像大小和预期标记大小仔细调整参数(尤其是最小距离和半径范围)。

  11. 代码改进:

  12. 循环优化: is_marker_pin 函数中,可以在计算圆度之前检查周长是否为零,以避免不必要的计算和潜在的零除错误。

修改后的代码:

import cv2
import numpy as np

# 读取图像
image = cv2.imread('Capture.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 自适应阈值化
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 2)

# 形态学操作
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

# 查找轮廓
contours, hierarchy = cv2.findContours(closing, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

marker_contours = []
for contour in contours:
    area = cv2.contourArea(contour)
    perimeter = cv2.arcLength(contour, True)
    if perimeter > 0:
        circularity = 4 * np.pi * (area / (perimeter * perimeter))
        x, y, w, h = cv2.boundingRect(contour)
        aspect_ratio = float(w) / h
        if 50 < area < 2500 and 0.4 < aspect_ratio < 2.5 and 0.5 < circularity < 1.5:
            marker_contours.append(contour)

# 绘制检测到的标记
image_with_markers = image.copy()
cv2.drawContours(image_with_markers, marker_contours, -1, (0, 255, 0), 2)

# 显示结果
cv2.imshow("Detected Markers", image_with_markers)
cv2.waitKey(0)
cv2.destroyAllWindows()

其他提示:

  • 尝试不同的参数组合,以找到最适合特定图像的组合。
  • 如果在不同环境中有多个图像,请考虑使用这些图像创建一个小型数据集,并使用它来微调参数和评估的方法。
  • 对于更高级的技术,可以探索基于深度学习的目标检测模型,例如 YOLO 或 Mask R-CNN,这些模型可以经过训练以检测复杂背景下的对象,即使是部分遮挡的对象。

请记住,没有一种万能的解决方案。可能需要尝试不同的方法和参数组合,以找到最适合特定应用程序的方法。

标签:python,opencv,computer-vision,detection
From: 78803325

相关文章

  • Python - Plotly Express - x 轴 xticks
    我有一个代码,我想用标签作为月份和年份的名称绘制x轴。但目前它正在x轴上绘制所有时间戳,如-代码片段是:fig=px.scatter(data_frame,x=data_frame.timestamp,y=data_frame.err_codes_integer,hover_name=data_frame.col3,......
  • 8:Python字符串的魔法属性
    test="alex"v=test.capitalize()#首字母的大写print(v)test1="alEx"v1=test1.casefold()#所有字母变小写print(v1)test2="alEx"v2=test2.center(20,"*")#设置宽度,并将内容居中,20代指总长度,*代指空白位置填充且只能填一个字符print(v2)test3="alexralexr"v3=te......
  • 如何在 Python 中创建正确显示素数的代码?
    素数是只能被自身和1整除的数。例如,数字5是素数,因为它只能被1整除和5.然而,数字6不是质数,因为它可以被整除通过2和3。编写一个名为is_prime的布尔函数,它接受一个整数作为参数如果参数是素数则返回true,否则返回false。使用程序中提示用户输入数字然后输......
  • 在 MySQL Workbench 中升级 python
    MySQLWorkbench中的python版本不断受到安全标记,因为它不是最新版本。我的电脑上有最新版本,但在MySQL文件中它似乎是旧版本。我怎样才能更新,使其与我的电脑版本相同?尝试看看是否可以更新python,但没有运气很遗憾,你无法直接升级MySQLWorkbench内置的Python版本......
  • Python科研武器库 - 文件/路径操作 - 判断路径是否存在
    使用场景:在科研中,用Python处理数据的一个核心目的是批量处理,批量处理节省了研究者大量的时间和精力,不然,还不如手动一个个地去处理。批量处理通常要求数据整体较为规整,能够进行统一的处理操作,但实际数据中总存在一些不规则的样本,甚至有些样本的命名都存在不规范,例如,整个数据集......
  • python刷题常用模板
    #=====================================素数筛Begin=====================================#MAXN=1000prime=[]isprime=[True]*(MAXN+1)defeuler():isprime[1]=Falseforiinrange(2,MAXN+1):ifisprime[i]:prime.append(i)......
  • [附开题]flask框架的全国汽车销售信息查询系统的设计与实现7m1w0(python+源码)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着中国汽车市场的蓬勃发展,汽车品牌的日益丰富以及消费者购车需求的多样化,汽车销售信息的准确性与时效性成为了市场关注的焦点。传统汽车......
  • [附开题]flask框架的校园停车场管理系统的设计与实现61m0e(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育的普及和校园规模的不断扩大,校园内车辆数量急剧增加,停车难问题日益凸显。传统的人工停车场管理模式已难以满足现代校园对高效......
  • [附开题]flask框架的校园学生管理系统s8h32(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着教育技术的不断进步和高校规模的不断扩大,传统的学生管理方式已难以满足现代校园管理的需求。学生数量激增、课程种类繁多、选课流程复......
  • [附开题]flask框架的校园疫情管理系统92tl0(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着新冠疫情的持续影响,校园作为人群密集、流动性大的场所,其疫情防控工作显得尤为重要。传统的手工记录和口头报告方式已难以满足当前复杂......