一、環(huán)境介紹
操作系統(tǒng): windows10 64位
QT版本: 5.12.6 (我的程序里主要是QT+OpenCV實(shí)現(xiàn)圖像處理顯示的)
OpenCV版本: OpenCV3.4.7
二、下載安裝OpenCV
windows下不用下載源碼,可以直接在官網(wǎng)下載編譯好的文件解壓即可使用。
OpenCV官網(wǎng)下載地址: https://opencv.org/releases/ 下載之后解壓到指定目錄即可,我這里是直接解壓到C盤的。

因?yàn)樵诠倬W(wǎng)下載的版本是VC版本,而我的QT使用的是MinGW編譯器,上面下在官網(wǎng)下載的安裝包里的庫用不了,需要再下載一個(gè)MinGW版本。 下載地址:https://github.com/huihut/OpenCV-MinGW-Build

為什么需要下載兩個(gè)版本? 其實(shí)主要是MinGW版本的OpenCV里帶的兩個(gè)訓(xùn)練分類器(opencv_traincascade.exe)的文件在我電腦上無法使用,可能庫沖突,具體問題沒有深究,就干脆再下載了一個(gè)VC版本是OpenCV,VC版本里opencv_traincascade.exe文件是可以正常使用。 其實(shí)下載的VC版本OpenCV主要是為了用這兩個(gè)文件(opencv_traincascade.exe、opencv_createsamples.exe)

三、測(cè)試OpenCV自帶的分類器
3.1 自帶的分類器文件介紹
OpenCV的官方已經(jīng)提供了很多訓(xùn)練好的分類器文件,在OpenCV的安裝目錄下有。

