Solucionado (ver solução)
Solucionado
(ver solução)
8
respostas

Aspecto razão - ValueError: Input vector should be 1-D

Olá. O meu código deu erro, mas pelo que verifiquei está igual do professor:

#Criando conjuntos de pontos
FACE_COMPLETA = list(range(0,68))
FACE  = list(range(17,68)) 
LABIO = list(range(48,61))
SOBRANCELHA_DIREITA = list(range(17,22))
SOBRANCELHA_ESQUERDA = list(range(22,27))
OLHO_DIREITO = list(range(36,42))
OLHO_ESQUERDO = list(range(42,48))
NARIZ = list(range(27,35))
MANDIBULA = list(range(0,17))
def aspecto_razao_olhos(pontos_olhos):
    a = dist.euclidean(pontos_olhos[1], pontos_olhos[5])
    b = dist.euclidean(pontos_olhos[2], pontos_olhos[4])
    c = dist.euclidean(pontos_olhos[0], pontos_olhos[3])

    aspecto_razao = (a+b)/(2.0 * c)

    return aspecto_razao
valor_olho_esquerdo = aspecto_razao_olhos(marcos_faciais[0][OLHO_ESQUERDO])
valor_olho_esquerdo
8 respostas

Oi, Vivian! Tudo certinho?

Pelo que observei, seu código está mesmo igual ao do professor. Pode ser que a diferença esteja em alguma outra parte do código, como na definição das funções, por exemplo.

Você pode ver o código completo no repositório do curso no GitHub, para comparar.

Se não achar a diferença e o erro persistir, me conte qual erro está recebendo, ou de que forma não está funcionando, por favor. Assim posso te responder de forma mais assertiva :)

Aguardo seu retorno. Abraços!

Olá. Verifiquei e todo o restante do código também está igual ao do professor, segue primeira parte:

import os
import cv2
import numpy as np
import dlib  
import matplotlib.pyplot as plt

from scipy.spatial import distance as dist

# Define um alias para o path
diretorio_base = '/home/vivian/Nextcloud/Vivian_Ferreira_Margarido/Codes/Alura/Analise_Classificacao_de_Faces_VC_Alura/'

#Carregar imagem
imagem = cv2.imread(os.path.join(diretorio_base,"px-woman-smilings.jpg")) #BGR
imagem = cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB)

plt.figure(figsize = (20,10))
plt.imshow(imagem)

classificador_dlib_68_path = os.path.join(diretorio_base,"Classificadores/shape_predictor_68_face_landmarks.dat") #contém os parâmetros e configurações do modelo já treinado

#Carregando classificador dentro da biblioteca dlib
classificador_dlib = dlib.shape_predictor(classificador_dlib_68_path) #carregar um modelo treinado para a predição de pontos de referência faciais

#Pegando o face detector do dlib que já está associado ao classificador
detector_face = dlib.get_frontal_face_detector() #função na biblioteca Dlib em Python que retorna um objeto detector de faces. 
#Esse detector é treinado para localizar faces em imagens e é especialmente eficiente na detecção de faces frontais.
'''Histogram of Oriented Gradients (HOG) combinada com um classificador linear (normalmente um classificador Support Vector Machine - SVM)'''

#Identificando rostos na imagem
def anotar_rosto(imagem):
    retangulos = detector_face(imagem,1) #1 indica que imagem NÃO será redimensionado para detecção de rostos em outras escalas

    if len(retangulos) == 0:
        return None #nenhum rosto detectado
    
    for k,d in enumerate(retangulos): #k = ínidice do elemento, d = elemento (par de tuplas = retângulo)
        print("Identificado rosto " + str(k))
        cv2.rectangle(imagem, (d.left(), d.top()),(d.right(), d.bottom()), (255,255,0),2) # Coordenadas dos vértices opostos: (d.left(), d.top()): As coordenadas do canto superior esquerdo do retângulo(d);(d.right(), d.bottom()): As coordenadas do canto inferior direito do retângulo, também obtidas do objeto d.

    return imagem
    
imagem_anotada = imagem.copy()
imagem_anotada = anotar_rosto(imagem_anotada)

plt.figure(figsize = (20,10))
plt.imshow(imagem_anotada)

