Python深度学习基于Tensorflow(10)目标检测

目标检测的主要任务有两步:1. 确定目标位置;2. 对目标位置的目标进行分类;前者属于定位问题,后者属于分类问题;

分类问题在前面的学习有了合理的解决办法,目前主要是定位问题怎么处理,这也是目标检测的重点;

边界框的表示

首先,目标定位一般使用矩形来作为边界框,边界框的表示方式有两种:一种是使用图像中左上角和右下角两点确定边界框,一种是根据矩形特定位置点以及宽和高确定边界框;plt.Rectangle 采取的方式是左上角以及宽和高;

# 两点式转化为中心式
def box_2p_to_center(box_2p):
    left, up, right, dowm = box_2p[:, 0], box_2p[:, 1], box_2p[:, 2], box_2p[:, 3]
    x = (left + right) / 2
    y = (up + dowm) / 2 
    width = right - left
    height = dowm - up
    return np.c_[x, y, width , height]

# 中心式转化为两点式
def box_center_to_2p(box_center):
    x, y, width, height = box_center[:,0], box_center[:,1], box_center[:,2], box_center[:,3]
    left = x - width/2
    right = x + width/2
    up = y - height/2
    dowm = y + height/2
    return np.c_[left, up, right, dowm]

这里以这张猫狗图片为例子,可以直接保存测试;

![[下载.jpg]]

使用 plt.Rectangle 在图片上标记

import numpy as np
import matplotlib.pyplot as plt


def bbox_to_rect(bbox, color):
    return plt.Rectangle(
        xy=(bbox[0], bbox[1]), width=bbox[2]-bbox[0], height=bbox[3]-bbox[1],
        fill=False, edgecolor=color, linewidth=2)

img = plt.imread('./cat-dog.jpg')

dog_bbox, cat_bbox,bak_bbox = [20.0, 5.0, 440.0, 480.0], [445.0, 86.0, 730.0, 490.0],[390.0, 17.0, 600.0, 71.0]

fig = plt.imshow(img)
fig.axes.add_patch(bbox_to_rect(dog_bbox, 'yellow'))
fig.axes.text(dog_bbox[0]+5,dog_bbox[1]+20,'dog',style='italic',bbox={
   'facecolor': 'white', 'alpha': 0.5, 'pad': 0})
fig.axes.add_patch(bbox_to_rect(bak_bbox, 'red'))
fig.axes.text(cat_bbox[0]+5,cat_bbox[1]+20,'cat',style='italic',bbox={
   'facecolor': 'white', 'alpha': 0.5, 'pad': 0})
fig.axes.add_patch(bbox_to_rect(cat_bbox, 'blue'))
fig.axes.text(bak_bbox[0]+5,bak_bbox[1]+20,'background',style='italic',bbox={
   'facecolor': 'white', 'alpha': 0.5, 'pad': 0})
plt.axis('off')
plt.savefig('cat-dog_.jpg')

得到如下结果:

![[Pasted image 20240514021205.png]]

在实际操作中,我们可以使用 LabelImg 快速标记出目标位置并给出目标分类制作数据;LabelImg 的链接如下: labelImg

使用 选择性搜索 框定目标

选择性搜索(Selective Search, SS)方法是通过图像中的纹理,边缘,颜色等信息对图像进行自底向上的分割,然后对分割区域进行不同尺度的合并,在合并过程中,每生成一个新的区域就产生一个候选框,区域肯定是不规则,我们通过选取区域的最大外接矩阵作为候选框区域,这种方法速度较慢;

在这篇博客中尝试使用了颜色分割合并:[Initial Image Segmentation Generator]论文实现:Efficient Graph-Based Image Segmentation;该方法的一个重要特点是,它能够在低变异性图像区域保留细节,而忽略了高变异性图像区域的细节。也就是说在变化不大的区域可以对细节进行保留,在变化很大的区域对细节进行剔除,这个效果根据后面合并小区域得到的。

在这里我们可以利用 OpenCVcreateSelectiveSearchSegmentation() 函数来获取候选框区域;该函数除了安装基本的 OpenCV 外,还需要安装拓展,代码: pip install opencv-contrib-python --user

import cv2 as cv

def get_ss_rects(img):
    cv.setUseOptimized(True)
    ss = cv.ximgproc.segmentation.createSelectiveSearchSegmentation()
    ss.setBaseImage(img)
    ss.switchToSelectiveSearchFast()
    rects = ss.process()
    return rects

测试一下SS方法:

import tensorflow as tf
import cv2 as cv
import matplotlib.pyplot as plt

