Capturar região de interesse com OpenCV

Já vimos em outros artigos como fazer o reconhecimento facial cadastrando pessoas conhecidas. Com apenas isso, já são inúmeras as aplicações. Por exemplo, o não reconhecimento de uma pessoa em um ambiente residencial pode ser considerado uma detecção de anomalia; pode se tratar de um furto (quando sozinho) ou um roubo (se acompanhado de um morador do imóvel). Mas e se for uma visita familiar ou de amigos? Para fazer um cadastro assim, podemos adicionar uma face ao capturar região de interesse com OpenCV, de diversas formas.

Sugiro primeiramente a leitura dos artigos relacionados a reconhecimento facial. Os artigos mais flexíveis para essa implementação são:

Tem um artigo com OpenFace nesse link, mas para adicionar uma nova pessoa não é tão flexível.

Capturar região de interesse com OpenCV

região de interesse

Esse é o primeiro passo. Essa seleção pode ser feita através de um vídeo gravado ou uma streaming, bastando implementar uma pequena porção de código:

import cv2
import numpy as np
 
if __name__ == '__main__' :
 
    # Read image
    im = cv2.imread("churruminos.jpg")
    showCrosshair = False 
    fromCenter    = False
    # Select ROI
    myroi = cv2.selectROI("imgName", im, fromCenter, showCrosshair)
     
    # Crop image
    imCrop = im[int(myroi[1]):int(myroi[1]+myroi[3]), int(myroi[0]):int(myroi[0]+myroi[2])]
 
    # Display cropped image
    cv2.imshow("Image", imCrop)
    cv2.waitKey(0)
    cv2.imwrite("imgName.jpg", imCrop)

O nome da imagem a ser salva pode ser baseada em um índice de uma base de suspeitos (para ambientes públicos onde, nesse caso, não pode ser tratado como anomaly detection porque pessoas estranhas em ambiente público é um padrão), ou uma base de exceções, para cadastro de familiares. Em ambos os casos, será necessário implementar um pouco de código (mais comum, não tendo relação com CV ou IA) para salvar a imagem em um diretório local, então treiná-lo. Quando eu postar um projeto completo, demonstro essa parte.

No exemplo, utilizei uma imagem disponível localmente, mas poderia vir de uma câmera IP, webcam ou de uma análise de vídeo de segurança, no caso de cadastro de suspeitos em ambientes públicos. O vídeo relacionado é esse.

Não reparem o código de fundo, estou fazendo um OCR para RG e CNH, talvez eu faça uma demonstração em breve.

Após selecionar a região de interesse, será necessário pressionar Enter. O selectROI está disponível na API de tracking do OpenCV, cuja documentação se encontra nesse link.

Tem um tutorial bacana do PyImageSearch que mostra outra maneira de fazer a captura da região de interesse, mas o retângulo só será visível ao final da seleção. Posteriormente, utiliza-se a tecla ‘C’ do teclado para fazer a captura.

O código fica um pouco mais complicado, necessitando de diversas alterações para flexibilizar a implementação em uma situação como a proposta nesse artigo. Apenas para ilustrar (e caso queira experimentar também):

# construct the argument parser and parse the arguments
import argparse
import numpy as np
import cv2

# initialize the list of reference points and boolean indicating
# whether cropping is being performed or not
refPt = []
cropping = False
 
def click_and_crop(event, x, y, flags, param):
    # grab references to the global variables
    global refPt, cropping
 
    # if the left mouse button was clicked, record the starting
    # (x, y) coordinates and indicate that cropping is being
    # performed
    if event == cv2.EVENT_LBUTTONDOWN:
        refPt = [(x, y)]
        cropping = True
 
    # check to see if the left mouse button was released
    elif event == cv2.EVENT_LBUTTONUP:
        # record the ending (x, y) coordinates and indicate that
        # the cropping operation is finished
        refPt.append((x, y))
        cropping = False
 
        # draw a rectangle around the region of interest
        cv2.rectangle(image, refPt[0], refPt[1], (0, 255, 0), 2)
        cv2.imshow("image", image)

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
 
# load the image, clone it, and setup the mouse callback function
image = cv2.imread(args["image"])
clone = image.copy()
cv2.namedWindow("image")
cv2.setMouseCallback("image", click_and_crop)
 
# keep looping until the 'q' key is pressed
while True:
    # display the image and wait for a keypress
    cv2.imshow("image", image)
    key = cv2.waitKey(1) & 0xFF
 
    # if the 'r' key is pressed, reset the cropping region
    if key == ord("r"):
        image = clone.copy()
 
    # if the 'c' key is pressed, break from the loop
    elif key == ord("c"):
        break
 
# if there are two reference points, then crop the region of interest
# from teh image and display it
if len(refPt) == 2:
    roi = clone[refPt[0][1]:refPt[1][1], refPt[0][0]:refPt[1][0]]
    cv2.imshow("ROI", roi)
    cv2.waitKey(0)
 
# close all open windows
cv2.destroyAllWindows()

Esse segundo código utilizei em um projeto que atuei por 6 meses e foi um dos componentes que integrou um sistema com mais de 20 mil linhas de código Python, apenas na parte de OpenCVn (tive que escrever sozinho, infelizmente). Acredite, em uma implementação adequada é muito útil, vou dispondo por partes até integrar um sistema completo.

Até a próxima!

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.