上面文件中提供了常見的 人臉檢測(cè)、眼睛檢測(cè)、貓臉檢測(cè)、行人檢測(cè)等,看XML文件的命名即可得知。
下面編寫QT程序,調(diào)用OpenCV的級(jí)聯(lián)分類器進(jìn)行測(cè)試。
3.2 QT的示例代碼
下面的QT界面很簡(jiǎn)單,主要是為了測(cè)試分類器文件。
xxx.cpp文件代碼:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
dir="C:/";
ui->label_source->setAlignment(Qt::AlignVCenter);
ui->label_2->setAlignment(Qt::AlignVCenter);
}
Widget::~Widget()
{
delete ui;
}
QImage Widget::Mat2QImage(const Mat& mat)
{
// 8-bits unsigned, NO. OF CHANNELS = 1
if(mat.type() == CV_8UC1)
{
QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
// Set the color table (used to translate colour indexes to qRgb values)
image.setColorCount(256);
for(int i = 0; i < 256; i++)
{
image.setColor(i, qRgb(i, i, i));
}
// Copy input Mat
uchar *pSrc = mat.data;
for(int row = 0; row < mat.rows; row ++)
{
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, mat.cols);
pSrc += mat.step;
}
return image;
}
// 8-bits unsigned, NO. OF CHANNELS = 3
else if(mat.type() == CV_8UC3)
{
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
else if(mat.type() == CV_8UC4)
{
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
}
else
{
return QImage();
}
}
//打開本地圖片
void Widget::on_pushButton_open_clicked()
{
filename=QFileDialog::getOpenFileName(this,"選擇打開的文件",dir,tr("*.bmp *.jpg *.png"));
if(filename.isEmpty())return;
QFileInfo info(filename);
dir=info.path(); //保存當(dāng)前路徑
}
//人臉檢測(cè)代碼
void Widget::opencv_face(QImage qImage)
{
QTime time;
time.start();
//定義級(jí)聯(lián)分類器
CascadeClassifier face_cascade;
//加載分類文件
//
if( !face_cascade.load("C:/OpenCV_3.4.7/OpenCV-MinGW-Build-OpenCV-3.4.7/etc/haarcascades/haarcascade_frontalcatface.xml") )
{
qDebug()<<"haarcascade_frontalface_alt.xml 分類器加載錯(cuò)誤";
return;
}
Mat frame=QImage2cvMat(qImage);
cvtColor( frame, frame, COLOR_BGR2GRAY );//轉(zhuǎn)換成灰度圖像
std::vector faces;
//正臉檢測(cè)
face_cascade.detectMultiScale(frame,faces);
qDebug()<("耗時(shí):%1>
xxx.h文件代碼:
#ifndef WIDGET_H
#define WIDGET_H
#include
#include "opencv2/core/core.hpp"
#include "opencv2/core/core_c.h"
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include
#include
#include
using namespace cv;
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
QImage Mat2QImage(const Mat& mat);
void opencv_face(QImage qImage);
Mat QImage2cvMat(QImage image);
QString dir;
QString filename;
private slots:
void on_pushButton_open_clicked();
void on_pushButton_start_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
xxx.pro文件
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#linu平臺(tái)的路徑設(shè)置
linux {
message('運(yùn)行l(wèi)inu版本')
#添加opencv頭文件的路徑,需要根據(jù)自己的頭文件路徑進(jìn)行修改
INCLUDEPATH+=/home/wbyq/work_pc/opencv-3.4.9/_install/install/include\
/home/wbyq/work_pc/opencv-3.4.9/_install/install/include/opencv\
/home/wbyq/work_pc/opencv-3.4.9/_install/install/include/opencv2
LIBS+=/home/wbyq/work_pc/opencv-3.4.9/_install/install/lib/libopencv_*
}
win32
{
message('運(yùn)行win32版本')
#添加opencv頭文件的路徑,需要根據(jù)自己的頭文件路徑進(jìn)行修改
INCLUDEPATH+=C:/OpenCV_3.4.7/OpenCV-MinGW-Build-OpenCV-3.4.7/include \
C:/OpenCV_3.4.7/OpenCV-MinGW-Build-OpenCV-3.4.7/include/opencv \
C:/OpenCV_3.4.7/OpenCV-MinGW-Build-OpenCV-3.4.7/include/opencv2
LIBS+=C:/OpenCV_3.4.7/OpenCV-MinGW-Build-OpenCV-3.4.7/x86/mingw/bin/libopencv_*.dll
}
xxx.ui文件:

3.3 測(cè)試人臉分類器效果
把代碼中的分類器文件換成:haarcascade_frontalface_alt2.xml



這份QT代碼只是為了簡(jiǎn)單的測(cè)試,就沒有開線程去識(shí)別,如果識(shí)別耗時(shí)比較久的話,識(shí)別過程中UI界面會(huì)卡住,等一會(huì)即可。
3.4 測(cè)試貓臉分類器效果
把代碼中的分類器文件換成:haarcascade_frontalcatface.xml

3.5 測(cè)試行人檢測(cè)分類器效果
把代碼中的分類器文件換成:haarcascade_fullbody.xml

四、訓(xùn)練自己的分類器
4.1 前言
如果自己實(shí)際要檢測(cè)的物體在OpenCV自帶的分類器里沒有,或者OpenCV自帶的分類器識(shí)別精度不滿足要求,就可以使用OpenCV自帶的分類器程序自己訓(xùn)練。訓(xùn)練的方法網(wǎng)上的教程非常多,下面就重復(fù)造輪子簡(jiǎn)單的敘述一下訓(xùn)練過程。
說明: 因?yàn)橄旅娴膬?nèi)容主要是簡(jiǎn)單的敘述一下訓(xùn)練過程,所以我準(zhǔn)備的樣本數(shù)量都較少,如果實(shí)際訓(xùn)練需要看下面說明增加樣本數(shù)量。
4.1 準(zhǔn)備訓(xùn)練的正負(fù)樣本素材說明
想要讓計(jì)算器識(shí)別指定的物體,那么首先得讓計(jì)算器知道你要識(shí)別的物體長(zhǎng)什么樣,需要提前學(xué)習(xí)一番。學(xué)習(xí)過程中,需要準(zhǔn)備一份正樣本和一份負(fù)樣本。 正樣本就是要識(shí)別的物體;負(fù)樣就是用來與正樣本比較的,負(fù)樣本里不包含正樣本里圖片或者相似的圖片,但是也不能亂選,最好與正樣本的取景在一個(gè)環(huán)境下,這樣效果最好,減少誤識(shí)別。
樣本圖片最好使用灰度圖(也就是黑白圖);樣本數(shù)量越多越好,盡量高于1000,樣本間差異性越大越好,正負(fù)樣本比例可以為1:3,訓(xùn)練樣本官方推薦最佳尺寸為20x20,樣本圖片的命名不要出現(xiàn)特殊字符,使用正常點(diǎn)的名字即可。
正樣本的所有的圖片尺寸必須一致,如果不一致的或者尺寸較大的,可以先將所有樣本統(tǒng)一縮放到20*20。
尺寸大小決定的是訓(xùn)練的時(shí)間長(zhǎng)短,大尺寸也可以訓(xùn)練,如果圖片太小也會(huì)損失很多細(xì)節(jié),尺寸可以根據(jù)實(shí)際情況權(quán)衡,但是太大的圖片樣本訓(xùn)練可能會(huì)導(dǎo)致內(nèi)存不夠用的情況,具體情況可以根據(jù)訓(xùn)練效果和情況進(jìn)行調(diào)整。
注意,為了提高訓(xùn)練準(zhǔn)確率,負(fù)樣本不能亂選。
比如: 檢測(cè)的正樣本是車輪,那么負(fù)樣本就最好是車身,馬路、護(hù)欄、等等環(huán)境。
4.2 正樣本圖片示例
下面是識(shí)別汽車的正樣本圖片,正樣本圖片可以創(chuàng)建一個(gè)PositiveSample文件夾存放。

