日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

OpneCV3——使用SURF、SVM、BOW对图像进行分类

發(fā)布時(shí)間:2025/3/21 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpneCV3——使用SURF、SVM、BOW对图像进行分类 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

1.按圖像中的內(nèi)容給圖像分類(lèi)是計(jì)算機(jī)視覺(jué)中比較適合初學(xué)者的項(xiàng)目,好多手機(jī)相冊(cè)都有這一個(gè)功能,比如把美食歸為一個(gè)標(biāo)簽,藍(lán)天白云歸為一個(gè)標(biāo)簽等等。還有我之前做過(guò)的車(chē)牌識(shí)別的項(xiàng)目都用到圖像分類(lèi)這個(gè)功能。
2.項(xiàng)目的環(huán)境:Winwods7 ,vs2015,OpenCV3.3加opencv_contrib庫(kù),boost庫(kù),實(shí)現(xiàn)語(yǔ)言是C++.
3.項(xiàng)目用到的知識(shí)點(diǎn)有OpenCV的SURF特征提取、BOW(Bag-of-words model-詞袋模型),SVM分類(lèi)器等,boost是用來(lái)操作文件。
4.項(xiàng)目的是功能是先對(duì)一些已經(jīng)手動(dòng)歸類(lèi)好的圖像樣本進(jìn)行輸入并訓(xùn)練,把訓(xùn)練好的結(jié)果保存,然后使用訓(xùn)練好的結(jié)果對(duì)未知的圖像進(jìn)行預(yù)測(cè)判斷并分類(lèi),我使用的樣本每個(gè)種類(lèi)只有120張,特性提取的SURF的hessianThreshold取值從400到2000,準(zhǔn)確率在70%到80%之間。

一.數(shù)據(jù)收集與處理

1.圖像數(shù)據(jù)是從ZOL壁紙網(wǎng)站下載,里面有分類(lèi)好的壁紙,可以整個(gè)系列下載。下載之后新建文件夾放同類(lèi)型的圖像,我收集了四個(gè)類(lèi)型圖像,新建一個(gè)data/train的文件夾,然后手工分類(lèi)并放到相關(guān)的文件夾里再放到該目錄下,每個(gè)種類(lèi)收集了差不多120張圖像。
????????
2.圖像不能太大,也不能太小,試過(guò)在訓(xùn)練集放了全是幾M以上的圖像,跑特征聚類(lèi)時(shí)跑了一天沒(méi)有跑出來(lái),如果圖像太小只有幾B,到特征提取那里有可能會(huì)報(bào)錯(cuò),認(rèn)為是空的圖像矩陣。從網(wǎng)上收集的圖像太大可以編寫(xiě)python腳本把每個(gè)文件夾下的圖像改成統(tǒng)一大小的像素的,該腳本把所有圖像改成寬384和高256的圖像。
resize.ipynb

from PIL import Image import glob, os w,h = 384,256 #更改成的分辨率 def timage():for files in glob.glob('E:/caffe/5/*.jpg'): #原文件路徑filepath,filename = os.path.split(files)filterame,exts = os.path.splitext(filename)opfile = r'E:/caffe/data/5/' #保存的文件路徑if (os.path.isdir(opfile)==False):os.mkdir(opfile)im=Image.open(files)im_ss=im.resize((int(w), int(h)))try:im_ss.save(opfile+filterame+'.jpg')except:print (filterame)os.remove(opfile+filterame+'.jpg')if __name__=='__main__':timage()

3.在data目錄再創(chuàng)建一個(gè)test的文件夾,用來(lái)放測(cè)試時(shí)用的圖像,就是放訓(xùn)練種類(lèi)相關(guān)的圖像,圖像大小隨便,沒(méi)有尺寸要求。

4.可以從這里下載我分好類(lèi)的正樣本和測(cè)試樣本,下載地址:https://download.csdn.net/download/matt45m/11044699
二.項(xiàng)目流程與步驟
1.訓(xùn)練代碼流程圖

2.測(cè)試代碼流程

三.代碼示例
1.初始化與讀取相關(guān)文件夾,如果第一次運(yùn)行,創(chuàng)建要用到的文件夾,有放模板的文件夾、放測(cè)試訓(xùn)練結(jié)果的文件夾、放訓(xùn)練好的文件的文件夾。然后從訓(xùn)練集每個(gè)文件夾拿出一張圖像放到模板文件夾里并按類(lèi)型命名。
創(chuàng)建相關(guān)文件夾

