mpvc 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mpvc-0.0.1/PKG-INFO +12 -0
- mpvc-0.0.1/README.md +0 -0
- mpvc-0.0.1/mpvc/__init__.py +17 -0
- mpvc-0.0.1/mpvc/detector_maos.py +244 -0
- mpvc-0.0.1/mpvc/detector_rosto.py +232 -0
- mpvc-0.0.1/mpvc/malha_rosto.py +160 -0
- mpvc-0.0.1/mpvc.egg-info/PKG-INFO +12 -0
- mpvc-0.0.1/mpvc.egg-info/SOURCES.txt +11 -0
- mpvc-0.0.1/mpvc.egg-info/dependency_links.txt +1 -0
- mpvc-0.0.1/mpvc.egg-info/requires.txt +2 -0
- mpvc-0.0.1/mpvc.egg-info/top_level.txt +1 -0
- mpvc-0.0.1/pyproject.toml +26 -0
- mpvc-0.0.1/setup.cfg +4 -0
mpvc-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mpvc
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Módulo para detecção de mão, rosto e malha facial usando MediaPipe e OpenCV
|
|
5
|
+
Author-email: Mundo Python <mundopython98@gmail.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: <=3.12,>=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: opencv-python
|
|
12
|
+
Requires-Dist: mediapipe==0.10.21
|
mpvc-0.0.1/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MPVC - MediaPipe & OpenCV Detectors
|
|
3
|
+
Módulo profissional para detecção simplificada de mãos, rostos e malha facial.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .detector_maos import DetectorMaos
|
|
7
|
+
from.detector_rosto import DetectorRosto
|
|
8
|
+
from .malha_rosto import DetectorMalhaRosto
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
'DetectorMaos',
|
|
12
|
+
'DetectorRosto',
|
|
13
|
+
'DetectorMalhaRosto'
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
__version__ = '0.0.1'
|
|
17
|
+
__author__ = 'Mundo Python'
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# --- Importar as bibliotecas --- #
|
|
2
|
+
import cv2
|
|
3
|
+
import math
|
|
4
|
+
import numpy as np
|
|
5
|
+
import mediapipe as mp
|
|
6
|
+
from typing import Any, List, Tuple
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DetectorMaos:
|
|
10
|
+
"""Classe responsável pela detecção de mãos."""
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
modo: bool = False,
|
|
14
|
+
max_maos: int = 2,
|
|
15
|
+
deteccao_confianca: float = 0.5,
|
|
16
|
+
rastreio_confianca: float = 0.5,
|
|
17
|
+
cor_pontos: Tuple[int, int, int] = (0, 0, 255),
|
|
18
|
+
cor_conexoes: Tuple[int, int, int] = (255, 255, 255),
|
|
19
|
+
):
|
|
20
|
+
"""
|
|
21
|
+
Função responsável por inicializar a classe.
|
|
22
|
+
|
|
23
|
+
:param modo: Modo de captura da imagem. Se True, a detecção e rastreio serão feitos a todo momento;
|
|
24
|
+
fica muito travado. Se False, não são feitas a detecção e rastreio a todo momento; pode perder por
|
|
25
|
+
alguns instantes as marcações, porém não trava.
|
|
26
|
+
|
|
27
|
+
:param max_maos: Quantidade máxima de mãos para serem detectadas.
|
|
28
|
+
|
|
29
|
+
:param deteccao_confianca: Percentual da taxa de detecção da mão. Se for menor do que este limite,
|
|
30
|
+
a deteção não ocorre.
|
|
31
|
+
|
|
32
|
+
:param rastreio_confianca: Percentual da taxa de detecção da mão. Se for menor do que este limite,
|
|
33
|
+
a detecção não ocorre.
|
|
34
|
+
|
|
35
|
+
:param cor_pontos: Cor dos pontos.
|
|
36
|
+
|
|
37
|
+
:param cor_conexoes: Cor das conexões.
|
|
38
|
+
"""
|
|
39
|
+
# --- Inicializar os módulos de detecção das mãos --- #
|
|
40
|
+
self.maos_mp = mp.solutions.hands
|
|
41
|
+
self.maos = self.maos_mp.Hands(
|
|
42
|
+
modo,
|
|
43
|
+
max_maos,
|
|
44
|
+
1,
|
|
45
|
+
deteccao_confianca,
|
|
46
|
+
rastreio_confianca
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# --- Função para desenhar os pontos nas mãos --- #
|
|
50
|
+
self.desenho = mp.solutions.drawing_utils
|
|
51
|
+
|
|
52
|
+
# --- Confifuração do desenho dos pontos --- #
|
|
53
|
+
self.desenho_pontos = self.desenho.DrawingSpec(color=cor_pontos)
|
|
54
|
+
|
|
55
|
+
# --- Configuração do desenho das conexões --- #
|
|
56
|
+
self.desenho_conexoes = self.desenho.DrawingSpec(color=cor_conexoes)
|
|
57
|
+
|
|
58
|
+
def encontrar_maos(self, imagem: np.ndarray, desenho: bool = True) -> np.ndarray:
|
|
59
|
+
"""
|
|
60
|
+
Função responsável por detectar a(s) mão(s).
|
|
61
|
+
:param imagem: Imagem capturada.
|
|
62
|
+
:param desenho: Desenhar os pontos e as conexões na(s) mão(s).
|
|
63
|
+
:return: Retorna a imagem com a detecção.
|
|
64
|
+
"""
|
|
65
|
+
# --- Converter a imagem de BGR para RGB --- #
|
|
66
|
+
imagem_rgb = cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB)
|
|
67
|
+
|
|
68
|
+
# --- Passar a imagem convertida para o detector --- #
|
|
69
|
+
self.resultado = self.maos.process(imagem_rgb)
|
|
70
|
+
|
|
71
|
+
# --- Verificar se alguma mão foi detectada --- #
|
|
72
|
+
if self.resultado.multi_hand_landmarks:
|
|
73
|
+
for pontos in self.resultado.multi_hand_landmarks:
|
|
74
|
+
if desenho:
|
|
75
|
+
# --- Desenhar os pontos nas mãos detectadas --- #
|
|
76
|
+
self.desenho.draw_landmarks(
|
|
77
|
+
imagem,
|
|
78
|
+
pontos,
|
|
79
|
+
self.maos_mp.HAND_CONNECTIONS,
|
|
80
|
+
self.desenho_pontos,
|
|
81
|
+
self.desenho_conexoes
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return imagem
|
|
85
|
+
|
|
86
|
+
def encontrar_pontos(
|
|
87
|
+
self,
|
|
88
|
+
imagem: np.ndarray,
|
|
89
|
+
mao_num: int = 0,
|
|
90
|
+
desenho: bool = True,
|
|
91
|
+
cor: Tuple[int, int, int] = (255, 0, 255),
|
|
92
|
+
raio: int = 7,
|
|
93
|
+
ponto_detectado: Any = 0
|
|
94
|
+
) -> List:
|
|
95
|
+
"""
|
|
96
|
+
Função responsável por encontrar a posição dps pontos da(s) mão(s).
|
|
97
|
+
:param imagem: Imagem capturada.
|
|
98
|
+
:param mao_num: Número da mão detectada.
|
|
99
|
+
:param desenho: Desenhar o ponto encontrado.
|
|
100
|
+
:param cor: Tupla com a cor do ponto (RGB).
|
|
101
|
+
:param raio: Raio do círculo do ponto.
|
|
102
|
+
:param ponto_detectado: Ponto a ser detectado.
|
|
103
|
+
:return: Lista com os pontos detectados.
|
|
104
|
+
"""
|
|
105
|
+
# --- Lista com os pontos detectados --- #
|
|
106
|
+
lista_pontos = []
|
|
107
|
+
|
|
108
|
+
# --- Garantir que o ponto_detectado seja uma lista --- #
|
|
109
|
+
if isinstance(ponto_detectado, int):
|
|
110
|
+
pontos_alvo = [ponto_detectado]
|
|
111
|
+
else:
|
|
112
|
+
pontos_alvo = ponto_detectado
|
|
113
|
+
|
|
114
|
+
# --- Obter as dimensões da imagem capturada --- #
|
|
115
|
+
altura, largura, _ = imagem.shape
|
|
116
|
+
|
|
117
|
+
# --- Verificar se alguma mão foi detectada --- #
|
|
118
|
+
if self.resultado.multi_hand_landmarks:
|
|
119
|
+
for num_mao, landmark_mao in enumerate(self.resultado.multi_hand_landmarks):
|
|
120
|
+
# --- Lista com os pontos da mão detectada --- #
|
|
121
|
+
lista_pontos_mao = []
|
|
122
|
+
# --- Obter as informações dos pontos --- #
|
|
123
|
+
for id_, ponto in enumerate(landmark_mao.landmark):
|
|
124
|
+
if id_ in pontos_alvo:
|
|
125
|
+
# --- Transformar a posição do ponto de proporção para pixel --- #
|
|
126
|
+
centro_x, centro_y = int(ponto.x * largura), int(ponto.y * altura)
|
|
127
|
+
|
|
128
|
+
# --- Adicionar os pontos da mão detectda na lista --- #
|
|
129
|
+
lista_pontos_mao.append([id_, centro_x, centro_y])
|
|
130
|
+
|
|
131
|
+
# --- Colocar um círculo em um ponto --- #
|
|
132
|
+
if desenho:
|
|
133
|
+
cv2.circle(
|
|
134
|
+
imagem,
|
|
135
|
+
(centro_x, centro_y),
|
|
136
|
+
raio,
|
|
137
|
+
cor,
|
|
138
|
+
cv2.FILLED
|
|
139
|
+
)
|
|
140
|
+
lista_pontos.append(lista_pontos_mao)
|
|
141
|
+
|
|
142
|
+
return lista_pontos
|
|
143
|
+
|
|
144
|
+
def encontrar_distancia(
|
|
145
|
+
self,
|
|
146
|
+
ponto_1: int,
|
|
147
|
+
ponto_2: int,
|
|
148
|
+
imagem: np.ndarray,
|
|
149
|
+
mao_num: int = 0,
|
|
150
|
+
desenho_linha: bool = True,
|
|
151
|
+
desenho_ponto: bool = True,
|
|
152
|
+
cor_linha: Tuple[int, int, int] = (255, 0, 255),
|
|
153
|
+
cor_ponto: Tuple[int, int, int] = (0, 255, 0),
|
|
154
|
+
espessura: int = 2,
|
|
155
|
+
raio: int = 7
|
|
156
|
+
) -> Tuple[float, np.ndarray, List[int]]:
|
|
157
|
+
"""
|
|
158
|
+
Função responsável por calcular a distância entre dois pontos da mão.
|
|
159
|
+
:param ponto_1: ID do primeiro ponto.
|
|
160
|
+
:param ponto_2: ID do segundo ponto.
|
|
161
|
+
:param imagem: Imagem capturada.
|
|
162
|
+
:param mao_num: Índice da mão detectada.
|
|
163
|
+
:param desenho_linha: Se True, desenha uma linha entre os pontos e o centro.
|
|
164
|
+
:param desenho_ponto: Se True, desenha o ponto médio entre os pontos selecionados.
|
|
165
|
+
:param cor_linha: Cor da linha.
|
|
166
|
+
:param cor_ponto: Cor do ponto médio.
|
|
167
|
+
:param espessura: Espessura da linha que conecta os pontos.
|
|
168
|
+
:param raio: Raio do ponto central da linha.
|
|
169
|
+
:return: Uma tupla contendo a distância calculada, a imagem e uma lista com as coordenadas.
|
|
170
|
+
"""
|
|
171
|
+
distancia = 0
|
|
172
|
+
info_pontos = []
|
|
173
|
+
|
|
174
|
+
# --- Verificar se alguma mão foi detectada e se o índice da mão existe --- #
|
|
175
|
+
if self.resultado.multi_hand_landmarks and len(self.resultado.multi_hand_landmarks) > mao_num:
|
|
176
|
+
mao_alvo = self.resultado.multi_hand_landmarks[mao_num]
|
|
177
|
+
altura, largura, _ = imagem.shape
|
|
178
|
+
|
|
179
|
+
# --- Extrair as coordenadas em pixels dos dois pontos --- #
|
|
180
|
+
x_1 = int(mao_alvo.landmark[ponto_1].x * largura)
|
|
181
|
+
y_1 = int(mao_alvo.landmark[ponto_1].y * altura)
|
|
182
|
+
|
|
183
|
+
x_2 = int(mao_alvo.landmark[ponto_2].x * largura)
|
|
184
|
+
y_2 = int(mao_alvo.landmark[ponto_2].y * altura)
|
|
185
|
+
|
|
186
|
+
# --- Encontrar o ponto central entre os pontos --- #
|
|
187
|
+
centro_x, centro_y = (x_1 + x_2) // 2, (y_1 + y_2) // 2
|
|
188
|
+
info_pontos = [x_1, y_1, x_1, y_2, centro_x, centro_y]
|
|
189
|
+
|
|
190
|
+
# --- Calcular a distância euclidiana --- #
|
|
191
|
+
distancia = math.hypot(x_2 - x_1, y_2 - y_1)
|
|
192
|
+
|
|
193
|
+
# --- Desenhar a linha e o ponto central --- #
|
|
194
|
+
if desenho_linha:
|
|
195
|
+
cv2.line(imagem, (x_1, y_1), (x_2, y_2), cor_linha, espessura)
|
|
196
|
+
if desenho_ponto:
|
|
197
|
+
cv2.circle(imagem, (centro_x, centro_y), raio, cor_ponto, cv2.FILLED)
|
|
198
|
+
|
|
199
|
+
return distancia, imagem, info_pontos
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def main():
|
|
203
|
+
# --- Capturar o vídeo pela webcam --- #
|
|
204
|
+
cap = cv2.VideoCapture(0)
|
|
205
|
+
|
|
206
|
+
# --- Instanciar a classe do detector --- #
|
|
207
|
+
detector = DetectorMaos()
|
|
208
|
+
|
|
209
|
+
# --- Realizar a captura --- #
|
|
210
|
+
while True:
|
|
211
|
+
# --- Obter a imagem --- #
|
|
212
|
+
_, imagem = cap.read()
|
|
213
|
+
|
|
214
|
+
# --- Inverter a imagem --- #
|
|
215
|
+
imagem = cv2.flip(imagem, 1)
|
|
216
|
+
|
|
217
|
+
# --- Realizar a detecção das mãos --- #
|
|
218
|
+
imagem = detector.encontrar_maos(imagem)
|
|
219
|
+
|
|
220
|
+
# --- Lista com os pontos --- #
|
|
221
|
+
lista_pontos = detector.encontrar_pontos(imagem)
|
|
222
|
+
|
|
223
|
+
# --- Distância entre os pontos --- #
|
|
224
|
+
if len(lista_pontos) != 0 and len(lista_pontos[0]) > 0:
|
|
225
|
+
distancia, imagem, info = detector.encontrar_distancia(4, 8, imagem, desenho_ponto=False)
|
|
226
|
+
cv2.putText(
|
|
227
|
+
imagem,
|
|
228
|
+
f'Dist: {int(distancia)}',
|
|
229
|
+
(10, 50),
|
|
230
|
+
cv2.FONT_HERSHEY_SIMPLEX,
|
|
231
|
+
1,
|
|
232
|
+
(255, 255, 0),
|
|
233
|
+
2
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# --- Mostrar a imagem de captura --- #
|
|
237
|
+
cv2.imshow('Captura', imagem)
|
|
238
|
+
|
|
239
|
+
# --- Tempo de atualização da captura --- #
|
|
240
|
+
cv2.waitKey(1)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
if __name__ == '__main__':
|
|
244
|
+
main()
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# --- Importar as bibliotecas --- #
|
|
2
|
+
import cv2
|
|
3
|
+
import numpy as np
|
|
4
|
+
import mediapipe as mp
|
|
5
|
+
from typing import List, Tuple
|
|
6
|
+
|
|
7
|
+
class DetectorRosto:
|
|
8
|
+
"""Classe responsável por detectar rostos."""
|
|
9
|
+
def __init__(self, deteccao_confianca: float = 0.5):
|
|
10
|
+
"""
|
|
11
|
+
Função responsável por iniciar a classe.
|
|
12
|
+
:param deteccao_confianca: Percentual da taxa de detecção do rosto. Se for menor que este limite,
|
|
13
|
+
a detecção não ocorre.
|
|
14
|
+
"""
|
|
15
|
+
# --- Inicializar a função de detecção do rosto --- #
|
|
16
|
+
self.rosto_mp = mp.solutions.face_detection
|
|
17
|
+
self.rosto = self.rosto_mp.FaceDetection(deteccao_confianca)
|
|
18
|
+
|
|
19
|
+
def encontrar_rosto(
|
|
20
|
+
self,
|
|
21
|
+
imagem: np.ndarray,
|
|
22
|
+
desenho: bool = True,
|
|
23
|
+
cor_caixa: Tuple[int, int, int] = (255, 0, 255),
|
|
24
|
+
cor_moldura: Tuple[int, int, int] = (255, 0, 255),
|
|
25
|
+
comprimento: int = 30,
|
|
26
|
+
espessura_moldura: int = 5,
|
|
27
|
+
espessura_retangulo: int = 1,
|
|
28
|
+
desenho_caixa: bool = True,
|
|
29
|
+
desenho_moldura: bool = True,
|
|
30
|
+
texto: bool = True
|
|
31
|
+
) -> Tuple[np.ndarray, List]:
|
|
32
|
+
"""
|
|
33
|
+
Função responsável por detectar o(s) rosto(s).
|
|
34
|
+
:param imagem: Imagem capturada.
|
|
35
|
+
:param desenho: Desenhar a(s) caixa(s) de detecção do(s) rosto(s).
|
|
36
|
+
:param cor_caixa: Cor da caixa.
|
|
37
|
+
:param cor_moldura: Cor da moldura.
|
|
38
|
+
:param comprimento: Comprimento da linha da moldura.
|
|
39
|
+
:param espessura_moldura: Espessura da linha da moldura.
|
|
40
|
+
:param espessura_retangulo: Espessura do retângulo da(s) caixa(s).
|
|
41
|
+
:param desenho_caixa: Desenhar a caixa de detecção.
|
|
42
|
+
:param desenho_moldura: Desenhar a moldura na caixa de detecção.
|
|
43
|
+
:param texto: Escrever o texto da porcentagem de detecção.
|
|
44
|
+
:return: Retorna a imagem com a detecção e a lista com a(s) caixa(s) de detecção.
|
|
45
|
+
"""
|
|
46
|
+
# --- Converter a imagem de BGR para RGB --- #
|
|
47
|
+
imagem_rgb = cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB)
|
|
48
|
+
|
|
49
|
+
# --- Passar a imagem convertida para o detector --- #
|
|
50
|
+
resultado = self.rosto.process(imagem_rgb)
|
|
51
|
+
|
|
52
|
+
# --- Dimensões da imagem de captura --- #
|
|
53
|
+
altura, largura, _ = imagem.shape
|
|
54
|
+
|
|
55
|
+
# --- Lista com as caixa de detecção do rosto --- #
|
|
56
|
+
caixas = []
|
|
57
|
+
|
|
58
|
+
# --- Verificar se ocorreu a detecção do rosto --- #
|
|
59
|
+
if resultado.detections:
|
|
60
|
+
# --- Obter o ID da detecção, bem como a detecção --- #
|
|
61
|
+
for id_, deteccao in enumerate(resultado.detections):
|
|
62
|
+
# --- Informações da caixa de reconhecimento --- #
|
|
63
|
+
info_caixa = deteccao.location_data.relative_bounding_box
|
|
64
|
+
|
|
65
|
+
# --- Caixa de detecção --- #
|
|
66
|
+
caixa = (int(info_caixa.xmin * largura), int(info_caixa.ymin * altura),
|
|
67
|
+
int(info_caixa.width * largura), int(info_caixa.height * altura))
|
|
68
|
+
|
|
69
|
+
# --- Adicionar a caixa à lista de caixas --- #
|
|
70
|
+
caixas.append([id_, caixa, deteccao.score])
|
|
71
|
+
|
|
72
|
+
# --- Desenhar a caixa em volta do rosto detectado --- #
|
|
73
|
+
if desenho:
|
|
74
|
+
imagem = self.desenho_moldura(
|
|
75
|
+
imagem,
|
|
76
|
+
caixa,
|
|
77
|
+
cor_caixa,
|
|
78
|
+
cor_moldura,
|
|
79
|
+
comprimento,
|
|
80
|
+
espessura_moldura,
|
|
81
|
+
espessura_retangulo,
|
|
82
|
+
desenho_caixa,
|
|
83
|
+
desenho_moldura
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if texto:
|
|
87
|
+
# --- Colocar na caixa de detecção a porcentagem de certeza da detecção --- #
|
|
88
|
+
cv2.putText(
|
|
89
|
+
imagem,
|
|
90
|
+
f'{int(deteccao.score[0] * 100)}%',
|
|
91
|
+
(caixa[0], caixa[1] - 20),
|
|
92
|
+
cv2.FONT_HERSHEY_PLAIN,
|
|
93
|
+
2,
|
|
94
|
+
cor_caixa,
|
|
95
|
+
2
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return imagem, caixas
|
|
99
|
+
|
|
100
|
+
def desenho_moldura(
|
|
101
|
+
self,
|
|
102
|
+
imagem: np.ndarray,
|
|
103
|
+
caixa: List,
|
|
104
|
+
cor_caixa: Tuple,
|
|
105
|
+
cor_moldura: Tuple,
|
|
106
|
+
comprimento: int,
|
|
107
|
+
espessura_moldura: int,
|
|
108
|
+
espessura_retangulo: int,
|
|
109
|
+
desenho_caixa: bool,
|
|
110
|
+
desenho_moldura: bool
|
|
111
|
+
)-> np.ndarray:
|
|
112
|
+
"""
|
|
113
|
+
Função responsável por criar a moldura da caixa de detecção do(s) rosto(s).
|
|
114
|
+
:param imagem: Imagem capturada.
|
|
115
|
+
:param caixa: Caixa de detecção.
|
|
116
|
+
:param cor_caixa: Cor da caixa.
|
|
117
|
+
:param cor_moldura: Cor da moldura.
|
|
118
|
+
:param comprimento: Comprimento da linha da moldura.
|
|
119
|
+
:param espessura_moldura: Espessura da linha da moldura.
|
|
120
|
+
:param espessura_retangulo: Espessura do retângulo da(s) caixa(s).
|
|
121
|
+
:param desenho_caixa: Desenhar a caixa de detecção.
|
|
122
|
+
:param desenho_moldura: DEsenhar a moldura na caixa de detecção.
|
|
123
|
+
:return: Retorna a imagem com a caixa de detecção desenhada.
|
|
124
|
+
"""
|
|
125
|
+
# --- Dimensões da caixa --- #
|
|
126
|
+
x, y, largura, altura = caixa
|
|
127
|
+
|
|
128
|
+
# --- Pontos iniciais da moldura --- #
|
|
129
|
+
x_1, y_1 = x + largura, y + largura
|
|
130
|
+
|
|
131
|
+
if desenho_caixa:
|
|
132
|
+
# --- Desenhar a caixa em volta do rosto detectado --- #
|
|
133
|
+
cv2.rectangle(
|
|
134
|
+
imagem,
|
|
135
|
+
caixa,
|
|
136
|
+
cor_caixa,
|
|
137
|
+
espessura_retangulo
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
if desenho_moldura:
|
|
141
|
+
# --- Canto superior esquerdo --- #
|
|
142
|
+
cv2.line(
|
|
143
|
+
imagem,
|
|
144
|
+
(x, y),
|
|
145
|
+
(x + comprimento, y),
|
|
146
|
+
cor_moldura,
|
|
147
|
+
espessura_moldura
|
|
148
|
+
)
|
|
149
|
+
cv2.line(
|
|
150
|
+
imagem,
|
|
151
|
+
(x, y),
|
|
152
|
+
(x, y + comprimento),
|
|
153
|
+
cor_moldura,
|
|
154
|
+
espessura_moldura
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# --- Canto superior direito --- #
|
|
158
|
+
cv2.line(
|
|
159
|
+
imagem,
|
|
160
|
+
(x_1, y),
|
|
161
|
+
(x_1 - comprimento, y),
|
|
162
|
+
cor_moldura,
|
|
163
|
+
espessura_moldura
|
|
164
|
+
)
|
|
165
|
+
cv2.line(
|
|
166
|
+
imagem,
|
|
167
|
+
(x_1, y),
|
|
168
|
+
(x_1, y + comprimento),
|
|
169
|
+
cor_moldura,
|
|
170
|
+
espessura_moldura
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# --- Canto inferior esquerdo --- #
|
|
174
|
+
cv2.line(
|
|
175
|
+
imagem,
|
|
176
|
+
(x, y_1),
|
|
177
|
+
(x + comprimento, y_1),
|
|
178
|
+
cor_moldura,
|
|
179
|
+
espessura_moldura
|
|
180
|
+
)
|
|
181
|
+
cv2.line(
|
|
182
|
+
imagem,
|
|
183
|
+
(x, y_1),
|
|
184
|
+
(x, y_1 - comprimento),
|
|
185
|
+
cor_moldura,
|
|
186
|
+
espessura_moldura
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# --- Canto inferior direito --- #
|
|
190
|
+
cv2.line(
|
|
191
|
+
imagem,
|
|
192
|
+
(x_1, y_1),
|
|
193
|
+
(x_1 - comprimento, y_1),
|
|
194
|
+
cor_moldura,
|
|
195
|
+
espessura_moldura
|
|
196
|
+
)
|
|
197
|
+
cv2.line(
|
|
198
|
+
imagem,
|
|
199
|
+
(x_1, y_1),
|
|
200
|
+
(x_1, y_1 - comprimento),
|
|
201
|
+
cor_moldura,
|
|
202
|
+
espessura_moldura
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
return imagem
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def main():
|
|
209
|
+
# --- Captura da webcam --- #
|
|
210
|
+
cap = cv2.VideoCapture(0)
|
|
211
|
+
|
|
212
|
+
# --- Instanciar o detector de rosto --- #
|
|
213
|
+
detector = DetectorRosto()
|
|
214
|
+
|
|
215
|
+
# --- Loop de captura --- #
|
|
216
|
+
while True:
|
|
217
|
+
# --- Obter a imagem --- #
|
|
218
|
+
_, imagem = cap.read()
|
|
219
|
+
|
|
220
|
+
# --- Inverter a imagem --- #
|
|
221
|
+
imagem = cv2.flip(imagem, 1)
|
|
222
|
+
|
|
223
|
+
imagem, caixas = detector.encontrar_rosto(imagem)
|
|
224
|
+
|
|
225
|
+
# --- Mostrar a captura --- #
|
|
226
|
+
cv2.imshow('Captura', imagem)
|
|
227
|
+
|
|
228
|
+
# --- Tempo de atualização da captura --- #
|
|
229
|
+
cv2.waitKey(1)
|
|
230
|
+
|
|
231
|
+
if __name__ == '__main__':
|
|
232
|
+
main()
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# --- Importar as bibliotecas --- #
|
|
2
|
+
import cv2
|
|
3
|
+
import numpy as np
|
|
4
|
+
import mediapipe as mp
|
|
5
|
+
from typing import List, Tuple
|
|
6
|
+
|
|
7
|
+
class DetectorMalhaRosto:
|
|
8
|
+
def __init__(
|
|
9
|
+
self,
|
|
10
|
+
modo: bool = False,
|
|
11
|
+
max_rosto: int = 2,
|
|
12
|
+
refinar_pontos: bool = False,
|
|
13
|
+
deteccao_confianca: float = 0.5,
|
|
14
|
+
rastreio_confianca: float = 0.5,
|
|
15
|
+
cor_pontos: Tuple = (255, 255, 255),
|
|
16
|
+
cor_conexoes: Tuple = (0, 255, 0)
|
|
17
|
+
):
|
|
18
|
+
"""
|
|
19
|
+
Função responsável por inicializar a classe.
|
|
20
|
+
|
|
21
|
+
:param modo: Modo de captura da imagem. Se True, a detecção e o rastrio serão feitos a todo momento;
|
|
22
|
+
deixa muito travado. Se False, não são feitas a detecção e rastrio a todo momento; pode perder
|
|
23
|
+
pos alguns instântes as marcações, porém não trava.
|
|
24
|
+
|
|
25
|
+
:param max_rostos: Quantidade máxima de rostos para serem detectados.
|
|
26
|
+
|
|
27
|
+
:param refinar_pontos: Refinar as coordenadas dos pontos da boca e dos olhos.
|
|
28
|
+
|
|
29
|
+
:param deteccao_confianca: Percentual da taxa de detecção do rosto. Se for menor do que este limite,
|
|
30
|
+
a detecção não ocorre.
|
|
31
|
+
|
|
32
|
+
:param rastreio_confianca: Percentual da taxa do rastreio do rosto. Se for menor do que este limite,
|
|
33
|
+
o rastreio não ocorre.
|
|
34
|
+
|
|
35
|
+
:param cor_pontos: Cor dos pontos.
|
|
36
|
+
|
|
37
|
+
:param cor_conexoes: Cor das conexões.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# --- Inicializar a função de detecção da malha do rosto --- #
|
|
41
|
+
self.malha_rosto_mp = mp.solutions.face_mesh
|
|
42
|
+
self.malha_rosto = self.malha_rosto_mp.FaceMesh(
|
|
43
|
+
modo,
|
|
44
|
+
max_rosto,
|
|
45
|
+
refinar_pontos,
|
|
46
|
+
deteccao_confianca,
|
|
47
|
+
rastreio_confianca
|
|
48
|
+
)
|
|
49
|
+
self.malha_rosto_conexoes = mp.solutions.face_mesh_connections
|
|
50
|
+
|
|
51
|
+
# --- Função para desenhar a malha no rosto --- #
|
|
52
|
+
self.desenho = mp.solutions.drawing_utils
|
|
53
|
+
|
|
54
|
+
# --- Configuração do desenho dos pontos --- #
|
|
55
|
+
self.desenho_pontos = self.desenho.DrawingSpec(
|
|
56
|
+
color=cor_pontos,
|
|
57
|
+
thickness=1,
|
|
58
|
+
circle_radius=1
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# --- Configuração do desenho das conexões --- #
|
|
62
|
+
self.desenho_conexoes = self.desenho.DrawingSpec(
|
|
63
|
+
color=cor_conexoes,
|
|
64
|
+
thickness=1
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def encontrar_malha_rosto(
|
|
68
|
+
self,
|
|
69
|
+
imagem: np.ndarray,
|
|
70
|
+
desenho: bool = True
|
|
71
|
+
)-> np.ndarray:
|
|
72
|
+
"""
|
|
73
|
+
Função responsável por detectar o(s) rosto(s) e aplicar a malha.
|
|
74
|
+
:param imagem: Imagem capturada.
|
|
75
|
+
:param desenho: Desenhar a(s) malha(s) no(s) rosto(s).
|
|
76
|
+
:return: Retorna a imagem com a malha facial.
|
|
77
|
+
"""
|
|
78
|
+
# --- Converter a imagem de BGR para RGB --- #
|
|
79
|
+
imagem_rgb = cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB)
|
|
80
|
+
|
|
81
|
+
# --- Passar a imagem convertida para o detector --- #
|
|
82
|
+
self.resultado = self.malha_rosto.process(imagem_rgb)
|
|
83
|
+
|
|
84
|
+
# --- Verificar se ocorreu detecção do rosto --- #
|
|
85
|
+
if self.resultado.multi_face_landmarks:
|
|
86
|
+
# --- Obter os pontos da malha facial --- #
|
|
87
|
+
for ponto in self.resultado.multi_face_landmarks:
|
|
88
|
+
if desenho:
|
|
89
|
+
# --- Desenhar os pontos da malha --- #
|
|
90
|
+
self.desenho.draw_landmarks(
|
|
91
|
+
imagem,
|
|
92
|
+
ponto,
|
|
93
|
+
self.malha_rosto_conexoes.FACEMESH_CONTOURS,
|
|
94
|
+
self.desenho_pontos,
|
|
95
|
+
self.desenho_conexoes
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return imagem
|
|
99
|
+
|
|
100
|
+
def encontrar_pontos(self, imagem: np.ndarray) -> List:
|
|
101
|
+
"""
|
|
102
|
+
Função responsável por informar os pontos da malha facial.
|
|
103
|
+
:param imagem: Imagem capturada.
|
|
104
|
+
:return: Retorna a lista com os pontos da(s) malha(s) do(s) rosto(s) detectado(s).
|
|
105
|
+
"""
|
|
106
|
+
# --- Lista com os pontos do rosto --- #
|
|
107
|
+
rostos = []
|
|
108
|
+
|
|
109
|
+
# --- Obter as dimensões da imagem --- #
|
|
110
|
+
altura, largura, _ = imagem.shape
|
|
111
|
+
|
|
112
|
+
# --- Verificar se ocorreu a detecção do rosto --- #
|
|
113
|
+
if self.resultado.multi_face_landmarks:
|
|
114
|
+
# --- Obter os pontos da malha facial --- #
|
|
115
|
+
for pontos in self.resultado.multi_face_landmarks:
|
|
116
|
+
# --- Lista com a malha do rosto detectado --- #
|
|
117
|
+
rosto = []
|
|
118
|
+
|
|
119
|
+
# --- Obter a informação de cada ponto da malha --- #
|
|
120
|
+
for id_, ponto in enumerate(pontos.landmark):
|
|
121
|
+
# --- Converter os valores de proporção para pixels --- #
|
|
122
|
+
x, y = int(ponto.x * largura), int(ponto.y * altura)
|
|
123
|
+
|
|
124
|
+
# --- Adicionar à lista de rosto o ponto do rosto --- #
|
|
125
|
+
rosto.append([id_, x, y])
|
|
126
|
+
|
|
127
|
+
# --- Adicionar a lista com os pontos do rosto à lista de rostos detectados --- #
|
|
128
|
+
rostos.append(rosto)
|
|
129
|
+
|
|
130
|
+
return rostos
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def main():
|
|
134
|
+
# --- Captura da webcam --- #
|
|
135
|
+
cap = cv2.VideoCapture(0)
|
|
136
|
+
|
|
137
|
+
# --- Instanciar o detector da malha facial --- #
|
|
138
|
+
detector = DetectorMalhaRosto()
|
|
139
|
+
|
|
140
|
+
# --- Loop de captura --- #
|
|
141
|
+
while True:
|
|
142
|
+
# --- Captura da imagem --- #
|
|
143
|
+
_, imagem = cap.read()
|
|
144
|
+
|
|
145
|
+
# --- Inverter a imagem --- #
|
|
146
|
+
imagem = cv2.flip(imagem, 1)
|
|
147
|
+
|
|
148
|
+
# --- Detectar a malha do rosto --- #
|
|
149
|
+
imagem = detector.encontrar_malha_rosto(imagem)
|
|
150
|
+
rostos = detector.encontrar_pontos(imagem)
|
|
151
|
+
|
|
152
|
+
# --- Mostrar a imagem --- #
|
|
153
|
+
cv2.imshow('Captura', imagem)
|
|
154
|
+
|
|
155
|
+
# --- Tempo de atualização --- #
|
|
156
|
+
cv2.waitKey(1)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
if __name__ == '__main__':
|
|
160
|
+
main()
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mpvc
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Módulo para detecção de mão, rosto e malha facial usando MediaPipe e OpenCV
|
|
5
|
+
Author-email: Mundo Python <mundopython98@gmail.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: <=3.12,>=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: opencv-python
|
|
12
|
+
Requires-Dist: mediapipe==0.10.21
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
mpvc/__init__.py
|
|
4
|
+
mpvc/detector_maos.py
|
|
5
|
+
mpvc/detector_rosto.py
|
|
6
|
+
mpvc/malha_rosto.py
|
|
7
|
+
mpvc.egg-info/PKG-INFO
|
|
8
|
+
mpvc.egg-info/SOURCES.txt
|
|
9
|
+
mpvc.egg-info/dependency_links.txt
|
|
10
|
+
mpvc.egg-info/requires.txt
|
|
11
|
+
mpvc.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mpvc
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mpvc"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Mundo Python", email="mundopython98@gmail.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "Módulo para detecção de mão, rosto e malha facial usando MediaPipe e OpenCV"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.9, <=3.12"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"opencv-python",
|
|
21
|
+
"mediapipe==0.10.21",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.packages.find]
|
|
25
|
+
where = ["."]
|
|
26
|
+
include = ["mpvc*"]
|
mpvc-0.0.1/setup.cfg
ADDED