"Время не упущено, творчество не останавливается, эта статья участвует вКонкурс эссе на конец 2021 года" |
---|
# Предисловие |
Я не хотел это писать, но на отечественном медиапайпе относительно мало туториалов. Это не настолько исчерпывающе, так что давайте запишем это здесь. |
# Установка окружения |
Если вы Anconada, то вам не нужно устанавливать, но если нет, вам просто нужно ввести следующую команду |
```python |
pip install mediapipe |
``` |
еще раз, прежде чем вам придется освоить python3 |
использование пичарма |
Основное использование opencv |
# Быстрый старт (захват жестов) |
Здесь мы приводим вещь, которая вот-вот сгниет на улице. |
```python |
import mediapipe as mp |
import cv2 |
cap = cv2.VideoCapture(0)
mpHand = mp.solutions.hands #захват руки депутата Hand = mpHand.Hands() #находим руку на картинке mphanddraw = mp.solutions.drawing_utils #инструменты рисования
while True: flag,img = cap.read()
RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把图片进行转换
result = Hand.process(RGBImage)
if(result.multi_hand_landmarks): #如果有手,那么就会得到手的列表记录了手的坐标
for handlist in result.multi_hand_landmarks:
mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS)
#绘制手的关节 HAND_CONNECTIONS 把点连接起来
cv2.imshow("Hands",img)
if(cv2.waitKey(1)==ord("q")):
break
cap.release() cv2.destroyAllWindows()
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bdcb4d2d0ff34276a2626d50ac217c31~tplv-k3u1fbpfcp-zoom-1.image)
注释应该说得很清楚了,这里就还不阐述了。
## 获取手的坐标
从刚才的效果你可以发现,handlist 包含了我们的一只手的完整坐标,并且可以绘制21个点
那么事实上 handlist 就是21个点的编号和坐标(这个坐标是按照百分比来算的),每个点对应下面的图
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/efb20258795c4ec9a342f632b78bedb3~tplv-k3u1fbpfcp-zoom-1.image)
所以我们可以非常清楚的去捕捉到我们手的状态。
接下来我们来对我们的手进行重新绘制。
![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/baf9b6f8aa1a4c24b078d7a11dc1d435~tplv-k3u1fbpfcp-zoom-1.image)
```python
import mediapipe as mp
import cv2
cap = cv2.VideoCapture(0)
mpHand = mp.solutions.hands #mp的手部捕捉
Hand = mpHand.Hands() #找到图片当中的手
mphanddraw = mp.solutions.drawing_utils #绘制工具
while True:
flag,img = cap.read()
RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把图片进行转换
result = Hand.process(RGBImage)
if(result.multi_hand_landmarks): #如果有手,那么就会得到手的列表记录了手的坐标
for handlist in result.multi_hand_landmarks:
for id,lm in enumerate(handlist.landmark):
h,w,c = img.shape
cx,cy = int(lm.x * w),int(lm.y * h)
cv2.circle(img,(cx,cy),15,(255,0,255),cv2.FILLED)
mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS,)
#绘制手的关节 HAND_CONNECTIONS 把点连接起来
cv2.imshow("Hands",img)
if(cv2.waitKey(1)==ord("q")):
break
cap.release()
cv2.destroyAllWindows()
После этого мы можем оптимизировать код.Мы знаем, что можем напрямую получить координаты каждого сустава ладони на нашей картинке, чтобы мы могли предсказывать и судить о положении нашей руки. Вот как это весело. Например это:
import mediapipe as mp
import cv2
import math
cap = cv2.VideoCapture(0)
cap.set(3,1280)
cap.set(4,720)
mpHand = mp.solutions.hands #mp的手部捕捉
Hand = mpHand.Hands() #找到图片当中的手
mphanddraw = mp.solutions.drawing_utils #绘制工具
while True:
flag,img = cap.read()
RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把图片进行转换
result = Hand.process(RGBImage)
if(result.multi_hand_landmarks): #如果有手,那么就会得到手的列表记录了手的坐标
hands_data = result.multi_hand_landmarks
for handlist in hands_data:
h, w, c = img.shape
shizhi_postion = (int(handlist.landmark[8].x*w),int(handlist.landmark[8].y*h))
muzhi_postion = (int(handlist.landmark[4].x * w), int(handlist.landmark[4].y * h))
cv2.line(img, muzhi_postion, shizhi_postion, (255, 0, 0), 5)
location = int(shizhi_postion[0]-muzhi_postion[0])**2\
+ int(shizhi_postion[1]-muzhi_postion[1])**2
location = int(math.sqrt(location))
showpostion = (int(((muzhi_postion[0]+shizhi_postion[0])/2)) ,int(((muzhi_postion[1]+shizhi_postion[1])/2)))
cv2.putText(img, str(location), showpostion, cv2.FONT_HERSHEY_PLAIN, 1, (255, 0, 255), 1)
for id,lm in enumerate(handlist.landmark):
cx,cy = int(lm.x * w),int(lm.y * h)
# 我们标注出大拇指和食指的距离
cv2.circle(img,(cx,cy),15,(255,0,255),cv2.FILLED)
cv2.putText(img,str(id),(cx,cy),cv2.FONT_HERSHEY_PLAIN,1,(0,255,255),1)
mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS,)
#绘制手的关节 HAND_CONNECTIONS 把点连接起来
cv2.imshow("Hands",img)
if(cv2.waitKey(1)==ord("q")):
break
cap.release()
cv2.destroyAllWindows()
Так что это весело.
Подробное объяснение возвращаемых параметров
Этот возвращаемый параметр очень важен, посмотрите на предыдущий пример, верно? Во-первых, hands_data — это общие координаты нескольких раздач, несколько раздач на экране, затем len() — количество раздач.
список рук состоит из 21 пункта, содержащих раздачу
хэндлист содержит [{point1},{point2}...] Итак, чтобы получить большой палец, нужно использовать handlist.landmark[4].x * w Так что все в порядке.
разные операторы
На самом деле, я не очень хорошо говорю, как эта штука называется, тут я сначала назову его оператором. Итак, какая польза от этого, на самом деле, это использование разных моделей алгоритмов, которые помогают нам извлекать разные функции для обработки.
Здесь вы можете видеть, что здесь много разных операторов. Все вызовы похожи, но обработка может немного отличаться. Конечно, мы все еще обсуждаем, как изменить руку здесь в первую очередь. Позже давайте поговорим о других вещах. В конце этой серии, возможно, мы сможем создать систему жестов и использовать положение тела для управления компьютером. Например, мы можем использовать наши руки, чтобы действовать как наша мышь (правая рука), и т.д., эта вещь должна быть круче! Либо комбинируем драйвер VR игры, геймпад нам не понадобится, просто камера с хорошими пикселями, а так как медиапайп работает напрямую в ЦП, то это означает, что мы можем работать на устройствах без графического процессора видеокарты, официальный представитель Google также сказал, что эту штуку можно использовать на мобильных терминалах, linux и так далее.
ok Продолжайте, что касается предыдущего кода, мы действительно можем сделать простой регулятор громкости, нам нужно только преобразовать расстояние между пальцами. Мало ли это еще не наша тема, наша сегодняшняя тема собственно как распознавать наши жесты, типа распознавание с 1 по 5.
Случай распознавания жестов
Хорошо, тогда давайте начнем наше дело, это дело на самом делеБыстрое использование Opencv (базовое использование и распознавание жестов)изЧасть, эта часть была скопирована прямо в то время, но оказалось, что этот парень на самом деле скопировал код видео, которое я прислал (спит-вейв действительно плохой, есть серьезная проблема с OOM. Так что я планирую написать его сам, забудь, все равно весело)
Решение о состоянии пальца
Во-первых, нам нетрудно выяснить, что на самом деле, сравните официальные изображения пальцев и изображение пальца передо мной. Нам нужно только сравнить координаты суставов, чтобы определить, стоит ли рука.
Довольно интуитивно, не так ли? Но на самом деле здесь есть проблема, и это проблема большого пальца. Поскольку большой палец слишком короткий, нет возможности судить напрямую, поэтому нам нужно использовать координату x, чтобы оценить нашу руку. Но тут опять возникает проблема, то есть строение нашей левой и правой руки немного отличается.Поэтому нам иногда приходится судить, левая у нас рука или правая.
Способ оценки левой и правой руки довольно прост, просто посмотрите на относительное положение X 1 и 5. Но есть еще проблема, это проблема ладони и тыла руки, а на самом деле проекция ладони и тыла руки такая же, как проекция левой и правой руки.
кодирование
import mediapipe as mp
import cv2
import math
cap = cv2.VideoCapture(0)
mpHand = mp.solutions.hands #mp的手部捕捉
Hand = mpHand.Hands() #找到图片当中的手
mphanddraw = mp.solutions.drawing_utils #绘制工具
TipsId = [4,8,12,16,20] #定点的坐标
while True:
flag,img = cap.read()
RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把图片进行转换
result = Hand.process(RGBImage)
if(result.multi_hand_landmarks): #如果有手,那么就会得到手的列表记录了手的坐标
hands_data = result.multi_hand_landmarks
for handlist in hands_data:
h, w, c = img.shape
fingers = []
#判断大拇指的开关
if(handlist.landmark[TipsId[0]-3].x < handlist.landmark[TipsId[0]+1].x):
if handlist.landmark[TipsId[0]].x > handlist.landmark[TipsId[0]-1].x:
fingers.append(0)
else:
fingers.append(1)
else:
if handlist.landmark[TipsId[0]].x < handlist.landmark[TipsId[0] - 1].x:
fingers.append(0)
else:
fingers.append(1)
# 判断其他手指
for id in range(1,5):
if(handlist.landmark[TipsId[id]].y > handlist.landmark[TipsId[id]-2].y):
fingers.append(0)
else:
fingers.append(1)
# 获得手指个数
totoalfingle = fingers.count(1)
cv2.putText(img,str(totoalfingle),(50,50),cv2.FONT_HERSHEY_PLAIN,
5,(255,255,255),5)
# 这个只是绘制手指关节的,可以忽略这段代码
for id,lm in enumerate(handlist.landmark):
cx,cy = int(lm.x * w),int(lm.y * h)
cv2.circle(img,(cx,cy),15,(255,0,255),cv2.FILLED)
cv2.putText(img,str(id),(cx,cy),cv2.FONT_HERSHEY_PLAIN,1,(0,255,255),1)
mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS,)
cv2.imshow("Hands",img)
if(cv2.waitKey(1)==ord("q")):
break
cap.release()
cv2.destroyAllWindows()
Эффект
Обновленная версия (Рождественский исповедник)
Далее, на этом мы должны были закончить, но вдруг вспомнили, что, мы можем не только отображать текст в нашем тексте, но и накладывать картинки,SO MAYBE IT CAN WORK SOME INTERESTING THINGS SUCH AS CONFESS TO SOMEBODY WHICH I CAN NOT USE IT RIGHT NOW!БЛЯДЬ, назовите меня производителем корма для собак, спасибо! Эффекткод
import mediapipe as mp
import cv2
import os
cap = cv2.VideoCapture(0)
cap.set(3,1280)
cap.set(4,720)
mpHand = mp.solutions.hands #mp的手部捕捉
Hand = mpHand.Hands() #找到图片当中的手
mphanddraw = mp.solutions.drawing_utils #绘制工具
MediaPath = "Media"
picsdir = os.listdir(MediaPath)
pics = []
for pic in picsdir:
img = cv2.imread(f"{MediaPath}/{pic}")
pics.append(img)
TipsId = [4,8,12,16,20] #定点的坐标
while True:
flag,img = cap.read()
RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把图片进行转换
result = Hand.process(RGBImage)
if(result.multi_hand_landmarks): #如果有手,那么就会得到手的列表记录了手的坐标
hands_data = result.multi_hand_landmarks
for handlist in hands_data:
h, w, c = img.shape
fingers = []
#判断大拇指的开关
if(handlist.landmark[TipsId[0]-2].x < handlist.landmark[TipsId[0]+1].x):
if handlist.landmark[TipsId[0]].x > handlist.landmark[TipsId[0]-1].x:
fingers.append(0)
else:
fingers.append(1)
else:
if handlist.landmark[TipsId[0]].x < handlist.landmark[TipsId[0] - 1].x:
fingers.append(0)
else:
fingers.append(1)
# 判断其他手指
for id in range(1,5):
if(handlist.landmark[TipsId[id]].y > handlist.landmark[TipsId[id]-2].y):
fingers.append(0)
else:
fingers.append(1)
# 获得手指个数,绘制图片
totoalfingle = fingers.count(1)
coverpic = pics[totoalfingle-1]
hc, wc, cc = coverpic.shape
img[0:wc,0:hc] = coverpic
# 这个只是绘制手指关节的,可以忽略这段代码
for id,lm in enumerate(handlist.landmark):
cx,cy = int(lm.x * w),int(lm.y * h)
cv2.circle(img,(cx,cy),15,(255,0,255),cv2.FILLED)
mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS,)
cv2.imshow("Hands",img)
if(cv2.waitKey(1)==ord("q")):
break
cap.release()
cv2.destroyAllWindows()
Картинка готова к работе (если кто-то успешно признается, не забудьте пнуть меня)
Суммировать
Самое основное использование на самом деле таково. Позже вы можете структурировать его так, как хотите. Это не имеет значения. Просто следуйте этому шаблону.