def get_ss_rects(img):
    cv.setUseOptimized(True)
    ss = cv.ximgproc.segmentation.createSelectiveSearchSegmentation()
    ss.setBaseImage(img)
    ss.switchToSelectiveSearchFast()
    rects = ss.process()
    return rects

im = cv.imread('./cat-dog.jpg')
rects = get_ss_rects(im)
imOut = im.copy()

for i, rect in enumerate(rects):
    x, y, w, h = rect
    cv.rectangle(imOut, (x,y), (x+w,y+h), (0,255,0), 1, cv.LINE_AA)
plt.imshow(imOut[:,:,::-1])
plt.axis('off')
plt.show()

得到结果如图所示:

![[Pasted image 20240514043723.png]]

得到处理时间为:CPU times: total: 2.08 s Wall time: 2.36 s

使用RPN框定目标

锚框和锚点

首先要介绍的是锚框和锚点,其定义是根据原图和特征图来说明的,首先原图(origin map)采取池化的方式缩小尺寸变成特征图(feature map);这样导致特征图某一点与原图某一块相对应,特征图的那一点被称为锚点;其对应的那一块被称为锚框,锚框的中心点也可以看做是锚点;

![[Pasted image 20240514133659.png]]

将锚框按照比例(如 1:2, 1:1, 2:1)进行变换,然后再依次进行宽和高的缩放和放大(如8, 16, 32)就可以得到9个框;

其中池化缩小的倍数被称为 base_size,变换比例被称为 ratios,对宽和高放大的倍数被称为 scales

使用代码获取特征图上第一个点的锚框实现如下:

def generate_anchors(base_size=16, ratios=[0.5, 1, 2], scales=2**np.arange(3, 6)):
    """
    Generate anchor (reference) windows by enumerating aspect ratios X
    scales wrt a reference (0, 0, 15, 15) window.
    """

    base_anchor = np.array([1, 1, base_size, base_size]) - 1
    ratio_anchors = _ratio_enum(base_anchor, ratios)
    anchors = np.vstack([_scale_enum(ratio_anchors[i, :], scales)
                         for i in range(ratio_anchors.shape[0])])
    return anchors

def _whctrs(anchor):
    """
    Return width, height, x center, and y center for an anchor (window).
    """

    w = anchor[2] - anchor[0] + 1
    h = anchor[3] - anchor[1] + 1
    x_ctr = anchor[0] + 0.5 * (w - 1)
    y_ctr = anchor[1] + 0.5 * (h - 1)
    return w, h, x_ctr, y_ctr

def _mkanchors(ws, hs, x_ctr, y_ctr):
    """
    Given a vector of widths (ws) and heights (hs) around a center
    (x_ctr, y_ctr), output a set of anchors (windows).
    """

    ws = ws[:, np.newaxis]
    hs = hs[:, np.newaxis]
    anchors = np.hstack((x_ctr - 0.5 * (ws - 1),
                         y_ctr - 0.5 * (hs - 1),
                         x_ctr + 0.5 * (ws - 1),
                         y_ctr + 0.5 * (hs - 1)))
    return anchors

def _ratio_enum(anchor, ratios):
    """
    Enumerate a set of anchors for each aspect ratio wrt an anchor.
    """

    w, h, x_ctr, y_ctr = _whctrs(anchor)
    size = w * h
    size_ratios = size / ratios
    ws = np.round(np.sqrt(size_ratios))
    hs = np.round(ws * ratios)
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
    return anchors

def _scale_enum(anchor, scales):
    """
    Enumerate a set of anchors for each scale wrt an anchor.
    """
    w, h, x_ctr, y_ctr = _whctrs(anchor)
    ws = w * scales
    hs = h * scales
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
    return anchors

获取特征图上所有点的锚框如下:

def get_anchors(height, width, base_size=16, ratios=[0.5, 1, 2], scales=2**np.arange(3, 6)):
    anchor_rect = []
    base_anchors = generate_anchors(base_size, ratios, scales)
    for i in range(width):
        for j in range(height):
            for item in base_anchors:
                x1, y1, x2, y2 = item
                x1, x2 = x1 + base_size*i, x2 + base_size*i
                y1, y2 = y1 + base_size*j, y2 + base_size*j
                item = [x1, y1, x2, y2]
                anchor_rect.append(item)
                
    anchor_rect = np.array(anchor_rect)
    return anchor_rect


# 画出锚框
def bbox_to_rect(bbox, color):
    return plt.Rectangle(
        xy=(bbox[0], bbox[1]), width=bbox[2]-bbox[0], height=bbox[3]-bbox[1],
        fill=False, edgecolor=color, linewidth=0.5)

# 一步到位
def plot_anchors(anchors)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值