时间紧张,先记一笔,后续优化与完善。
呆板学习算法是总离不开练习样本的,通常情况下,你找到的图片并非仅仅含有正样本的,而应该是同时含有正样本和负样本的图片;例如,你盘算利用呆板学习的算法来行进人脸测检,要需找到人脸的正样本(人脸图片)和负样本(非人脸图片),这个时候,正样本和负样本往往不是那么易容找到的(当然,人脸的练习样本前目在网上能找到很多开公的练习样本库,但如果你要找车辆的练习样本呢?情表的练习样本呢?猫的练习样本?飞机的练习样本?。。。);这个时候,就要需拍摄或者下载很多含包正样本(如,人脸)的图片;当然,这个图片当中,某些域区是人脸(正样本),其它域区长短人脸(负样本);明显,用图画工具之类的软件把一张一张的图片中的正样本域区人工扣去来下,作为正样本, 剩下的域区,作为负样本,这是一个可行的方法;你可以这么做,但作为序程员,乎似写个序程,遍历文件夹中所有的图片,顺次表现图片,由户用通过鼠标点击几下到得正样本域区和负样本域区,这样要更高效一些吧。前者是纯人工的方法,后者是半人工的方法;当你扣取了够足的正负样本,练习到得分类器以后,利用呆板(计算机)就可以主动的把图片中的正样本域区(人脸)给扣取出来,这就是全主动的方法了;呆板学习的目标,就是让呆板来取代人工高效的实现重复性的任务嘛;当然了,在没有到得练习样本之前,你还是得利用纯人工或者半人工的方法来决解练习样本的题问;笔者给出一个半人工的序程,便方朋友们当前在样本作制过程当中应用;
参考代码:
#include "stdafx.h" #include "windows.h" #include <vector> #include <string> #include "opencv.hpp" #include "iostream" #include "fstream" using namespace std; typedef std::vector<std::string> file_lists; static int str_compare(const void *arg1, const void *arg2) { return strcmp((*(std::string*)arg1).c_str(), (*(std::string*)arg2).c_str());//较比字符串arg1 and arg2 } file_lists ScanDirectory(const std::string &path, const std::string &extension) { WIN32_FIND_DATA wfd;//WIN32_FIND_DATA:Contains information about the file that is found by the //FindFirstFile, FindFirstFileEx, or FindNextFile function HANDLE hHandle; string searchPath, searchFile; file_lists vFilenames; int nbFiles = 0; searchPath = path + "/*" + extension; hHandle = FindFirstFile(searchPath.c_str(), &wfd);//Searches a directory for a file or subdirectory //with a name that matches a specific name if (INVALID_HANDLE_VALUE == hHandle) { fprintf(stderr, "ERROR(%s, %d): Cannot find (*.%s)files in directory %s/n", __FILE__, __LINE__, extension.c_str(), path.c_str()); exit(0); } do { //. or .. if (wfd.cFileName[0] == '.') { continue; } // if exists sub-directory if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)//dwFileAttributes:The file attributes of a file { //FILE_ATTRIBUTE_DIRECTORY:The handle identifies a directory continue; } else//if file { searchFile = path + "/" + wfd.cFileName; vFilenames.push_back(searchFile); nbFiles++; } }while (FindNextFile(hHandle, &wfd));//Call this member function to continue a file search begun //with a call to CGopherFileFind::FindFile FindClose(hHandle);//Closes a file search handle opened by the FindFirstFile, FindFirstFileEx, //or FindFirstStreamW function // sort the filenames qsort((void *)&(vFilenames[0]), (size_t)nbFiles, sizeof(string), str_compare);//Performs a quick sort return vFilenames; } bool rBtnDown = false; const int ptsSize = 4; CvPoint pts[ptsSize]; int ptsCount = 0; void mouseOn(int e,int x,int y,int flags,void* param) { if (e == CV_EVENT_LBUTTONDOWN) { pts[ptsCount++] = cvPoint(x,y); } else if (e == CV_EVENT_RBUTTONDOWN) { rBtnDown = true; } } void GetTrainSample() { string folderIn, fileExt, folderOut; ifstream fileIn; fileIn.open("config.ini", ios::in); if (!fileIn) { cout<<"config.ini open error"<<endl; system("pause"); exit(-1); } char str[512]; memset(str, '\0', 512*sizeof(char)); fileIn>>str; folderIn = str; memset(str, '\0', 512*sizeof(char)); fileIn>>str; fileExt = str; memset(str, '\0', 512*sizeof(char)); fileIn>>str; folderOut = str; file_lists files = ScanDirectory(folderIn, fileExt); int size = files.size(); cout<<"文件夹中的图片总数:"<<size<<endl; string fileName; string path; string ptsName; int len; cvNamedWindow("img", 0); cvSetMouseCallback("img", mouseOn); for (int i=0; i<size; i++) { cout<<i+1<<"/"<<size<<endl; int idx = files[i].find_last_of('\/'); fileName.clear(); fileName = files[i].substr(idx+1, files[i].length()-idx); path = folderOut + "/"+ fileName; ptsName = path; len = ptsName.length(); if (ptsName[len-4] = '.') { ptsName[len-1] = 't'; ptsName[len-2] = 'x'; ptsName[len-3] = 't'; } else { ptsName[len-1] = '\0'; ptsName[len-2] = 't'; ptsName[len-3] = 'x'; ptsName[len-4] = 't'; } ofstream fileOut; fileOut.open(ptsName.c_str(), ios::out); IplImage* pImg = cvLoadImage(files[i].c_str()); if (!pImg) { cout<<"img load error, fileName: "<<files[i].c_str(); continue; } cvSaveImage(path.c_str(), pImg); while(!rBtnDown) { cvShowImage("img", pImg); cvWaitKey(1); if (ptsCount == ptsSize) { int minX,minY,maxX,maxY; minX = maxX = pts[0].x; minY = maxY = pts[0].y; for (int j=1; j<ptsSize; j++) { minX = minX<pts[j].x ? minX:pts[j].x; minY = minY<pts[j].y ? minY:pts[j].y; maxX = maxX>pts[j].x ? maxX:pts[j].x; maxY = maxY>pts[j].y ? maxY:pts[j].y; } fileOut<<minX<<" "<<minY<<" "<<maxX<<" "<<maxY<<endl; ptsCount = 0; cvRectangle(pImg, cvPoint(minX,minY), cvPoint(maxX,maxY), CV_RGB(255,0,0)); cvShowImage("img", pImg); cvWaitKey(1); } } rBtnDown = false; ptsCount = 0; cvReleaseImage(&pImg); fileOut.close(); } } void Usage() { cout<<"config.ini说明"<<endl; cout<<"序程从config.ini文件中顺次读取三行信息:\n输入图片文件夹路径 \n输入图片后缀 \n输出路径;\n\nconfig.ini中的内容举例:\nc:\\inputDir \n.bmp \nD:\\result"<<endl; cout<<endl; cout<<"本序程应用说明:"<<endl; cout<<"户用鼠标左键单击4次即可选定图片中的一个矩形域区,选定若干个矩形域区以后,单击鼠标右键即可切换到下一张图片"<<endl; cout<<"//////////////////////////////////////////////////////////////////////"<<endl; } int _tmain(int argc, _TCHAR* argv[]) { Usage(); GetTrainSample(); system("pause"); return 0; }
说明:
(1)以上代码要需opencv,请自行配置相关的lib和dll;
(2)以上代码在编译过程当中,请勿选择“Unicode”字符集,如,VS2008,VS2010中,请如下设置,项目-->属性-->常规-->字符集-->未设置;
(3)可执行文件所在路径请创建一个config.ini文件,该文件含包三行:
输入图片路径
图片后缀名
输出路径;
config.ini参考设置:
E:\Images
.bmp
E:\result
(4)config.ini中的输入和输出路径请尽量不要含包中文路径,可能会出错;
文章结束给大家分享下程序员的一些笑话语录:
一条狗在街上闲逛,看见橱窗里一张告示:「招聘程序员。会编程,有团队精神,至少精通两种语言。均等机会。」
那条狗就进去申请,但是被拒绝了。
「我不能雇一条狗在公司里做事。」经理说。
狗不服气,指着告示上「均等机会」几字抗议。
经理没法,叹了口气,不屑地问道:「你会编程吗?」
那条狗默默地走到电脑前,编了个程序,运作准确。
「你有团队精神吗?」经理问。
那条狗掉头看了看门外,一大群野狗在外面虎视耽耽。
「我真的不能雇狗做这份工作。」经理气急败坏地说。
「就算会编程、有团队精神,但是我需要的雇员至少要能精通两种语言。」
那条狗抬头看着经理说:「喵-噢。」