风痕天际 2024-10-21 21:58 采纳率: 66.7%
浏览 5

关于#opencv#的问题:识别空心图形总是出错

识别正确的效果是框住图形并写出它的颜色形状,但识别空心图形的时候标了两个框,且没有写出颜色形状。

import cv2
import numpy as np
import time

cv2.MORPH_ELLIPSE
cv2.MORPH_OPEN
cv2.MORPH_CLOSE

# 定义颜色范围(HSV 颜色空间)
lower_red = np.array([0, 43, 46])
upper_red = np.array([10, 255, 255])
lower_blue = np.array([100, 43, 46])
upper_blue = np.array([124, 255, 255])
# 黑色通常是低明度值区域,这里假设 HSV 中明度值小于 50
lower_black = np.array([0, 0, 0])
upper_black = np.array([180, 255, 50])

# 打开摄像头
cap = cv2.VideoCapture(0)
# 开启总动曝光
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0)

# 用以判断识别内容是否稳定
f_shape = ""
shape = ""
timer1 = 0
aspect_ratio = 0
is_running = True  # 新增变量,用于控制识别是否运行
history = []  # 用于存储历史识别结果

while True:
    # 读取键盘输入
    key = cv2.waitKey(1) & 0xFF
    if key == ord('s'):
        is_running = not is_running
        print(f"识别功能 {'开启' if is_running else '关闭'}")

    if not is_running:
        continue

    # 读取帧
    ret, frame = cap.read()
    if not ret:
        break

    # 转换为 HSV 颜色空间
    hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    # 根据颜色范围创建掩膜
    red_mask = cv2.inRange(hsv_frame, lower_red, upper_red)
    blue_mask = cv2.inRange(hsv_frame, lower_blue, upper_blue)
    black_mask = cv2.inRange(hsv_frame, lower_black, upper_black)

    # 合并颜色掩码
    combined_mask = cv2.bitwise_or(red_mask, cv2.bitwise_or(blue_mask, black_mask))

    # 形态学操作
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
    combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_OPEN, kernel)
    combined_mask = cv2.morphologyEx(combined_mask, cv2.MORPH_CLOSE, kernel)
    # 平衡亮度
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    average_brightness = cv2.mean(gray_frame)[0]
    if average_brightness < 50 or average_brightness > 200:
        alpha = 1.5 if average_brightness < 50 else 0.8
        frame = cv2.convertScaleAbs(frame, alpha=alpha, beta=0)

    # 查找轮廓
    contours, hierarchy = cv2.findContours(combined_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    # 先进行颜色判断
    for contour in contours:
        area = cv2.contourArea(contour)
        if area < 10000:  # 设置面积阈值,可根据实际情况调整
            continue
        # 获取轮廓的中心坐标
        M = cv2.moments(contour)
        if M["m00"]!= 0:
            cx = int(M["m10"] / M["m00"])
            cy = int(M["m01"] / M["m00"])
            color = ""
            pixel_color = hsv_frame[cy, cx]
            if np.all((lower_red <= pixel_color) & (pixel_color <= upper_red)):
                color = "Red"
            elif np.all((lower_blue <= pixel_color) & (pixel_color <= upper_blue)):
                color = "Blue"
            elif np.all((lower_black <= pixel_color) & (pixel_color <= upper_black)):
                color = "Black"
            if color:
                # 进行形状判断
                approx = cv2.approxPolyDP(contour, 0.02 * cv2.arcLength(contour, True), True)
                if len(approx) == 4:
                    x, y, w, h = cv2.boundingRect(approx)
                    aspect_ratio = float(w) / h
                    diagonal_length = np.sqrt(w * w + h * h)
                    # 更严格的正方形判断
                    if aspect_ratio >= 0.95 and aspect_ratio <= 1.2 and abs(diagonal_length - np.sqrt(2) * w) < 5:
                        if color == "Red":
                            shape = "Red hollow square"
                        elif color == "Blue":
                            shape = "Blue solid square"
                    elif aspect_ratio >= 1.4 and aspect_ratio <= 1.8:
                        if color == "Red":
                            shape = "Red solid rectangle"
                        elif color == "Blue":
                            shape = "Blue hollow rectangle"
                    else:
                        top_width = min(approx[0][0][0], approx[1][0][0]) - min(approx[2][0][0], approx[3][0][0])
                        bottom_width = max(approx[0][0][0], approx[1][0][0]) - max(approx[2][0][0], approx[3][0][0])
                        height = h
                        if top_width > bottom_width and top_width!= 0:
                            if height / top_width < 0.8:
                                if color == "Red":
                                    shape = "Red hollow lower trapezoid"
                                elif color == "Blue":
                                    shape = "Blue solid lower trapezoid"
                                else:
                                    shape = "Lower Trapezoid"
                        elif top_width < bottom_width and bottom_width!= 0:
                            if height / bottom_width < 0.8:
                                if color == "Red":
                                    shape = "Red solid upper trapezoid"
                                elif color == "Blue":
                                    shape = "Blue hollow upper trapezoid"
                else:
                    # 更严格的圆形判断
                    (x, y), radius = cv2.minEnclosingCircle(contour)
                    center = (int(x), int(y))
                    radius = int(radius)
                    area_circle = np.pi * radius * radius
                    if abs(area - area_circle) < 0.1 * area:
                        if color == "Blue":
                            shape = "Blue solid circle"
                        elif color == "Black":
                            shape = "Black solid circle"
                cv2.putText(frame, shape, (cx - 50, cy), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 254), 2)
                history.append(shape)
                if len(history) > 10:
                    history.pop(0)
                if all(result == history[0] for result in history):
                    f_shape = history[0]
                    timer1 += 1
                else:
                    f_shape = ""

        # 用方框框住识别内容
        x, y, w, h = cv2.boundingRect(contour)
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

    # 显示结果
    cv2.imshow('Frame', frame)

    if timer1 == 30:  # 增加连续判断次数
        print(f_shape)
        timer1 = 0

    # 按下 'q' 键退出
    if key == ord('q'):
        break

    print(aspect_ratio)