4.3 負(fù)樣本圖片示例
負(fù)樣本圖片可以創(chuàng)建一個(gè)NegativeSample文件夾存放。
負(fù)樣本圖片不要求樣本的尺寸,但要大于等于正樣本的大小;且負(fù)樣本不能重復(fù),要增大負(fù)樣本的差異性。
負(fù)樣本也要灰度化,同正樣本操作相同。

4.4 創(chuàng)建工作目錄
在電腦任意目錄,創(chuàng)建一個(gè)工作目錄OpenCV_TrainingData,將存放正負(fù)樣本的目錄拷貝到OpenCV_TrainingData目錄下,再創(chuàng)建一個(gè)XML目錄,用于存放生成的訓(xùn)練文件。

3.2 創(chuàng)建正樣本描述文件
打開電腦命令行終端。

使用cd命令進(jìn)入到正樣本的目錄下。

執(zhí)行命令如下:
命令1-進(jìn)入到正樣本目錄下:cd /d D:\linux-share-dir\OpenCV_TrainingData\PositiveSample
命令2-將目錄下所有圖片名字和路徑輸出到pos.txt文件:dir /b/s/p/w *.jpg > pos.txt
打開生成的pos.txt文件內(nèi)容如下。

將文件的內(nèi)容稍作修改,加上檢測(cè)目標(biāo)個(gè)數(shù)、目標(biāo)圖片左上位置坐標(biāo)、圖片寬高參數(shù)。
我這里準(zhǔn)備的樣本圖片尺寸都是40x40,所以填寫的代碼:1 0 0 40 40
修改效果如下:

如果圖片數(shù)量很大,手動(dòng)修改比較麻煩, 直接使用文本編輯器,搜索替換即可。
****

3.3 創(chuàng)建負(fù)樣本描述文件
負(fù)樣本描述文件創(chuàng)建方法與正樣本描述文件一樣,進(jìn)入到負(fù)樣本圖片的目錄下,生成neg.txt文件,代碼如下:
命令1:cd /d D:\linux-share-dir\OpenCV_TrainingData\NegativeSample
命令2:dir /b/s/p/w *.jpg > neg.txt
注意:負(fù)樣本neg.txt文件不需要做任何修改,以下就是最終文件。

3.4 生成正樣本的.vec文件
為了方便填路徑,將生成的正負(fù)樣本描述文件pos.txt和neg.txt拷貝到上層目錄下。

正樣本的.vec文件生成,執(zhí)行命令如下:
命令1:cd /d D:\linux-share-dir\OpenCV_TrainingData
命令2:C:\OpenCV_3.4.7\opencv-vc-3.4.7\build\x64\vc15\bin\opencv_createsamples.exe -vec pos.vec -info pos.txt -num 54 -w 40 -h 40
參數(shù)介紹:
opencv_createsamples.exe: 生成樣本描述文件的可執(zhí)行程序(opencv自帶),前面是我電腦上的路徑。
-vec pos.vec 指定生成的vec文件
-info pos.txt 指定源樣本的描述文件
-num 54 指定標(biāo)定目標(biāo)樣本總數(shù)量,就是樣本描述文件里所有第2列的數(shù)字之和。
-w 40 指定樣本縮放后的寬,如果之前圖片不是40,那么這里就會(huì)縮放成40,有了這個(gè)參數(shù)就可以省去之前的圖片處理過程。
-h 40 指定樣本縮放后的高,如果之前圖片不是40,那么這里就會(huì)縮放成40,有了這個(gè)參數(shù)就可以省去之前的圖片處理過程。
我電腦上OpenCV的安裝路徑:

