高级目标检测与图像分割技术解析
立即解锁
发布时间: 2025-09-01 01:57:41 阅读量: 4 订阅数: 13 AIGC 

### 高级目标检测与图像分割技术解析
#### 1. 基于YOLO的目标检测
我们可以使用如下代码对卡车和巴士的图像进行目标检测:
```python
image_paths = Glob('images-of-trucks-and-busses')
for f in image_paths:
!./darknet detector test \
data/obj.data cfg/yolov4-tiny-bus-trucks.cfg\
backup/yolov4-tiny-bus-trucks_4000.weights {f}
!mv predictions.jpg {stem(f)}_pred.jpg
for i in Glob('*_pred.jpg'):
show(read(i, 1), sz=20)
```
上述代码会在输入图像上预测边界框和类别。
#### 2. 单阶段检测器(SSD)
##### 2.1 SSD工作原理
SSD通过以下方式克服不同尺度目标检测的问题:
1. 利用预训练的VGG网络,并添加额外层直到得到1 x 1的块。
2. 不仅使用最后一层进行边界框和类别预测,还利用最后几层进行预测。
3. 使用具有特定尺度和宽高比的默认框代替锚框。
4. 每个默认框需要预测目标和边界框偏移,类似于YOLO中的锚框。
##### 2.2 SSD网络架构
将300 x 300 x 3的图像通过预训练的VGG - 16网络得到conv5_3层的输出,再对conv5_3的输出添加卷积层进行扩展。每个单元和每个默认框会得到边界框偏移和类别预测。各层的检测数量如下表所示:
| 层 | 每类检测数量 |
| ---- | ---- |
| conv5_3 | 38 x 38 x 4 = 5,776 |
| FC6 | 19 x 19 x 6 = 2,166 |
| conv8_2 | 10 x 10 x 6 = 600 |
| conv9_2 | 5 x 5 x 6 = 150 |
| conv10_2 | 3 x 3 x 4 = 36 |
| conv11_2 | 1 x 1 x 4 = 4 |
| 总检测数 | 8,732 |
##### 2.3 默认框的尺度和宽高比
- **尺度**:假设目标的最小尺度是图像高度和宽度的20%,最大尺度是90%,可以通过公式 \(𝑠𝑠_{𝑙}= 𝑠_{min}+ \frac{𝑠_{max}-𝑠_{min}}{𝐿 - 1}(𝑙 - 1)\) 逐渐增加各层的尺度。
- **宽高比**:可能的宽高比为 \(\{1, 2, 1/2, 3, 1/3\}\)。不同层框的中心为 \((𝑐_{x}^𝑙, 𝑐_{y}^𝑙) = (\frac{i + 0.5}{m}, \frac{j + 0.5}{n})\),宽度和高度分别为 \(𝑤_{r}^𝑙 = 𝑠_{l}\sqrt{r}\) 和 \(h_{r}^𝑙 = \frac{𝑠_{l}}{\sqrt{r}}\)。如果要使用4个框,则去除 \(\{3, 1/3\}\) 宽高比;否则考虑6个可能的框,第六个框的宽高比为 \(a_{l}' = \sqrt{s_{l}s_{l + 1}}\)。
##### 2.4 训练数据集准备
默认框与真实框的交并比(IoU)大于阈值(如0.5)的被视为正匹配,其余为负匹配。在SSD的输出中,预测框属于某类别的概率(第0类表示背景)以及真实框相对于默认框的偏移。
##### 2.5 损失函数优化
- **分类损失**:\(𝐿_{cls}= -\sum_{i \in pos}\sum_{k = 1}^{K}log(𝑐_{i}^k) - \sum_{i \in neg}log(𝑐_{i}^0)\),其中pos表示与真实框高度重叠的默认框,neg表示误分类的框,并且要保证pos:neg比例最多为1:3。
- **定位损失**:仅当目标存在分数大于某个阈值时考虑损失值,计算公式为 \(𝐿_{loc}= \sum_{i \in pos}\sum_{m \in \{cx, cy, w, h\}}1_{i}^{m}𝐿_{1 - smooth}(𝑑_{m}^i - 𝑡_{m}^j)\),其中 \(𝐿_{1 - smooth}(𝑥) = \begin{cases} 0.5𝑥^2, & |𝑥| < 1 \\ |𝑥| - 0.5, & otherwise \end{cases}\),\(t\) 是预测偏移,\(d\) 是实际偏移。
#### 3. SSD代码组件
##### 3.1 SSD300
该模型包含三个子模块:
```python
class SSD300(nn.Module):
...
def __init__(self, n_classes, device):
...
self.base = VGGBase()
self.aux_convs = AuxiliaryConvolutions()
self.pred_convs = PredictionConvolutions(n_classes)
...
```
输入先经过VGGBase得到两个特征向量,第二个输出作为AuxiliaryConvolutions的输入,最后将VGGBase的第一个输出和AuxiliaryConvolutions的四个特征图送入PredictionConvolutions得到8,732个锚框。`create_prior_boxes` 方法为每个特征图创建锚框列表,`detect_objects` 方法将分类和回归值转换为实际边界框坐标。
##### 3.2 MultiBoxLoss
该类负责计算损失,输入为模型的锚框预测和真实边界框。首先将真实框转换为8,732个锚框,然后对回归张量执行MSE损失,对定位张量执行交叉熵损失,并将它们相加作为最终损失。
#### 4. 在自定义数据集上训练SSD
具体步骤如下:
1. **下载数据集和代码库**:
```python
import os
if not os.path.exists('open-images-bus-trucks'):
!pip install -q torch_snippets
!wget --quiet https://www.dropbox.com/s/agmzwk95v96ihic/\
open-images-bus-trucks.tar.xz
!tar -xf open-images-bus-trucks.tar.xz
!rm open-images-bus-trucks.tar.xz
!git clone https://github.com/sizhky/ssd-utils/
%cd ssd-utils
```
2. **数据预处理**:
```python
from torch_snippets import *
DATA_ROOT = '../open-images-bus-trucks/'
IMAGE_ROOT = f'{DATA_ROOT}/images'
DF_RAW = pd.read_csv(f'{DATA_ROOT}/df.csv')
df = DF_RAW.copy()
df = df[df['ImageID'].isin(df['ImageID'].unique().tolist())]
label2target = {l:t+1 for t,l in enumerate(DF_RAW['LabelName'].unique())}
label2target['background'] = 0
target2label = {t:l for l,t in label2target.items()}
background_class = label2target['background']
num_classes = len(label2target)
device = 'cuda' if torch.cuda.is_available() else 'cpu'
```
3. **准备数据集类**:
```python
import collections, os, torch
from PIL import Image
from torchvision import transforms
normalize = transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)
denormalize = transforms.Normalize(
mean=[-0.485/0.229,-0.456/0.224,-0.406/0.255],
std=[1/0.229, 1/0.224, 1/0.255]
)
def preprocess_image(img):
img = torch.tensor(img).permute(2,0,1)
img = normalize(img)
return img.to(device).float()
class OpenDataset(torch.utils.data.Dataset):
w, h = 300, 300
def __init__(self, df, image_dir=IMAGE_ROOT):
self.image_dir = image_dir
self.files = glob.glob(self.image_dir+'/*')
self.df = df
self.image_infos = df.ImageID.unique()
logger.info(f'{len(self)} items loaded')
def __getitem__(self, ix):
# load ima
```
0
0
复制全文
相关推荐









