Virtual-Puzzle-on-google-meet-with-python-and-opencv

Virtual Puzzle on google meet with python and opencv

INTRODUÇÃO

Trabalho final da disciplina de Processamento digital de imagens da UFRN. Inspirado no vídeo do MurtazasWorkshopRoboticsandAI, o quebra-cabeça virtual é um programa que faz com que o usuário consiga manipular fotos presentes no seu visor utilizando o movimento de suas mãos, assim sendo possível criar um quebra-cabeça para ser montado.

Exemplo de funcionamento:

ezgif.com-gif-maker.gif

COMO UTILIZAR

para poder utilizar você vai ter instalado o python, eu utilizei a versão 3.9, o programa de captura de tela OBS para gerar a câmera virtual para usar no meet e instalar no python a biblioteca cvzone versão 1.4.

Para exemplo utilizei uma imagem 1000x200 com o nome test.jpg, assim quando for executar e tiver outra imagem basta muda o endereço no código.

Passo a passo

  1. abri o OBS e iniciar a câmera virtual
  2. executar o código python
  3. se divertir com o a montagem do quebra-cabeça

caso queria ver o passo a passo pode assistir o vídeo:

https://www.youtube.com/watch?v=5MpKMHGrYTk

FUNCIONAMENTO DO CÓDIGO

import cv2
import cvzone
import pyvirtualcam
from pyvirtualcam import PixelFormat
from cvzone.HandTrackingModule import HandDetector # detectar mãos

cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)

detector = HandDetector(detectionCon=0.7) #precisão de 70%

class imgObject():
    #iniciando varaiveis da imagem
    def __init__(self,posCenter,size=[200,200]):
        self.posCenter = posCenter
        self.size = size

    def updata(self,cursor):
        cx,cy = self.posCenter
        w,h = self.size

        # conferir se o dedo esta em cima da imagem e move para a posição do dedo
        if cx - w // 2 < cursor[0] < cx + w // 2 and cy - h // 2 < cursor[1] < cy + h // 2 :
            self.posCenter = cursor

imgList = []

#preparando a imagem para o quebra cabeça
imagem = cv2.imread("test.jpg")
imagem1 = imagem[0:200,0:200]
imagem2 = imagem[0:200,200:400]
imagem3 = imagem[0:200,400:600]
imagem4 = imagem[0:200,600:800]
imagem5 = imagem[0:200,800:1000]
cv2.imwrite("test3.jpg",imagem1)
cv2.imwrite("test4.jpg",imagem2)
cv2.imwrite("test1.jpg",imagem3)
cv2.imwrite("test2.jpg",imagem4)
cv2.imwrite("test0.jpg",imagem5)

for x in range(5):
    imgList.append(imgObject([x*250+150,150]))