#Detectando os marcos_faciais de rostos na imagem
def pontos_marcos_faciais(imagem):
    retangulos = detector_face(imagem, 1) #1 indica que imagem NÃO será redimensionado para detecção de rostos em outras escalas

    if len(retangulos) == 0: 
        return None #nenhum rosto detectado
    
    marcos_faciais = [] 

    for ret in retangulos:#para cada retângulo identificado (rosto identificado)
        marcos_faciais.append(np.matrix([[p.x, p.y] for p in classificador_dlib(imagem, ret).parts()])) #organizando os conjuntos dos pontos dos marcos faciais

        return marcos_faciais
        
#Aplicando a função "pontos_marcos_faciais" em uma imagem
marcos_faciais = pontos_marcos_faciais(imagem)

len(marcos_faciais) #número de rostos detectados na imagem

len(marcos_faciais[0]) #número de marcos_faciais encontrados no rosto de índice 0

#Desenhando os marcos faciais na imagem

def anotar_marcos_faciais(imagem, marcos_faciais):

    for marco in marcos_faciais: #cada marco é uma coordenada em formato de matrix, por exemplo: [[245 262]] -> matriz de 1 linha e 2 colunas >> aqui, ponto[0,0] = 245
        for idx, ponto in enumerate (marco): #enumerando os pontos (marcos faciais)
            centro = (ponto[0,0], ponto[0,1]) #coordenada do ponto a ser plotado >> ponto[0,0] = ponto[linha da matriz, coluna da matriz]
            cv2.circle(imagem, centro, 3, (255,255,0), -1) #desenhando círculo: recebe a imagem na qual o círculo será desenhado, 3: raio, (255,255,0): cor, -1: pintar todo o círculo (maior que zero irá pintar apenas o contorno do círculo)
            cv2.putText(imagem, str(idx), centro, cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255,255,255), 2) #escrevendo um texto na imagem: str(idx) = o que será escrito, centro = coordenada do texto, cv2.FONT_HERSHEY_SIMPLEX = estilo da fonte do texto, 0.8 = tamanho da fonte, (255,255,255) = cor da fonte (branco), 2 = espessura da linha

        return imagem

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Segue segunda parte do código (devido ao limite de caracteres, não consegui enviar tudo de uma vez):

#Aplicando função "anotar_marcos_faciais" em uma imagem
imagem_anotada = imagem.copy()
imagem_anotada = anotar_marcos_faciais(imagem_anotada, marcos_faciais)

plt.figure(figsize=(20,10))
plt.imshow(imagem_anotada)

imagem_pessoa = cv2.imread(os.path.join(diretorio_base,"px-man-happy.jpg")) 
imagem_pessoa = cv2.cvtColor(imagem_pessoa, cv2.COLOR_BGR2RGB)

plt.figure(figsize=(20,10))
plt.imshow(imagem_pessoa)

imagem_anotada = imagem_pessoa.copy()
marcos_faciais = pontos_marcos_faciais(imagem_anotada)
imagem_anotada = anotar_marcos_faciais(imagem_anotada, marcos_faciais)

plt.figure(figsize = (20,10))
plt.imshow(imagem_anotada)

#Separar regiões da face

#Criando conjuntos de pontos
FACE = list(range(17, 68))
FACE_COMPLETA = list(range(0, 68))
LABIO = list(range(48, 61))
SOMBRANCELHA_DIRETA = list(range(17, 22))
SOMBRANCELHA_ESQUERDA = list(range(22, 27))
OLHO_DIREITO = list(range(36,42))
OLHO_ESQUERDO = list(range(42,48))
NARIZ = list(range(27,35))
MANDIBULA = list(range(0,17))

def aspecto_razao_olhos(pontos_olhos):
    
    a = dist.euclidean(pontos_olhos[1], pontos_olhos[5])
    b = dist.euclidean(pontos_olhos[2], pontos_olhos[4])
    c = dist.euclidean(pontos_olhos[0], pontos_olhos[3])
    
    aspecto_razao = (a + b)/(2.0 * c)
    
    return aspecto_razao
    
def anotar_marcos_casca_convexa(imagem, marcos):
    retangulos = detector_face(imagem,1)

    if len(retangulos) == 0:
        return None
    
    for idx, ret in enumerate(retangulos):
        marco = marcos[idx] #pega os marcos de uma única face

        pontos = cv2.convexHull(marco[OLHO_ESQUERDO])
        cv2.drawContours(imagem, [pontos], 0, (0,255,0), 2)

        pontos = cv2.convexHull(marco[OLHO_DIREITO])
        cv2.drawContours(imagem, [pontos], 0, (0,255,0), 2)

        return imagem
        
