zhoutao 6 months ago
parent db11516c68
commit 71ed9b8b50

@ -1,76 +1,72 @@
import cv2 import cv2
import numpy as np import numpy as np
# 初始化摄像头 def init_camera():
cap = cv2.VideoCapture(0) global cap
cap = cv2.VideoCapture(0)
# 用于标记是否已经选择颜色区域的变量 def select_color_area(frame):
color_selected = False global color_selected, greenLower, greenUpper
greenLower = None cv2.imshow('Select color area', frame)
greenUpper = None
while True: if cv2.waitKey(1) & 0xFF == ord('c'):
# 从摄像头读取一帧 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
ret, frame = cap.read() roi = cv2.selectROI('Select color area', hsv)
if not ret: if roi != (0, 0, 0, 0):
break 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)
# 如果还没有选择颜色区域,显示当前帧并允许用户选择 greenLower = np.array([max(color_mean[0] - 10, 0), 50, 50])
if not color_selected: greenUpper = np.array([min(color_mean[0] + 10, 179), 255, 255])
cv2.imshow('Select color area', frame) print(f"Selected color: {color_mean}, Lower bound: {greenLower}, Upper bound: {greenUpper}")
color_selected = True
cv2.destroyAllWindows()
else:
print("No ROI selected. Exiting...")
cv2.destroyAllWindows()
return False
return True
# 用户按下'c'键时截取当前帧并允许用户选择ROI def track_color(frame, greenLower, greenUpper):
if cv2.waitKey(1) & 0xFF == ord('c'): hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 转换到HSV mask = cv2.inRange(hsv, greenLower, greenUpper)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
roi = cv2.selectROI('Select color area', 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)
# 创建颜色范围 kernel = np.ones((5, 5), np.uint8)
greenLower = np.array([max(color_mean[0] - 10, 0), 50, 50]) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
greenUpper = np.array([min(color_mean[0] + 10, 179), 255, 255]) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
print(f"Selected color: {color_mean}, Lower bound: {greenLower}, Upper bound: {greenUpper}") contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
color_selected = True
cv2.destroyWindow('Select color area')
else:
print("No ROI selected. Exiting...")
break
else: for contour in contours:
# 颜色区域已选择,进行颜色追踪 if cv2.contourArea(contour) > 200:
# 将BGR图像转换为HSV x, y, w, h = cv2.boundingRect(contour)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
# 创建掩码 return frame, mask
mask = cv2.inRange(hsv, greenLower, greenUpper)
# 应用开运算和闭运算去除噪声 def main():
kernel = np.ones((5, 5), np.uint8) init_camera()
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) color_selected = False
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# 查找轮廓 while True:
contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) ret, frame = cap.read()
if not ret:
break
# 遍历轮廓,画出边界框 if not color_selected:
for contour in contours: if not select_color_area(frame):
if cv2.contourArea(contour) > 200: break
x, y, w, h = cv2.boundingRect(contour) else:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) frame, mask = track_color(frame, greenLower, greenUpper)
cv2.imshow('Original', frame)
cv2.imshow('Mask', mask)
# 显示原图和结果图像 if cv2.waitKey(1) & 0xFF == ord('q'):
cv2.imshow('Original', frame) break
cv2.imshow('Mask', mask)
# 按'q'键退出循环 cap.release()
if cv2.waitKey(1) & 0xFF == ord('q'): cv2.destroyAllWindows()
break
# 释放资源并关闭所有窗口 if __name__ == "__main__":
cap.release() main()
cv2.destroyAllWindows()

