Adaboost训练汽车零配件定位

1、正样本

这里写图片描述
这里写图片描述

'''
Created on 2017年10月5日

@author: XT
'''
import os.path
import cv2
import numpy as np

file_dir = "F:\\objectmarker_AutoSparePart\\"
classes = {"pos0"}
i = 0
for index,name in enumerate(classes):
    class_path = file_dir+name+"\\"
    for img_name in os.listdir(class_path):
        img_path = class_path+img_name#读取每一个图片路径
        image = cv2.imread(img_path)
        winW = 80#目标宽resize
        winH = 70#目标高resize
        resizeImg = cv2.resize(image,(winW,winH))
        #cv2.imshow("resizeImg",resizeImg)
        #cv2.waitKey(0)


        cv2.imwrite('F:\\objectmarker_AutoSparePart\\pos\\{:08d}.jpg'.format(i),resizeImg)
        with open("F:\\objectmarker_AutoSparePart\\sample_pos.dat",'a',encoding='utf-8') as f:
            f.write("{_i_}.jpg 1 0 0 {_w_} {_h_}\n".format(_i_=str(i).zfill(8),_w_=winW,_h_=winH))
        i +=1

生成正样本描述文件vet:
cmd:

F:\objectmarker_AutoSparePart

opencv_createsamples.exe -info ./pos/sample_pos.dat -vec ./pos/sample_pos.vec -num 1031 -w 40 -h 35 -show YES

这里写图片描述
这里写图片描述

2、负样本

'''
Created on 2017年10月5日

@author: XT
'''
import os.path
import cv2
import numpy as np

file_dir = "F:\\objectmarker_AutoSparePart\\"
classes = {"neg0"}
i = 0
for index,name in enumerate(classes):
    class_path = file_dir+name+"\\"
    for img_name in os.listdir(class_path):
        img_path = class_path+img_name#读取每一个图片路径
        image = cv2.imread(img_path)
#         winW = 80#目标宽resize
#         winH = 70#目标高resize
#         resizeImg = cv2.resize(image,(winW,winH))
        #cv2.imshow("resizeImg",resizeImg)
        #cv2.waitKey(0)


        cv2.imwrite('F:\\objectmarker_AutoSparePart\\neg\\neg{:08d}.jpg'.format(i),image)
        with open("F:\\objectmarker_AutoSparePart\\sample_neg.dat",'a',encoding='utf-8') as f:
            f.write("neg{_i_}.jpg\n".format(_i_=str(i).zfill(8)))
        i +=1

这里写图片描述

640÷40×(480÷35)=219
219×1173=256887

3、转灰度图像

#include <opencv2\opencv.hpp>
#include <windows.h> 
#include<vector>
#include<string>  
#include<iostream>

using namespace std;
using namespace cv;


int main()
{
    string dir_path = "F:\\objectmarker_AutoSparePart\\neg\\";
    char outDirName[50];
    Directory dir;
    string extenttype = "*.jpg";
    vector<string> fileNames = dir.GetListFiles(dir_path, extenttype, false);

    for (int item = 0; item < fileNames.size(); item++)
    {
        //get image name  
        string fileName = fileNames[item];
        string fileFullName = dir_path + fileName;
        //cout << "File name:" << fileName << endl;
        cout << "Full path:" << fileFullName << endl;

        Mat img = cv::imread(fileFullName);

        Mat grayImg;
        cvtColor(img, grayImg, CV_BGR2GRAY);
        /*cv::imshow("gray", grayImg);
        cv::waitKey();*/

        sprintf_s(outDirName, "F:\\objectmarker_AutoSparePart\\neg1\\neg%05d.jpg", item);


        /*Mat resizeImg;
        resize(img, resizeImg, Size(320, 280));*/
        /*imshow("resizeImg", resizeImg);
        waitKey(500);*/



        imwrite(outDirName, grayImg);
    }

    return 0;

}

4、运行

这里写图片描述

opencv_haartraining.exe -data ./cascade -vec ./pos/sample_pos.vec -bg ./neg/sample_neg.dat -npos 931 -nneg 5000 -nstage 15 -mem 2560 -mode ALL -featureType HARR -w 40 -h 35

参数意义:
-data 指定生成的文件目录, 是训练生成的检测器存放的目录,你可以自己在工作目录下面建一个叫做cascade的目录,然后训练的时候就可以使用这个作为参数填进去

