?
識別并跟蹤矩形目標
識別視頻中符合矩形輪廓的目標區域,并標記中心點位置。
實現思路
- **圖像預處理:灰度 + 二值化
- **閉運算消除孔洞
- 二值化處理
- 查找并篩選矩形輪廓
- 解算中心點
- 目標篩選
- 結果繪制
環境
使用 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()