.. _sec_bbox:
Hộp phát hiện và giới hạn đối tượng
===================================
Trong các phần trước (ví dụ:
:numref:`sec_alexnet`—:numref:`sec_googlenet`), chúng tôi đã giới
thiệu các mô hình khác nhau để phân loại hình ảnh. Trong các tác vụ phân
loại hình ảnh, chúng tôi giả định rằng chỉ có \* một\* đối tượng chính
trong hình ảnh và chúng tôi chỉ tập trung vào cách nhận dạng danh mục
của nó. Tuy nhiên, thường có các đối tượng \* nhiều\* trong hình ảnh
quan tâm. Chúng tôi không chỉ muốn biết danh mục của họ, mà còn là vị
trí cụ thể của họ trong hình ảnh. Trong tầm nhìn máy tính, chúng tôi đề
cập đến các tác vụ như *phát hiện đối tượng* (hoặc *nhận dạng đối
tượng*).
Phát hiện đối tượng đã được ứng dụng rộng rãi trong nhiều lĩnh vực. Ví
dụ, tự lái cần lên kế hoạch cho các tuyến đường di chuyển bằng cách phát
hiện vị trí của phương tiện, người đi bộ, đường xá và chướng ngại vật
trong các hình ảnh video đã chụp. Bên cạnh đó, robot có thể sử dụng kỹ
thuật này để phát hiện và bản địa hóa các đối tượng quan tâm trong suốt
quá trình điều hướng môi trường. Hơn nữa, các hệ thống an ninh có thể
cần phải phát hiện các vật bất thường, chẳng hạn như kẻ xâm nhập hoặc
bom.
Trong vài phần tiếp theo, chúng tôi sẽ giới thiệu một số phương pháp học
sâu để phát hiện đối tượng. Chúng tôi sẽ bắt đầu với phần giới thiệu về
*vị trí* (hoặc *locations*) của các đối tượng.
.. raw:: html
.. raw:: html
.. code:: python
#@save
def box_corner_to_center(boxes):
"""Convert from (upper-left, lower-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, lower-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, lower-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, lower-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, lower-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, lower-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
Chúng tôi sẽ xác định các hộp giới hạn của chó và con mèo trong hình ảnh
dựa trên thông tin tọa độ. Nguồn gốc của tọa độ trong hình ảnh là góc
trên bên trái của hình ảnh, và bên phải và xuống là các hướng dương của
các trục :math:`x` và :math:`y`, tương ứng.
.. code:: python
# Here `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]
Chúng tôi có thể xác minh tính chính xác của hai chức năng chuyển đổi
hộp giới hạn bằng cách chuyển đổi hai lần.
.. 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([[ True, True, True, True],
[ True, True, True, True]])
.. 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([[True, True, True, True],
[True, True, True, True]])
.. 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
Hãy để chúng tôi vẽ các hộp giới hạn trong hình ảnh để kiểm tra xem
chúng có chính xác không. Trước khi vẽ, chúng ta sẽ xác định một hàm
helper ``bbox_to_rect``. Nó đại diện cho hộp giới hạn ở định dạng hộp
giới hạn của gói ``matplotlib``.
.. code:: python
#@save
def bbox_to_rect(bbox, color):
"""Convert bounding box to matplotlib format."""
# Convert the bounding box (upper-left x, upper-left y, lower-right x,
# lower-right y) format to the 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)
Sau khi thêm các hộp giới hạn trên hình ảnh, chúng ta có thể thấy rằng
đường viền chính của hai đối tượng về cơ bản nằm trong hai hộp.
.. raw:: html