Capa de invisibilidade usando OpenCV

Uma das abilidades indispensável para um projetista de visão computacional é sobre o uso máscaras. A capa de invisibilidade é um excelente exercício para compreensão dessa técnica.

Para repetir esse experimento você vai precisar dos seguintes itens.

  • Python3
  • Opencv-python ou opencv-contrib-python
  • numpy
  • Video de fundo
  • Uma toalha ou lençou de cor vermelho (com edição pode ser outra cor)

Podemos dividir esse propblemas nos seguintes tópicos:

  • Obtenção do fundo
  • mascaras para cor vermelha
  • Operações lógicas
import cv2
import numpy as np
cap=cv2.VideoCapture("input.mp4")
cap_fundo=cv2.VideoCapture("fundo.mp4")
mean_fundo=[]
# calcula mediana de de 10 frame
for i in range(10):
fundo=cap_fundo.read()[1]
mean_fundo.append(fundo)
fundo = np.median(np.array(mean_fundo),axis=0)
fundo=fundo.astype(np.uint8)
#gravar resultado
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
h, w, _ =fundo.shape
out = cv2.VideoWriter('my_saida.mp4', fourcc, 30, (h, w))
while(cap.isOpened()):
ret,frame=cap.read()
if not ret:
break
print(frame.shape)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([0, 120, 70])
upper_red = np.array([30, 255, 255])
mask1 = cv2.inRange(hsv, lower_red, upper_red)
lower_red = np.array([120, 120, 70])
upper_red = np.array([180, 255, 255])
mask2 = cv2.inRange(hsv, lower_red, upper_red)
mask1 = mask1 + mask2
mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))
mask1 = cv2.morphologyEx(mask1, cv2.MORPH_DILATE, np.ones((3, 3), np.uint8))
mask2 = cv2.bitwise_not(mask1)
res1 = cv2.bitwise_and(frame, frame, mask=mask2)
res2 = cv2.bitwise_and(fundo, fundo, mask=mask1)
saida = cv2.addWeighted(res1, 1, res2, 1, 0)
cv2.imshow("janela", saida)
k = cv2.waitKey(3)
#out.write(frame)
if k == ord("q"):
break
cv2.destroyAllWindows()
import cv2 import numpy as np cap=cv2.VideoCapture("input.mp4") cap_fundo=cv2.VideoCapture("fundo.mp4") mean_fundo=[] # calcula mediana de de 10 frame for i in range(10): fundo=cap_fundo.read()[1] mean_fundo.append(fundo) fundo = np.median(np.array(mean_fundo),axis=0) fundo=fundo.astype(np.uint8) #gravar resultado fourcc = cv2.VideoWriter_fourcc(*'mp4v') h, w, _ =fundo.shape out = cv2.VideoWriter('my_saida.mp4', fourcc, 30, (h, w)) while(cap.isOpened()): ret,frame=cap.read() if not ret: break print(frame.shape) hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower_red = np.array([0, 120, 70]) upper_red = np.array([30, 255, 255]) mask1 = cv2.inRange(hsv, lower_red, upper_red) lower_red = np.array([120, 120, 70]) upper_red = np.array([180, 255, 255]) mask2 = cv2.inRange(hsv, lower_red, upper_red) mask1 = mask1 + mask2 mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8)) mask1 = cv2.morphologyEx(mask1, cv2.MORPH_DILATE, np.ones((3, 3), np.uint8)) mask2 = cv2.bitwise_not(mask1) res1 = cv2.bitwise_and(frame, frame, mask=mask2) res2 = cv2.bitwise_and(fundo, fundo, mask=mask1) saida = cv2.addWeighted(res1, 1, res2, 1, 0) cv2.imshow("janela", saida) k = cv2.waitKey(3) #out.write(frame) if k == ord("q"): break cv2.destroyAllWindows()
import cv2
import numpy as np

cap=cv2.VideoCapture("input.mp4")
cap_fundo=cv2.VideoCapture("fundo.mp4")
mean_fundo=[]

# calcula mediana de de 10 frame
for i in range(10):
    fundo=cap_fundo.read()[1]
    mean_fundo.append(fundo)

fundo = np.median(np.array(mean_fundo),axis=0)
fundo=fundo.astype(np.uint8)

#gravar resultado
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
h, w, _ =fundo.shape
out = cv2.VideoWriter('my_saida.mp4', fourcc, 30, (h, w))

