浏览网页的时候发现一篇不错的文章"用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分钟时间,最后的效果不如作者的效果。主要差距在核心算法上面。看来日常的算法总结重构的确很有价值。
这篇文章先写到这里,最近事多,等到闲下来再进行重构。欢迎大家批评指正。