分类部分使用的是录制视频的方式,定位部分仅使用数据增强技术。
分类
分类数据集的获取方法是,为待识别的物体和物体所在的背景分别录制一段或多段视频,并在dataset文件中给出说明(以后可能会把程序改成多个视频放在2个文件夹中)使用视频作为数据集与图片是一个道理,把视频中的每一帧图像分别送入网络即可。拍摄视频时需注意要让待检测的物体以不同的距离、不同的角度(如果需要的话)出现在图像的不同位置处,也就是要让物体出现在实际环境中该物体可能出现的位置。
负样本理所当然地就是录一段(或多段)背景视频。另外为了保持正负样本的匹配,我在代码中限制每段视频时长20秒。
定位
这部分方法是我自己想到的,而且有很多创新的地方,所以我在前言中写禁止转载。目标检测的标注一直是一个很大的问题,有很多的自动标注工具,而我的方法只需要对一张图片(多张也可以,越多越好)进行标注即可。
平移缩放进行数据集扩充
图像平移的仿射变换的公式如下:
[
x
′
y
′
]
=
[
1
0
d
x
0
1
d
y
]
[
x
y
1
]
\left[\begin{matrix}x'\\y'\end{matrix}\right]=\left[\begin{matrix}1&0&dx\\0&1&dy\end{matrix}\right]\left[\begin{matrix}x\\y\\1\end{matrix}\right]
[x′y′]=[1001dxdy]⎣⎡xy1⎦⎤考虑缩放的话公式就变得相当复杂。不能直接进行缩放,像这样
[
x
′
y
′
]
=
[
k
0
d
x
0
k
d
y
]
[
x
y
1
]
\left[\begin{matrix}x'\\y'\end{matrix}\right]=\left[\begin{matrix}k&0&dx\\0&k&dy\end{matrix}\right]\left[\begin{matrix}x\\y\\1\end{matrix}\right]
[x′y′]=[k00kdxdy]⎣⎡xy1⎦⎤这样就成了
{
x
′
=
k
x
+
d
x
y
′
=
k
y
+
d
y
\begin{cases} x'=kx+dx\\y'=ky+dy\end{cases}
{x′=kx+dxy′=ky+dy相当于是相对原点进行缩放。另外要注意我们想要的也不是
{
x
′
=
k
(
x
+
d
x
)
y
′
=
k
(
y
+
d
y
)
\begin{cases} x'=k(x+dx)\\y'=k(y+dy)\end{cases}
{x′=k(x+dx)y′=k(y+dy)而是特别复杂的一个式子,因为简单地乘k只是相对原点进行缩放,但我们要做的是相对框的中心进行缩放。接下来进行详细讲解。
我们现在定义
(
c
x
,
c
y
)
(c_x,c_y)
(cx,cy)是框出的物体的中心坐标,分别代表宽高方向(x和y轴的正方向必须事先指明),
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1)是框的左上角坐标,
k
k
k为缩放倍数,
(
w
,
h
)
(w,h)
(w,h)是框的宽高,
(
m
x
,
m
y
)
(m_x,m_y)
(mx,my)是从原点开始的平移坐标。
想让框和框出的物体先平移到某一位置,在沿框的中心进行缩放,此时为了便于计算,以平移仿射变换为例,将式子扩展成
[
x
′
y
′
1
]
=
[
1
0
d
x
0
1
d
y
0
0
1
]
[
x
y
1
]
\left[\begin{matrix}x'\\y'\\1\end{matrix}\right]=\left[\begin{matrix}1&0&dx\\0&1&dy\\0&0&1\end{matrix}\right]\left[\begin{matrix}x\\y\\1\end{matrix}\right]
⎣⎡x′y′1⎦⎤=⎣⎡100010dxdy1⎦⎤⎣⎡xy1⎦⎤这样的话,将框沿框的中心点原地缩放可看作先将框平移到原点,再将框进行简单的缩放,最后再将框平移回去,公式如下
[
1
0
c
x
0
1
c
y
0
0
1
]
[
k
0
0
0
k
0
0
0
1
]
[
1
0
−
c
x
0
1
−
c
y
0
0
1
]
[
x
y
1
]
=
[
k
0
c
x
−
k
c
x
0
k
c
y
−
k
c
y
0
0
1
]
[
x
y
1
]
\left[\begin{matrix}1&0&c_x\\0&1&c_y\\0&0&1\end{matrix}\right]\left[\begin{matrix}k&0&0\\0&k&0\\0&0&1\end{matrix}\right]\left[\begin{matrix}1&0&-c_x\\0&1&-c_y\\0&0&1\end{matrix}\right]\left[\begin{matrix}x\\y\\1\end{matrix}\right]=\left[\begin{matrix}k&0&c_x-kc_x\\0&k&c_y-kc_y\\0&0&1\end{matrix}\right]\left[\begin{matrix}x\\y\\1\end{matrix}\right]
⎣⎡100010cxcy1⎦⎤⎣⎡k000k0001⎦⎤⎣⎡100010−cx−cy1⎦⎤⎣⎡xy1⎦⎤=⎣⎡k000k0cx−kcxcy−kcy1⎦⎤⎣⎡xy1⎦⎤
然后综合考虑平移和缩放,要做的事是先将原图片中目标的中心平移到框的中心,平移量是
(
m
x
−
x
1
,
m
y
−
y
1
)
(m_x-x_1,m_y-y_1)
(mx−x1,my−y1),然后再沿框的中心缩放,公式如下
[
k
0
c
x
−
k
c
x
0
k
c
y
−
k
c
y
0
0
1
]
[
1
0
m
x
−
x
1
0
1
m
y
−
y
1
0
0
1
]
[
x
y
1
]
\left[\begin{matrix}k&0&c_x-kc_x\\0&k&c_y-kc_y\\0&0&1\end{matrix}\right]\left[\begin{matrix}1&0&m_x-x_1\\0&1&m_y-y_1\\0&0&1\end{matrix}\right]\left[\begin{matrix}x\\y\\1\end{matrix}\right]
⎣⎡k000k0cx−kcxcy−kcy1⎦⎤⎣⎡100010mx−x1my−y11⎦⎤⎣⎡xy1⎦⎤去掉最后一行,写成能用opencv的warpaffine函数调用的矩阵就是
[
k
0
k
(
m
x
−
x
1
)
+
c
x
−
k
c
x
0
k
k
(
m
y
−
y
1
)
+
c
y
−
k
c
y
]
[
x
y
1
]
\left[\begin{matrix}k&0&k(m_x-x_1)+c_x-kc_x\\0&k&k(m_y-y_1)+c_y-kc_y\end{matrix}\right]\left[\begin{matrix}x\\y\\1\end{matrix}\right]
[k00kk(mx−x1)+cx−kcxk(my−y1)+cy−kcy]⎣⎡xy1⎦⎤
迭代数据分配
pytorch中dataset类的使用方法是有一个控制迭代的函数__getitem__(self,item),表示要取出数据集中的第几个数据。对于边框定位要做的事是能让真实框出现在图像中的每个位置。先只考虑平移,图像分辨率是(640x512),假设真实框的尺寸是(100x200),想让框出现在图像的每一个位置,就生成了540x312=168480张图片,所以item是一个[0,168479]中的整数,要根据这个整数决定框出现在哪个位置。
从零搭建自己的目标检测网络教程(四)损失函数
从零搭建自己的目标检测网络教程(零)前言
附一个平移缩放的例子
import numpy as np
import cv2 as cv
k = 0.5
move_x, move_y = 100, 100
bkcolor = 212, 216, 206
x1, y1 = 366, 335
x2, y2 = 632, 471
cx, cy = (x1+x2)/2, (y1+y2)/2
img = cv.imread('origin.png')
m = np.float32([[k, 0, k*(move_x-x1)+cx-k*cx], [0, k, k*(move_y-y1)+cy-k*cy]])
img = cv.warpAffine(img, m, (img.shape[1], img.shape[0]), borderValue=bkcolor)
cv.imshow('test', img)
cv.waitKey(0)