while(cap.isOpened()):
    ret,frame=cap.read()
    if not ret:
        break
    print(frame.shape)

    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    lower_red = np.array([0, 120, 70])
    upper_red = np.array([30, 255, 255])
    mask1 = cv2.inRange(hsv, lower_red, upper_red)

    lower_red = np.array([120, 120, 70])
    upper_red = np.array([180, 255, 255])

    mask2 = cv2.inRange(hsv, lower_red, upper_red)

    mask1 = mask1 + mask2

    mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))
    mask1 = cv2.morphologyEx(mask1, cv2.MORPH_DILATE, np.ones((3, 3), np.uint8))
    mask2 = cv2.bitwise_not(mask1)

    res1 = cv2.bitwise_and(frame, frame, mask=mask2)

    res2 = cv2.bitwise_and(fundo, fundo, mask=mask1)

    saida = cv2.addWeighted(res1, 1, res2, 1, 0)

    cv2.imshow("janela", saida)
    k = cv2.waitKey(3)
    #out.write(frame)
    if k == ord("q"):
        break

cv2.destroyAllWindows()

Das linhas 8 à 14 pegamos os 10 primeiros frames do fundo e criamos um fundo usando a mediana. Isso pode ser útil caso tenha alguma variação luminosa durante a gravação do video.

for i in range(10):
fundo=cap_fundo.read()[1]
mean_fundo.append(fundo)
fundo = np.median(np.array(mean_fundo),axis=0)
fundo=fundo.astype(np.uint8)
for i in range(10): fundo=cap_fundo.read()[1] mean_fundo.append(fundo) fundo = np.median(np.array(mean_fundo),axis=0) fundo=fundo.astype(np.uint8)
for i in range(10):
    fundo=cap_fundo.read()[1]
    mean_fundo.append(fundo)

fundo = np.median(np.array(mean_fundo),axis=0)
fundo=fundo.astype(np.uint8)

Das linhas 27 à 38 criamos as máscaras para detectar nossa capa

A segmentação realizada aqui segue os passos desse artigo link. Com excessão de que a cor vermelho esta entre 120 a 30 do canal H. Assim precisamos definir duas mascas porque o OpenCV mapear o canal H até 180.

Ou seja, uma mascara pega a região de 0 a 30 e a outra de 120 a 180.

hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([0, 120, 70])
upper_red = np.array([30, 255, 255])
mask1 = cv2.inRange(hsv, lower_red, upper_red)
lower_red = np.array([120, 120, 70])
upper_red = np.array([180, 255, 255])
mask2 = cv2.inRange(hsv, lower_red, upper_red)
mask1 = mask1 + mask2
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) lower_red = np.array([0, 120, 70]) upper_red = np.array([30, 255, 255]) mask1 = cv2.inRange(hsv, lower_red, upper_red) lower_red = np.array([120, 120, 70]) upper_red = np.array([180, 255, 255]) mask2 = cv2.inRange(hsv, lower_red, upper_red) mask1 = mask1 + mask2
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    lower_red = np.array([0, 120, 70])
    upper_red = np.array([30, 255, 255])
    mask1 = cv2.inRange(hsv, lower_red, upper_red)

    lower_red = np.array([120, 120, 70])
    upper_red = np.array([180, 255, 255])

    mask2 = cv2.inRange(hsv, lower_red, upper_red)

    mask1 = mask1 + mask2

Linhas 40 e 41 Aplicamos duas operações morfológica para remover ruídos e preencher buracos na máscara.

mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))
mask1 = cv2.morphologyEx(mask1, cv2.MORPH_DILATE, np.ones((3, 3), np.uint8))
mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8)) mask1 = cv2.morphologyEx(mask1, cv2.MORPH_DILATE, np.ones((3, 3), np.uint8))
    mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))
    mask1 = cv2.morphologyEx(mask1, cv2.MORPH_DILATE, np.ones((3, 3), np.uint8))

A mask1 tem valor 1 para a capa e 0 para o restante. A operação cv2.bitwise_not inverte criando a mask2. Assim quando aplicamos na imagem original, apenas a capa é removida.

a) mask1. b) mask2. d) res1. d) res2
mask2 = cv2.bitwise_not(mask1)
res1 = cv2.bitwise_and(frame, frame, mask=mask2)
res2 = cv2.bitwise_and(fundo, fundo, mask=mask1)
saida = cv2.addWeighted(res1, 1, res2, 1, 0)
mask2 = cv2.bitwise_not(mask1) res1 = cv2.bitwise_and(frame, frame, mask=mask2) res2 = cv2.bitwise_and(fundo, fundo, mask=mask1) saida = cv2.addWeighted(res1, 1, res2, 1, 0)
 mask2 = cv2.bitwise_not(mask1)

    res1 = cv2.bitwise_and(frame, frame, mask=mask2)

    res2 = cv2.bitwise_and(fundo, fundo, mask=mask1)

    saida = cv2.addWeighted(res1, 1, res2, 1, 0)

Na saída combinamos res1 e res2.

Se ficou com alguma dúvida deixe um comentário abaixo.

Creditos: learnopencv

15 Replies to “Capa de invisibilidade usando OpenCV”

  1. We are a group of volunteers and opening a new scheme in our community.

    Your web site provided us with valuable info to work on. You have done a formidable job and our entire community will be grateful to you.

Responder a bluray Cancelar resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *