diff --git a/工程/Area_tracking.py b/工程/Area_tracking.py index 6a13de2..c79ea66 100644 --- a/工程/Area_tracking.py +++ b/工程/Area_tracking.py @@ -1,76 +1,72 @@ import cv2 import numpy as np -# 初始化摄像头 -cap = cv2.VideoCapture(0) +def init_camera(): + global cap + cap = cv2.VideoCapture(0) -# 用于标记是否已经选择颜色区域的变量 -color_selected = False -greenLower = None -greenUpper = None +def select_color_area(frame): + global color_selected, greenLower, greenUpper + cv2.imshow('Select color area', frame) -while True: - # 从摄像头读取一帧 - ret, frame = cap.read() - if not ret: - break + if cv2.waitKey(1) & 0xFF == ord('c'): + hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) + roi = cv2.selectROI('Select color area', hsv) + if roi != (0, 0, 0, 0): + 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) - # 如果还没有选择颜色区域,显示当前帧并允许用户选择 - if not color_selected: - cv2.imshow('Select color area', frame) + greenLower = np.array([max(color_mean[0] - 10, 0), 50, 50]) + greenUpper = 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.destroyAllWindows() + else: + print("No ROI selected. Exiting...") + cv2.destroyAllWindows() + return False + return True - # 用户按下'c'键时,截取当前帧并允许用户选择ROI - if cv2.waitKey(1) & 0xFF == ord('c'): - # 转换到HSV - 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) +def track_color(frame, greenLower, greenUpper): + hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) + mask = cv2.inRange(hsv, greenLower, greenUpper) - # 创建颜色范围 - greenLower = np.array([max(color_mean[0] - 10, 0), 50, 50]) - greenUpper = np.array([min(color_mean[0] + 10, 179), 255, 255]) + kernel = np.ones((5, 5), np.uint8) + mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) + mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) - print(f"Selected color: {color_mean}, Lower bound: {greenLower}, Upper bound: {greenUpper}") - color_selected = True - cv2.destroyWindow('Select color area') - else: - print("No ROI selected. Exiting...") - break + contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - else: - # 颜色区域已选择,进行颜色追踪 - # 将BGR图像转换为HSV - hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) + for contour in contours: + if cv2.contourArea(contour) > 200: + x, y, w, h = cv2.boundingRect(contour) + cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) - # 创建掩码 - mask = cv2.inRange(hsv, greenLower, greenUpper) + return frame, mask - # 应用开运算和闭运算去除噪声 - kernel = np.ones((5, 5), np.uint8) - mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) - mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) +def main(): + init_camera() + color_selected = False - # 查找轮廓 - contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + while True: + ret, frame = cap.read() + if not ret: + break - # 遍历轮廓,画出边界框 - for contour in contours: - if cv2.contourArea(contour) > 200: - x, y, w, h = cv2.boundingRect(contour) - cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) + if not color_selected: + if not select_color_area(frame): + break + else: + frame, mask = track_color(frame, greenLower, greenUpper) + cv2.imshow('Original', frame) + cv2.imshow('Mask', mask) - # 显示原图和结果图像 - cv2.imshow('Original', frame) - cv2.imshow('Mask', mask) + if cv2.waitKey(1) & 0xFF == ord('q'): + break - # 按'q'键退出循环 - if cv2.waitKey(1) & 0xFF == ord('q'): - break + cap.release() + cv2.destroyAllWindows() -# 释放资源并关闭所有窗口 -cap.release() -cv2.destroyAllWindows() +if __name__ == "__main__": + main() diff --git a/工程/Color_tracking.py b/工程/Color_tracking.py index 07cc876..43221d6 100644 --- a/工程/Color_tracking.py +++ b/工程/Color_tracking.py @@ -10,7 +10,7 @@ color_hsv_ranges = { 'upper': np.array([140, 255, 255], dtype=np.uint8)}, 'green': {'lower': np.array([35, 46, 120], 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)}, 'custom': {'lower': np.array([0, 0, 0], 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 - -# 初始化卡尔曼滤波器 -# 卡尔曼滤波器用于预测物体的位置 -kf = cv2.KalmanFilter(4, 2) # 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 +kf = None +cap = None +root = None +def initialize_kalman_filter(): + """初始化卡尔曼滤波器""" + global kf + 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 update_color_threshold(color_name): - global lower_hsv, upper_hsv - # 根据选择的颜色更新颜色阈值 - lower_hsv = color_hsv_ranges[color_name]['lower'] - upper_hsv = color_hsv_ranges[color_name]['upper'] +def initialize_camera(): + """初始化摄像头""" + global cap + cap = cv2.VideoCapture(0) + +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(): + """开始或停止摄像头处理""" global running if not running: running = True thread = Thread(target=camera_thread) thread.start() - start_button.config(text="Stop Camera") else: running = False - start_button.config(text="Start Camera") - -# 摄像头处理线程函数 def camera_thread(): - global running, initial_measurement + """摄像头处理线程函数""" + global running, initial_measurement, lower_hsv, upper_hsv while running: ret, frame = cap.read() if not ret: @@ -73,19 +174,20 @@ def camera_thread(): running = False break - # 将BGR图像转换为HSV hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 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) - mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) - mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) + # 应用闭运算(先膨胀后腐蚀)以填充孔洞 + kernel_closing = np.ones((5, 5), np.uint8) + mask_closed = cv2.morphologyEx(mask_opened, cv2.MORPH_CLOSE, kernel_closing) - # 查找轮廓 - 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: @@ -114,116 +216,21 @@ def camera_thread(): 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]) -# 初始化摄像头 -cap = cv2.VideoCapture(0) +def main(): + """主函数,程序入口""" + initialize_kalman_filter() + initialize_camera() + initialize_gui() + root.mainloop() -# 启动GUI主循环 -root.mainloop() \ No newline at end of file +if __name__ == "__main__": + main() diff --git a/工程/invoke.py b/工程/invoke.py new file mode 100644 index 0000000..9c03835 --- /dev/null +++ b/工程/invoke.py @@ -0,0 +1,3 @@ +import Color_tracking +import PyQt6 +Color_tracking.main() \ No newline at end of file