云天 发表于 2022-5-2 16:39:27

树莓派电容式触摸屏试用——瞳孔跟踪

本帖最后由 云天 于 2022-5-2 16:39 编辑

【项目背景】
4月份获得了试用树莓派5寸TFT电容式触摸屏的机会,到手后,因工作原因,一直没有去过。这两天有点时间,看了一下Mediapipe官网,发现了“MediaPipe Iris”功能,


可惜,MediaPipe SDK的 python版本是不支持虹膜检测。
这个难不住我。


【项目设计】
先通过MediaPipe的人脸landmark提供了468个点位的人脸点云数据,

根据编号,很容筛选出左眼与右眼所在的区域所有点,然后完成区域的截取。


再使用Opencv的cv2.findContours实现瞳孔识别与跟踪。

【程序代码】
1、加载Mediapipe和OpenCV库
import cv2 as cv2
importmediapipe as mp
import numpy as np2、人脸landmark检测代码如下:

# 导入可视化函数和可视化样式
mp_drawing=mp.solutions.drawing_utils
#mp_drawing_styles=mp.solutions.drawing_styles
# 导入三维人脸关键点检测模型
mp_face_mesh=mp.solutions.face_mesh
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
cap = cv2.VideoCapture(0)
with mp_face_mesh.FaceMesh(
    max_num_faces=4,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5) as face_mesh:
while cap.isOpened():
    success, frame = cap.read()
    if not success:
      print("Ignoring empty camera frame.")
      # If loading a video, use 'break' instead of 'continue'.
      break

    h, w, c = frame.shape
    # image = cv2.resize(frame, (w //2, h//2))
    # frame = cv2.flip(frame, 1)
    image = np.copy(frame)
    h2, w2, c2 = image.shape
    # To improve performance, optionally mark the image as not writeable to
    # pass by reference.
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    results = face_mesh.process(image)

    # Draw the face mesh annotations on the image.
    image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
    left_eyes = []
    right_eyes = []
    if results.multi_face_landmarks:
      for face_landmarks in results.multi_face_landmarks:
      for idx, landmark in enumerate(face_landmarks.landmark):
         
          if idx == 246 or idx == 159 or idx == 158or idx == 145 or idx == 153 or idx == 190:# left
          #if idx == 53 or idx == 111:# left
            x1 = np.int(landmark.x * w2)
            y1 = np.int(landmark.y * h2)
            left_eyes.append((x1, y1))
            #cv2.circle(image, (x1, y1), 4, (255, 0, 255), 4, cv2.LINE_AA)
          if idx ==374 or idx == 380or idx == 385 or idx == 386 or idx == 390or idx == 414: # right
          #if idx == 276 or idx == 340: # right
            x1 = np.int(landmark.x * w2)
            y1 = np.int(landmark.y * h2)
            right_eyes.append((x1, y1))
            #cv2.circle(image, (x1, y1), 4, (0, 255, 255), 4, cv2.LINE_AA)
      if len(right_eyes)+len(left_eyes)==12:
         #矩形边框(Bounding Rectangle)是说,用一个最小的矩形,把找到的形状包起来。
         right_box = cv2.boundingRect(np.asarray(right_eyes))
      
         left_box = cv2.boundingRect(np.asarray(left_eyes))
         
         detect_iris(image, right_box, left_box)
    cv2.imshow('MediaPipe Face Mesh', image)
    if cv2.waitKey(5) & 0xFF == 27:
      cv2.imwrite("D:/iris_detect_result.png", image)
      break
cap.release()
cv2.waitKey(0)
cv2.destroyAllWindows()


3、虹膜l检测代码如下:

def detect_iris(image, right_box, left_box):
   
left_roi = image:left_box + left_box, left_box:left_box + left_box]
cv2.imshow('left_eye', left_roi)
lh, lw, lc = left_roi.shape
right_roi = image:right_box+right_box,right_box:right_box+right_box]
cv2.imshow('right_eye', right_roi)
rh, rw, rc = right_roi.shape
if rh>0 and lh>0:
    rows, cols, _ =right_roi.shape   #保存视频尺寸以备用
    gray_roi = cv2.cvtColor(right_roi, cv2.COLOR_BGR2GRAY)   #转灰度
    gray_roi = cv2.GaussianBlur(gray_roi, (7, 7), 0)    #高斯滤波一次
    _, threshold = cv2.threshold(gray_roi, 30, 255, cv2.THRESH_BINARY_INV)#二值化,依据需要改变阈值
    contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #画连通域
    contours = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)

    for cnt in contours:
      (x, y, w, h) = cv2.boundingRect(cnt)
      cv2.circle(right_roi, (x + int(w/2), y + int(h/2)), int(h/2), (0, 0, 255), 3)
      break

    rows, cols, _ =left_roi.shape   #保存视频尺寸以备用
    gray_roi = cv2.cvtColor(left_roi, cv2.COLOR_BGR2GRAY)   #转灰度
    gray_roi = cv2.GaussianBlur(gray_roi, (7, 7), 0)    #高斯滤波一次
    _, threshold = cv2.threshold(gray_roi, 30, 255, cv2.THRESH_BINARY_INV)#二值化,依据需要改变阈值
    contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #画连通域
    contours = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)

    for cnt in contours:
      (x, y, w, h) = cv2.boundingRect(cnt)
      cv2.circle(left_roi, (x + int(w/2), y + int(h/2)), int(h/2), (0, 0, 255), 3)
      break

【硬件连接】

【测试图片】






【演示视频】

https://www.bilibili.com/video/BV1xZ4y1y7jQ?share_source=copy_web

发表于 2022-5-7 13:28:38

貌似懂了电影里的特效之一~

发表于 2022-5-7 13:31:19

占个板凳

水晶 发表于 2022-5-10 16:04:03

666666666666666

macCosmo 发表于 2022-5-16 11:27:52

666,很科幻

盐焗海盐 发表于 2022-5-21 13:08:47

6666666666666666666

盐焗海盐 发表于 2022-5-23 10:37:59

大写的佩服!!!!!

大熊小明 发表于 2022-6-15 16:44:28

666666666666

派大星ym 发表于 2022-8-1 13:38:00

{:7_218:},,
页: [1]
查看完整版本: 树莓派电容式触摸屏试用——瞳孔跟踪