@ -10,7 +10,7 @@ color_hsv_ranges = {
'upper': np.array([140, 255, 255], dtype=np.uint8)}, 'upper': np.array([140, 255, 255], dtype=np.uint8)},
'green': {'lower': np.array([35, 46, 120], dtype=np.uint8), 'green': {'lower': np.array([35, 46, 120], dtype=np.uint8),
'upper': np.array([60, 255, 255], dtype=np.uint8)}, 'upper': np.array([60, 255, 255], dtype=np.uint8)},
'red': {'lower': np.array([0, 94, 161], dtype=np.uint8), 'red': {'lower': np.array([0, 116, 164], dtype=np.uint8),
'upper': np.array([180, 255, 255], dtype=np.uint8)}, 'upper': np.array([180, 255, 255], dtype=np.uint8)},
'custom': {'lower': np.array([0, 0, 0], dtype=np.uint8), 'custom': {'lower': np.array([0, 0, 0], dtype=np.uint8),
'upper': np.array([180, 255, 255], dtype=np.uint8)} 'upper': np.array([180, 255, 255], dtype=np.uint8)}
@ -24,48 +24,149 @@ lower_hsv, upper_hsv = (color_hsv_ranges[selected_color]['lower'],
# 全局变量 # 全局变量
running = False running = False
kf = None
# 初始化卡尔曼滤波器 cap = None
# 卡尔曼滤波器用于预测物体的位置 root = None
kf = cv2.KalmanFilter(4, 2) # 4状态2测量 def initialize_kalman_filter():
kf.measurementMatrix = np.array([[1, 0, 0, 0], """初始化卡尔曼滤波器"""
[0, 1, 0, 0]], np.float32) global kf
kf.transitionMatrix = np.array([[1, 0, 1, 0], kf = cv2.KalmanFilter(4, 2)
[0, 1, 0, 1], kf.measurementMatrix = np.array([[1, 0, 0, 0],
[0, 0, 1, 0], [0, 1, 0, 0]], np.float32)
[0, 0, 0, 1]], np.float32) kf.transitionMatrix = np.array([[1, 0, 1, 0],
kf.processNoiseCov = np.array([[1, 0, 0, 0], [0, 1, 0, 1],
[0, 1, 0, 0], [0, 0, 1, 0],
[0, 0, 1, 0], [0, 0, 0, 1]], np.float32)
[0, 0, 0, 1]], np.float32) * 0.03 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 initial_measurement = None
# 更新颜色阈值的函数 def initialize_camera():
def update_color_threshold(color_name): """初始化摄像头"""
global lower_hsv, upper_hsv global cap
# 根据选择的颜色更新颜色阈值 cap = cv2.VideoCapture(0)
lower_hsv = color_hsv_ranges[color_name]['lower']
upper_hsv = color_hsv_ranges[color_name]['upper'] def choose_color():
global selected_color
# 显示颜色选择对话框
color_options = list(color_hsv_ranges.keys())
selected_color = simpledialog.askstring("Choose Color", "Enter the color (blue, green, red, custom):",
initialvalue=selected_color, parent=root)
# 检查颜色选择是否有效,更新阈值
if selected_color in color_options:
update_color_threshold(selected_color)
else:
messagebox.showerror("Error", "Invalid color selection.")
def choose_custom_color():
color_code = colorchooser.askcolor(title="Choose Custom Color")
if color_code[0] is not None:
lower = np.array([color_code[0][0] / 2, color_code[0][1] / 2, color_code[0][2] / 2])
upper = np.array([color_code[0][0], color_code[0][1], color_code[0][2]])
update_custom_hsv(lower, upper)
def update_custom_hsv(lower, upper):
global color_hsv_ranges
color_hsv_ranges['custom']['lower'] = lower.astype(np.uint8)
color_hsv_ranges['custom']['upper'] = upper.astype(np.uint8)
update_color_threshold('custom')
def exit_app():
global running, cap
running = False
cap.release()
root.quit()
def initialize_gui():
"""初始化GUI界面"""
global root
root = tk.Tk()
root.title("Color Tracker")
# 开始/停止摄像头按钮
start_button = tk.Button(root, text="开始/停止", command=start_camera)
start_button.pack()
# 颜色选择按钮
choose_color_button = tk.Button(root, text="选择颜色", command=choose_color)
choose_color_button.pack()
# 自定义颜色按钮
custom_color_button = tk.Button(root, text="自定义颜色", command=choose_custom_color)
custom_color_button.pack()
# 退出按钮
exit_button = tk.Button(root, text="退出", command=exit_app)
exit_button.pack()
# 自定义颜色HSV滑块
def set_custom_hsv(lower_h, lower_s, lower_v, upper_h, upper_s, upper_v):
update_custom_hsv(
np.array([lower_h, lower_s, lower_v]),
np.array([upper_h, upper_s, upper_v])
)
# 自定义颜色HSV滑块
lower_h_scale = Scale(root, from_=0, to=180, orient=HORIZONTAL, label="Hue Min",
command=lambda v: set_custom_hsv(v, lower_s_scale.get(), lower_v_scale.get(),
upper_h_scale.get(),
upper_s_scale.get(), upper_v_scale.get()))
lower_h_scale.pack()
lower_s_scale = Scale(root, from_=0, to=255, orient=HORIZONTAL, label="Saturation Min",
command=lambda v: set_custom_hsv(lower_h_scale.get(), v, lower_v_scale.get(),
upper_h_scale.get(),
upper_s_scale.get(), upper_v_scale.get()))
lower_s_scale.pack()
lower_v_scale = Scale(root, from_=0, to=255, orient=HORIZONTAL, label="Value Min",
command=lambda v: set_custom_hsv(lower_h_scale.get(), lower_s_scale.get(), v,
upper_h_scale.get(),
upper_s_scale.get(), upper_v_scale.get()))
lower_v_scale.pack()
upper_h_scale = Scale(root, from_=0, to=180, orient=HORIZONTAL, label="Hue Max",
command=lambda v: set_custom_hsv(lower_h_scale.get(), lower_s_scale.get(),
lower_v_scale.get(), v,
upper_s_scale.get(), upper_v_scale.get()))
upper_h_scale.pack()
upper_s_scale = Scale(root, from_=0, to=255, orient=HORIZONTAL, label="Saturation Max",
command=lambda v: set_custom_hsv(lower_h_scale.get(), lower_s_scale.get(),
lower_v_scale.get(),
upper_h_scale.get(), v, upper_v_scale.get()))
upper_s_scale.pack()
upper_v_scale = Scale(root, from_=0, to=255, orient=HORIZONTAL, label="Value Max",
command=lambda v: set_custom_hsv(lower_h_scale.get(), lower_s_scale.get(),
lower_v_scale.get(),
upper_h_scale.get(), upper_s_scale.get(), v))
upper_v_scale.pack()
# 初始化滑块值
lower_h_scale.set(color_hsv_ranges['custom']['lower'][0])
lower_s_scale.set(color_hsv_ranges['custom']['lower'][1])
lower_v_scale.set(color_hsv_ranges['custom']['lower'][2])
upper_h_scale.set(color_hsv_ranges['custom']['upper'][0])
upper_s_scale.set(color_hsv_ranges['custom']['upper'][1])
upper_v_scale.set(color_hsv_ranges['custom']['upper'][2])
# 开始摄像头处理线程
def start_camera(): def start_camera():
"""开始或停止摄像头处理"""
global running global running
if not running: if not running:
running = True running = True
thread = Thread(target=camera_thread) thread = Thread(target=camera_thread)
thread.start() thread.start()
start_button.config(text="Stop Camera")
else: else:
running = False running = False
start_button.config(text="Start Camera")
# 摄像头处理线程函数
def camera_thread(): def camera_thread():
global running, initial_measurement """摄像头处理线程函数"""
global running, initial_measurement, lower_hsv, upper_hsv
while running: while running:
ret, frame = cap.read() ret, frame = cap.read()
if not ret: if not ret:
@ -73,19 +174,20 @@ def camera_thread():
running = False running = False
break break
# 将BGR图像转换为HSV # 将BGR图像转换为HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_hsv, upper_hsv) mask = cv2.inRange(hsv, lower_hsv, upper_hsv)
# 应用开运算(先腐蚀后膨胀)以去除噪声
kernel_opening = np.ones((5, 5), np.uint8)
mask_opened = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel_opening)
# 应用开运算和闭运算去除噪声 # 应用闭运算(先膨胀后腐蚀)以填充孔洞
kernel = np.ones((5, 5), np.uint8) kernel_closing = np.ones((5, 5), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask_closed = cv2.morphologyEx(mask_opened, cv2.MORPH_CLOSE, kernel_closing)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# 查找轮廓 # 使用闭合后的掩模找到轮廓
contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours, _ = cv2.findContours(mask_closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 遍历轮廓,画出边界框 # 遍历轮廓,画出边界框
for contour in contours: for contour in contours:
@ -114,116 +216,21 @@ def camera_thread():
cv2.destroyAllWindows() cv2.destroyAllWindows()
def update_color_threshold(color_name):
"""更新颜色阈值"""
global lower_hsv, upper_hsv, selected_color
# 根据选择的颜色更新颜色阈值
selected_color = color_name # 更新selected_color
lower_hsv = color_hsv_ranges[color_name]['lower']
upper_hsv = color_hsv_ranges[color_name]['upper']
# 选择颜色
def choose_color():
global selected_color
# 显示颜色选择对话框
color_options = list(color_hsv_ranges.keys())
selected_color = simpledialog.askstring("Choose Color", "Enter the color (blue, green, red, custom):",
initialvalue=selected_color, parent=root)
# 检查颜色选择是否有效,更新阈值
if selected_color in color_options:
update_color_threshold(selected_color)
else:
messagebox.showerror("Error", "Invalid color selection.")
# 选择自定义颜色
def choose_custom_color():
color_code = colorchooser.askcolor(title="Choose Custom Color")
if color_code[0] is not None:
lower = np.array([color_code[0][0] / 2, color_code[0][1] / 2, color_code[0][2] / 2])
upper = np.array([color_code[0][0], color_code[0][1], color_code[0][2]])
update_custom_hsv(lower, upper)
# 更新自定义颜色的HSV阈值
def update_custom_hsv(lower, upper):
global color_hsv_ranges
color_hsv_ranges['custom']['lower'] = lower.astype(np.uint8)
color_hsv_ranges['custom']['upper'] = upper.astype(np.uint8)
update_color_threshold('custom')
# 退出程序
def exit_app():
global running, cap
running = False
cap.release()
root.quit()
# 创建主窗口
root = tk.Tk()
root.title("Color Tracker")
# 开始/停止摄像头按钮
start_button = tk.Button(root, text="开始/停止", command=start_camera)
start_button.pack()
# 颜色选择按钮
choose_color_button = tk.Button(root, text="选择颜色", command=choose_color)
choose_color_button.pack()
# 自定义颜色按钮
custom_color_button = tk.Button(root, text="自定义颜色", command=choose_custom_color)
custom_color_button.pack()
# 退出按钮
exit_button = tk.Button(root, text="退出", command=exit_app)
exit_button.pack()
# 自定义颜色HSV滑块
def set_custom_hsv(lower_h, lower_s, lower_v, upper_h, upper_s, upper_v):
update_custom_hsv(
np.array([lower_h, lower_s, lower_v]),
np.array([upper_h, upper_s, upper_v])
)
# 自定义颜色HSV滑块
lower_h_scale = Scale(root, from_=0, to=180, orient=HORIZONTAL, label="Hue Min",
command=lambda v: set_custom_hsv(v, lower_s_scale.get(), lower_v_scale.get(), upper_h_scale.get(),
upper_s_scale.get(), upper_v_scale.get()))
lower_h_scale.pack()
lower_s_scale = Scale(root, from_=0, to=255, orient=HORIZONTAL, label="Saturation Min",
command=lambda v: set_custom_hsv(lower_h_scale.get(), v, lower_v_scale.get(), upper_h_scale.get(),
upper_s_scale.get(), upper_v_scale.get()))
lower_s_scale.pack()
lower_v_scale = Scale(root, from_=0, to=255, orient=HORIZONTAL, label="Value Min",
command=lambda v: set_custom_hsv(lower_h_scale.get(), lower_s_scale.get(), v, upper_h_scale.get(),
upper_s_scale.get(), upper_v_scale.get()))
lower_v_scale.pack()
upper_h_scale = Scale(root, from_=0, to=180, orient=HORIZONTAL, label="Hue Max",
command=lambda v: set_custom_hsv(lower_h_scale.get(), lower_s_scale.get(), lower_v_scale.get(), v,
upper_s_scale.get(), upper_v_scale.get()))
upper_h_scale.pack()
upper_s_scale = Scale(root, from_=0, to=255, orient=HORIZONTAL, label="Saturation Max",
command=lambda v: set_custom_hsv(lower_h_scale.get(), lower_s_scale.get(), lower_v_scale.get(),
upper_h_scale.get(), v, upper_v_scale.get()))
upper_s_scale.pack()
upper_v_scale = Scale(root, from_=0, to=255, orient=HORIZONTAL, label="Value Max",
command=lambda v: set_custom_hsv(lower_h_scale.get(), lower_s_scale.get(), lower_v_scale.get(),
upper_h_scale.get(), upper_s_scale.get(), v))
upper_v_scale.pack()
# 初始化滑块值
lower_h_scale.set(color_hsv_ranges['custom']['lower'][0])
lower_s_scale.set(color_hsv_ranges['custom']['lower'][1])
lower_v_scale.set(color_hsv_ranges['custom']['lower'][2])
upper_h_scale.set(color_hsv_ranges['custom']['upper'][0])
upper_s_scale.set(color_hsv_ranges['custom']['upper'][1])
upper_v_scale.set(color_hsv_ranges['custom']['upper'][2])
# 初始化摄像头 def main():
cap = cv2.VideoCapture(0) """主函数,程序入口"""
initialize_kalman_filter()
initialize_camera()
initialize_gui()
root.mainloop()
# 启动GUI主循环 if __name__ == "__main__":
root.mainloop() main()

@ -0,0 +1,3 @@
import Color_tracking
import PyQt6
Color_tracking.main()
Loading…
Cancel
Save