with pyvirtualcam.Camera(width=1280, height=720, fps=24, fmt=PixelFormat.BGR) as cam:
    while True:
        success, img = cap.read()
        img = detector.findHands(img)
        lmList, _ = detector.findPosition(img) # posição da mão e dos dedos

        if lmList:
            l, _, _ = detector.findDistance(8,12,img,draw=False) # conta a distancia dos dedos

            #conferir se os dedos estão juntos ou não (click)
            if l < 40 :
                cursor = lmList[8] #posição do dedo indicador
                # atualiza a posição
                for rect in imgList:
                    rect.updata(cursor)
        try:
            #desenhar imagem na tela
            for i, rect in enumerate(imgList):
                filename = "test%d.jpg" % i
                cx, cy = rect.posCenter
                w, h = rect.size
                imagem = cv2.imread(filename)
                imagem = cv2.flip(imagem, 1)
                img[cy-h//2:cy+h//2,cx-w//2:cx+w//2] = imagem.copy()

                #parte verde do retangulo
                cvzone.cornerRect(img,(cx-w//2,cy-h//2,w,h),20,rt=0)
        except:
            pass

        cam.send(img)
        cam.sleep_until_next_frame()

        cv2.waitKey(1)

Começo com a importação das bibliotecas necessárias para o funcionamento: cv2 para o opencv, cvzone para poder utilizar bibliotecas de visão computacional,pyvirtualcam para criar a câmera virtual.

import cv2
import cvzone
import pyvirtualcam
from pyvirtualcam import PixelFormat
from cvzone.HandTrackingModule import HandDetector # detectar mãos

logo após inicio a variável de captura o vídeo da webcam e seleciono o seu tamanho para ser 1280x720 e também inicializo a função que responsável por detectar minha mão com 70% de precisão.

cap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)

detector = HandDetector(detectionCon=0.7) #precisão de 70%

Aqui eu crio a classe imgObject responsável por guarda todas as informações importantes para minha imagem, e o método update que atualiza a posição central da imagem, que vamos usar para poder fazer seu movimento na tela, futuramente.

class imgObject():
    #iniciando varaiveis da imagem
    def __init__(self,posCenter,size=[200,200]):
        self.posCenter = posCenter
        self.size = size

    def updata(self,cursor):
        cx,cy = self.posCenter
        w,h = self.size

        # conferir se o dedo esta em cima da imagem e move para a posição do dedo
        if cx - w // 2 < cursor[0] < cx + w // 2 and cy - h // 2 < cursor[1] < cy + h // 2 :
            self.posCenter = cursor

Crio a lista imgList que vai guarda todas as imagens do quebra cabeça. Então finalmente pego a imagem completa do quebra-cabeça e divido em 5 partes iguais e as salvo, depois crio uma lista com 5 objetos imgObject.

imgList = []

#preparando a imagem para o quebra cabeça
imagem = cv2.imread("test.jpg")
imagem1 = imagem[0:200,0:200]
imagem2 = imagem[0:200,200:400]
imagem3 = imagem[0:200,400:600]
imagem4 = imagem[0:200,600:800]
imagem5 = imagem[0:200,800:1000]
cv2.imwrite("test3.jpg",imagem1)
cv2.imwrite("test4.jpg",imagem2)
cv2.imwrite("test1.jpg",imagem3)
cv2.imwrite("test2.jpg",imagem4)
cv2.imwrite("test0.jpg",imagem5)

for x in range(5):
    imgList.append(imgObject([x*250+150,150]))

Essa linha em especifico é responsável por fazer a câmera virtual

with pyvirtualcam.Camera(width=1280, height=720, fps=24, fmt=PixelFormat.BGR) as cam:

Aqui que começa propriamente dito o código. Começo então pegando a imagem da webcam e já começo desenhando a minha mão no vídeo. Logo após pega a posição dos dedos. Dentro do if confiro a distancia entre os dedos indicador e médio, se for menos que 40 então eles estão não posição de click, segura a imagem e logo depois confiro se estão dentro da imagem, se estiver então eu atualizo a posição da imagem para a do meu cursor.

success, img = cap.read()
        img = detector.findHands(img)
        lmList, _ = detector.findPosition(img) # posição da mão e dos dedos

        if lmList:
            l, _, _ = detector.findDistance(8,12,img,draw=False) # conta a distancia dos dedos

            #conferir se os dedos estão juntos ou não (click)
            if l < 40 :
                cursor = lmList[8] #posição do dedo indicador
                # atualiza a posição
                for rect in imgList:
                    rect.updata(cursor)

Por ultimo eu uso o try e except para tentar plotar a imagem do quebra-cabeça na tela, usando os dados do imgObject, para isso uso o imagem.copy()

try:
            #desenhar imagem na tela
            for i, rect in enumerate(imgList):
                filename = "test%d.jpg" % i
                cx, cy = rect.posCenter
                w, h = rect.size
                imagem = cv2.imread(filename)
                imagem = cv2.flip(imagem, 1)
                img[cy-h//2:cy+h//2,cx-w//2:cx+w//2] = imagem.copy()

                #parte verde do retangulo
                cvzone.cornerRect(img,(cx-w//2,cy-h//2,w,h),20,rt=0)
        except:
            pass