25电赛e题杂乱环境稳定识别矩形框(附源码)
识别并跟踪矩形目标
识别视频中符合矩形轮廓的目标区域,并标记中心点位置。
实现思路
- **图像预处理:灰度 + 二值化
- **闭运算消除孔洞
- 二值化处理
- 查找并筛选矩形轮廓
- 解算中心点
- 目标筛选
- 结果绘制
环境
使用 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)
- 红色画出识别轮廓
- 红点标记中心点位置
最终效果
电赛e题,杂乱环境稳定识别,-哔哩哔哩
完整cv代码
创作不易,点个赞再走哦
import cv2
import numpy as npdef 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)), approxdef calc_center(approx):M = cv2.moments(approx)if M["m00"] == 0:return Nonereturn 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("打开视频失败")returnprev_center = Nonewhile True:ret, frame = cap.read()if not ret:breakgray = 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 = Noneelif 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:breakselected = max(top_n, key=lambda x: x[2])display_frame = frame.copy()contour_img = np.zeros_like(frame)if selected:approx, center, _ = selectedcv2.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 = centerelse:prev_center = Nonecv2.imshow("原视频", display_frame)cv2.imshow("二值化", binary)cv2.imshow("闭运算", closed)cv2.imshow("轮廓", contour_img)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()if __name__ == "__main__":main()