Nesne algılama, bir görüntüdeki çeşitli nesneleri tanımlamak ve konumlarını belirlemek için kullanılan bir tekniktir. İmge sınıflandırmadan farklı olarak, nesne algılama sadece bir nesnenin var olup olmadığını değil, aynı zamanda bu nesnenin görüntüdeki spesifik konumunu da tespit eder.
Kuşatan Kutular
Kuşatan kutular, bir nesnenin uzamsal konumunu belirlemek için kullanılır. Bu kutular genellikle dikdörtgen şeklindedir ve iki farklı yöntemle tanımlanabilir:
1. Köşe koordinatları: Sol üst köşe (x1, y1) ve sağ alt köşe (x2, y2) koordinatları ile belirlenir.
2. Merkez koordinatları ve boyutlar: Merkez koordinatları (cx, cy) ve kutunun genişliği (w) ve yüksekliği (h) ile belirlenir.
Kodlarla Uygulama
Köşe Koordinatlarından Merkez ve Boyutlara Dönüştürme
Çapa Kutularına Gerçek Referans Değeri Kuşatan Kutuları Atama
Kuşatan Kutuları Çapalar İçin Etiketleme
Kuşatan kutuları çapa kutularına atadıktan sonra, her çapa kutusu için gerçek değerleri ve sınıf etiketlerini belirlememiz gerekiyor.
Tahminleri Gerçek Değerlerle Karşılaştırma
Tahmin edilen kuşatan kutuları ve sınıflandırmaları gerçek değerlerle karşılaştırmak için bir kayıp fonksiyonu tanımlamak gerekiyor.
Kuşatan Kutular
Kuşatan kutular, bir nesnenin uzamsal konumunu belirlemek için kullanılır. Bu kutular genellikle dikdörtgen şeklindedir ve iki farklı yöntemle tanımlanabilir:
1. Köşe koordinatları: Sol üst köşe (x1, y1) ve sağ alt köşe (x2, y2) koordinatları ile belirlenir.
2. Merkez koordinatları ve boyutlar: Merkez koordinatları (cx, cy) ve kutunun genişliği (w) ve yüksekliği (h) ile belirlenir.
Kodlarla Uygulama
Köşe Koordinatlarından Merkez ve Boyutlara Dönüştürme
Python:
import torch
def box_corner_to_center(boxes):
(sol üst, sağ alt) konumundan (merkez, genişlik, yükseklik) konumuna dönüştür.
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
def box_center_to_corner(boxes):
(merkez, genişlik, yükseklik) konumundan (sol üst, sağ alt) konumuna dönüştür.
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
# Test verisi ile doğrulama
dog_bbox, cat_bbox = [60.0, 45.0, 378.0, 516.0], [400.0, 112.0, 655.0, 493.0]
boxes = torch.tensor([dog_bbox, cat_bbox])
print(box_center_to_corner(box_corner_to_center(boxes)) == boxes)
Kuşatan Kutuları Çizme
Python:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
def bbox_to_rect(bbox, color):
Kuşatan kutuyu matplotlib biçimine dönüştürün.
return patches.Rectangle(
(bbox[0], bbox[1]), bbox[2] - bbox[0], bbox[3] - bbox[1],
linewidth=2, edgecolor=color, facecolor='none')
img = plt.imread('catdog.jpg')
fig, ax = plt.subplots(1)
ax.imshow(img)
dog_bbox = [60.0, 45.0, 378.0, 516.0]
cat_bbox = [400.0, 112.0, 655.0, 493.0]
ax.add_patch(bbox_to_rect(dog_bbox, 'blue'))
ax.add_patch(bbox_to_rect(cat_bbox, 'red'))
plt.show()
Çapa Kutuları Oluşturma
python
def multibox_prior(data, sizes, ratios):
Her pikselde ortalanmış farklı şekillere sahip çapa kutuları oluşturun.
in_height, in_width = data.shape[-2:]
device, num_sizes, num_ratios = data.device, len(sizes), len(ratios)
boxes_per_pixel = (num_sizes + num_ratios - 1)
size_tensor = torch.tensor(sizes, device=device)
ratio_tensor = torch.tensor(ratios, device=device)
offset_h, offset_w = 0.5, 0.5
steps_h = 1.0 / in_height
steps_w = 1.0 / in_width
center_h = (torch.arange(in_height, device=device) + offset_h) * steps_h
center_w = (torch.arange(in_width, device=device) + offset_w) * steps_w
shift_y, shift_x = torch.meshgrid(center_h, center_w)
shift_y, shift_x = shift_y.reshape(-1), shift_x.reshape(-1)
w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),
sizes[0] * torch.sqrt(ratio_tensor[1:]))) * in_height / in_width
h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),
sizes[0] / torch.sqrt(ratio_tensor[1:])))
anchor_manipulations = torch.stack((-w, -h, w, h)).T.repeat(
in_height * in_width, 1) / 2
out_grid = torch.stack([shift_x, shift_y, shift_x, shift_y],
dim=1).repeat_interleave(boxes_per_pixel, dim=0)
output = out_grid + anchor_manipulations
return output.unsqueeze(0)
img = plt.imread('catdog.jpg')
h, w = img.shape[:2]
X = torch.rand(size=(1, 3, h, w)) # Girdi verisi oluştur
Y = multibox_prior(X, sizes=[0.75, 0.5, 0.25], ratios=[1, 2, 0.5])
print(Y.shape) # (1, çapa kutusu sayısı, 4)
Kesişim Birleşim Üzerinde (IoU) Hesaplama
python
def box_iou(boxes1, boxes2):
İki çapa veya kuşatan kutu listesinde ikili IoU hesaplayın.
box_area = lambda boxes: ((boxes[:, 2] - boxes[:, 0]) *
(boxes[:, 3] - boxes[:, 1]))
areas1 = box_area(boxes1)
areas2 = box_area(boxes2)
inter_upperlefts = torch.max(boxes1[:, None, :2], boxes2[:, :2])
inter_lowerrights = torch.min(boxes1[:, None, 2:], boxes2[:, 2:])
inters = (inter_lowerrights - inter_upperlefts).clamp(min=0)
inter_areas = inters[:, :, 0] * inters[:, :, 1]
union_areas = areas1[:, None] + areas2 - inter_areas
return inter_areas / union_areas
# Örnek verilerle test
boxes1 = torch.tensor([[0.1, 0.1, 0.2, 0.2], [0.2, 0.2, 0.3, 0.3]])
boxes2 = torch.tensor([[0.15, 0.15, 0.25, 0.25], [0.25, 0.25, 0.35, 0.35]])
print(box_iou(boxes1, boxes2))
Çapa Kutularına Gerçek Referans Değeri Kuşatan Kutuları Atama
Python:
def assign_anchor_to_bbox(ground_truth, anchors, device, iou_threshold=0.5):
En yakın gerçek referans değeri kuşatan kutuları çapa kutularına atayın.
num_anchors, num_gt_boxes = anchors.shape[0], ground_truth.shape[0]
jaccard = box_iou(anchors, ground_truth)
anchors_bbox_map = torch.full((num_anchors,), -1, dtype=torch.long, device=device)
max_ious, indices = torch.max(jaccard, dim=1)
anc_i = torch.nonzero(max_ious >= iou_threshold).reshape(-1)
box_j = indices[max_ious >= iou_threshold]
anchors_bbox_map[anc_i] = box_j
for _ in range(num_gt_boxes):
max_idx = torch.argmax(jaccard)
box_idx = (max_idx % num_gt_boxes).long()
anc_idx = (max_idx // num_gt_boxes).long()
anchors_bbox_map[anc_idx] = box_idx
jaccard[:, box_idx] = -1
jaccard[anc_idx, :] = -1
return anchors_bbox_map
# Örnek verilerle test
ground_truth = torch.tensor([[0.1, 0.1, 0.2, 0.2], [0.2, 0.2, 0.3, 0.3], [0.3, 0.3, 0.4, 0.4]])
anchors = torch.tensor([[0.1, 0.1, 0.2, 0.2], [0.2, 0.2, 0.3, 0.3], [0.3, 0.3, 0.4, 0.4], [0.4, 0.4, 0.5, 0.5]])
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
anchors_bbox_map = assign_anchor_to_bbox(ground_truth, anchors, device)
print(anchors_bbox_map)
Kuşatan Kutuları Çapalar İçin Etiketleme
Kuşatan kutuları çapa kutularına atadıktan sonra, her çapa kutusu için gerçek değerleri ve sınıf etiketlerini belirlememiz gerekiyor.
Python:
def offset_boxes(anchors, assigned_bb, eps=1e-6):
Çapa kutuları ile atanan kuşatan kutuları arasındaki offsetleri hesapla.
c_anc = box_corner_to_center(anchors)
c_assigned_bb = box_corner_to_center(assigned_bb)
offset_xy = 10 * (c_assigned_bb[:, :2] - c_anc[:, :2]) / c_anc[:, 2:]
offset_wh = 5 * torch.log(eps + c_assigned_bb[:, 2:] / c_anc[:, 2:])
offset = torch.cat([offset_xy, offset_wh], axis=1)
return offset
def multibox_target(anchors, labels):
Etiketleri ve offsetleri hesapla.
batch_size, anchors = labels.shape[0], anchors.squeeze(0)
batch_offset, batch_mask, batch_cls_labels = [], [], []
device, num_anchors = anchors.device, anchors.shape[0]
for i in range(batch_size):
label = labels[i, :, :]
anchors_bbox_map = assign_anchor_to_bbox(label[:, 1:], anchors, device)
bbox_mask = ((anchors_bbox_map >= 0).float().unsqueeze(-1)).repeat(1, 4)
cls_labels = torch.zeros(num_anchors, dtype=torch.long, device=device)
assigned_bb = torch.zeros((num_anchors, 4), dtype=torch.float32, device=device)
indices_true = torch.nonzero(anchors_bbox_map >= 0)
bb_idx = anchors_bbox_map[indices_true]
assigned_bb[indices_true] = label[bb_idx, 1:]
cls_labels[indices_true] = label[bb_idx, 0].long() + 1
offset = offset_boxes(anchors, assigned_bb) * bbox_mask
batch_offset.append(offset.reshape(-1))
batch_mask.append(bbox_mask.reshape(-1))
batch_cls_labels.append(cls_labels)
return (torch.stack(batch_offset), torch.stack(batch_mask), torch.stack(batch_cls_labels))
# Örnek verilerle test
anchors = torch.tensor([[[0.1, 0.1, 0.2, 0.2], [0.2, 0.2, 0.3, 0.3], [0.3, 0.3, 0.4, 0.4], [0.4, 0.4, 0.5, 0.5]]])
labels = torch.tensor([[[0, 0.15, 0.15, 0.25, 0.25], [1, 0.25, 0.25, 0.35, 0.35]]])
print(multibox_target(anchors, labels))
Tahminleri Gerçek Değerlerle Karşılaştırma
Tahmin edilen kuşatan kutuları ve sınıflandırmaları gerçek değerlerle karşılaştırmak için bir kayıp fonksiyonu tanımlamak gerekiyor.
Python:
def cls_loss(cls_preds, cls_labels):
Sınıf tahminlerinin kaybını hesapla.
return nn.CrossEntropyLoss(reduction='none')(cls_preds, cls_labels)
def bbox_loss(bbox_preds, bbox_labels, bbox_masks):
Kuşatan kutu tahminlerinin kaybını hesapla.
return (bbox_masks * F.smooth_l1_loss(bbox_preds, bbox_labels, reduction='none')).mean(dim=1)
# Örnek verilerle test
cls_preds = torch.tensor([[0.1, 0.2, 0.3, 0.4], [0.2, 0.3, 0.4, 0.5], [0.3, 0.4, 0.5, 0.6], [0.4, 0.5, 0.6, 0.7]])
cls_labels = torch.tensor([1, 0, 2, 3])
print(cls_loss(cls_preds, cls_labels))
bbox_preds = torch.tensor([[0.1, 0.2, 0.3, 0.4], [0.2, 0.3, 0.4, 0.5], [0.3, 0.4, 0.5, 0.6], [0.4, 0.5, 0.6, 0.7]])
bbox_labels = torch.tensor([[0.1, 0.2, 0.3, 0.4], [0.2, 0.3, 0.4, 0.5], [0.3, 0.4, 0.5, 0.6], [0.4, 0.5, 0.6, 0.7]])
bbox_masks = torch.tensor([[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]])
print(bbox_loss(bbox_preds, bbox_labels, bbox_masks))


