25电赛e题杂乱环境稳定识别矩形框(附源码)

发布于:2025-08-02 ⋅ 阅读:(13) ⋅ 点赞:(0)

识别并跟踪矩形目标

识别视频中符合矩形轮廓的目标区域,并标记中心点位置。

实现思路

  1. **图像预处理:灰度 + 二值化
  2. **闭运算消除孔洞
  3. 二值化处理
  4. 查找并筛选矩形轮廓
  5. 解算中心点
  6. 目标筛选
  7. 结果绘制

环境

使用 OpenCV 和 python:

图像预处理:灰度 + 二值化

将读取到的帧转换为灰度图,再进行阈值二值化处理。
这里采用 反向二值化(白底黑物体),便于检测黑色矩形:

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 120, 255, cv2.THRESH_BINARY_INV)

在这里插入图片描述

闭运算消除孔洞

closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_RECT, (50, 50)))
  • 闭运算 : 膨胀后腐蚀,可去除图中小孔洞和断裂,提高矩形轮廓连通性。
    在这里插入图片描述
    闭运算后图像(轮廓更完整)

查找并筛选矩形轮廓

使用 cv2.findContours() 提取所有闭合轮廓,再筛选出“近似矩形”的轮廓:

is_rect, approx = is_approx_rect(cnt)
def is_approx_rect(contour, epsilon_factor=0.02):     peri = cv2.arcLength(contour, True)     approx = cv2.approxPolyDP(contour, epsilon_factor * peri, True)     return (4 <= len(approx) <= 5 and cv2.isContourConvex(approx)), approx
  • 调用 cv2.approxPolyDP() 将轮廓多边形逼近
  • 条件:点数为 4~5 且轮廓是凸的

在这里插入图片描述

                 保留下的近似矩形轮廓图像

解算中心点

通过轮廓的几何矩获取中心点坐标:

def calc_center(approx):     M = cv2.moments(approx)     if M["m00"] == 0:         return None     return int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])

目标筛选(追踪最近矩形)

  • 第一帧:选取面积最大的矩形
  • 后续帧:优先选取与上一帧中心点距离最近的矩形
  • 距离在 50 像素内的多个候选中,选择面积最大的
    距离计算函数如下:
cv2.drawContours(display_frame, [approx], -1, (0, 0, 255), 5)
cv2.circle(display_frame, center, 7, (0, 0, 255), -1)

结果绘制

cv2.drawContours(display_frame, [approx], -1, (0, 0, 255), 5) cv2.circle(display_frame, center, 7, (0, 0, 255), -1)

完整cv代码

创作不易,点个赞再走哦

import cv2
import numpy as np

def is_approx_rect(contour, epsilon_factor=0.02):
    peri = cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, epsilon_factor * peri, True)
    return (4 <= len(approx) <= 5 and cv2.isContourConvex(approx)), approx

def calc_center(approx):
    M = cv2.moments(approx)
    if M["m00"] == 0:
        return None
    return int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])

def distance(p1, p2):
    return np.sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)

def main():
    cap = cv2.VideoCapture("222.mp4")
    if not cap.isOpened():
        print("打开视频失败")
        return

    prev_center = None

    while True:
        ret, frame = cap.read()
        if not ret:
            break

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        _, binary = cv2.threshold(gray, 120, 255, cv2.THRESH_BINARY_INV)
        closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_RECT, (50, 50)))

        contours_data = cv2.findContours(closed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        contours = contours_data[1] if len(contours_data) == 3 else contours_data[0]

        candidates = []
        for cnt in contours:
            is_rect, approx = is_approx_rect(cnt)
            if is_rect:
                center = calc_center(approx)
                if center:
                    candidates.append((approx, center, cv2.contourArea(approx)))

        if not candidates:
            selected = None
        elif prev_center is None:
            selected = max(candidates, key=lambda x: x[2])
        else:
            candidates.sort(key=lambda x: distance(x[1], prev_center))
            top_n = [candidates[0]]
            for c in candidates[1:]:
                if distance(c[1], prev_center) - distance(candidates[0][1], prev_center) < 50:
                    top_n.append(c)
                else:
                    break
            selected = max(top_n, key=lambda x: x[2])

        display_frame = frame.copy()
        contour_img = np.zeros_like(frame)

        if selected:
            approx, center, _ = selected
            cv2.drawContours(display_frame, [approx], -1, (0, 0, 255), 5)
            cv2.circle(display_frame, center, 7, (0, 0, 255), -1)
            cv2.drawContours(contour_img, [approx], -1, (0, 255, 0), 3)
            prev_center = center
        else:
            prev_center = None

        cv2.imshow("原视频", display_frame)
        cv2.imshow("二值化", binary)
        cv2.imshow("闭运算", closed)
        cv2.imshow("轮廓", contour_img)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()