.. _sec_bbox:
Detecção de Objetos e Caixas Delimitadoras
==========================================
Na seção anterior, apresentamos muitos modelos para classificação de
imagens. Nas tarefas de classificação de imagens, presumimos que haja
apenas uma característica principal na imagem e nos concentramos apenas
em como identificar a categoria de destino. No entanto, em muitas
situações, existem várias características na imagem que nos interessam.
Não queremos apenas classificá-las, mas também queremos obter suas
posições específicas na imagem. Na visão computacional, nos referimos a
tarefas como detecção de objetos (ou reconhecimento de objetos).
A detecção de objetos é amplamente usada em muitos campos. Por exemplo,
na tecnologia de direção autônoma, precisamos planejar rotas
identificando a localização de veículos, pedestres, estradas e
obstáculos na imagem de vídeo capturada. Os robôs geralmente realizam
esse tipo de tarefa para detectar alvos de interesse. Os sistemas no
campo da segurança precisam detectar alvos anormais, como intrusos ou
bombas.
Nas próximas seções, apresentaremos vários modelos de aprendizado
profundo usados para detecção de objetos. Antes disso, devemos
discutir o conceito de localização de destino. Primeiro, importe os
pacotes e módulos necessários para o experimento.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def box_corner_to_center(boxes):
"""Convert from (upper_left, bottom_right) to (center, width, height)"""
x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
cx = (x1 + x2) / 2
cy = (y1 + y2) / 2
w = x2 - x1
h = y2 - y1
boxes = np.stack((cx, cy, w, h), axis=-1)
return boxes
#@save
def box_center_to_corner(boxes):
"""Convert from (center, width, height) to (upper_left, bottom_right)"""
cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
x1 = cx - 0.5 * w
y1 = cy - 0.5 * h
x2 = cx + 0.5 * w
y2 = cy + 0.5 * h
boxes = np.stack((x1, y1, x2, y2), axis=-1)
return boxes
.. raw:: html
.. raw:: html
.. code:: python
#@save
def box_corner_to_center(boxes):
"""Convert from (upper_left, bottom_right) to (center, width, height)"""
x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
cx = (x1 + x2) / 2
cy = (y1 + y2) / 2
w = x2 - x1
h = y2 - y1
boxes = torch.stack((cx, cy, w, h), axis=-1)
return boxes
#@save
def box_center_to_corner(boxes):
"""Convert from (center, width, height) to (upper_left, bottom_right)"""
cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
x1 = cx - 0.5 * w
y1 = cy - 0.5 * h
x2 = cx + 0.5 * w
y2 = cy + 0.5 * h
boxes = torch.stack((x1, y1, x2, y2), axis=-1)
return boxes
.. raw:: html
.. raw:: html
.. code:: python
#@save
def box_corner_to_center(boxes):
"""Convert from (upper_left, bottom_right) to (center, width, height)"""
x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
cx = (x1 + x2) / 2
cy = (y1 + y2) / 2
w = x2 - x1
h = y2 - y1
boxes = tf.stack((cx, cy, w, h), axis=-1)
return boxes
#@save
def box_center_to_corner(boxes):
"""Convert from (center, width, height) to (upper_left, bottom_right)"""
cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
x1 = cx - 0.5 * w
y1 = cy - 0.5 * h
x2 = cx + 0.5 * w
y2 = cy + 0.5 * h
boxes = tf.stack((x1, y1, x2, y2), axis=-1)
return boxes
.. raw:: html
.. raw:: html
Vamos definir as caixas delimitadoras do cão e do gato na imagem baseada
nas informações de coordenadas. A origem das coordenadas na imagem é o
canto superior esquerdo da imagem, e para a direita e para baixo estão
as direções positivas do eixo :math:`x` e do eixo :math:`y`,
respectivamente.
.. code:: python
# bbox is the abbreviation for bounding box
dog_bbox, cat_bbox = [60.0, 45.0, 378.0, 516.0], [400.0, 112.0, 655.0, 493.0]
Podemos verificar a exatidão das funções de conversão da caixa
convertendo duas vezes.
.. raw:: html
.. raw:: html
.. code:: python
boxes = np.array((dog_bbox, cat_bbox))
box_center_to_corner(box_corner_to_center(boxes)) - boxes
.. parsed-literal::
:class: output
array([[0., 0., 0., 0.],
[0., 0., 0., 0.]])
.. raw:: html
.. raw:: html
.. code:: python
boxes = torch.tensor((dog_bbox, cat_bbox))
box_center_to_corner(box_corner_to_center(boxes)) - boxes
.. parsed-literal::
:class: output
tensor([[0., 0., 0., 0.],
[0., 0., 0., 0.]])
.. raw:: html
.. raw:: html
.. code:: python
boxes = tf.constant((dog_bbox, cat_bbox))
box_center_to_corner(box_corner_to_center(boxes)) - boxes
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Podemos desenhar a caixa delimitadora na imagem para verificar se ela é
precisa. Antes de desenhar a caixa, definiremos uma função auxiliar
``bbox_to_rect``. Ele representa a caixa delimitadora no formato de
caixa delimitadora de ``matplotlib``.
.. code:: python
#@save
def bbox_to_rect(bbox, color):
"""Convert bounding box to matplotlib format."""
# Convert the bounding box (top-left x, top-left y, bottom-right x,
# bottom-right y) format to matplotlib format: ((upper-left x,
# upper-left y), width, height)
return d2l.plt.Rectangle(
xy=(bbox[0], bbox[1]), width=bbox[2]-bbox[0], height=bbox[3]-bbox[1],
fill=False, edgecolor=color, linewidth=2)
Depois de carregar a caixa delimitadora na imagem, podemos ver que o
contorno principal do alvo está basicamente dentro da caixa.
.. raw:: html