-vec vec文件名, 也就是前面说的sample_neg.vec文件

-bg 负样本描述文件名称,也就是负样本的说明文件(.dat)

-nstage 20 指定训练层数,推荐15~20,层数越高,耗时越长。

-nsplits 分裂子节点数目,选取默认值 2

-minhitrate 最小命中率,即训练目标准确度。这里的参数表示的是一个stage训练到什么程度就结束,然后开始训练下一个stage呢?标准就是在这个stage的正负样本中,检测率不能小于-minHitRate,虚警率不能高于-maxFalseAlarmRate。比如这里我们都采用默认值,-maxFalseAlarmRate为0.995,-maxFalseAlarmRate为0.5,表示的就是给出1000个正样本,至少分类器要将其中的995个样本判断为正样本,如果给出1000个负样本,最多只能将500个判断为正样本。

-maxfalsealarm最大虚警(误检率),每一层训练到这个值小于0.5时训练结束,进入下一层训练,
这里写图片描述
-npos 在每个阶段用来训练的正样本数目,训练的时候用到的正样本的个数 ,这个个数要比你实际拥有的正样本的个数少个100到200个,因为每一个stage的分类器会将少量正样本识别为负样本,因此需要新的正样本补充进来,也就是那100到200个,如果你这里填的-numPos参数是你实际拥有的也就是sample_pos.vec文件中包含的正样本个数,那么当需要补充正样本的时候你就没有新的正样本可以来补充了。我总共有1030个正样本,所以这里我可以填写930作为训练时候的正样本数,留下100个正样本做替补队员。

-nneg在每个阶段用来训练的负样本数目 这个值可以设置大于真正的负样本图像数目,程序可以自动从负样本图像中切割出和正样本大小一致的,这个参数一半设置为正样本数目的1~3倍或者1~5倍,训练的时候用到的负样本个数,这个个数和你neg.txt(sample_neg.dat )中负样本大图片的个数没什么直接关系,举个栗子我这里填的是5150,那么程序会从neg.txt中的大图中按照某种规则抠出指定个数以及w=40和h=35的小图作为负样本,也就是说一张负样本大图可以产生数十上百个负样本小图,这些小图才是真正在训练的时候作为负样本出现的。一个经验的填法是-numNeg是-numPos的5倍左右。比例太低导致虚警高,太高了导致检测率低。正负比为1:5挺合适的。

-w -h样本尺寸,与前面对应
-mem 程序可使用的内存,这个设置为256即可,实际运行时根本就不怎么耗内存,以MB为单位

-featureType:是你可以选择的特征的种类,总共3种特征可以选择,harr,lbp以及hog。我训练过手掌和人头的检测器,实践表明,harr特征往往在adaboost中有着更好的表现,因此这里我填的是HARR,也就是默认值其实可以不填的。

-mode 指定haar特征的种类,BASIC仅仅使用垂直特征,ALL表示使用垂直以及45度旋转特征,这是选择了HARR特征之后所独有的一个参数,BASIC、CORE、ALL分别含有不同的特征,但三者是包含关系,也就是ALL包含了CORE中的特征,CORE包含了BASIC中的特征。
这里写图片描述

#include "stdafx.h"
 #include <opencv2/core/core.hpp>  
 #include <opencv2/highgui/highgui.hpp>  
 #include<iostream>  
 #include <direct.h>//for mk_dir
 #include <io.h>//for _acess()
 #include <opencv2\contrib\contrib.hpp>  
 #include <string>
using namespace std;
using namespace cv;

int recursive_mkdir(char *dir);//创建多级目录
int ImageToVideo(char* outDir, char* videoName, char* inputDir, int startFrame, int endFrame, int imgW,
    int imgH, char* imgExt, double fps, int isColor, int fourcc);//图片序列转化为视频
int  VideoToImage(char* videoName, char* outDir, char* imgExt, int maxFrameCount);//视频转化为图片序列
int g_i = 1;

