瀏覽網頁的時候發現一篇不錯的文章"用Python和OpenCV創建一個圖片搜索引擎的完整指南
"
http://python.jobbole.com/80860/.
作者在瀏覽自己旅游的照片的時候,發現照片太多了分類不過來,一時技癢寫了個分類軟件,雖然簡單但是有用。關鍵的是我發現他在原文中使用了半個小時就寫出來了。
蠻快的嘛,我想。那么我要用多長時間寫出來了,畢竟對於CBIR也是研究過的。
那么立即來做,首先我要找到是圖片。我沒有那么多旅游圖片(汗),但是別人的照片也是可以一樣用的。找到了之前專門用於測試CBIR的圖片集,大概是這個樣子
就是各種奇奇怪
怪
的照片。然后搭建opencv的基本框架。我們python用的不熟,但是c++下面自己是有類庫的,所以用起來也不是很復雜
首先是讀入所有的圖片:
//遞歸讀取目錄下全部文件
void getFiles(string path, vector <string > & files,string flag){
//文件句柄
long hFile = 0;
//文件信息
struct _finddata_t fileinfo;
string p;
if((hFile = _findfirst(p.assign(path).append( "\\*").c_str(), &fileinfo)) != - 1){
do{
//如果是目錄,迭代之,如果不是,加入列表
if((fileinfo.attrib & _A_SUBDIR)){
if(strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0 && flag == "r")
getFiles( p.assign(path).append( "\\").append(fileinfo.name), files,flag );
}
else{
files.push_back(p.assign(path).append( "\\").append(fileinfo.name) );
}
} while(_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
//遞歸讀取目錄下全部圖片
void getFiles(string path, vector <Mat > & files,string flag){
vector <string > fileNames;
getFiles(path,fileNames,flag);
for ( int i = 0;i <fileNames.size();i ++){
Mat tmp = imread(fileNames[i]);
if (tmp.rows > 0) //如果是圖片
files.push_back(tmp);
}
}
//遞歸讀取目錄下全部圖片和名稱
void getFiles(string path, vector <pair <Mat,string >> & files,string flag){
vector <string > fileNames;
getFiles(path,fileNames,flag);
for ( int i = 0;i <fileNames.size();i ++){
Mat tmp = imread(fileNames[i]);
if (tmp.rows > 0){
pair <Mat,string > apir;
apir.first = tmp;
apir.second = fileNames[i];
files.push_back(apir);
}
}
}
void getFiles(string path, vector <string > & files,string flag){
//文件句柄
long hFile = 0;
//文件信息
struct _finddata_t fileinfo;
string p;
if((hFile = _findfirst(p.assign(path).append( "\\*").c_str(), &fileinfo)) != - 1){
do{
//如果是目錄,迭代之,如果不是,加入列表
if((fileinfo.attrib & _A_SUBDIR)){
if(strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0 && flag == "r")
getFiles( p.assign(path).append( "\\").append(fileinfo.name), files,flag );
}
else{
files.push_back(p.assign(path).append( "\\").append(fileinfo.name) );
}
} while(_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
//遞歸讀取目錄下全部圖片
void getFiles(string path, vector <Mat > & files,string flag){
vector <string > fileNames;
getFiles(path,fileNames,flag);
for ( int i = 0;i <fileNames.size();i ++){
Mat tmp = imread(fileNames[i]);
if (tmp.rows > 0) //如果是圖片
files.push_back(tmp);
}
}
//遞歸讀取目錄下全部圖片和名稱
void getFiles(string path, vector <pair <Mat,string >> & files,string flag){
vector <string > fileNames;
getFiles(path,fileNames,flag);
for ( int i = 0;i <fileNames.size();i ++){
Mat tmp = imread(fileNames[i]);
if (tmp.rows > 0){
pair <Mat,string > apir;
apir.first = tmp;
apir.second = fileNames[i];
files.push_back(apir);
}
}
}
然后是編寫hsv距離,這個參考以前的資料
double GetHsVDistance(Mat src_base,Mat src_test1){
Mat hsv_base;
Mat hsv_test1;
/// Convert to HSV
cvtColor( src_base, hsv_base, COLOR_BGR2HSV );
cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV );
/// Using 50 bins for hue and 60 for saturation
int h_bins = 50; int s_bins = 60;
int histSize[] = { h_bins, s_bins };
// hue varies from 0 to 179, saturation from 0 to 255
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 256 };
const float * ranges[] = { h_ranges, s_ranges };
// Use the o-th and 1-st channels
int channels[] = { 0, 1 };
/// Histograms
MatND hist_base;
MatND hist_test1;
/// Calculate the histograms for the HSV images
calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false );
normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, - 1, Mat() );
calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false );
normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, - 1, Mat() );
/// Apply the histogram comparison methods
double base_test1 = compareHist( hist_base, hist_test1, 0 );
return base_test1;
}
Mat hsv_base;
Mat hsv_test1;
/// Convert to HSV
cvtColor( src_base, hsv_base, COLOR_BGR2HSV );
cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV );
/// Using 50 bins for hue and 60 for saturation
int h_bins = 50; int s_bins = 60;
int histSize[] = { h_bins, s_bins };
// hue varies from 0 to 179, saturation from 0 to 255
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 256 };
const float * ranges[] = { h_ranges, s_ranges };
// Use the o-th and 1-st channels
int channels[] = { 0, 1 };
/// Histograms
MatND hist_base;
MatND hist_test1;
/// Calculate the histograms for the HSV images
calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false );
normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, - 1, Mat() );
calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false );
normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, - 1, Mat() );
/// Apply the histogram comparison methods
double base_test1 = compareHist( hist_base, hist_test1, 0 );
return base_test1;
}
封裝成函數。這個函數比原文中作者提出的方法要簡單,我偷懶了。
然后就是要編寫主函數程序,這個比較麻煩的地方就是要比較出最前面的10 個圖片 。我采用比較笨的方法,趕時間嘛:
int _tmain(
int argc, _TCHAR
* argv[])
{
vector <pair <Mat,string >> imagepairs;
vector < double > dresult;
double dmax = 0;
int imax = - 1;
//讀入圖片
getFiles( "images",imagepairs);
Mat src = imread( "images/0.jpg");
//距離測算
for ( int i = 0;i <imagepairs.size();i ++){
double tmp = GetHsVDistance(src,imagepairs[i].first);
if (tmp == 1)
tmp = 0; //不能搞自己
char cbuf[ 1024];
sprintf_s(cbuf, "dst/%d.jpg",i);
dresult.push_back(tmp); //推入vecresult中
}
//尋找前10個圖片
for ( int index = 0;index < 10;index ++){
for ( int i = 0;i <imagepairs.size();i ++){
if (dresult[i] >dmax){
dmax = dresult[i];
imax = i;
}
}
char cbuf[ 1024];
sprintf_s(cbuf, "dst/%d.jpg",index);
imwrite(cbuf,imagepairs[imax].first);
dresult[imax] = 0; //剔出隊列
dmax = 0;
imax = - 1;
}
printf( "OK");
waitKey();
return 0;
}
{
vector <pair <Mat,string >> imagepairs;
vector < double > dresult;
double dmax = 0;
int imax = - 1;
//讀入圖片
getFiles( "images",imagepairs);
Mat src = imread( "images/0.jpg");
//距離測算
for ( int i = 0;i <imagepairs.size();i ++){
double tmp = GetHsVDistance(src,imagepairs[i].first);
if (tmp == 1)
tmp = 0; //不能搞自己
char cbuf[ 1024];
sprintf_s(cbuf, "dst/%d.jpg",i);
dresult.push_back(tmp); //推入vecresult中
}
//尋找前10個圖片
for ( int index = 0;index < 10;index ++){
for ( int i = 0;i <imagepairs.size();i ++){
if (dresult[i] >dmax){
dmax = dresult[i];
imax = i;
}
}
char cbuf[ 1024];
sprintf_s(cbuf, "dst/%d.jpg",index);
imwrite(cbuf,imagepairs[imax].first);
dresult[imax] = 0; //剔出隊列
dmax = 0;
imax = - 1;
}
printf( "OK");
waitKey();
return 0;
}


前后花了40-50分鍾時間,最后的效果不如作者的效果。主要差距在核心算法上面。看來日常的算法總結重構的確很有價值。
這篇文章先寫到這里,最近事多,等到閑下來再進行重構。歡迎大家批評指正。