Sol medidas
PROCESSAMENTO DE IMAGENS¶
Objetivos da aula:
- reconhecer e fazer medidas básicas e aproximadas de objetos
O PROBLEMA
Como obter os tamanhos dos objetos?
%matplotlib inline
import cv2
from matplotlib import pyplot as plt
import numpy as np
img = cv2.imread('objects.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.figure(figsize = (10,10))
plt.imshow(img); plt.show();
EXERCÍCIO
Calcular as arestas dos objetos da imagem acima.
#carregamos a imagem, convertemos para níveis de cinza e a borramos levemente
image = cv2.imread('objects.png')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# aplico um filtro gaussiano para suaviazar a imagem...
gray = cv2.GaussianBlur(gray, (9,9), 0)
#calculamos as arestas e realizamos uma dilatação + erosão para fechar
#eventuais gaps entre as arestas dos objetos
edged = cv2.Canny(gray, 50, 250)
dilate = cv2.dilate(edged, None, iterations=2)
erode = cv2.erode(dilate, None, iterations=2)
plt.figure(figsize = (20,15))
plt.subplot(2, 2, 1), plt.imshow(image)
plt.subplot(2, 2, 2), plt.imshow(gray, 'gray'), plt.title('gray')
plt.subplot(2, 2, 3), plt.imshow(dilate, 'gray'), plt.title('dilate')
plt.subplot(2, 2, 4), plt.imshow(erode, 'gray'), plt.title('erode')
plt.show();
#uma solução possivel...
#carregamos a imagem, convertemos para níveis de cinza e a borramos levemente
image = cv2.imread('objects.png')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# aplico um filtro gaussiano para suaviazar a imagem...
gray = cv2.GaussianBlur(gray, (7,7), 0)
#calculamos as arestas e realizamos uma dilatação + erosão para fechar
#eventuais gaps entre as arestas dos objetos
edged = cv2.Canny(gray, 50, 150)
dilate = cv2.dilate(edged, None, iterations=2)
erode = cv2.erode(dilate, None, iterations=1)
plt.figure(figsize = (20,15))
plt.subplot(2, 2, 1), plt.imshow(gray, 'gray'), plt.title('gray')
plt.subplot(2, 2, 2), plt.imshow(edged, 'gray'), plt.title('edged')
plt.subplot(2, 2, 3), plt.imshow(dilate, 'gray'), plt.title('dilate')
plt.subplot(2, 2, 4), plt.imshow(erode, 'gray'), plt.title('erode')
plt.show();
desafio1¶
Dica rápida de python. Vamos utilizar a função zip
do python que retorna uma sequência de tuplas. Pratique um pouco essa função.
- http://devfuria.com.br/python/built-in-zip/
- https://pythonhelp.wordpress.com/2013/04/16/funcao-zip-em-python/
- https://www.programiz.com/python-programming/methods/built-in/zip
obs. O operador *
pode ser utilizado com o zip() para descompactar (unzip) uma lista.
## pratique um pouco, rode os exemplos dos links para te ajudar a compreender o que está acontecendo...
# A funçao zip() é utilizada para unir duas listas.
lista_a = [6, 7, 8, 9, 1, 2, 3, 4, 5]
lista_b = ['R', 'A', 'I', 'M', 'U', 'N', 'D', 'O','S']
print('Unindo as listas...')
zipado = zip(lista_a, lista_b)
# print(zipado[0]) ### essa linha vai dar erro, pois zipado é um objeto do tipo zip, e não uma lista.
print(list(zipado)) ### para visualizar o conteúdo de zipado, precisamos converter para lista.
for x in zip(lista_a, lista_b):
print(x)
# Aproveitando para mostrar a funçao enumerate()...
# A funçao enumerate() é utilizada para retornar o índice e o valor de um item em uma lista.
print('listas com enumerate...')
for x,y in enumerate(zip(lista_a, lista_b)):
print(x,y)
desafio2¶
Dica rápida de python. Vamos utilizar list comprehensions
que basicamente realiza de forma compacta uma manipulação de listas. Pratique um pouco essa função.
## pratique um pouco, rode os exemplos dos links para te ajudar a compreender o que está acontecendo...
# A funcao list comprehension é uma forma de criar listas de forma mais compacta e elegante. 'Pythonica'.
# A sintaxe é: [expressao for item in lista]
# Exemplo 1:
# da forma tradicional, teriamos que fazer algo assim:
fruits = ["apple", "banana", "cherry", "kiwi", "mango"]
newlist = []
for x in fruits:
if "a" in x:
newlist.append(x)
print(newlist)
# usando list comprehension, podemos fazer assim:
fruits = ["apple", "banana", "cherry", "kiwi", "mango"]
newlist = [x for x in fruits if "a" in x]
print(newlist)
# Exemplo 2:
# da forma tradicional, teriamos que fazer algo assim:
lista = [1, 2, 3, 4, 5]
nova_lista = []
for x in lista:
nova_lista.append(x + 10)
print(nova_lista)
# usando list comprehension, podemos fazer assim:
lista = [1, 2, 3, 4, 5]
nova_lista = [x + 10 for x in lista]
print(nova_lista)
# Exemplo 3:
# podemos usar list comprehension para somar os elementos de duas listas...
lista1 = [1, 2, 3, 4, 5]
lista2 = [6, 7, 8, 9, 10]
soma = [x + y for x, y in zip(lista1, lista2)]
print(soma)
desafio3¶
Dica rápida de python. Vamos utilizar a função lambda
que basicamente realiza de forma pratica uma função anônima. Pratique um pouco essa função.
- https://www.hashtagtreinamentos.com/funcoes-lambda-python?gclid=CjwKCAjwiuuRBhBvEiwAFXKaNF77HmSrHlWg1Tx5Okpt6x9QFZemjbINiX9sX43R-fCNnXkuy8fiTxoCkiEQAvD_BwE
- https://www.w3schools.com/python/python_lambda.asp
- https://www.codingame.com/playgrounds/52499/programacao-python-intermediario---prof--marco-vaz/funcao-lambda
## pratique um pouco, rode os exemplos dos links para te ajudar a compreender o que está acontecendo...
# a função lambda é uma forma de criar funções anônimas, ou seja, funções que não tem um nome associado.
# Elas são úteis quando você precisa de uma função simples por um curto período de tempo e não quer defini-la usando a sintaxe padrão def.
# A sintaxe é: lambda arguments : expression
# Exemplo 1:
x = lambda a : a + 10
print(x(5))
# Exemplo 2:
x = lambda a, b : a * b
print(x(5, 6))
# Exemplo 3:
x = lambda a, b, c : a + b + c
print(x(5, 6, 2))
# Exemplo 4:
# podemos usar lambda para ordenar uma lista de tuplas...
lista = [(1, 2), (4, 1), (9, 10), (13, -3)]
lista.sort(key=lambda x: x[1])
print(lista)
# Para avançar na programação em linguagem python, sugiro praticar e conhecer essas funções e outras tais como: 'map', 'filter' e 'sorted'.
# A prática leva a perfeição.
OBTENÇÃO DOS CONTORNOS¶
A partir das arestas, podemos obter os contornos dos objetos.
cnts, _ = cv2.findContours(erode.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# Ordena a lista de contornos para ficar da esquerda para direita.
# Vamos precisar disso mais tarde.
# https://github.com/jrosebr1/imutils/blob/master/imutils/contours.py
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, [cv2.boundingRect(c) for c in cnts]), key=lambda b: b[1][0], reverse=False))
# https://github.com/jrosebr1/imutils/blob/master/imutils/perspective.py
# ordena os pontos do contorno de tal modo que eles
# apareçam na seguinte ordem: topo-esquerda, topo-direita,
# base-direita e base-esquerda
import numpy as np
from scipy.spatial import distance as dist
def order_points(pts):
xSorted = pts[np.argsort(pts[:, 0]), :]
# grab the left-most and right-most points from the sorted
# x-roodinate points
leftMost = xSorted[:2, :]
rightMost = xSorted[2:, :]
# now, sort the left-most coordinates according to their
# y-coordinates so we can grab the top-left and bottom-left
# points, respectively
leftMost = leftMost[np.argsort(leftMost[:, 1]), :]
(tl, bl) = leftMost
# now that we have the top-left coordinate, use it as an
# anchor to calculate the Euclidean distance between the
# top-left and right-most points; by the Pythagorean
# theorem, the point with the largest distance will be
# our bottom-right point
D = dist.cdist(tl[np.newaxis], rightMost, "euclidean")[0]
(br, tr) = rightMost[np.argsort(D)[::-1], :]
# return the coordinates in top-left, top-right,
# bottom-right, and bottom-left order
return np.array([tl, tr, br, bl], dtype="float32")
orig = image.copy()
#Percorre todos os contornos
for c in cnts:
# se o contorno não é suficientemente grande, ignorá-lo
if cv2.contourArea(c) < 100:
continue
# calcula a bounding box rotacionada do contorno
box = cv2.minAreaRect(c)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
#ordena os pontos do contorno de tal modo que eles
#apareçam na seguinte ordem: topo-esquerda, topo-direita,
#base-direita e base-esquerda
box = order_points(box)
#print(box)
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
for (x, y) in box:
cv2.circle(orig, (int(x), int(y)), 5, (255, 0, 0), -1)
plt.figure(figsize = (10,10))
plt.imshow(orig); plt.show();
OBTENÇÃO DOS PONTOS MÉDIOS
Vamos, agora, obter os pontos-médios de cada região identificada e desenhá-los:
import numpy as np
def midpoint(ptA, ptB):
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
orig = image.copy()
#Percorre todos os contornos
for c in cnts:
# ignora contornos muito pequenos
if cv2.contourArea(c) < 100:
continue
# calcula a bounding box rotacionada do contorno
box = cv2.minAreaRect(c)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
#ordena os pontos do contorno de tal modo que eles
#apareçam na seguinte ordem: top-left, top-right,
#bottom-right e bottom-left
box = order_points(box)
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
for (x, y) in box:
cv2.circle(orig, (int(x), int(y)), 5, (255, 0, 0), -1)
#-----------------------------------isso é novidade ----------------
#obtém os pontos médios de top-left/top-right e bottom-left e bottom-right
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
#obtém os pontos médios de top-left/bottom-left e top-right e bottom-right
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
#desenha cículos nos pontos-médios
cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
#une os pontos-médios com segmentos de reta
cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),(255, 0, 255), 2)
cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),(255, 0, 255), 2)
plt.figure(figsize = (10,10))
plt.imshow(orig); plt.show();
OBTENÇÃO DAS MEDIDAS
Para obter as medidas dos objetos, precisamos tomar um objeto de referência (ponto de calibração) de tamanho conhecido. Na imagem anterior, vamos tomar como medida de referência a moeda de dólar norte-americano, cujo comprimento é 2.43 cm. A partir dela, definimos todas as outras medidas.
É neste ponto que vai servir ter feito a ordenação do cnts
da esquerda para a direita, a nossa moeda de dólar esta bem destacada no lado esquerdo da imagem, desta forma fica facil fazer a calibração pois será o primeiro item da lista.
width=2.43
pixelsPerMetric=None
def midpoint(ptA, ptB):
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
orig = image.copy()
#Percorre todos os contornos
for c in cnts:
# se o contorno não é suficientemente grande, ignorá-lo
if cv2.contourArea(c) < 100:
continue
# calcula a bounding box rotacionada do contorno
box = cv2.minAreaRect(c)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
#ordena os pontos do contorno de tal modo que eles
#apareçam na seguinte ordem: top-left, top-right,
#bottom-right e bottom-left
box = order_points(box)
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
for (x, y) in box:
cv2.circle(orig, (int(x), int(y)), 5, (25, 0, 0), -1)
#obtém os pontos médios de top-left/top-right e bottom-left e bottom-right
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
#obtém os pontos médios de top-left/bottom-left e top-right e bottom-right
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
#desenha cículos nos pontos-médios
cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
#une os pontos-médios com segmentos de reta
cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),(255, 0, 255), 2)
cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),(255, 0, 255), 2)
###-------------não te mnovidade
# Cálculo da distância entre dois pontos, distância euclidiana
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
##########---------------isso é novidade--------------------------------------------------------------------
# define a escala para relacionar pixel por centrimetro
if pixelsPerMetric is None:
pixelsPerMetric = dB / width
dimA = dA / pixelsPerMetric
dimB = dB / pixelsPerMetric
cv2.putText(orig, "{:.2f}cm".format(dimB),(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,0.50, (255, 255, 255), 1)
cv2.putText(orig, "{:.2f}cm".format(dimA),(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,0.50, (255, 255, 255), 1)
plt.figure(figsize = (10,10))
plt.imshow(orig); plt.show();
Desafio¶
Realize o processamento da imagem abaixo a fim de obter os dimensionais de todos os cartões. Faça a escolha de um dos cartões para ser a referência e servir de calibração.
O cartão da esquerda possui 8.89 x 5.08 cm.
%matplotlib inline
import cv2
from matplotlib import pyplot as plt
import numpy as np
img = cv2.imread('objects2.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.figure(figsize = (10,10))
plt.imshow(img); plt.show();
### Seu código aqui....
## uma soluçao simples é basicamente copiar e colar o código acima e adaptar para a nova imagem.
# funciona? sim, mas não é a melhor forma de fazer.
# Sugiro utilizar essa exercicio para praticar python e programação, tente criar novas funções para refatorar o código.
%matplotlib inline
import cv2
from matplotlib import pyplot as plt
import numpy as np
from scipy.spatial import distance as dist
width=8.89
pixelsPerMetric=None
def order_points(pts):
xSorted = pts[np.argsort(pts[:, 0]), :]
# grab the left-most and right-most points from the sorted
# x-roodinate points
leftMost = xSorted[:2, :]
rightMost = xSorted[2:, :]
# now, sort the left-most coordinates according to their
# y-coordinates so we can grab the top-left and bottom-left
# points, respectively
leftMost = leftMost[np.argsort(leftMost[:, 1]), :]
(tl, bl) = leftMost
# now that we have the top-left coordinate, use it as an
# anchor to calculate the Euclidean distance between the
# top-left and right-most points; by the Pythagorean
# theorem, the point with the largest distance will be
# our bottom-right point
D = dist.cdist(tl[np.newaxis], rightMost, "euclidean")[0]
(br, tr) = rightMost[np.argsort(D)[::-1], :]
# return the coordinates in top-left, top-right,
# bottom-right, and bottom-left order
return np.array([tl, tr, br, bl], dtype="float32")
def midpoint(ptA, ptB):
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
#carregamos a imagem, convertemos para níveis de cinza e a borramos levemente
image = cv2.imread('objects2.png')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# aplico um filtro gaussiano para suaviazar a imagem...
gray = cv2.GaussianBlur(gray, (9,9), 0)
#calculamos as arestas e realizamos uma dilatação + erosão para fechar
#eventuais gaps entre as arestas dos objetos
edged = cv2.Canny(gray, 50, 250)
dilate = cv2.dilate(edged, None, iterations=2)
erode = cv2.erode(dilate, None, iterations=2)
cnts, _ = cv2.findContours(erode.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, [cv2.boundingRect(c) for c in cnts]), key=lambda b: b[1][0], reverse=False))
orig = image.copy()
#Percorre todos os contornos
for c in cnts:
# se o contorno não é suficientemente grande, ignorá-lo
if cv2.contourArea(c) < 100:
continue
# calcula a bounding box rotacionada do contorno
box = cv2.minAreaRect(c)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
#ordena os pontos do contorno de tal modo que eles
#apareçam na seguinte ordem: top-left, top-right,
#bottom-right e bottom-left
box = order_points(box)
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
for (x, y) in box:
cv2.circle(orig, (int(x), int(y)), 5, (25, 0, 0), -1)
#obtém os pontos médios de top-left/top-right e bottom-left e bottom-right
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
#obtém os pontos médios de top-left/bottom-left e top-right e bottom-right
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
#desenha cículos nos pontos-médios
cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
#une os pontos-médios com segmentos de reta
cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),(255, 0, 255), 2)
cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),(255, 0, 255), 2)
###-------------não te mnovidade
# Cálculo da distância entre dois pontos, distância euclidiana
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
##########---------------isso é novidade--------------------------------------------------------------------
# define a escala para relacionar pixel por centrimetro
if pixelsPerMetric is None:
pixelsPerMetric = dB / width
dimA = dA / pixelsPerMetric
dimB = dB / pixelsPerMetric
cv2.putText(orig, "{:.2f}cm".format(dimB),(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,0.50, (255, 255, 255), 1)
cv2.putText(orig, "{:.2f}cm".format(dimA),(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,0.50, (255, 255, 255), 1)
plt.figure(figsize = (10,10))
plt.imshow(orig); plt.show();
### vou criar algumas funções para refatorar o código acima...
%matplotlib inline
import cv2
from matplotlib import pyplot as plt
import numpy as np
from scipy.spatial import distance as dist
def order_points(pts):
x_sorted = pts[np.argsort(pts[:, 0]), :]
left_most = x_sorted[:2, :]
right_most = x_sorted[2:, :]
left_most = left_most[np.argsort(left_most[:, 1]), :]
tl, bl = left_most
d = dist.cdist(tl[np.newaxis], right_most, "euclidean")[0]
br, tr = right_most[np.argsort(d)[::-1], :]
return np.array([tl, tr, br, bl], dtype="float32")
def midpoint(pt_a, pt_b):
return ((pt_a[0] + pt_b[0]) * 0.5, (pt_a[1] + pt_b[1]) * 0.5)
def process_image(image_path):
image = cv2.imread(image_path)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
gray = cv2.GaussianBlur(gray, (9, 9), 0)
edged = cv2.Canny(gray, 50, 250)
dilate = cv2.dilate(edged, None, iterations=2)
erode = cv2.erode(dilate, None, iterations=2)
return erode
def find_and_sort_contours(eroded_image):
cnts, _ = cv2.findContours(eroded_image.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
(cnts, bounding_boxes) = zip(*sorted(zip(cnts, [cv2.boundingRect(c) for c in cnts]), key=lambda b: b[1][0]))
return cnts, bounding_boxes
def draw_contours(image, cnts):
orig = image.copy()
for c in cnts:
if cv2.contourArea(c) < 100:
continue
box = cv2.minAreaRect(c)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
box = order_points(box)
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
for (x, y) in box:
cv2.circle(orig, (int(x), int(y)), 5, (25, 0, 0), -1)
return orig
def draw_midpoints(image, cnts):
orig = image.copy()
for c in cnts:
if cv2.contourArea(c) < 100:
continue
box = cv2.minAreaRect(c)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
box = order_points(box)
tl, tr, br, bl = box
tltr_x, tltr_y = midpoint(tl, tr)
blbr_x, blbr_y = midpoint(bl, br)
tlbl_x, tlbl_y = midpoint(tl, bl)
trbr_x, trbr_y = midpoint(tr, br)
cv2.circle(orig, (int(tltr_x), int(tltr_y)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(blbr_x), int(blbr_y)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(tlbl_x), int(tlbl_y)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(trbr_x), int(trbr_y)), 5, (255, 0, 0), -1)
cv2.line(orig, (int(tltr_x), int(tltr_y)), (int(blbr_x), int(blbr_y)), (255, 0, 255), 2)
cv2.line(orig, (int(tlbl_x), int(tlbl_y)), (int(trbr_x), int(trbr_y)), (255, 0, 255), 2)
return orig
def draw_dimensions(image, cnts, pixels_per_metric):
orig = image.copy()
for c in cnts:
if cv2.contourArea(c) < 100:
continue
box = cv2.minAreaRect(c)
box = cv2.boxPoints(box)
box = np.array(box, dtype="int")
box = order_points(box)
tl, tr, br, bl = box
tltr_x, tltr_y = midpoint(tl, tr)
blbr_x, blbr_y = midpoint(bl, br)
tlbl_x, tlbl_y = midpoint(tl, bl)
trbr_x, trbr_y = midpoint(tr, br)
da = dist.euclidean((tltr_x, tltr_y), (blbr_x, blbr_y))
db = dist.euclidean((tlbl_x, tlbl_y), (trbr_x, trbr_y))
if pixels_per_metric is None:
pixels_per_metric = db / width
dim_a = da / pixels_per_metric
dim_b = db / pixels_per_metric
cv2.putText(orig, "{:.2f}cm".format(dim_b), (int(tltr_x - 15), int(tltr_y - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.50, (255, 255, 255), 1)
cv2.putText(orig, "{:.2f}cm".format(dim_a), (int(trbr_x + 10), int(trbr_y)), cv2.FONT_HERSHEY_SIMPLEX, 0.50, (255, 255, 255), 1)
return orig
def display_image(image, title="Image", figsize=(10, 10)):
plt.figure(figsize=figsize)
plt.imshow(image)
plt.title(title)
plt.axis('off') # Oculta os eixos
plt.show()
### o código principal fica mais limpo e fácil de entender...
width = 8.89
pixels_per_metric = None
erode = process_image('objects2.png')
cnts, bounding_boxes = find_and_sort_contours(erode)
contours_image = draw_contours(image, cnts)
midpoints_image = draw_midpoints(contours_image, cnts)
dimensions_image = draw_dimensions(midpoints_image, cnts, pixels_per_metric)
display_image(dimensions_image, title="Imagem final")
## da pra melhorar ainda mais o código, mas acredito que já deu pra ter uma ideia de como refatorar o código.
Desafio extra top!¶
Um grande problemada industria de manufatura está na determinção do dimensional de alguns objetos para controle de qualidade. Nesse sentido, você foi contratado para desenvolver um sistema que irá capturar um frame de um vídeo, processar e definir o seu dimenssional.
Se topar o desafio, vamos fazer um projeto IC?
### Bora fazer uma IC??