opencv训练自己的模型,实现特定物体的识别

1.说明

  • opencv安装包中有训练好的分类器文件,可以实现人脸的识别。当然,我们也可以训练自己的分类器文件,实现对特定物体的识别。本文章就详细介绍下如何训练自己的分类器文件。

2.效果

  • 我训练的是检测苹果的的分类器文件,可以实现对苹果的识别。
    opencv训练自己的模型,实现特定物体的识别

; 3.准备

3.1 程序准备

  • 训练自己的分类器文件,需要用到两个程序 : opencv_createsamples.exe_和 _opencv_traincascade.exe
  • opencv最新的安装包中没有这两个程序,我们可以下载 3.4.14这个版本的安装包进行安装。
  • opencv安装包 : opencv-3.4.14-vc14_vc15.exe
  • 安装完成后,在这个目录下就会有这两个程序文件 opencv\build\x64\vc15\bin

3.2 样本数据准备

  • 正样本数据 : 也就是我们需要检测的物体图片,可以自己用手机拍摄下你要检测的物体的图片,多拍摄一些不同角度的图片。
  • 我的正样本数据在这个目录下 image\positive\img,大概有50多张图片
    opencv训练自己的模型,实现特定物体的识别
  • 然后在image\positive目录下新建一个info.dat文件,在其中记录正样本图片信息
    opencv训练自己的模型,实现特定物体的识别
  • 参数介绍
  • img/1.jpg : 文件路径和文件名
  • 1:表示图片中有几个目标物体,一般一个就行了
  • 0,0:目标物体起始坐标
  • 1280,1706:目标物体大小
  • 负样本数据:不包含我们要检测物体的图片,可以拍摄一些风景之类的图片,尽量多一些。
  • 我的负样本数据在这个目录下 image\negitive\img
    opencv训练自己的模型,实现特定物体的识别
  • 然后在image\negitive目录下新建一个bg.txt文件,在其中记录负样本图片信息
  • 负样本图片信息我们只需记录路径和文件名就行了,但是这里要注意, 路径名要写绝对路径,后面会说为什么。
    opencv训练自己的模型,实现特定物体的识别

; 3.3 正样本VEC文件创建

  • 训练样本之前先要生成vec文件,要用到 opencv_createsamples.exe程序
  • opencv_createsamples.exe部分参数介绍
  [-info <collection_file_name>]  # &#x8BB0;&#x5F55;&#x6837;&#x672C;&#x6570;&#x636E;&#x7684;&#x6587;&#x4EF6;(&#x5C31;&#x662F;&#x6211;&#x4EEC;&#x521A;&#x624D;&#x521B;&#x5EFA;&#x7684;info.data&#x6587;&#x4EF6;)
  [-img <image_file_name>]
  [-vec <vec_file_name>]   # &#x8F93;&#x51FA;&#x6587;&#x4EF6;&#xFF0C;&#x5185;&#x542B;&#x7528;&#x4E8E;&#x8BAD;&#x7EC3;&#x7684;&#x6B63;&#x6837;&#x672C;&#x3002;
  [-bg <background_file_name>]  # &#x80CC;&#x666F;&#x56FE;&#x50CF;&#x7684;&#x63CF;&#x8FF0;&#x6587;&#x4EF6;
  [-num <number_of_samples 1000 =>]   #&#x6837;&#x672C;&#x6570;&#x91CF;&#xFF08;&#x9ED8;&#x8BA4;&#x4E3A;1000&#xFF09;
  [-bgcolor <background_color 0 =>]    #&#x6307;&#x5B9A;&#x80CC;&#x666F;&#x989C;&#x8272;
  [-w <sample_width 24 =>]#&#x8F93;&#x51FA;&#x6837;&#x672C;&#x7684;&#x5BBD;&#x5EA6;&#xFF08;&#x4EE5;&#x50CF;&#x7D20;&#x4E3A;&#x5355;&#x4F4D;&#xFF09;
  [-h <sample_height 24 =>]#&#x8F93;&#x51FA;&#x6837;&#x672C;&#x7684;&#x9AD8;&#x5EA6;&#xFF08;&#x4EE5;&#x50CF;&#x7D20;&#x4E3A;&#x5355;&#x4F4D;&#xFF09;
</sample_height></sample_width></background_color></number_of_samples></background_file_name></vec_file_name></image_file_name></collection_file_name>

参考

  • 在安装包的这个目录下opencv\build\x64\vc15\bin可以找到opencv_createsamples.exe程序,我们生成下vec文件
D:\opencv3.4.12\opencv\build\x64\vc15\bin\opencv_createsamples.exe -info C:\Users\lng\Desktop\image\positive\info.dat -vec C:\Users\lng\Desktop\image\sample.vec -num 58 -bgcolor 0 -bgthresh 0 -w 24 -h 24
  • 在image目录下就生成了vec文件
    opencv训练自己的模型,实现特定物体的识别

