Skip to content
Merged
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
852109a
完成选题并提交
jiangyi2302 Dec 18, 2025
6fe47f5
完成选题并提交
jiangyi2302 Dec 18, 2025
af14f99
完成选题并提交
jiangyi2302 Dec 18, 2025
c1ae4ac
完成选题并提交
jiangyi2302 Dec 18, 2025
ddaa9d5
完成选题并提交
jiangyi2302 Dec 18, 2025
d66962d
完成选题并提交
jiangyi2302 Dec 18, 2025
9293e17
完成选题并提交
jiangyi2302 Dec 18, 2025
e8fef31
完成选题并提交
jiangyi2302 Dec 18, 2025
7a9fab5
完成选题并提交
jiangyi2302 Dec 18, 2025
79cc531
完成选题并提交
jiangyi2302 Dec 18, 2025
29f7770
完成选题并提交
jiangyi2302 Dec 18, 2025
4b1aca1
完成选题并提交
jiangyi2302 Dec 18, 2025
edcd60e
完成选题并提交
jiangyi2302 Dec 18, 2025
e43731a
完成选题并提交
jiangyi2302 Dec 18, 2025
0f8575a
完成选题并提交
jiangyi2302 Dec 18, 2025
60db4b4
完成选题并提交
jiangyi2302 Dec 18, 2025
d9535ba
完成选题并提交
jiangyi2302 Dec 18, 2025
7886980
完成选题:更新Unmanned_Aircraft_System的README.md
jiangyi2302 Dec 18, 2025
b498537
提交选题
jiangyi2302 Dec 19, 2025
bc14972
修改选题
jiangyi2302 Dec 19, 2025
c0679cb
完成选题并提交
jiangyi2302 Dec 19, 2025
2d1e296
重命名文件夹:Unmanned_Aircraft_System → UAV_Small_Target_Recognition
jiangyi2302 Dec 19, 2025
d49e121
完成选题并提交
jiangyi2302 Dec 19, 2025
2c57293
重命名文件夹为Gesture_Control_for_Airsim_UAV,并更新README.md补充无人机手势控制内容
jiangyi2302 Dec 19, 2025
d5f2c9d
重命名文件夹:Gesture_Control_for_Airsim_UAV → Drone_gesture_operation
jiangyi2302 Dec 19, 2025
f1d3167
更新Drone_gesture_operation/README.md:基于轻量级 CNN 的无人机手势操控指令识别
jiangyi2302 Dec 19, 2025
5a5639c
无人机手势识别
jiangyi2302 Dec 20, 2025
0ecd007
更新Drone_gesture_operation:同步main.py代码
jiangyi2302 Dec 20, 2025
786c598
无人机手势识别
jiangyi2302 Dec 20, 2025
2bd5954
优化Drone_gesture_operation/main.py:给代码添加注释,增加可读性
jiangyi2302 Dec 20, 2025
c6eea87
新增Drone_gesture_operation/keypoint_classifier.py:无人机手势关键点分类器
jiangyi2302 Dec 21, 2025
f2dc1af
优化Drone_gesture_operation/main.py:可切换三种模式
jiangyi2302 Dec 21, 2025
0b9f52d
给代码添加注释
jiangyi2302 Dec 22, 2025
049d707
能够识别手势:拳头
jiangyi2302 Dec 22, 2025
d5a28cd
优化手势切换的流畅度
jiangyi2302 Dec 22, 2025
d15abc4
使画面帧率更稳定
jiangyi2302 Dec 23, 2025
f507f0e
添加了对五指张开的手势识别
jiangyi2302 Dec 24, 2025
032575a
修改了对手指的识别
jiangyi2302 Dec 24, 2025
89e210e
修改了手势识别后的输出
jiangyi2302 Dec 24, 2025
b40eaa4
添加了识别区域
jiangyi2302 Dec 25, 2025
5016971
添加识区别
jiangyi2302 Dec 25, 2025
bf80de6
Merge branch 'main' into main
jiangyi2302 Dec 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions src/Drone_gesture_operation/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,79 @@ class StableFPSHandRecognizer:
def __init__(self, target_fps=30):
# 1. 帧率锁定参数
self.target_fps = target_fps
self.frame_interval = 1.0 / target_fps
self.last_frame_time = time.time()

# 2. 优化后的肤色检测阈值
self.skin_lower = np.array([0, 20, 70], np.uint8) # 放宽下界
self.skin_upper = np.array([20, 255, 255], np.uint8) # 调整上界
self.kernel = np.ones((5, 5), np.uint8) # 更大的核去噪