# 释放资源
cap.release()
cv2.destroyAllWindows()

识别空心图形:

img


识别实心图形:

img

  • 写回答

3条回答 默认 最新

  • 无疆76 2024-10-21 22:00
    关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    根据您提供的问题和代码,我注意到在识别空心图形时可能出现的问题是轮廓近似处理和形状判断的部分。以下是可能的问题和建议的解决方案:

    1. 轮廓近似的问题: 在识别图形的轮廓时,您使用了cv2.approxPolyDP()函数来近似轮廓。对于空心图形,其轮廓可能更复杂,单一的近似方法可能无法准确识别。您可能需要调整近似函数的参数或者尝试不同的方法以更准确地捕捉空心图形的轮廓。
    2. 形状判断的逻辑: 在判断形状时,您基于长宽比和一些特定的条件来判断图形的类型。对于空心图形,由于其轮廓的复杂性,可能需要更精细的逻辑来判断其形状。您可以考虑增加更多的条件或者改进现有的条件以更准确地识别空心图形。
    3. 颜色判断的问题: 在您的代码中,颜色判断似乎是基于像素点的HSV值来确定的。这可能对于颜色均匀的区域有效,但对于边缘或复杂纹理的区域可能不准确。您可以考虑使用其他方法来确定颜色,例如基于区域的平均颜色或基于颜色直方图的匹配。
    4. 形态学操作的顺序: 您在代码中使用了形态学开操作和闭操作来处理图像。对于某些情况,调整这些操作的顺序或参数可能会影响结果。您可以尝试调整这些参数或顺序以改善识别效果。
    5. 连续的识别结果判断: 您在代码中使用了history列表来存储连续的识别结果,并基于这些结果进行判断。这是一个很好的方法,但在处理空心图形时,可能需要更精细的逻辑来处理偶尔的误识别。

    针对上述问题,您可以尝试以下改进:

    • 调整轮廓近似函数的参数或尝试不同的轮廓检测方法。
    • 增加或修改形状判断的逻辑以更准确地识别空心图形。
    • 考虑使用其他方法来确定颜色或纹理。
    • 调整形态学操作的参数或顺序以改善图像质量。

    由于问题的复杂性,可能需要多次尝试和调整才能找到最佳的解决方案。希望上述建议能帮助您解决问题。

    评论

报告相同问题?

问题事件

  • 创建了问题 10月21日

悬赏问题

  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