4.样本数据训练

  • 完成上面的准备工作,就可以开始训练样本。训练样本需要用到 opencv_traincascaded.exe程序
  • opencv_traincascaded.exe程序部分参数介绍
 -data <cascade_dir_name>     #&#x76EE;&#x5F55;&#x540D;&#xFF0C;&#x5982;&#x4E0D;&#x5B58;&#x5728;&#x8BAD;&#x7EC3;&#x7A0B;&#x5E8F;&#x4F1A;&#x521B;&#x5EFA;&#x5B83;&#xFF0C;&#x7528;&#x4E8E;&#x5B58;&#x653E;&#x8BAD;&#x7EC3;&#x597D;&#x7684;&#x5206;&#x7C7B;&#x5668;
 -vec <vec_file_name>              #&#x5305;&#x542B;&#x6B63;&#x6837;&#x672C;&#x7684;vec&#x6587;&#x4EF6;&#x540D;
 -bg <background_file_name>   #&#x80CC;&#x666F;&#x63CF;&#x8FF0;&#x6587;&#x4EF6;
 [-numPos <number_of_positive_samples 2000 =>]   #&#x6BCF;&#x7EA7;&#x5206;&#x7C7B;&#x5668;&#x8BAD;&#x7EC3;&#x65F6;&#x6240;&#x7528;&#x7684;&#x6B63;&#x6837;&#x672C;&#x6570;&#x76EE;
 [-numNeg <number_of_negative_samples 1000 =>]   #&#x6BCF;&#x7EA7;&#x5206;&#x7C7B;&#x5668;&#x8BAD;&#x7EC3;&#x65F6;&#x6240;&#x7528;&#x7684;&#x8D1F;&#x6837;&#x672C;&#x6570;&#x76EE;
 [-numStages <number_of_stages 20 =>]   #&#x8BAD;&#x7EC3;&#x7684;&#x5206;&#x7C7B;&#x5668;&#x7684;&#x7EA7;&#x6570;
--cascadeParams--
 [-featureType <{haar(default), lbp, hog}>]  # &#x7279;&#x5F81;&#x7684;&#x7C7B;&#x578B;&#xFF1A; HAAR - &#x7C7B;Haar&#x7279;&#x5F81;&#xFF1B; LBP - &#x5C40;&#x90E8;&#x7EB9;&#x7406;&#x6A21;&#x5F0F;&#x7279;&#x5F81;
 [-w <samplewidth 24 =>] #&#x8BAD;&#x7EC3;&#x6837;&#x672C;&#x7684;&#x5C3A;&#x5BF8;&#xFF08;&#x5355;&#x4F4D;&#x4E3A;&#x50CF;&#x7D20;&#xFF09;
 [-h <sampleheight 24 =>] #&#x8BAD;&#x7EC3;&#x6837;&#x672C;&#x7684;&#x5C3A;&#x5BF8;&#xFF08;&#x5355;&#x4F4D;&#x4E3A;&#x50CF;&#x7D20;&#xFF09;
--boostParams--
 [-minHitRate <min_hit_rate> = 0.995>] #&#x5206;&#x7C7B;&#x5668;&#x7684;&#x6BCF;&#x4E00;&#x7EA7;&#x5E0C;&#x671B;&#x5F97;&#x5230;&#x7684;&#x6700;&#x5C0F;&#x68C0;&#x6D4B;&#x7387;
 [-maxFalseAlarmRate <max_false_alarm_rate = 0.5>] #&#x5206;&#x7C7B;&#x5668;&#x7684;&#x6BCF;&#x4E00;&#x7EA7;&#x5E0C;&#x671B;&#x5F97;&#x5230;&#x7684;&#x6700;&#x5927;&#x8BEF;&#x68C0;&#x7387;
