项目简介
本项目利用OpenCV和Python实现了对手部图像的轮廓检测和凸包缺陷分析。通过检测手部轮廓和计算凸包缺陷,可以估算手指的数量并绘制相关图形,适用于图像处理和计算机视觉中的手部识别和姿态分析。
项目特点
凸包和凸包缺陷检测: 使用OpenCV的函数快速计算手部轮廓的凸包,并识别可能的手指缺陷。
HSV色彩空间转换: 利用肤色掩膜提取手部轮廓,适应不同肤色和光照条件下的图像。
图像显示与交互: 提供图像显示和交互功能,方便用户观察和调整检测结果。
实现步骤
- 图像加载与显示: 读取手部图像并显示原始图像。
- 肤色提取: 将图像转换为HSV色彩空间,创建肤色掩膜以便于后续轮廓检测。
- 轮廓检测: 使用OpenCV的轮廓查找函数检测手部轮廓。
- 凸包计算与绘制: 计算手部轮廓的凸包,并在图像上绘制凸包。
- 凸包缺陷检测: 计算凸包的缺陷点,并根据角度判断缺陷是否为手指。
- 结果展示: 显示绘制了凸包和手指缺陷的最终图像,标注手指数量。
使用技术
- Python: 编程语言,主要用于脚本开发和图像处理。
- OpenCV: 开源计算机视觉库,用于图像处理、轮廓检测和凸包分析。
- NumPy: 数值计算库,用于处理图像数据和数学运算。
项目用途
- 手势识别: 可用于手势控制系统的初步识别,例如识别手指的数量和位置。
- 生物识别: 在生物识别领域中,用于手部特征的分析和认证。
使用说明
环境配置:
确保已安装Python 3.x、OpenCV和NumPy库。
可通过 pip install opencv-python numpy 安装所需库。
运行项目:
import cv2
import os
import numpy as np
# 获取脚本的绝对路径
script_path = os.path.abspath(__file__)
# 获取脚本所在的目录
script_dir = os.path.dirname(script_path)
# 更改当前工作目录到脚本所在的目录
os.chdir(script_dir)
def show_img(img, WindowsName=None):
"""
显示图片在窗口中,并等待用户关闭窗口。
Args:
img (numpy.ndarray): 要显示的图片,类型为numpy数组。
WindowsName (str, optional): 窗口名称。默认为None,此时窗口名默认为'window'。
Returns:
None
"""
cv2.imshow(WindowsName, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
def detect_hand_contours_and_defects(img_path):
"""
检测手部轮廓和缺陷。
Args:
img_path (str): 图片路径。
Returns:
None
"""
img = cv2.imread(img_path)
if img is None:
print(f"Error: 图像 {img_path} 读取失败。")
return
# 显示原始图片
show_img(img, WindowsName="src_img")
# 转换为HSV色彩空间
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 提取肤色
lower = np.array([0, 30, 100], dtype="uint8")
upper = np.array([128, 255, 255], dtype="uint8")
# 创建肤色掩膜
skin_mask_hsv = cv2.inRange(hsv_img, lower, upper)
# show_img(skin_mask_hsv, WindowsName="skin_mask")
blurred_skin_mask = cv2.blur(skin_mask_hsv, (2,2))
# show_img(blurred_skin_mask, WindowsName="skin_mask")
ret, thresh = cv2.threshold(blurred_skin_mask, 0, 255, cv2.THRESH_BINARY)
show_img(thresh, WindowsName="skin_mask")
# 查找轮廓
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if contours:
max_contour = max(contours, key=lambda x: cv2.contourArea(x))
# 绘制最大轮廓
cv2.drawContours(img, [max_contour], -1, (0, 0, 255), 2)
# 在原图上展示轮廓
# show_img(img, WindowsName="max_contours")
# 对轮廓进行凸包检测
hull = cv2.convexHull(max_contour)
cv2.drawContours(img, [hull], -1, (0, 255, 0), 2) # 绘制凸包
show_img(img, WindowsName="hull")
# 凸包缺陷检测
hull_detect = cv2.convexHull(max_contour, returnPoints=False) # 返回凸包缺陷
defects = cv2.convexityDefects(max_contour, hull_detect)
# 如果存在缺陷,则绘制
if defects is not None:
cnt = 0
for i in range(defects.shape[0]):
s, e, f, d = defects[i, 0] # 获取缺陷信息, s, e, f分别表示起始点、终点、最远点, d表示距离
start = tuple(max_contour[s][0])
end = tuple(max_contour[e][0])
far = tuple(max_contour[f][0])
a = np.sqrt((end[0] - start[0]) ** 2 + (end[1] - start[1]) ** 2) # 计算边长
b = np.sqrt((far[0] - start[0]) ** 2 + (far[1] - start[1]) ** 2) # 计算边长
c = np.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2) # 计算边长
angle = np.arccos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)) # 计算角度
if angle <= np.pi / 2: # 角度小于90度,认为为手指
cnt += 1
# 绘制手指缺陷相关的图形
cv2.line(img, start, end, [0, 255, 0], 1) # 绘制缺陷的起始和结束点之间的线
cv2.circle(img, far, 5, [255, 0, 0], -1) # 绘制缺陷的远点(蓝色)
# 仅在检测到手指缺陷时,才显示手指数量和绘制相关图形
if cnt > 0:
cnt += 1
cv2.putText(img, str(cnt), (0, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2, cv2.LINE_AA) # 在原图上绘制手指数量
show_img(img, WindowsName="defects")
def process_hand_image(img_path):
"""
处理手部图像。
Args:
img_path (str): 图片路径。
Returns:
None
"""
# 读取图片
detect_hand_contours_and_defects(img_path)
if __name__ == '__main__':
# 测试手部图像
img_path = "./images/hand.jpg"
process_hand_image(img_path)
脚本将显示原始图像、手部轮廓、绘制的凸包以及检测到的手指缺陷,同时标注手指数量。
结语
本项目提供了一个基于OpenCV的简单但有效的手部图像处理方法,可以作为进一步研究和开发更复杂应用的基础。通过这些功能,可以在计算机视觉和图像处理的多个领域中应用和扩展。