imagem_anotada = imagem_pessoa.copy()
imagem_anotada = anotar_marcos_casca_convexa(imagem_anotada, marcos_faciais)

plt.figure(figsize = (10,20))
plt.imshow(imagem_anotada)

valor_olho_esquerdo = aspecto_razao_olhos(marcos_faciais[0][OLHO_ESQUERDO])
valor_olho_esquerdo

valor_olho_direito = aspecto_razao_olhos(marcos_faciais[0][OLHO_DIREITO])
valor_olho_direito

Oi, Vivian! Tudo certinho?

Peço desculpas pela demora em te retornar.

Vivian, acredito que entendi melhor o problema. Como você está utilizando outro ambiente, pode ser que algumas configurações sobre como os dados são manipulados internamente sejam ligeiramente diferentes, então é necessário fazer algumas adaptações.

Seu código parece estar correto, assim como o do professor. Porém, o erro na execução da função aspecto_razao_olhos indica que o input para a função que calcula o valor euclidiano deve ser unidimensional.

Modifique a função da seguinte maneira, especificando que os arrays são unidimensionais:

def aspecto_razao_olhos(pontos_olhos):
    a = dist.euclidean(pontos_olhos[1][0], pontos_olhos[5][0])
    b = dist.euclidean(pontos_olhos[2][0], pontos_olhos[4][0])
    c = dist.euclidean(pontos_olhos[0][0], pontos_olhos[3][0])
    
    aspecto_razao = (a + b) / (2.0 * c)
    
    return aspecto_razao

Essa correção deve resolver o erro. Espero que dê tudo certo!

Abraços.

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓. Bons Estudos!

Olá, Larissa! Ainda está dando o mesmo erro :( Eu estou chamando a função "aspecto_razao_olhos" da seguinte maneira:

valor_olho_esquerdo = aspecto_razao_olhos(marcos_faciais[0][OLHO_ESQUERDO])
valor_olho_esquerdo

Está correto ou eu preciso fazer modificações na chamada uma vez que alterei a função?

Oi, Vivian.

Está correto. É estranho que não esteja funcionando. Pode ser que precise mais adaptações para o IDE ou que seja algum conflito de biblioteca.

Sugiro que, se possível, você teste seu projeto no Jupyter, com o ambiente criado conforme a aula. Assim, fica possível descobrir se o erro é relacionado a essas particularidades que conversamos ou a alguma parte do código, mesmo.

Abraços.

Olá. Eu vi em outro fórum uma solução que rodou para mim, porém os valores estão diferentes do professor.

Saberia me explicar por que funcionou desse jeito e por que os valores ficaram diferentes do professor?

A solução que encontrei foi:

def aspecto_razao_olhos(pontos_olhos):

    a = dist.euclidean(pontos_olhos[1].tolist()[0], pontos_olhos[5].tolist()[0])
    b = dist.euclidean(pontos_olhos[2].tolist()[0], pontos_olhos[4].tolist()[0])
    c = dist.euclidean(pontos_olhos[0].tolist()[0], pontos_olhos[3].tolist()[0])

    aspecto_razao = (a + b)/(2.0 * c)

    return aspecto_razao

Para o homem sorrindo os resultados deram: 0.12169073046467273 para olho esquerdo e 0.12044973520917499 para olho direito.

E para o homem sério: 0.2715204726310253 olho esquerdo e 0.27133313866169434 olho direito.

Posso usar essa solução mesmo ou está errada?

solução!

Oi, Vivian! Como vai?

Legal que você encontrou essa solução! A função tolist garante que o vetor sendo passado é unidimensional, ao transformar o array Numpy em uma lista Python.

A diferença nos valores pode ser referente às versões das bibliotecas. Como o principal objetivo da função aspecto_razao_olhos é compreender se os olhos estão abertos ou fechados, a comparação entre os valores retornados para olho esquerdo e direito já responde o necessário. Então, fique a vontade para utilizar essa solução.

Porém, reforço que o mais recomendado é criar um ambiente virtual com as mesmas versões do Python e das bibliotecas utilizadas pelo instrutor, conforme está na aula Preparando o ambiente. Assim o código deve funcionar sem conflitos.

Espero ter ajudado! Bons estudos.