</max_false_alarm_rate></min_hit_rate></sampleheight></samplewidth></{haar(default),></number_of_stages></number_of_negative_samples></number_of_positive_samples></background_file_name></vec_file_name></cascade_dir_name>

参考

  • 在安装包的这个目录下opencv\build\x64\vc15\bin可以找到opencv_traincascade.exe程序,开始训练样本
  • 这里注意下
  • 指定-bg参数时,文件名前不能加路径,所以需要把刚才在image\negitive下创建的bg.txt文件拷贝到opencv_traincascade.exe程序所在目录下,所以要在bg.txt写负样本图片的绝对路径。
  • 指定numPos参数时,因为每个阶段训练时有些正样本可能会被识别为负样本,故每个训练阶段后都会消耗一定的正样本。因此,此处使用的正样本数量绝对不能等于或超过positive文件夹下的正样本个数,一般留有一定的余量
  • 指定-numNeg参数时,可以多于negitive目录下的负样本数量
D:\opencv3.4.12\opencv\build\x64\vc15\bin\opencv_traincascade.exe -data C:\Users\lng\Desktop\image -vec C:\Users\lng\Desktop\image\sample.vec -bg bg.txt -numPos 50 -numNeg 500 -numStages 12 -feattureType HAAR -w 24 -h 24 -minHitRate 0.995 -maxFalseAlarmRate 0.5
  • 执行结果
PARAMETERS:
cascadeDirName: C:\Users\lng\Desktop\image
vecFileName: C:\Users\lng\Desktop\image\sample.vec
bgFileName: bg.txt
numPos: 50
numNeg: 500
numStages: 12
precalcValBufSize[Mb] : 1024
precalcIdxBufSize[Mb] : 1024
acceptanceRatioBreakValue : -1
stageType: BOOST
featureType: HAAR
sampleWidth: 24
sampleHeight: 24
boostType: GAB
minHitRate: 0.995
maxFalseAlarmRate: 0.5
weightTrimRate: 0.95
maxDepth: 1
maxWeakCount: 100
mode: BASIC
Number of unique features given windowSize [24,24] : 162336

===== TRAINING 0-stage =====
<begin 1 50 500 pos count : consumed neg acceptanceratio precalculation time: 0.581 +----+---------+---------+ | n hr fa 1| 2| 0.05| end>
Training until now has taken 0 days 0 hours 0 minutes 1 seconds.

===== TRAINING 1-stage =====
<begin 50 500 pos count : consumed neg acceptanceratio 0.084832 precalculation time: 0.576 +----+---------+---------+ | n hr fa 1| 2| 0.146| end>
Training until now has taken 0 days 0 hours 0 minutes 3 seconds.

===== TRAINING 2-stage =====
<begin 50 500 pos count : consumed neg acceptanceratio 0.0149993 precalculation time: 0.592 +----+---------+---------+ | n hr fa 1| 2| 0.186| end>
Training until now has taken 0 days 0 hours 0 minutes 5 seconds.

===== TRAINING 3-stage =====
<begin 50 500 pos count : consumed neg acceptanceratio 0.00288033 precalculation time: 0.652 +----+---------+---------+ | n hr fa 1| 2| 0.298| end>
Training until now has taken 0 days 0 hours 0 minutes 7 seconds.

===== TRAINING 4-stage =====
<begin 50 500 pos count : consumed neg acceptanceratio 0.000768845 precalculation time: 0.615 +----+---------+---------+ | n hr fa 1| 2| 3| 0.366| end>
Training until now has taken 0 days 0 hours 0 minutes 11 seconds.

===== TRAINING 5-stage =====
<begin 50 500 pos count : consumed neg acceptanceratio 0.000375057 precalculation time: 0.61 +----+---------+---------+ | n hr fa 1| 2| 3| 0.366| end>
Training until now has taken 0 days 0 hours 0 minutes 15 seconds.

===== TRAINING 6-stage =====
<begin 2 50 pos count : consumed neg acceptanceratio 0.00016276 required leaf false alarm rate achieved. branch training t < code></begin></begin></begin></begin></begin></begin></begin>
  • 训练完成后,在img目录下就会生成以下文件。
    opencv训练自己的模型,实现特定物体的识别
  • cascade.xml就是我们需要的分类器文件,其他都是过程文件。

5.测试代码

  • main.cpp
#include <iostream>
#include <opencv2 opencv.hpp>

char* face_cascade_name = "C:\\Users\\lng\\Desktop\\image\\cascade.xml";

void faceRecongize(cv::CascadeClassifier faceCascade, cv::Mat frame);

int main(){
    cv::VideoCapture *videoCap = new cv::VideoCapture;

    cv::CascadeClassifier faceCascade;

    // &#x52A0;&#x8F7D;&#x82F9;&#x679C;&#x5206;&#x7C7B;&#x5668;&#x6587;&#x4EF6;
    if (!faceCascade.load(face_cascade_name)) {
        std::cout << "load face_cascade_name failed. " << std::endl;
        return -1;
    }

    // &#x6253;&#x5F00;&#x6444;&#x50CF;&#x673A;
    videoCap->open(0);

    if (!videoCap->isOpened()) {
        videoCap->release();
        std::cout << "open camera failed"<< std::endl;
        return -1;
    }

    std::cout << "open camera success"<< std::endl;

    while(1){
        cv::Mat frame;
        //&#x8BFB;&#x53D6;&#x89C6;&#x9891;&#x5E27;
        videoCap->read(frame);

        if (frame.empty()) {
            videoCap->release();
            return -1;
        }

        //&#x8FDB;&#x884C;&#x82F9;&#x679C;&#x8BC6;&#x522B;
        faceRecongize(faceCascade, frame);

        //&#x7A97;&#x53E3;&#x8FDB;&#x884C;&#x5C55;&#x793A;
        imshow("face", frame);

        //&#x7B49;&#x5F85;&#x56DE;&#x8F66;&#x952E;&#x6309;&#x4E0B;&#x9000;&#x51FA;&#x7A0B;&#x5E8F;
        if (cv::waitKey(30) == 13) {
            cv::destroyAllWindows();
            return 0;
        }
    }

    system("pause");
    return 0;
}

void faceRecongize(cv::CascadeClassifier faceCascade, cv::CascadeClassifier eyesCascade, cv::CascadeClassifier mouthCascade, cv::Mat frame) {
    std::vector<cv::rect> faces;

    // &#x68C0;&#x6D4B;&#x82F9;&#x679C;
    faceCascade.detectMultiScale(frame, faces, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30));
    for (int i = 0; i < faces.size(); i++) {

        // &#x7528;&#x692D;&#x5706;&#x753B;&#x51FA;&#x82F9;&#x679C;&#x90E8;&#x5206;
        cv::Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2);
        ellipse(frame, center, cv::Size(faces[i].width / 2, faces[i].height / 2), 0, 0, 360, cv::Scalar(255, 0, 255), 4, 8, 0);

        cv::Mat faceROI = frame(faces[i]);
        std::vector<cv::rect> eyes;

        // &#x82F9;&#x679C;&#x4E0A;&#x65B9;&#x533A;&#x57DF;&#x5199;&#x5B57;&#x8FDB;&#x884C;&#x6807;&#x8BC6;
        cv::Point centerText(faces[i].x + faces[i].width / 2 - 40, faces[i].y - 20);
        cv::putText(frame, "apple", centerText, cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2);

    }
}

