- 1. Operações bit a bit e mascaramento
- 2. Convolução e desfoque
- 3. Nitidez - Invertendo as manchas de imagem
- 4. Threshoding (Binarização)
- 5. Dilatação, Erosão, Abertura / Fechamento
- 6. Detecção de borda e gradientes de imagem
- 14. Perspectiva e transformação afim
- 8. Aplicativo Live Sketch
Nos tutoriais anteriores, aprendemos sobre OpenCV e fizemos alguns processamentos básicos de imagem e então no próximo tutorial fizemos alguma manipulação de imagens em OpenCV como recorte, rotação, transformação de imagem etc. Então, na continuação do tutorial anterior de Manipulação de Imagem, aqui aprendemos mais algumas técnicas de manipulação de imagem como e no final do tutorial iremos construir um programa python-opencv para fazer sketch ao vivo a partir do feed da webcam. Este aplicativo usará muitas das funções de processamento de imagens que aprendemos até agora ou que aprenderemos neste tutorial, então este será um bom exemplo prático para cobrir todas as funções.
Como dito no tutorial anterior, OpenCV é Open Source Commuter Vision Library que possui interfaces C ++, Python e Java e oferece suporte a Windows, Linux, Mac OS, iOS e Android. Portanto, ele pode ser facilmente instalado no Raspberry Pi com ambiente Python e Linux. E o Raspberry Pi com OpenCV e câmera conectada pode ser usado para criar muitos aplicativos de processamento de imagem em tempo real, como detecção de rosto, bloqueio de rosto, rastreamento de objeto, detecção de placa de carro, sistema de segurança residencial etc.
Neste tutorial, veremos mais algumas manipulações de imagens usando Python OpenCV. Aqui, aprenderemos a aplicar a seguinte função em uma imagem usando Python OpenCV:
- Operações bit a bit e mascaramento
- Convolução e desfoque
- Nitidez - Invertendo as manchas de imagem
- Limiar (Binarização)
- Dilatação, Erosão, Abertura / Fechamento
- Detecção de bordas e gradientes de imagem
- Perspectiva e transformação afim
- Aplicativo Live Sketch
1. Operações bit a bit e mascaramento
As operações bit a bit o ajudam no mascaramento de imagens e ajudam a criar algumas imagens simples.
Fazendo um quadrado
import cv2 import numpy as np # usamos apenas duas dimensões porque esta é uma imagem em tons de cinza, se estivéssemos usando uma imagem #colored, teríamos usado um retângulo = np.zeros ((300,300,3), np.uint8) # Fazendo um quadrado quadrado = np.zeros ((300,300), np.uint8) cv2.rectangle (quadrado, (50,50), (250,250), 255, -1) cv2.imshow ("quadrado", quadrado) cv2. waitKey (0)
Fazendo uma elipse
elipse = np.zeros ((300,300), np.uint8) cv2.ellipse (elipse, (150,150), (150,150), 30,0,180,255, -1) cv2.imshow ("elipse", elipse) cv2.waitKey (0)
Experimentar operações bit a bit
#AND_mostra apenas onde os dois se cruzam
BitwiseAND = cv2.bitwise_and (quadrado, elipse) cv2.imshow ("AND", BitwiseAND) cv2.waitKey (0)
#OR_mostra apenas onde o quadrado ou elipse está
OR bit a bit = cv2.bitwise_or (quadrado, elipse) cv2.imshow ("OR", OR bit a bit) cv2.waitKey (0)
#XOR_mostra apenas onde existe por si só
BitwiseXOR = cv2.bitwise_xor (quadrado, elipse) cv2.imshow ("XOR", BitwiseXOR) cv2.waitKey (0)
#NOT_mostra tudo o que não faz parte da elipse e a operação NÃO pode ser aplicada apenas a uma figura
BitwiseNOT_elp = cv2.bitwise_not (elipse) cv2.imshow ("NOT_ellipse", BitwiseNOT_elp) cv2.waitKey (0) cv2.destroyAllWindows ()
2. Convolução e desfoque
Uma convolução é uma operação matemática realizada em duas funções, produzindo uma terceira função, que normalmente é uma versão modificada da função original.
Imagem de saída = imagem Função tamanho do kernel
Na visão computacional, usamos o kernel para especificar o tamanho sobre o qual executamos nossa função de manipulação de nossa imagem.
Desfoque é uma operação em que calculamos a média dos pixels de uma região (Kernel)
O OpenCV desfoca uma imagem aplicando kernels, um kernel diz a você como alterar o valor de qualquer pixel, combinando-o com diferentes quantidades de pixels vizinhos, o kernel é aplicado a cada pixel na imagem, um por um, para produzir a imagem final.
Simplesmente dizendo, uma convolução de imagem é simplesmente uma multiplicação elementar de duas matrizes seguida por uma soma.
Podemos simplesmente entendê-lo pelo seguinte exemplo.
O acima é um Kernel 3X3.
Multiplicamos por 1/25 para normalizar, ou seja, somamos a 1 que estivemos aumentando a intensidade ou diminuindo a intensidade como no caso de clareamento ou escurecimento das imagens.
Vamos testar um método de desfoque opencv filter2D, fornecido pela função cv2.filter2D (imagem, -1, kernel)
import cv2 import numpy as np image = cv2.imread ('elephant.jpg') cv2.imshow ('original', imagem) cv2.waitKey (0)
#criando uma matriz de kernel 3x3
kernel_3x3 = np.ones ((3,3), np.float32) / 9
# usamos cv2.filter2D para convolver o kernel com uma imagem
desfocado = cv2.filter2D (imagem, -1, kernel_3x3) cv2.imshow ('3x3_blurring', desfocado) cv2.waitKey (0)
#criando uma matriz de kernel 7x7
kernel_7x7 = np.ones ((7,7), np.float32) / 49
# usamos cv2.filter2D para convolver o kernel com uma imagem
desfocado = cv2.filter2D (imagem, -1, kernel_7x7) cv2.imshow ('7x7_blurring', desfocado) cv2.waitKey (0) cv2.destroyAllWindows ()
Existem outros tipos de métodos de desfoque:
cv2.blur - Valor médio em uma janela especificada.
cv2.GaussianBlur - Semelhante, mas usa uma janela Gaussiana (mais ênfase nos pontos ao redor do centro).
cv2.medianBlur– Usa a mediana de todos os elementos da janela.
cv2.bilateralFilter– Desfoca enquanto mantém as bordas nítidas, preservando as bordas e os detalhes da linha.
Veremos um por um abaixo, primeiro exiba a imagem original usando o código abaixo:
import cv2 import numpy as np image = cv2.imread ('elephant.jpg') cv2.imshow ('original', imagem) cv2.waitKey (0)
cv2.blur:
Neste método, o cálculo da média é feito pela convolução da imagem com um filtro de caixa normalizado, que ocupa o lugar sob a caixa e substitui o elemento central. Aqui, o tamanho da caixa deve ser ímpar e positivo .
# cv2.blur blur = cv2.blur (image, (3,3)) cv2.imshow ('Averaging', blur) cv2.waitKey (0)
cv2.GaussianBlur:
# cv2.GaussianBlur #em vez do filtro de caixa, vamos tentar o kernel Gaussian Gaussian = cv2.GaussianBlur (imagem, (7,7), 0) cv2.imshow ('Gaussian blurring', Gaussian) cv2.waitKey (0)
cv2.medianBlur:
Leva a mediana de todos os pixels sob a área do kernel e o elemento central é substituído por esse valor mediano.
# cv2.medianBlur #torna a mediana de todos os pixels sob a área do kernel e o elemento central #é substituído por este valor mediano. mediana = cv2.medianBlur (imagem, 5) cv2.imshow ('mediana borrar', mediana) cv2.waitKey (0)
cv2.bilateralFilter:
Bilateral é muito eficaz na remoção de ruído, mantendo as bordas afiadas
# cv2.bilateralFilter #Bilateral é muito eficaz na remoção de ruído, mantendo as bordas nítidas bilateral = cv2.bilateralFilter (imagem, 9,75,75) cv2.imshow ('borrão bilateral', bilateral) cv2.waitKey (0) cv2. destroyAllWindows ()
Image De-noising-non Local significa Denoising
import cv2 import numpy as np image = cv2.imread ('elephant.jpg') cv2.imshow ('original', imagem) cv2.waitKey (0)
#parameter after None é a intensidade do filtro 'h' (5-10 é um bom intervalo) # próximo é h para componentes de cor, defina o mesmo valor de h novamente
dst = cv2.fastNlMeansDenoisingColored (image, None, 6,6,7,21) cv2.imshow ('Fast significa denois', dst) cv2.waitKey (0) cv2.destroyAllWindows ()
Existem 4 variações de eliminação de ruído de meios não locais
cv2.fastNlMeansDenoising () - para uma única imagem em escala de cinza
cv2.fastNlMeansDenoisingColored () - Imagem de cor única
cv2.fastNlmeansDenoisingMulti () - para a sequência de imagens em tons de cinza
cv2.fastNlmeansDenoisingcoloredMulti () - para sequência de imagens coloridas
3. Nitidez - Invertendo as manchas de imagem
A nitidez é o oposto de desfoque, ela fortalece ou enfatiza as bordas da imagem.
Kernel =,,
Nossa matriz de kernel soma um, então não há necessidade de normalizar (ou seja, multiplicar por um fator para o mesmo brilho do original), se o kernel não for normalizado para 1, a imagem seria mais clara ou mais escura.
import cv2 import numpy as np image = cv2.imread ('elephant.jpg') cv2.imshow ('original', imagem) cv2.waitKey (0)
kernel_sharpening = np.array (,
])
#applying sharpening kernel to input image
sharpened = cv2.filter2D (image, -1, kernel_sharpening) cv2.imshow ('sharpened image', sharpened) cv2.waitKey (0) cv2.destroyAllWindows ()
4. Threshoding (Binarização)
Limiar é o ato de converter uma imagem em forma binária. Em opencv, há uma função separada para o limiar definido como
Cv2.threshold (imagem, valor limite, valor máximo, tipo limite)
Existem os seguintes tipos de limite:
- cv2.THRESH_BINARY - mais comum
- cv2. THRESH_BINARY_INV - mais comum
- cv2.THRESH_TRUNC
- cv2.THRESH_TOZERO
- cv2. THRESH_TOZERO_INV
NOTA: a imagem deve ser convertida em tons de cinza antes do limiar
import cv2 import numpy as np # carregar imagem como grayscale image = cv2.imread ('gradient.jpg', 0) cv2.imshow ('original', image) cv2.waitKey (0)
#valor abaixo de 127 vai para 0 (preto), e acima de 127 vai para 255 (branco)
_, thresh1 = cv2.threshold (image, 127.255, cv2.THRESH_BINARY) cv2.imshow ('1 threshold', thresh1) cv2.waitKey (0)
#valor abaixo de 127 vai para 255 e valores acima de 127 vão para 0 (reverso do acima)
_, thresh2 = cv2.threshold (image, 127.255, cv2.THRESH_BINARY_INV) cv2.imshow ('2 threshold', thresh2) cv2.waitKey (0)
#valores acima de 127 são truncados (mantidos) em 127, o argumento 255 não é usado.
_, thresh3 = cv2.threshold (image, 127.255, cv2.THRESH_TRUNC) cv2.imshow ('3 thresh trunc', thresh3) cv2.waitKey (0)
# valores abaixo de 127 vão para 0, acima de 127 permanecem inalterados
_, thresh4 = cv2.threshold (image, 127.255, cv2.THRESH_TOZERO) cv2.imshow ('4 threshold', thresh4) cv2.waitKey (0)
#Revesrse de acima, abaixo de 127 permanece inalterado, acima de 127 vai para zero
_, thresh5 = cv2.threshold (imagem, 127,255, cv2.THRESH_TOZERO_INV) cv2.imshow ('5 threshold', thresh5) cv2.waitKey (0) cv2.destroyAllWindows ()
5. Dilatação, Erosão, Abertura / Fechamento
Estas são as operações no campo da morfologia matemática
Dilatação - adiciona pixels aos limites do objeto em uma imagem.
Erosão - remove pixels nos limites do objeto em uma imagem.
Abertura - Erosão seguida de dilatação.
Fechamento - Dilatação seguida de erosão.
A abertura é muito útil para diminuir o ruído das imagens, pois primeiro afina a imagem por erosão (remove o ruído) e depois a dilata.
Confusão com dilatação e erosão
Às vezes, há confusão entre dilatação e erosão geralmente em fotos com fundo branco, pois opencv considera fundo branco como imagem a ser dilatada ou erodida em vez da imagem original, portanto, neste caso, a erosão funciona como dilatação e vice-versa, conforme mostrado na amostra de imagem mostrado abaixo.
Lembre-se, a dilatação adiciona pixels aos limites dos objetos em uma imagem, enquanto a erosão remove pixels nos limites dos objetos em uma imagem
import cv2 import numpy as np image = cv2.imread ('imagecv.png', 0) cv2.imshow ('original', imagem) cv2.waitKey (0)
#Erosion
# vamos definir o tamanho do nosso kernel
kernel = np.ones ((5,5), np.uint8)
# agora nós corroemos a imagem, aqui a iteração não é nenhuma vez que você quer corroer a imagem
erosion = cv2.erode (image, kernel, iterations = 1) cv2.imshow ('Erosion', erosion) cv2.waitKey (0)
#dilatação
dilatação = cv2.dilate (imagem, kernel, iterações = 1) cv2.imshow ('dilatação', dilatação) cv2.waitKey (0)
#opening, bom para remover o ruído
abrindo = cv2.morphologyEx (imagem, cv2.MORPH_OPEN, kernel) cv2.imshow ('abrindo', abrindo) cv2.waitKey (0)
#closing, bom para remover ruído
fechando = cv2.morphologyEx (imagem, cv2.MORPH_CLOSE, kernel) cv2.imshow ('fechando', fechando) cv2.waitKey (0) cv2.destroyAllWindows ()
6. Detecção de borda e gradientes de imagem
A detecção de bordas é uma área muito importante na visão computacional, especialmente quando se trata de contornos.
As arestas podem ser definidas como limites da imagem, na verdade são arestas que definem o objeto nas imagens, preservam muitas informações sobre a imagem.
Formalmente, as arestas podem ser definidas como mudanças repentinas (descontinuidades) em uma imagem e podem codificar tantas informações quanto pixels.
A imagem acima mostra como a visão computacional identifica e reconhece a imagem.
Algoritmos de detecção de bordas: - Existem três tipos principais de algoritmos de detecção de bordas
- Sobel - para dar ênfase a imagens verticais ou horizontais.
- Laplaciano - ótimo devido à baixa taxa de erro, bordas bem definidas e detecção precisa.
- Algoritmo de detecção do Canny Edge (desenvolvido por john.F.Canny em 1986)
1. Aplica desfoque gaussiano
2. Encontra gradiente de intensidade da imagem
3. aplica supressão não máxima (ou seja, remove pixels que não são bordas).
4. A histerese aplica o limite (ou seja, se o pixel estiver dentro do limite superior e inferior, é considerado uma borda)
import cv2 import numpy as np image = cv2.imread ('input.jpg', 0) height, width = image.shape
#sobel
#extraindo bordas sobel
sobel_x = cv2.Sobel (imagem, cv2.CV_64F, 0,1, ksize = 5) sobel_y = cv2.Sobel (imagem, cv2.CV_64F, 1,0, ksize = 5) cv2.imshow ('original', imagem) cv2.waitKey (0) cv2.imshow ('sobelx', sobel_x) cv2.waitKey (0)
#Sobely
cv2.imshow ('sobely', sobel_y) cv2.waitKey (0)
sobel_OR = cv2.bitwise_or (sobel_x, sobel_y) cv2.imshow ('sobelOR', sobel_OR) cv2.waitKey (0)
#laplaian
laplacian = cv2.Laplacian (imagem, cv2.CV_64F) cv2.imshow ('Laplacian', laplacian) cv2.waitKey (0)
O algoritmo de detecção de borda #canny usa valores de gradiente como limites
#in canny, precisamos fornecer dois valores: threshold1 e threshold2.
# qualquer gradiente maior que o limite 2 é considerado uma borda.
# qualquer gradiente maior que o limite 1 é considerado não uma borda.
#valores entre o limite 1 e o limite 2 são como limite ou não limite
# em como suas intensidades são conectadas, neste caso qualquer valor abaixo de 60 é considerado #não
limite enquanto qualquer valor acima de 120 é considerado como limite.
canny = cv2.Canny (imagem, 60,120) cv2.imshow ('canny', astuto) cv2.waitKey (0) cv2.destroyAllWindows ()
14. Perspectiva e transformação afim
Vamos dar um passo atrás e dar uma olhada nas transformações afins e não afins, a imagem original mostrada abaixo é claramente uma imagem não afim, pois as bordas vão se encontrar em algum ponto, no entanto, podemos endireitá-la entortando e tomando a perspectiva transformar.
Para esta transformação de perspectiva, precisamos das quatro coordenadas da imagem original e, em seguida, dos quatro pontos da imagem de saída, eles são denotados por pontos_A e pontos_B. Em primeiro lugar, com a ajuda desses pontos, calculamos uma matriz de transformação, M, com a ajuda da função getPerspectiveTransform.
E então essa matriz é dada à função warpPerspective para gerar a saída final.
Agora, vamos primeiro tentar a transformação Perspectiva.
import cv2 import numpy as np import matplotlib.pyplot as plt image = cv2.imread ('paper.jpg') cv2.imshow ('original', imagem) cv2.waitKey (0)
#coordenada de 4 cantos da imagem original
points_A = np.float32 (,,,])
#coordenadas de 4 cantos da saída desejada
# usamos uma proporção de um papel A4 1: 1,41
points_B = np.float32 (,,,])
# use os dois conjuntos de dois pontos para calcular a matriz de transformação em perspectiva , M
M = cv2.getPerspectiveTransform (points_A, points_B) warped = cv2.warpPerspective (image, M, (420.594)) cv2.imshow ('warpprespective', warped) cv2.waitKey (0) cv2.destroyAllWindows ()
A transformação afim é mais fácil do que a transformação não afim, pois precisamos de apenas três pontos para obter a transformação. Todo o processo é o mesmo, mas em vez da transformação de perspectiva, agora temos a transformação afim e também definimos cols e linhas em warpAffine a partir da função de forma em vez de inseri -la manualmente.
import cv2 import numpy as np import matplotlib.pyplot as plt image = cv2.imread ('box.jpg') rows, cols = image.shape cv2.imshow ('original', image) cv2.waitKey (0)
#coordenada de 3 cantos da imagem original
points_A = np.float32 (,,])
#coordenadas de 3 cantos da saída desejada
# usamos uma proporção de um papel A4 1: 1,41
points_B = np.float32 (,,])
#use os dois conjuntos de dois pontos para calcular a
matriz #transformation Affine, M
M = cv2.getAffineTransform (points_A, points_B) warped = cv2.warpAffine (imagem, M, (cols, linhas)) cv2.imshow ('warpaffine', warped) cv2.waitKey (0) cv2.destroyAllWindows ()
8. Aplicativo Live Sketch
Em primeiro lugar, parabenize-se por ter feito esse mini projeto depois de ler todas as funções de manipulação de imagens acima. Portanto, neste mini projeto do Python OpenCV vamos aprender alguns novos conceitos de loops e funções. Se você está familiarizado com programação, deve ter uma ideia mais ampla do que são a função e os loops. No entanto, em python, o conceito básico de loops e funções permanece o mesmo, mas o método para defini-los muda um pouco.
Portanto, no início deste programa, podemos ver um certo grupo de instruções sob o “ esboço def (imagem): ” esta é uma definição formal de uma função - um grupo de instruções trabalhando juntas para uma determinada saída.
Portanto, este esboço é uma função, em python, a função é definida por “def” e termina com uma marca “:”. Além disso, as instruções que devem estar dentro da função ou você pode dizer quais são necessárias para que a função funcione corretamente, são alinhadas lateralmente automaticamente pela função. Portanto, para sair das funções, as instruções precisavam ser totalmente alinhadas à esquerda. Para referências adicionais, você pode consultar o google sobre como as funções são definidas em python.
Portanto , nesta função de esboço, introduzimos várias camadas de processamento de imagem que se combinam para fornecer uma saída. Em primeiro lugar, a imagem é convertida em tons de cinza para que o opencv possa processá-la facilmente e, em seguida, um desfoque gaussiano é aplicado à imagem em escala de cinza para reduzir o ruído. Em seguida, as arestas estão sendo extraídas com a ajuda do algoritmo de detecção de arestas do canny, em seguida, um inverso binário é aplicado na imagem definida pela aresta, aqui o inverso binário também poderia ser feito por bitwise_NOT, mas tínhamos escolhido deliberadamente esse inverso binário limite, pois dá liberdade para definir seus parâmetros até obtermos uma imagem clara.
Observe também que a função obtém os argumentos imagem e retorna os dois argumentos ret e máscara. Enquanto ret é o booleano informando que a função foi executada com sucesso ou não e a máscara é a saída final da função, ou seja, a imagem processada.
Então o segundo conceito é operar a webcam em opencv que é feito pela função cv2.VideoCapture (0) , que armazena a imagem em um cap de objeto que cap pode ser lido com a função cap.read () , também aqui para observar esse cap. read () está dentro do loop while infinito , já que teve que capturar continuamente as imagens, para dar uma sensação de um vídeo ao vivo, onde a taxa de quadros do vídeo seria a taxa de quadros de sua webcam, que é principalmente entre 24 a 60 fps.
cap.read () retorna ret e frame, onde ret é o booleano indicando que a função foi executada com sucesso ou não e o frame contém a imagem obtida pela webcam.
Abaixo está o código Python OpenCV completo para executar o Live Sketch
import cv2 import numpy as np #sketch gerando função def sketch (image): #converter imagem em tons de cinza img_gray = cv2.cvtColor (image, cv2.COLOR_BGR2GRAY) #cleaning up a imagem usando Gaussian blur img_gray_blur = cv2.GaussianBlur (img_gray, 5,5), 0) #extract Edge canny_edges = cv2.Canny (img_gray_blur, 10,70) #do an invert binarize a imagem ret, mask = cv2.threshold (canny_edges, 70,255, cv2.THRESH_BINARY_INV) return mask #initialize webcam, cap é o objeto fornecido pela captura de vídeo # ele contém um booleano indicando se foi bem-sucedido (ret) #também contém as imagens coletadas da webcam (frame) cap = cv2.VideoCapture (0) enquanto True: ret, frame = cap.read () cv2.imshow ('livesketcher', sketch (frame)) if cv2.waitKey (1) == 13: # 13 é o enterkey pausa câmera #release e perto da janela, lembre-se de liberar o webcam com a ajuda de cap.release () cap.release () cv2.destroyAllWindows ()
Portanto, este é o fim da Parte 2 das manipulações de imagens em Python-OpenCV. Para entender melhor a visão computacional e o OpenCV, leia os artigos anteriores (Introdução ao OpenCV Python e Manipulações de imagem no OpenCV Python (Parte 1) e você será capaz de fazer algo legal com a Visão computacional.