1. 背景
以两级级联模型为例,第一级目标检测模型用于检测人员,第二级目标检测模型用于检测手机、对讲机等。然后实际数据采集过程中,手机、对讲机这些设备并不在人员的一级检测框内,使得二级模型训练的样本较少。
二级目标检测模型训练阶段,在数据采样时不能仅仅只将一级目标检测框裁剪得到的图像作为输入,还需要动态的裁剪原图,使得手机、对讲机这些设备包含进来,减少背景的干扰。
上面三幅图分别是原图、一级目标检测框区域、训练时想要的目标区域(需要将其他的手机也要揽括进来)。
基本思路:基于opencv的鼠标事件,对显示的原图画矩形框得到感兴趣区域,并将其保存下来。
2. OpenCV鼠标事件
2.1 设置鼠标事件
setMouseCallback(const String & winname, #要设置鼠标事件的窗口名
MouseCallback onMouse, #回调函数,当指定窗口产生鼠标事件时,调用的函数名
void* userdata = 0) #传递给回调函数的可选参数
2.2 回调函数原型
void MouseCallback(int event, #鼠标基础事件
int x, int y, #鼠标在x轴y轴方向上的坐标值,窗口左上角为原点(0,0)
int flags, #flags的值代表鼠标拖拽事件和Ctrl、Shift、Alt按键事件的代号
void *userdata) #用户数据
2.3 鼠标事件
2.3.1 event基本事件
这个对应对调函数的第一个参数event,当鼠标执行相应的动作,event会变成相应的值。
enum
{
CV_EVENT_MOUSEMOVE =0, //鼠标移动
CV_EVENT_LBUTTONDOWN =1, //按下左键
CV_EVENT_RBUTTONDOWN =2, //按下右键
CV_EVENT_MBUTTONDOWN =3, //按下中键
CV_EVENT_LBUTTONUP =4, //放开左键
CV_EVENT_RBUTTONUP =5, //放开右键
CV_EVENT_MBUTTONUP =6, //放开中键
CV_EVENT_LBUTTONDBLCLK =7, //左键双击
CV_EVENT_RBUTTONDBLCLK =8, //右键双击
CV_EVENT_MBUTTONDBLCLK =9, //中键双击
CV_EVENT_MOUSEWHEEL =10, //滚轮滚动
CV_EVENT_MOUSEHWHEEL =11 //横向滚轮滚动
};
2.3.2 flag拖拽事件
这个对应回调函数的第四个参数,当存在鼠标拖拽或者于CTRL、shift、ALT相结合拖拽时,flag变成对应的值。
enum
{
CV_EVENT_FLAG_LBUTTON =1, //左键拖拽
CV_EVENT_FLAG_RBUTTON =2, //右键拖拽
CV_EVENT_FLAG_MBUTTON =4, //中键拖拽
CV_EVENT_FLAG_CTRLKEY =8, //按住CTRL拖拽
CV_EVENT_FLAG_SHIFTKEY =16, //按住Shift拖拽
CV_EVENT_FLAG_ALTKEY =32 //按住ALT拖拽
};
在这里插入代码片
3. 动态裁剪图像
具体的实现代码如下:
import cv2
import os
ROOT = "data7" # 原图路径
img_cnt = 0
def mouse_callback(event, x, y, flags, param):
global img_data, point1, point2,g_rect, img_cnt
img2 = img_data.copy()
if event == cv2.EVENT_LBUTTONDOWN: # 左键点击,则在原图打点
print("1-EVENT_LBUTTONDOWN")
point1 = (x, y)
cv2.circle(img2, point1, 10, (0, 255, 0), 5)
cv2.imshow('image', img2)
elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON): # 按住左键拖曳,画框
print("2-EVENT_FLAG_LBUTTON")
cv2.rectangle(img2, point1, (x, y), (255, 0, 0), thickness=2)
cv2.imshow('image', img2)
elif event == cv2.EVENT_LBUTTONUP: # 左键释放,显示
print("3-EVENT_LBUTTONUP")
point2 = (x, y)
cv2.rectangle(img2, point1, point2, (0, 0, 255), thickness=2)
cv2.imshow('image', img2)
if point1!=point2:
min_x = int(min(point1[0], point2[0]))
min_y = int(min(point1[1], point2[1]))
width = int(abs(point1[0] - point2[0]))
height = int(abs(point1[1] - point2[1]))
g_rect=[min_x,min_y,width,height]
cut_img = img_data[min_y:min_y + height, min_x:min_x + width] # 从原图上裁剪
cv2.imwrite("crop_img_{}.jpg".format(img_cnt), cut_img) # 图像文件保存
print("save image.")
img_cnt += 1
if __name__ == "__main__":
img_lists = os.listdir(ROOT)
cv2.namedWindow("image")
cv2.setMouseCallback("image", mouse_callback)
for img in img_lists:
img_path = os.path.join(ROOT, img)
if os.path.exists(img_path):
print("file existed.")
img_data = cv2.imread(img_path)
cv2.imshow("image", img_data)
k = cv2.waitKey(0)
if k == ord('q'):
break
cv2.destroyAllWindows()
大致的步骤如下:
- 新建窗口,设置回调函数;
- 读取并显示原始图像数据;
- 捕获左键点击、左键拖拽、左键释放的鼠标事件,进行区域目标框绘制;
- 并将区域目标保存下来;
4. 总结
本文主要介绍了针对两级模型级联情况下,二级目标检测算法训练时样本少时一种解决方案,通过上述脚本可以可视化人为的裁剪区域并保存增加训练样本,减少背景干扰。