[Opencv]Cascade级联分类器

文章目录​​​​​​

  1. 训练级联分类器
  2. 使用级联分类器检测
  3. 总结 



前言

        最近在尝试识别指定物体,之前用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指令查看。

        [Opencv]Cascade级联分类器_第1张图片

3.训练级联分类器

        同样是使用应用程序,运行指令:

        opencv_traincascade.exe -data data -vec pos.vec -bg neg.dat -numPos 12 -numNeg 50 -numStages 16 -w 72 -h 72 -mode ALL

        每个参数的意义也可以通过上面的方法看到,在此不一一列举。

        训练过程如下所示:

        [Opencv]Cascade级联分类器_第2张图片

 训练结果[Opencv]Cascade级联分类器_第3张图片



二、使用分类器检测

检测的步骤大致分为转换为灰度图——>直方图均衡化——>送入分类器检测——>框出目标。

#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& objects,
                          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参数能排除干扰,使检测结果更加准确

附上自己训练并检测的结果

[Opencv]Cascade级联分类器_第4张图片


四、总结

        Cascade级联分类器的检测效果总的来说较为普通,但实测帧率高,一般可以达到20—25帧,可作为目标检测的备选方案。      

你可能感兴趣的:(opencv,c++)