前言

Python OpenCV图像方框识别
Python Version: 3.11.9

引用库

numpy==1.26.4
opencv-python==4.9.0.80

安装命令:

pip install numpy==1.26.4
pip install opencv-python==4.9.0.80

实现代码

import cv2 as cv
import numpy as np

def find_and_draw_boxes(frame, max_depth=3, current_depth=1, offsetWidth = 0):
    if current_depth > max_depth:  # 递归基准情形
        return

    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)  # 将彩色图像转换为灰度图像
    blurred = cv.GaussianBlur(gray, (5, 5), 0)  # 对灰度图像进行高斯模糊
    edged = cv.Canny(blurred, 75, 200)  # 使用Canny边缘检测算法找到图像中的边缘

    contours, _ = cv.findContours(edged.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)  # 查找轮廓

    if not contours:  # 如果没有找到轮廓,直接返回
        return

    for c in contours:
        area = cv.contourArea(c)  # 计算轮廓的面积
        if area < 500:  # 面积过滤
            continue

        # 获取最小的外接旋转矩形
        rect = cv.minAreaRect(c)
        box = cv.boxPoints(rect)  # 获取旋转矩形的四个顶点坐标
        box = np.intp(box)  # 将坐标值取整

        aspect_ratio = float(rect[1][0])/float(rect[1][1])  # 计算长宽比
        
        # 长宽比过滤
        if aspect_ratio < 0.5 or aspect_ratio > 2:
            continue

        # 绘制旋转矩形
        drawer = box.copy()
        if current_depth % 2 == 1:
            drawer[0][0] -= offsetWidth
            drawer[0][1] -= offsetWidth
            drawer[1][0] += offsetWidth
            drawer[1][1] -= offsetWidth
            drawer[2][0] += offsetWidth
            drawer[2][1] += offsetWidth
            drawer[3][0] -= offsetWidth
            drawer[3][1] += offsetWidth
        else:
            drawer[0][0] += offsetWidth
            drawer[0][1] += offsetWidth
            drawer[1][0] -= offsetWidth
            drawer[1][1] += offsetWidth
            drawer[2][0] -= offsetWidth
            drawer[2][1] -= offsetWidth
            drawer[3][0] += offsetWidth
            drawer[3][1] -= offsetWidth
        cv.drawContours(frame, [drawer], 0, (0, 0, 255), 2)  # 在原始图像上绘制旋转矩形
        
        # 计算并绘制中心的十字架
        cx, cy = np.mean(box, axis=0)
        cv.line(frame, (int(cx - 10), int(cy)), (int(cx + 10), int(cy)), (0, 0, 255), 2)
        cv.line(frame, (int(cx), int(cy - 10)), (int(cx), int(cy + 10)), (0, 0, 255), 2)

        # 为下一层裁剪图像
        if 0 < rect[1][1] < frame.shape[1] and 0 < rect[1][0] < frame.shape[0]: 
            minX = min(box[:,0])
            maxX = max(box[:,0])
            minY = min(box[:,1])
            maxY = max(box[:,1])
            roi = frame[max(int(minY) + offsetWidth + 2,0):min(int(maxY) - offsetWidth + 2,frame.shape[0]), max(int(minX) + offsetWidth + 2,0):min(int(maxX) - offsetWidth + 2,frame.shape[1])]
            find_and_draw_boxes(roi, max_depth, current_depth + 1, offsetWidth)  # 递归调用函数处理下一层图像
        break

# 打开摄像头
cap = cv.VideoCapture(0)

while True:
    ret, frame = cap.read()  # 读取摄像头捕获的每一帧图像
    if not ret:
        break

    find_and_draw_boxes(frame, max_depth=4, offsetWidth=5)  # 调用函数处理图像
    cv.imshow('Frame with Rotated Boxes', frame)  # 显示处理后的图像
    if cv.waitKey(1) & 0xFF == ord('q'):  # 如果按下'q'键,退出循环
        break

cap.release()  # 释放摄像头资源
cv.destroyAllWindows()  # 关闭所有窗口

温馨提示:注释由人工智能提供