/*創(chuàng)建相關(guān)文件夾*/ if (create_file) {fs::create_directory(temp_path);fs::create_directory(result_path);fs::create_directory(xml_path);vector<string> temp_name = getFileNameFromDir(TRAIN_FOLDER);for (size_t i = 0; i < temp_name.size(); i++){fs::path dir(temp_name.at(i));fs::directory_iterator itEnd;fs::directory_iterator itDir(dir);int last_index = temp_name.at(i).find_last_of("\\");string name = temp_name.at(i).substr(last_index + 1);// 遍歷路徑下所有文件for (; itDir != itEnd; itDir++){string file_name = itDir->path().string();// 判斷文件是否是文件夾fs::path file(file_name);if (file.extension().string() == ".jpg"){fs::copy_file(file_name, temp_path + name + ".jpg");fs::remove(file_name);break;}}} }

3.遍歷訓(xùn)練集文件夾下的所有圖像文件,保存multimap容器。
(1).循環(huán)遍歷train文件夾下的訓(xùn)練文件夾

fs::recursive_directory_iterator begin_iter(TRAIN_FOLDER); fs::recursive_directory_iterator end_iter; //遞歸迭代rescursive 直接定義兩個(gè)迭代器:begin_iter為迭代起點(diǎn)(有參數(shù)),end_iter迭代終點(diǎn) for (; begin_iter != end_iter; ++begin_iter) {string file_path = begin_iter->path().string();fs::path file_name(file_path);//判斷是否為目錄if (fs::is_directory(file_name)){// 將類(lèi)目名稱(chēng)設(shè)置為目錄的名稱(chēng)categor = file_name.filename().string();category_name.push_back(categor);}else{string filename = string(TRAIN_FOLDER) + categor + string("/") + begin_iter->path().filename().string();Mat temp = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);string name = begin_iter->path().filename().string();if (temp.empty()){continue;}pair<string, Mat> p(categor, temp);std::cout << "開(kāi)始讀取訓(xùn)練集" << categor << "下的" << name << std::endl;//加到multimap,鍵名可重復(fù)出現(xiàn)train_set.insert(p);} }

(2)multimap的存儲(chǔ)方式如下圖:

4.提取訓(xùn)練集里每張圖像的特征點(diǎn),得出BOW詞典,并保存BOW文件。

// 對(duì)于每一幅模板,提取SURF算子,存入到vocab_descriptors中 multimap<string, Mat> ::iterator i = train_set.begin();for (; i != train_set.end(); i++) {vector<KeyPoint>keypoints;Mat temp = (*i).second;Mat descrip;//detect函數(shù)檢測(cè)SURF/SIFT特征的關(guān)鍵點(diǎn),并保存在vector容器中,最后使用drawKeypoints函數(shù)繪制出特征點(diǎn)。feature_decter->detect(temp, keypoints);//用視覺(jué)詞典計(jì)算圖像特征描述子descriptor_extractor->compute(temp, keypoints, descrip);//把特征點(diǎn)加到矩陣vocab_descriptors.push_back(descrip); }

5.構(gòu)造與保存BOW文件。

// 對(duì)于每一幅模板,提取SURF算子,存入到vocab_descriptors中 multimap<string, Mat> ::iterator i = train_set.begin();for (; i != train_set.end(); i++) {//定義關(guān)鍵點(diǎn)vector<KeyPoint>key_point;//從容器里讀出文件絕對(duì)路徑string cate_name = (*i).first;//從容器里讀出圖片Mat temp_image = (*i).second;Mat imageDescriptor;//detect函數(shù)檢測(cè)SURF/SIFT特征的關(guān)鍵點(diǎn),并保存在vector容器中,最后使用drawKeypoints函數(shù)繪制出特征點(diǎn)。feature_decter->detect(temp_image, key_point);//用視覺(jué)詞典計(jì)算圖像特征描述子bow_descriptor_extractor->compute(temp_image, key_point, imageDescriptor);//push_back(Mat);在原來(lái)的Mat的最后一行后再加幾行,元素為Mat時(shí), 其類(lèi)型和列的數(shù)目 必須和矩陣容器是相同的allsamples_bow[cate_name].push_back(imageDescriptor); }

6.訓(xùn)練分類(lèi)器并保存訓(xùn)練好的文件,訓(xùn)練完成。

for (int i = 0; i < categories_size; i++) {//在創(chuàng)建對(duì)象同時(shí),提供矩陣行數(shù)、列數(shù)、存儲(chǔ)類(lèi)型Mat tem_Samples(0, allsamples_bow.at(category_name[i]).cols,allsamples_bow.at(category_name[i]).type());//新行一個(gè)0行一列的矩陣Mat responses(0, 1, CV_32SC1);//把上面包含特征點(diǎn)的矩陣加到新建的矩陣后面tem_Samples.push_back(allsamples_bow.at(category_name[i]));//新建一個(gè)跟特征模板行數(shù)一樣,1列,并全部初始化為1的矩陣Mat posResponses(allsamples_bow.at(category_name[i]).rows, 1, CV_32SC1, Scalar::all(1));//把數(shù)據(jù)壓入矩陣responses.push_back(posResponses);//遍歷容器for (auto itr = allsamples_bow.begin(); itr != allsamples_bow.end(); ++itr){if (itr->first == category_name[i]){continue;}//壓入數(shù)據(jù)tem_Samples.push_back(itr->second);Mat response(itr->second.rows, 1, CV_32SC1, Scalar::all(-1));responses.push_back(response);}//samples是訓(xùn)練樣本特征的矩陣,layout參數(shù)有ROW_SAMPLE和COL_SMAPLE兩個(gè)選擇,//說(shuō)明了樣本矩陣中一行還是一列代表一個(gè)樣本,response矩陣和samples矩陣相對(duì)應(yīng),說(shuō)明了樣本的標(biāo)記Ptr<TrainData> t_tdata = TrainData::create(tem_Samples,ROW_SAMPLE, responses);//開(kāi)始訓(xùn)練stor_svms.at(i)->train(t_tdata);//存儲(chǔ)svmstring svm_filename = xml_path + category_name[i] + string("SVM.xml");stor_svms.at(i)->save(svm_filename.c_str()); }

四、測(cè)試
1.測(cè)試代碼

for (int i = 0; i<categories_size; i++) {string class_name = category_name[i];string svm_path = xml_path + class_name + string(".xml");cout << svm_path << endl;FileStorage svm_file(svm_path, FileStorage::READ);//讀取SVM.xmlif (svm_file.isOpened()){//svm_file.release();Ptr<SVM> st_svm = Algorithm::load<SVM>(svm_path.c_str());if (sign == 0){float score_Value = st_svm->predict(test, noArray(), true);float class_Value = st_svm->predict(test, noArray(), false);sign = (score_Value < 0.0f) == (class_Value < 0.0f) ? 1 : -1;}cur_confidence = sign * st_svm->predict(test, noArray(), true);}else{if (sign == 0){float scoreValue = stor_svms[i]->predict(test, noArray(), true);float classValue = stor_svms[i]->predict(test, noArray(), false);sign = (scoreValue < 0.0f) == (classValue < 0.0f) ? 1 : -1;}cur_confidence = sign * stor_svms[i]->predict(test, noArray(), true);}if (cur_confidence>best_score){best_score = cur_confidence;prediction_category = class_name;} }

2.測(cè)試結(jié)果
卡通這個(gè)類(lèi)別的,可以看到有幾張是錯(cuò)誤的。

花這個(gè)類(lèi)別的,也有幾張誤判的:

結(jié)語(yǔ):

1.同樣的數(shù)據(jù),使用opencv進(jìn)行預(yù)測(cè)時(shí),所有的時(shí)間和準(zhǔn)確率和caffe訓(xùn)練成模型之后調(diào)用,完全不是一個(gè)級(jí)別的,caffe的模型預(yù)測(cè)速度比opencv這個(gè)項(xiàng)目要快差不多3倍。
caffe預(yù)測(cè)一張圖像所花的時(shí)間:

SVM分類(lèi)預(yù)測(cè)一張圖像所花的時(shí)間:

2.準(zhǔn)確率也不一樣,如果樣本數(shù)量少,caffe還可使用遷移學(xué)習(xí)來(lái)提高準(zhǔn)確率,caffe預(yù)測(cè)能達(dá)到97%上,但SVM分類(lèi)器只能達(dá)到80%左右,也許是代碼優(yōu)化的問(wèn)題吧。
3.關(guān)于工程的源碼,運(yùn)行程序時(shí)的bug,都可以加這個(gè)群(487350510)互相討論學(xué)習(xí)。

總結(jié)

以上是生活随笔為你收集整理的OpneCV3——使用SURF、SVM、BOW对图像进行分类的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。