int _tmain(int argc, _TCHAR* argv[])
{
    string dir_path = "F:\\AutoSparePart2\\BackgroundVideo\\";
    Directory dir;
    vector<string> fileNames = dir.GetListFiles(dir_path, "*.avi", false);

    for (int i = 0; i < fileNames.size(); i++)
    {
        //get image name  
        string fileName = fileNames[i];
        string fileFullName = dir_path + fileName;
        cout << "File name:" << fileName << endl;
        cout << "Full path:" << fileFullName << endl;

        //read video
        cvNamedWindow(fileName.c_str(), CV_WINDOW_AUTOSIZE);
        CvCapture* capture = cvCreateFileCapture(fileFullName.c_str());
        IplImage* frame;
        //视频转图片
        char* videoPathName = &fileFullName[0];
        char* outDir = "F:\\objectmarker_AutoSparePart\\neg\\";
        int images = VideoToImage(videoPathName, outDir, ".jpg", 1280);
        std::cout << "total frames have been extracted from video." << std::endl;

        cvReleaseCapture(&capture);
        cvDestroyWindow(fileName.c_str());
        g_i++;
    }
    return 0;
}


//将图片序列转换为视频,返回视频帧数
int ImageToVideo(char* outDir, char* videoName, char* inputDir, int startFrame, int endFrame, int imgW,
    int imgH, char* imgExt, double fps = 24, int isColor = 1, int fourcc = CV_FOURCC('X', 'V', 'I', 'D')){
    //判断输入文件夹是否存在
    if (_access(inputDir, 0) == -1){
        std::cout << "the input directory does not exist!" << std::endl;
        return 0;
    }
    //判断输出文件夹是否创建 若没有则创建;若为NULL则默认当前工作目录
    char fullVideoName[255];//输出视频的完整文件名:路径+文件名
    strcpy_s(fullVideoName, "");
    if (outDir == NULL)
    {
        sprintf_s(fullVideoName, "%s", videoName);//把videoName打印成一个字符串保存在fullVideoName中 
    }
    else{
        if (_access(outDir, 0) == -1){
            recursive_mkdir(outDir);
        }
        sprintf_s(fullVideoName, "%s%s", outDir, videoName);//将字符串outDir和videoName连接起来,打印,保存在fullVideoName中
    }
    int frameCount = 0;
    CvVideoWriter *pWriter = NULL;
    CvSize size = cvSize(imgW, imgH);
    pWriter = cvCreateVideoWriter(videoName, fourcc, fps, size, isColor);//CREATE WRITER
    IplImage *pImg = NULL;
    char cur_fn[255];//表示某张图片的路径
    while (startFrame <= endFrame){
        strcpy_s(cur_fn, "");
        sprintf_s(cur_fn, "%s%03d%s", inputDir, startFrame, imgExt);//need to change  
        pImg = cvLoadImage(cur_fn, isColor);
        if (!pImg){
            std::cout << "can't open an image file" << std::endl;
            return frameCount;
        }
        cvWriteFrame(pWriter, pImg);
        cvWaitKey(1);
        std::cout << "Write frame " << startFrame << std::endl;
        startFrame++;
        cvReleaseImage(&pImg);
        frameCount++;
    }
    cvReleaseVideoWriter(&pWriter);
    rename(videoName, fullVideoName);//移动文件到指定文件夹
    return  frameCount;
}

//将视频转换为图片序列 返回由视频分解得到的图片总帧数 目前OpenCV只支持AVI格式 因此使用之前需要
//将视频转化问AVI格式

int  VideoToImage(char* videoName, char* outDir, char* imgExt, int maxFrameCount)
{
    CvCapture *cap = cvCaptureFromFile(videoName);
    if (cap == NULL)
    {
        return 0;
    }
    //保存图片的文件夹路径一定要有,因为OpenCV不会自动创建文件夹
    if (_access(outDir, 0) == -1)
    {
        recursive_mkdir(outDir);
        std::cout << "the ouput directory does not exist, and the have been created autonomously!" << std::endl;
    }
    char cur_fn[255];//保存当前帧所得图片的文件名
    IplImage* pImg = NULL;
    int frame = 0;
    while ((pImg = cvQueryFrame(cap)) != NULL && (frame < maxFrameCount))
    {
        frame++;
        strcpy_s(cur_fn, "");
        sprintf_s(cur_fn, "%sindex%d_%04d%s", outDir, g_i,frame, imgExt);//这里的设置适合形如 index[i]_123.jpg的图片序列
        cvSaveImage(cur_fn, pImg, NULL);
    }
    cvReleaseImage(&pImg);
    cvReleaseCapture(&cap);
    return frame;
}

