Hoşgeldin Misafir

Nesne Algılama ve Kuşatan Kutular

Mustafa73

20 Eyl 2023
423 Mesaj

Aktiflik

Seviye

Deneyim

TIM / GÖREV:
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

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))