# 3. 优化后的手指检测参数(降低阈值,提高识别率)
self.defect_depth_threshold = 10 # 降低深度阈值
self.min_defect_distance = 5 # 降低距离阈值
self.min_contour_area = 500 # 降低最小轮廓面积

# 4. 手势缓存&帧缓存
self.gesture_buffer = []
self.stable_gesture = "None"
self.frame_queue = []
self.queue_lock = threading.Lock()

# 5. 识别区域参数(仅显示边框)
self.recognition_area = None
self.area_color = (0, 255, 0) # 边框颜色

def _init_recognition_area(self, frame_shape):
"""初始化识别区域(调大尺寸,右侧更大范围)"""
h, w = frame_shape[:2]
x1 = int(w * 1.5 / 3) # 左边界左移(从2/3改为1.5/3),扩大宽度
y1 = int(h * 0.05) # 上边界上移(从0.1改为0.05),扩大高度
x2 = w - 10 # 右边界右移(从-20改为-10),减少右侧边距
y2 = int(h * 0.95) # 下边界下移(从0.9改为0.95),减少底部边距
self.recognition_area = (x1, y1, x2, y2)

def _draw_recognition_area(self, frame):
"""绘制识别区域(仅显示边框,无背景色)"""
if self.recognition_area is None:
self._init_recognition_area(frame.shape)
x1, y1, x2, y2 = self.recognition_area

# 仅绘制边框(移除半透明背景)
cv.rectangle(frame, (x1, y1), (x2, y2), self.area_color, 2)

# 添加区域提示文字(在边框上方)
cv.putText(frame, "Recognition Area", (x1 + 10, y1 - 10),
cv.FONT_HERSHEY_SIMPLEX, 0.6, self.area_color, 2)
return frame

def _get_roi(self, frame):
"""获取识别区域的ROI(确保坐标有效)"""
if self.recognition_area is None:
self._init_recognition_area(frame.shape)
x1, y1, x2, y2 = self.recognition_area

# 边界保护
x1 = max(0, x1)
y1 = max(0, y1)
x2 = min(frame.shape[1], x2)
y2 = min(frame.shape[0], y2)

return frame[y1:y2, x1:x2], (x1, y1)

def count_fingers(self, cnt):
"""优化后的手指计数逻辑(更鲁棒)"""
try:
# 计算凸包(带坐标)和凸包缺陷
hull = cv.convexHull(cnt)
hull_indices = cv.convexHull(cnt, returnPoints=False)
defects = cv.convexityDefects(cnt, hull_indices)

if defects is None or len(defects) == 0:
return 0

finger_count = 0
# 遍历缺陷点
self.frame_interval = 1.0 / target_fps # 每帧间隔时间(秒)
self.last_frame_time = time.time()

Expand Down Expand Up @@ -51,6 +124,27 @@ def count_fingers(self, cnt, frame_small):
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])

# 计算缺陷深度(实际像素值)
depth = d / 256.0

# 计算角度(过滤误判的缺陷)
a = np.linalg.norm(np.array(end) - np.array(start))
b = np.linalg.norm(np.array(far) - np.array(start))
c = np.linalg.norm(np.array(end) - np.array(far))
angle = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)) * 180 / np.pi

# 有效缺陷:深度足够 + 角度小于90度
if depth > self.defect_depth_threshold and angle < 90:
finger_count += 1

# 缺陷数+1=手指数量
return min(finger_count + 1, 5)
except Exception as e:
print(f"手指计数错误: {e}")
return 0

def capture_frames(self, cap):
"""帧采集线程(稳定)"""
# 计算缺陷深度(转换为实际像素值)
depth = d / 256.0

Expand All @@ -74,6 +168,63 @@ def capture_frames(self, cap):
if not ret:
break
with self.queue_lock:
self.frame_queue = [frame] # 只保留最新帧
time.sleep(self.frame_interval * 0.5)

def process_frame(self, frame):
"""优化后的帧处理逻辑"""
# 镜像翻转
frame = cv.flip(frame, 1)
# 绘制识别区域(仅边框)
frame = self._draw_recognition_area(frame)
# 获取ROI
roi, (roi_x, roi_y) = self._get_roi(frame)
current_gesture = "None"

if roi.size > 0: # 确保ROI有效
# 预处理:缩小+转HSV+肤色掩码
roi_small = cv.resize(roi, (320, 240)) # 适度放大ROI
hsv = cv.cvtColor(roi_small, cv.COLOR_BGR2HSV)
mask = cv.inRange(hsv, self.skin_lower, self.skin_upper)