//该函数借鉴了网上资料,自动创建多级目录
int recursive_mkdir(char *dir)
{
    //分解路径名E:\\AA\\BB\\CC\\
    //  
    std::string str = dir;
    int index = 0;
    int i = 0;
    while (1)
    {
        std::string::size_type pos = str.find("\\", index);
        std::string str1;
        str1 = str.substr(0, pos);
        if (pos != -1 && i > 0)
        {
            if (_access(str1.c_str(), 0) == -1)
            {
                _mkdir(str1.c_str());
            }
        }
        if (pos == -1)
        {
            break;
        }
        i++;
        index = pos + 1;
    }
    return 0;
}

5、出现问题

使用opencv训练问题及解决办法 - CSDN博客
http://blog.csdn.net/kxc0720/article/details/49252719
这里写图片描述
在Windows下安装好opencv2.4.9之后,在”xxx/build/x64/vc10/bin”下有训练中要用到的可执行程序opencv_xxxx.exe等四个可执行程序。注意,由于本人为win7 64bits系统,安装了VS2010,故使用该目录下的可执行程序。
当使用自带程序进行人脸检测训练时,遇到一些问题,整理如下:
1.训练中途,程序突然终止,提示”OpenCV Error: Assertion failed (elements_read == 1) in icvGetHaarTraininDataFromVecCallback, file ……..\opencv\apps\haartraining\cvhaartraining.cpp, line 1861”
解决办法:比如训练参数是“D:\Program Files\opencv\build\x64\vc10\bin>opencv_haartraining.exe -data xml -vec pos.vec -bg neg_img.txt -nstage 15 -nsplits 1 -npos 1632 -nneg 3987 -w 40 -h 35 -mem 1024 -mode ALL”,其中,1632为pos.vec中样本的总数目。-npos的意思是每次训练从.vec文件中随机选取npos个正样本。由于存在虚警,在每一次训练一个强分类器之后,会把那些分类错误的从整个样本库中剔除掉,总的样本就剩下 CountVec = CountVec - (1 - minhitrate)* npos,在第二个强分类器的训练过程中就是从剩下的Countvec抽样,一直这样进行nstage次,所以就有CountVec >= (npos + (nstages - 1)(1 -minhitrate) npos ) + nneg 。当把npos设置与vec中总样本数相同时,第二个强分类器训练时,必然就会报错,提示样本数不足。故,将npos和nneg都减少,改成1000和2000即可。

2.训练过程中出现“Premature end of JPEG file”
解决办法:这个一般是样本存在问题可以从两个方面来检查:(1)训练使用的是灰度图像256色,查看是否有些图片是24位图;(2)预览图像,看是否有些图片已损坏或者存储大小明显异常。我的样本中有张352*288的灰度图像,大小才6KB。

3.训练过程中卡在某一stage,过了很久都没有动静。
解决办法:问题出现在取负样本的那个函数icvGetHaarTrainingDataFromBG中。当剩下所有的negtive样本在临时的cascade Classifier中evaluate的结果都是0(也就是拒绝了),随机取样本的数目到几百万都是找不到误检测的neg样本了,因而没法跳出循环!解决方法是,增大负样本数目,增大负样本之间的变化! 因为负样本原则应该是无强大而且多样性越大越好,这在现实中是不可行的,所以我们采集的负样本一般无论从数量上还是多样性上都很难满足要求,所以出现上述问题就很正常了,不过此时的分类器已经完全额、可以使用,因为它的误检率已经很低,从实用性上时没有任何问题的。注:该解释转自:http://www.opencv.org.cn/forum.php?mod=viewthread&tid=33579

6、合并子分类器生成xml文件

输入命令:cd /d F:\objectmarker_AutoSparePart
convert_cascade.exe –size=40x35 ./cascade ./cascade/haarcascade_AutoSparePart.xml
这里写图片描述

7、应用

// Apply_Img.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <opencv2\opencv.hpp>

using namespace std;
using namespace cv;

void detect_and_draw(IplImage* img);
CvHaarClassifierCascade* cascade;
CvMemStorage* storage;
//CascadeClassifier cascade;与CvHaarClassifierCascade* 区别?