</cv::rect></cv::rect></opencv2></iostream>
  • CMakeLists
cmake_minimum_required (VERSION 3.5)
project (faceRecongize2015)

MESSAGE(STATUS "PROJECT_SOURCE_DIR " ${PROJECT_SOURCE_DIR})
SET(SRC_LISTS ${PROJECT_SOURCE_DIR}/src/main.cpp)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

#set(CMAKE_AUTOMOC ON)
#set(CMAKE_AUTOUIC ON)
#set(CMAKE_AUTORCC ON)

&#x914D;&#x7F6E;&#x5934;&#x6587;&#x4EF6;&#x76EE;&#x5F55;
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories("D:\\opencv3.4.12\\opencv\\build\\include")
include_directories("D:\\opencv3.4.12\\opencv\\build\\include\\opencv2")

&#x8BBE;&#x7F6E;&#x4E0D;&#x663E;&#x793A;&#x547D;&#x4EE4;&#x6846;
if(MSVC)
    #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
endif()

&#x6DFB;&#x52A0;&#x5E93;&#x6587;&#x4EF6;
set(PRO_OPENCV_LIB "D:\\opencv3.4.12\\opencv\\build\\x64\\vc15\\lib\\opencv_world3412.lib" "D:\\opencv3.4.12\\opencv\\build\\x64\\vc15\\lib\\opencv_world3412d.lib")

IF(WIN32)
    # &#x751F;&#x6210;&#x53EF;&#x6267;&#x884C;&#x7A0B;&#x5E8F;
    ADD_EXECUTABLE(faceRecongize2015 ${SRC_LISTS})
    # &#x94FE;&#x63A5;&#x5E93;&#x6587;&#x4EF6;
    TARGET_LINK_LIBRARIES(faceRecongize2015 ${PRO_OPENCV_LIB})
ENDIF()

6.编译说明

  • 我的opencv 3.4.12的安装路径是 D:\opencv3.4.12
  • 目录结构
- src
  - mian.cpp
- build_x64
- CMakeLists
  • 编译命令, 在build_x64目录下执行
cmake -G "Visual Studio 14 2015 Win64" ..

cmake --build ./ --config Release
  • 编译完成后拷贝D:\opencv3.4.12\opencv\build\x64\vc15\bin目录下的opencv_world3412.dll和opencv_world3412d.dll到可执行程序目录下。

备注

  • 经过测试,自己训练的样本,准确度还是比较差的。可能是正样本数据太少,且图片背景占据位置较多。要提高准确度,首先增加正样本图片数量,还要就是尽量让你的目标物体占满整个图片,不要留有太多的背景。而且也要有尽可能多的负样本数据。

Original: https://blog.csdn.net/new9232/article/details/127439039
Author: 大草原的小灰灰
Title: opencv训练自己的模型,实现特定物体的识别

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/637713/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球