# 形态学操作(去噪+填充)
mask = cv.morphologyEx(mask, cv.MORPH_OPEN, self.kernel)
mask = cv.morphologyEx(mask, cv.MORPH_CLOSE, self.kernel)
mask = cv.dilate(mask, self.kernel, iterations=2)

# 查找轮廓
contours, _ = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
if contours:
# 取最大轮廓
cnt = max(contours, key=cv.contourArea)
area = cv.contourArea(cnt)

if area > self.min_contour_area:
# 计算密实度
hull = cv.convexHull(cnt)
hull_area = cv.contourArea(hull)
solidity = area / hull_area if hull_area > 0 else 0

# 手指计数
finger_count = self.count_fingers(cnt)

# 可视化调试
cnt_scaled = cnt * (roi.shape[1] / roi_small.shape[1], roi.shape[0] / roi_small.shape[0])
cnt_scaled = cnt_scaled.astype(np.int32)
cnt_scaled[:, :, 0] += roi_x
cnt_scaled[:, :, 1] += roi_y
cv.drawContours(frame, [cnt_scaled], -1, (255, 0, 0), 2)

# 手势判断逻辑
if solidity > 0.8: # 握拳
current_gesture = "stop"
elif finger_count == 2: # 食指+中指
current_gesture = "front"
elif finger_count >= 4: # 手掌张开
current_gesture = "back"
# 其他情况(1/3指)归为None

# 手势缓存稳定
# 只保留最新1帧,避免堆积
self.frame_queue = [frame]
# 采集线程限速,匹配目标帧率
Expand Down Expand Up @@ -272,6 +423,7 @@ def main():
if len(set(self.gesture_buffer)) == 1:
self.stable_gesture = self.gesture_buffer[0]

# 绘制UI
# 5. 绘制极简UI(显示修改后的手势文本)
# 5. 绘制极简UI(仅保留手势和FPS显示)
# 5. 绘制极简UI(仅保留手势和FPS显示,移除手指数量)
Expand All @@ -281,11 +433,43 @@ def main():
cv.putText(frame, f"FPS: {self.target_fps}", (10, 80),
cv.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 2)

# 拉伸
# 拉伸显示(保持清晰)
frame_show = cv.resize(frame, (640, 480))
return frame_show

def run(self):
"""主运行逻辑"""
# 摄像头初始化
cap = cv.VideoCapture(0)
cap.set(cv.CAP_PROP_FRAME_WIDTH, 640) # 提高摄像头分辨率
cap.set(cv.CAP_PROP_FRAME_HEIGHT, 480)
cap.set(cv.CAP_PROP_FOURCC, cv.VideoWriter_fourcc(*'MJPG'))
cap.set(cv.CAP_PROP_BUFFERSIZE, 1)
cap.set(cv.CAP_PROP_FPS, self.target_fps)

# 启动采集线程
capture_thread = threading.Thread(target=self.capture_frames, args=(cap,), daemon=True)
capture_thread.start()

# 提示信息
print("=" * 50)
print(f"✅ 帧率锁定 {self.target_fps} 帧 | ESC退出")
print("💡 调试提示:")
print(" 1. 把手放在右侧绿色边框的识别区域内(已扩大范围)")
print(" 2. 握拳 → stop | 食指+中指 → front | 手掌张开 → back")
print(" 3. 蓝色轮廓表示检测到的手部区域")
print("=" * 50)

# 主循环
while cap.isOpened():
# 帧率控制
current_time = time.time()
elapsed = current_time - self.last_frame_time
if elapsed < self.frame_interval:
time.sleep(self.frame_interval - elapsed)

# 读取帧
"""主运行逻辑,帧率锁死"""
# 1. 摄像头初始化(硬件级优化)
cap = cv.VideoCapture(0)
Expand Down Expand Up @@ -325,6 +509,9 @@ def run(self):

# 处理并显示
frame_show = self.process_frame(frame)
cv.imshow("Hand Gesture Recognition", frame_show)

# 更新时间戳
cv.imshow("Stable FPS Gesture", frame_show)

# 更新时间戳,确保下一帧同步
Expand All @@ -340,6 +527,9 @@ def run(self):


if __name__ == '__main__':
# 可降低帧率(如15)提高稳定性
recognizer = StableFPSHandRecognizer(target_fps=20)
recognizer.run()
# 实例化并运行,锁定30帧(可改20/15帧,更低更稳)
recognizer = StableFPSHandRecognizer(target_fps=30)
recognizer.run()
Expand Down
Loading