int _tmain(int argc, _TCHAR* argv[])
{

    char* cascade_name = "F:\\objectmarker_AutoSparePart\\cascade\\haarcascade_AutoSparePart.xml"; //上文最终生成的xml文件命名为"haarcascade_AutoSparePart.xml"
    cascade = (CvHaarClassifierCascade*)cvLoad(cascade_name, 0, 0, 0); //加载xml文件

    if (!cascade)
    {
        fprintf(stderr, "ERROR: Could not load classifier cascade\n");
        system("pause");
        return -1;
    }
    storage = cvCreateMemStorage(0);
    cvNamedWindow("result", 1);

    const char* filename = "F:\\AutoSparePart2\\20171017\\Camera\\Cam4\\0\\Cam4-20171018 12-11-47.bmp";
    IplImage* image = cvLoadImage(filename, 1);

    if (image)
    {
        detect_and_draw(image); //函数见下方
        cvWaitKey(0);
        cvReleaseImage(&image);//因为使用了IplImage,所以要释放资源
    }
    cvDestroyWindow("result");
    return 0;


}

void detect_and_draw(IplImage* img)
{
    double scale = 5.6;
    static CvScalar colors[] = {
        { { 0, 0, 255 } }, { { 0, 128, 255 } }, { { 0, 255, 255 } }, { { 0, 255, 0 } },
        { { 255, 128, 0 } }, { { 255, 255, 0 } }, { { 255, 0, 0 } }, { { 255, 0, 255 } }
    };//Just some pretty colors to draw with

    //Image Preparation 
    // 
    IplImage* gray = cvCreateImage(cvSize(img->width, img->height), 8, 1);
    IplImage* small_img = cvCreateImage(cvSize(cvRound(img->width / scale), cvRound(img->height / scale)), 8, 1);
    cvCvtColor(img, gray, CV_BGR2GRAY);
    cvResize(gray, small_img, CV_INTER_LINEAR);

    cvEqualizeHist(small_img, small_img); //直方图均衡

    //Detect objects if any 
    // 
    cvClearMemStorage(storage);
    double t = (double)cvGetTickCount();//计时开始
    CvSeq* objects = cvHaarDetectObjects(small_img,
        cascade,
        storage,
        1.1,
        2,
        0/*CV_HAAR_DO_CANNY_PRUNING*/,
        cvSize(40, 35));

    t = (double)cvGetTickCount() - t;//计时结束
    printf("detection time = %gms\n", t / ((double)cvGetTickFrequency()*1000.));

    //Loop through found objects and draw boxes around them 
    //for (int i = 0; i<(objects ? objects->total : 0); ++i)
    //{
    //  CvRect* r = (CvRect*)cvGetSeqElem(objects, i);//draw Rectangle
    //  cvRectangle(img, cvPoint(r->x*scale, r->y*scale), cvPoint((r->x + r->width)*scale, (r->y + r->height)*scale), colors[i % 8]);//choose color
    //}

    CvRect* r = (CvRect*)cvGetSeqElem(objects, 1);//draw Rectangle
    cvRectangle(img, cvPoint(r->x*scale, r->y*scale), cvPoint((r->x + r->width)*scale, (r->y + r->height)*scale), colors[1 % 8]);


    cvShowImage("result", img);
    cvReleaseImage(&gray);
    cvReleaseImage(&small_img);
}

这里写图片描述

8、采用Mat的改进版视频detect

#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\objdetect\objdetect.hpp>
#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;




void detectAndDisplay(Mat frame);

//--------------------------------【全局变量声明】----------------------------------------------
//      描述:声明全局变量
//-------------------------------------------------------------------------------------------------
//注意,需要把"F:\\objectmarker\\haarcascade_plate.xml"这个文件复制到工程路径下
String face_cascade_name = "F:\\objectmarker_AutoSparePart\\cascade\\haarcascade_AutoSparePart.xml";
CascadeClassifier face_cascade;
string window_name = "AutoSparePart Detection";
RNG rng(12345);


//--------------------------------【help( )函数】----------------------------------------------
//      描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
static void ShowHelpText()
{
    //输出欢迎信息和OpenCV版本
    cout << "\n\n\t\t\t本程序是调用摄像头的detect运行的程序,采取了Mat的图片格式非IplImage*\n"
        << "\n\n\t\t\t展示的是多个方形detect的结果\n"
        << "\n\n\t\t\t   当前使用的OpenCV版本为:" << CV_VERSION
        << "\n\n  ----------------------------------------------------------------------------";
}