生成結(jié)果如下:
****

執(zhí)行成功之后在當(dāng)前目錄下生成pos.vec文件。

說明: 負(fù)樣本不需要生成vec文件。
3.5 開始訓(xùn)練樣本
命令1:cd /d D:\linux-share-dir\OpenCV_TrainingData
命令2:C:\OpenCV_3.4.7\opencv-vc-3.4.7\build\x64\vc15\bin\opencv_traincascade.exe -data XML -vec pos.vec -bg neg.txt -numPos 50 -numNeg 133 -numStages 20 -w 40 -h 40 -mode ALL
參數(shù)介紹:
-data 指定輸出目錄,訓(xùn)練生成的xml文件就放在這個(gè)目錄下
-vec 指定正樣本生成的 vec 文件
-bg 指定負(fù)樣本數(shù)據(jù)文件,即前面生成的neg.txt文件
-numPos 指定正樣本數(shù)目,這個(gè)數(shù)值一定要比準(zhǔn)備正樣本時(shí)的數(shù)目少,不然會(huì)報(bào) can not get new positive sample。
參考理由:minHitRate:影響每個(gè)強(qiáng)分類器閾值,當(dāng)設(shè)置為0.95時(shí)如果正訓(xùn)練樣本個(gè)數(shù)為10000個(gè),那么其中的500個(gè)就很可能背叛別為負(fù)樣本,第二次選擇的時(shí)候必須多選擇后面的500個(gè),按照這種規(guī)律我們?yōu)楹竺娴拿考?jí)多增加numPos*minHitRate個(gè)正樣本,根據(jù)訓(xùn)練的級(jí)數(shù)可以得到如下公式
numPos+(numStages-1)numPos(1-minHitRate)《=準(zhǔn)備的訓(xùn)練樣本
以上式子也只是根據(jù)訓(xùn)練級(jí)數(shù)和準(zhǔn)備的正樣本總和設(shè)置一個(gè)參與訓(xùn)練的正樣本個(gè)數(shù),只能作為估算,小于計(jì)算出來的數(shù)可能沒有問題,但是大于那個(gè)數(shù)肯定有問題
現(xiàn)在解釋下”可能有問題“是如何理解的:因?yàn)槲覀兛偸悄J(rèn)每次添加固定個(gè)數(shù)的正訓(xùn)練樣本,但是有時(shí)候后面的固定個(gè)數(shù)的正訓(xùn)練樣本中也可能存在不滿足條件的樣本,這些樣本跟我們排除的樣本類似,所以比如我們打算添加500個(gè)樣本就夠了,但是實(shí)際需要添加600個(gè),這時(shí)候就出現(xiàn)問題了。
從上面例子的結(jié)果中可以看出,每級(jí)我們?cè)试S丟掉12000*0.001個(gè)正樣本=12,需要注意的是萬一第11個(gè)或者第10個(gè)跟第12個(gè)的閾值是一樣的,那么我們之丟掉了前面的10個(gè)或者9個(gè)而已,因此每次增加的個(gè)數(shù)可能要小于12個(gè),大于12個(gè)的情況就是上面所說的”可能有問題“。
-numStages 指定訓(xùn)練級(jí)數(shù)
-numNeg 指定負(fù)樣本數(shù)目
-w 40 -h 40 指定樣本圖尺寸
-mode 指定haar特征的種類,basio僅僅使用垂直特征,al1表示使用垂直以及45度旋轉(zhuǎn)特征
開始訓(xùn)練:

訓(xùn)練成功之后在XML目錄下會(huì)生成cascade.xml文件,這個(gè)文件就是最終訓(xùn)練成功的文件,可以替換到到上面代碼里測(cè)試。

審核編輯:湯梓紅("耗時(shí):%1>
-
分類器
+關(guān)注
關(guān)注
0文章
152瀏覽量
13394 -
OpenCV
+關(guān)注
關(guān)注
32文章
642瀏覽量
42382
發(fā)布評(píng)論請(qǐng)先 登錄
評(píng)論