|
|
import cv2
|
|
|
import numpy as np
|
|
|
|
|
|
kf = cv2.KalmanFilter(4, 2)
|
|
|
kf.measurementMatrix = np.array([[1, 0, 0, 0],
|
|
|
[0, 1, 0, 0]], np.float32)
|
|
|
kf.transitionMatrix = np.array([[1, 0, 1, 0],
|
|
|
[0, 1, 0, 1],
|
|
|
[0, 0, 1, 0],
|
|
|
[0, 0, 0, 1]], np.float32)
|
|
|
kf.processNoiseCov = np.array([[1, 0, 0, 0],
|
|
|
[0, 1, 0, 0],
|
|
|
[0, 0, 1, 0],
|
|
|
[0, 0, 0, 1]], np.float32) * 0.03
|
|
|
|
|
|
# 用于初始化卡尔曼滤波器的变量
|
|
|
initial_measurement = None
|
|
|
|
|
|
def main():
|
|
|
global initial_measurement, kf
|
|
|
# 初始化摄像头
|
|
|
cap = cv2.VideoCapture(0)
|
|
|
|
|
|
# 用于标记是否已经选择颜色区域的变量
|
|
|
color_selected = False
|
|
|
color_lower = None
|
|
|
color_upper = None
|
|
|
|
|
|
while True:
|
|
|
# 从摄像头读取一帧
|
|
|
ret, frame = cap.read()
|
|
|
if not ret:
|
|
|
break
|
|
|
|
|
|
# 如果还没有选择颜色区域,显示当前帧并允许用户选择
|
|
|
if not color_selected:
|
|
|
cv2.imshow('选择颜色区域', frame)
|
|
|
|
|
|
# 用户按下'c'键时,截取当前帧并允许用户选择ROI
|
|
|
if cv2.waitKey(1) & 0xFF == ord('c'):
|
|
|
# 转换到HSV
|
|
|
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
|
|
|
roi = cv2.selectROI('选择颜色区域', hsv)
|
|
|
if roi != (0, 0, 0, 0):
|
|
|
# 计算ROI的平均颜色
|
|
|
roi_hsv = hsv[int(roi[1]):int(roi[1] + roi[3]), int(roi[0]):int(roi[0] + roi[2])]
|
|
|
color_mean = np.mean(roi_hsv, axis=(0, 1))
|
|
|
color_mean = np.uint8(color_mean)
|
|
|
|
|
|
color_lower = np.array(
|
|
|
[max(color_mean[0] - 30, 0), max(color_mean[1] - 60, 0), max(color_mean[2] - 55, 0)])
|
|
|
color_upper = np.array(
|
|
|
[min(color_mean[0] + 10, 179), 255, 255])
|
|
|
# print(f"Selected color: {color_mean}, Lower bound: {greenLower}, Upper bound: {greenUpper}")
|
|
|
color_selected = True
|
|
|
cv2.destroyWindow('选择颜色区域')
|
|
|
else:
|
|
|
print("未选择区域,退出...")
|
|
|
break
|
|
|
|
|
|
else:
|
|
|
# 颜色区域已选择,进行颜色追踪
|
|
|
# 将BGR图像转换为HSV
|
|
|
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
|
|
|
|
|
|
# 创建掩码
|
|
|
mask = cv2.inRange(hsv, color_lower, color_upper)
|
|
|
|
|
|
# 应用开运算和闭运算去除噪声
|
|
|
kernel = np.ones((5, 5), np.uint8)
|
|
|
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
|
|
|
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
|
|
|
|
|
|
# 查找轮廓
|
|
|
contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
|
|
# 遍历轮廓,画出边界框
|
|
|
for contour in contours:
|
|
|
if cv2.contourArea(contour) > 300:
|
|
|
x, y, w, h = cv2.boundingRect(contour)
|
|
|
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
|
|
|
|
|
|
# 初始化卡尔曼滤波器的测量值
|
|
|
if initial_measurement is None:
|
|
|
initial_measurement = np.array([[x], [y]], np.float32)
|
|
|
kf.statePost = initial_measurement
|
|
|
else:
|
|
|
# 更新卡尔曼滤波器
|
|
|
measurement = np.array([[x], [y]], np.float32)
|
|
|
kf.correct(measurement)
|
|
|
prediction = kf.predict()
|
|
|
cv2.rectangle(frame, (int(prediction[0]), int(prediction[1])),
|
|
|
(int(prediction[0] + w), int(prediction[1] + h)),
|
|
|
(255, 0, 0), 2)
|
|
|
|
|
|
# 显示原图和结果图像
|
|
|
cv2.imshow('Original', frame)
|
|
|
cv2.imshow('Mask', mask)
|
|
|
|
|
|
# 按'q'键退出循环
|
|
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
|
break
|
|
|
|
|
|
# 释放资源并关闭所有窗口
|
|
|
cap.release()
|
|
|
cv2.destroyAllWindows()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
main() |