//-----------------------------------【main( )函数】--------------------------------------------
//      描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main(void)
{
    VideoCapture capture;
    Mat frame;


    //-- 1. 加载级联(cascades)
    if (!face_cascade.load(face_cascade_name)){ printf("--(!)Error loading\n"); return -1; };

    //-- 2. 读取视频
    capture.open(0);
    ShowHelpText();
    if (capture.isOpened())
    {
        for (;;)
        {
            capture >> frame;

            //-- 3. 对当前帧使用分类器(Apply the classifier to the frame)
            if (!frame.empty())
            {
                detectAndDisplay(frame);
            }
            else
            {
                printf(" --(!) No captured frame -- Break!"); break;
            }

            int c = waitKey(1);
            if ((char)c == 'c') { break; }

        }
    }
    return 0;
}


void detectAndDisplay(Mat frame)
{
    std::vector<Rect> faces;
    Mat frame_gray;
    Rect select;//声明矩形 

    cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
    equalizeHist(frame_gray, frame_gray);
    //-- 车牌检测
    face_cascade.detectMultiScale(frame_gray, faces, 5.6, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(80, 70));

    //多目标识别
    /*for (size_t i = 0; i < faces.size(); i++)
    {
        select.x = faces[i].x;
        select.y = faces[i].y;
        select.width = faces[i].width;
        select.height = faces[i].height;
        rectangle(frame, select, Scalar(255, 0, 255), 2, 8, 0);//用矩形画矩形窗

        Mat faceROI = frame_gray(faces[i]);

    }*/

    //单目标识别
    select.x = faces[0].x;
    select.y = faces[0].y;
    select.width = faces[0].width;
    select.height = faces[0].height;
    rectangle(frame, select, Scalar(255, 0, 255), 2, 8, 0);//用矩形画矩形窗

    Mat faceROI = frame_gray(faces[0]);

    //-- 显示最终效果图
    imshow(window_name, frame);
}

这里写图片描述

9、采用Mat读取文件夹下的所有图片,停留0.5秒

这里写图片描述

// objectmarker_AutoSparePart_Detection.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <opencv2\opencv.hpp>
#include <iostream>
#include <windows.h> 
using namespace std;
using namespace cv;

void detectAndDisplay(Mat frame);

//--------------------------------【全局变量声明】----------------------------------------------
//      描述:声明全局变量
//-------------------------------------------------------------------------------------------------
//注意,需要把"F:\\objectmarker\\haarcascade_plate.xml"这个文件复制到工程路径下
String face_cascade_name = "F:\\objectmarker_AutoSparePart\\cascade\\haarcascade_AutoSparePart.xml";
CascadeClassifier face_cascade;
string window_name = "AutoSparePart Detection";
RNG rng(12345);


//--------------------------------【help( )函数】----------------------------------------------
//      描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
static void ShowHelpText()
{
    //输出欢迎信息和OpenCV版本
    cout << "\n\n\t\t本程序是读取所有图片,采取了Mat的图片格式非IplImage*\n"
        << "\n\n\t\t  展示的是多个方形detect的结果,停留的时间是0.5秒\n"
        << "\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION
        << "\n\n  ----------------------------------------------------------------------------";
}


//-----------------------------------【main( )函数】--------------------------------------------
//      描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------

