最近在尝试识别指定物体,之前用Opencv自带的级联分类器做过人脸识别感觉效果不错,所以想用级联分类器来做其它物体的识别。
选择学习这种传统目标检测算法,主要是迎合电赛上的需求。虽然深度学习算法已经有许多种,但在树莓派这样没有GPU加速的平台上运行的帧率并不理想,做不到实时性。而Cascade用CPU就可以达到比较高的帧率。
不可否认,Cascade在精确度上远不及其它深度学习的方法,但在背景单一,目标特征较简单的环境下,也可以有较好的效果。
本文分享训练分类器和使用分类器进行检测的方法
1.收集数据
首先就是收集正负样本
正样本是只包含要识别物体的图像,负样本就是背景图片,只要不包含目标就行,最好用所在环境的背景图片。
附规范化命名和图像灰度化代码:
import os
#图片路径
path = 'C:/Users/lyf31/yolov5-boat/data/train/images'
num= 1
for file in os.listdir(path):
os.rename(os.path.join(path,file),os.path.join(path,str(num)+".jpg"))
num+=1
import cv2
#图片数量
num=22
#图片路径
path = "G:/Image_process/project/cascade/earphone/train/pos/"
for i in range(1, num+1):
print(path+str(i)+'.jpg')
img = cv2.imread(path+str(i)+'.jpg', cv2.IMREAD_GRAYSCALE)
#图片大小
img = cv2.resize(img, (72, 72))
cv2.imshow("img", img)
cv2.imwrite(path+str(i)+'.jpg', img)
print(str(i)+'.jpg')
正样本要求大小一致,Opencv默认是24*24,并且为灰度图。负样本也为灰度图,但大小无要求。
准备好图片后生成正负样本索引。
在官方文档中,正样本索引的格式为:
img/img1.jpg 1 140 100 45 45
分别是图片路径,目标数量,坐标。
我是参照下面的博文来生产索引的,注意格式的意义更改代码。
python生成opencv正样本和负样本描述文件_interstellar-ai的博客-CSDN博客
2.生成vec文件
使用Opencv自带的应用程序来生成,在编译生成的bin文件夹里。
将上图两个应用程序加入文件夹。我们用opencv_createsamples.exe生产vec文件,在文件夹里用CMD或PowerShell运行指令:
opencv_createsamples.exe -info pos.dat -vec pos.vec -num 22 -w 72 -h 72
-info是正样本索引文件,-vec 是生成的vec文件,-num是样本个数,-w和-h是样本宽和高。
以上是我测试过必须输入的参数,其实还有其它参数,可以运行opencv_createsamples.exe指令查看。
3.训练级联分类器
同样是使用应用程序,运行指令:
opencv_traincascade.exe -data data -vec pos.vec -bg neg.dat -numPos 12 -numNeg 50 -numStages 16 -w 72 -h 72 -mode ALL
每个参数的意义也可以通过上面的方法看到,在此不一一列举。
训练过程如下所示:
检测的步骤大致分为转换为灰度图——>直方图均衡化——>送入分类器检测——>框出目标。
#include
#include
using namespace cv;
using namespace std;
String fileName = "cascade.xml";
CascadeClassifier earphones_classifier;
int main(int argc, char** argv)
{
vector earphones;
if (!earphones_classifier.load(fileName))
{
printf("could not load face feature data...\n");
return -1;
}
VideoCapture cap(1);
Mat image, gray_image;
while (1)
{
cap >> image;
resize(image, image, Size(320, 240));
cvtColor(image, gray_image, COLOR_BGR2GRAY);
equalizeHist(gray_image, gray_image);
earphones_classifier.detectMultiScale(gray_image, earphones, 1.1, 3,0,Size(5,5),Size(100,100));
for (size_t t = 0; t < earphones.size(); t++)
{
rectangle(image, earphones[static_cast(t)], Scalar(0, 0, 255), 2, 8, 0);
}
imshow("detect earphone", image);
if (waitKey(5) == 'q')
{
destroyAllWindows();
break;
}
}
return 0;
}
其中detectMultiScale()函数的参数尤为重要。
void detectMultiScale( InputArray image,
CV_OUT std::vector
double scaleFactor = 1.1,
int minNeighbors = 3, int flags = 0,
Size minSize = Size(),
Size maxSize = Size() );
1.image表示的是要检测的输入图像。
2.objects表示检测到的人脸目标序列。
3.scaleFactor表示每次图像尺寸减小的比例。
4. minNeighbors表示每一个目标至少要被检测到3次才算是真的目标。
5.flags--要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域, 因此这些区域通常不会是人脸所在区域;
6.minSize为目标的最小尺寸
7.minSize为目标的最大尺寸
调节4、6、7参数能排除干扰,使检测结果更加准确
附上自己训练并检测的结果
Cascade级联分类器的检测效果总的来说较为普通,但实测帧率高,一般可以达到20—25帧,可作为目标检测的备选方案。