int _tmain(int argc, _TCHAR* argv[])
{
    Mat frame;
    Directory dir;
    //-- 1. 加载级联(cascades)
    if (!face_cascade.load(face_cascade_name)){ printf("--(!)Error loading\n"); return -1; };

    //-- 2. 读取图片
    string dir_path = "F:\\AutoSparePart2\\20171017\\Camera\\Cam4\\0\\";
    string extenttype = "*.bmp";
    vector<string> fileNames = dir.GetListFiles(dir_path, extenttype, false);
    for (int item = 0; item < fileNames.size(); item++)
    {
        string fileName = fileNames[item];
        string fullFilename = dir_path + fileName;
        cout << "FullPath:" << fullFilename << endl;
        Mat img = imread(fullFilename);
        if (!img.empty())
        {
            detectAndDisplay(img);
        }
        else
        {
            printf(" --(!) No captured frame -- Break!"); break;
        }
    }

    /*if (capture.isOpened())
    {
    for (;;)
    {
    capture >> frame;

    //-- 3. 对当前帧使用分类器(Apply the classifier to the frame)
    if (!frame.empty())
    {
    detectAndDisplay(frame);
    }
    else
    {
    printf(" --(!) No captured frame -- Break!"); break;
    }

    int c = waitKey(1);
    if ((char)c == 'c') { break; }

    }
    }*/
    return 0;
}
void detectAndDisplay(Mat frame)
{
    std::vector<Rect> faces;
    Mat frame_gray;
    Rect select;//声明矩形 

    cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
    equalizeHist(frame_gray, frame_gray);
    //-- 汽车零配件检测
    face_cascade.detectMultiScale(frame_gray, faces, 5.6, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(80, 70));

    //多目标识别
    /*for (size_t i = 0; i < faces.size(); i++)
    {
    select.x = faces[i].x;
    select.y = faces[i].y;
    select.width = faces[i].width;
    select.height = faces[i].height;
    rectangle(frame, select, Scalar(255, 0, 255), 2, 8, 0);//用矩形画矩形窗

    Mat faceROI = frame_gray(faces[i]);

    }*/

    //单目标识别
    select.x = faces[0].x;
    select.y = faces[0].y;
    select.width = faces[0].width;
    select.height = faces[0].height;
    rectangle(frame, select, Scalar(255, 0, 255), 2, 8, 0);//用矩形画矩形窗

    Mat faceROI = frame_gray(faces[0]);

    //-- 显示最终效果图
    imshow(window_name, frame);
    cv::waitKey(500);
}

出现问题:
这里写图片描述

Expression vector subscript out of range找了好久,终于知道哪里出问题了:
有些检测不到,size为空!!!
这里写图片描述
修改后的代码:

// objectmarker_AutoSparePart_Detection.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <opencv2\opencv.hpp>
#include <iostream>
#include <windows.h> 
using namespace std;
using namespace cv;

void detectAndDisplay(Mat frame);

//--------------------------------【全局变量声明】----------------------------------------------
//      描述:声明全局变量
//-------------------------------------------------------------------------------------------------
//注意,需要把"F:\\objectmarker\\haarcascade_plate.xml"这个文件复制到工程路径下
String face_cascade_name = "F:\\objectmarker_AutoSparePart\\cascade\\haarcascade_AutoSparePart.xml";
CascadeClassifier face_cascade;
string window_name = "AutoSparePart Detection";
RNG rng(12345);


//--------------------------------【help( )函数】----------------------------------------------
//      描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
static void ShowHelpText()
{
    //输出欢迎信息和OpenCV版本
    cout << "\n\n\t\t本程序是读取所有图片,采取了Mat的图片格式非IplImage*\n"
        << "\n\n\t\t  展示的是多个方形detect的结果,停留的时间是0.5秒\n"
        << "\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION
        << "\n\n  ----------------------------------------------------------------------------";
}


//-----------------------------------【main( )函数】--------------------------------------------
//      描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------

int _tmain(int argc, _TCHAR* argv[])
{
    Mat frame;
    Directory dir;
    //-- 1. 加载级联(cascades)
    if (!face_cascade.load(face_cascade_name)){ printf("--(!)Error loading\n"); return -1; };

    //-- 2. 读取图片
    string dir_path = "F:\\AutoSparePart2\\20171017\\Camera\\Cam4\\0\\";
    string extenttype = "*.bmp";
    vector<string> fileNames = dir.GetListFiles(dir_path, extenttype, false);
    for (int item = 0; item < fileNames.size(); item++)
    {
        string fileName = fileNames[item];
        string fullFilename = dir_path + fileName;
        cout << "FullPath:" << fullFilename << endl;
        Mat img = imread(fullFilename);
        if (!img.empty())
        {
            detectAndDisplay(img);
        }
        else
        {
            printf(" --(!) No captured frame -- Break!"); break;
        }
    }

    /*if (capture.isOpened())
    {
    for (;;)
    {
    capture >> frame;

    //-- 3. 对当前帧使用分类器(Apply the classifier to the frame)
    if (!frame.empty())
    {
    detectAndDisplay(frame);
    }
    else
    {
    printf(" --(!) No captured frame -- Break!"); break;
    }

    int c = waitKey(1);
    if ((char)c == 'c') { break; }

    }
    }*/
    return 0;
}
void detectAndDisplay(Mat frame)
{
    std::vector<Rect> faces;
    Mat frame_gray;
    Rect select;//声明矩形 

    cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
    equalizeHist(frame_gray, frame_gray);
    //-- 汽车零配件检测
    face_cascade.detectMultiScale(frame_gray, faces, 5.6, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(80, 70));

    //多目标识别
    if (faces.empty()){ cout << "检测不到!!!!" << endl; }
    for (size_t i = 0; i < faces.size(); i++)//排除了为空的情况
    {
        select.x = faces[i].x;
        select.y = faces[i].y;
        select.width = faces[i].width;
        select.height = faces[i].height;
        rectangle(frame, select, Scalar(255, 0, 255), 2, 8, 0);//用矩形画矩形窗

        Mat faceROI = frame_gray(faces[i]);

    }

    //-- 显示最终效果图
    imshow(window_name, frame);
    cv::waitKey(500);
}

只想检验一个的代码,加个if判断:

// objectmarker_AutoSparePart_Detection.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <opencv2\opencv.hpp>
#include <iostream>
#include <windows.h> 
using namespace std;
using namespace cv;

void detectAndDisplay(Mat frame);

//--------------------------------【全局变量声明】----------------------------------------------
//      描述:声明全局变量
//-------------------------------------------------------------------------------------------------
//注意,需要把"F:\\objectmarker\\haarcascade_plate.xml"这个文件复制到工程路径下
String face_cascade_name = "F:\\objectmarker_AutoSparePart\\cascade\\haarcascade_AutoSparePart.xml";
CascadeClassifier face_cascade;
string window_name = "AutoSparePart Detection";
RNG rng(12345);


//--------------------------------【help( )函数】----------------------------------------------
//      描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
static void ShowHelpText()
{
    //输出欢迎信息和OpenCV版本
    cout << "\n\n\t\t本程序是读取所有图片,采取了Mat的图片格式非IplImage*\n"
        << "\n\n\t\t  展示的是多个方形detect的结果,停留的时间是0.5秒\n"
        << "\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION
        << "\n\n  ----------------------------------------------------------------------------";
}


//-----------------------------------【main( )函数】--------------------------------------------
//      描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------

int _tmain(int argc, _TCHAR* argv[])
{
    Mat frame;
    Directory dir;
    //-- 1. 加载级联(cascades)
    if (!face_cascade.load(face_cascade_name)){ printf("--(!)Error loading\n"); return -1; };

    //-- 2. 读取图片
    string dir_path = "F:\\AutoSparePart2\\20171017\\Camera\\Cam4\\0\\";
    string extenttype = "*.bmp";
    vector<string> fileNames = dir.GetListFiles(dir_path, extenttype, false);
    for (int item = 0; item < fileNames.size(); item++)
    {
        string fileName = fileNames[item];
        string fullFilename = dir_path + fileName;
        cout << "FullPath:" << fullFilename << endl;
        Mat img = imread(fullFilename);
        if (!img.empty())
        {
            detectAndDisplay(img);
        }
        else
        {
            printf(" --(!) No captured frame -- Break!"); break;
        }
    }

    /*if (capture.isOpened())
    {
    for (;;)
    {
    capture >> frame;

    //-- 3. 对当前帧使用分类器(Apply the classifier to the frame)
    if (!frame.empty())
    {
    detectAndDisplay(frame);
    }
    else
    {
    printf(" --(!) No captured frame -- Break!"); break;
    }

    int c = waitKey(1);
    if ((char)c == 'c') { break; }

    }
    }*/
    return 0;
}
void detectAndDisplay(Mat frame)
{
    std::vector<Rect> faces;
    Mat frame_gray;
    Rect select;//声明矩形 

    cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
    equalizeHist(frame_gray, frame_gray);
    //-- 汽车零配件检测
    face_cascade.detectMultiScale(frame_gray, faces, 5.6, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(80, 70));

    //单目标识别
    if (faces.empty())
    { 
        cout << "检测不到!!!!" << endl; 
    }
    else
    {
        select.x = faces[0].x;
        select.y = faces[0].y;
        select.width = faces[0].width;
        select.height = faces[0].height;
        rectangle(frame, select, Scalar(255, 0, 255), 2, 8, 0);//用矩形画矩形窗

        Mat faceROI = frame_gray(faces[0]);
    }

    //-- 显示最终效果图
    imshow(window_name, frame);
    cv::waitKey(500);
}

参考

【1】使用opencv训练问题及解决办法 - CSDN博客
http://blog.csdn.net/kxc0720/article/details/49252719

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何以问天涯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值