目的:使用python基于caffe,批量抽取图像特征
官网链接:http://nbviewer.ipython.org/github/BVLC/caffe/blob/master/examples/00-classification.ipynb
说明方法:根据我自己写的特征提取代码,一步步解释
1 导入需要的库文件
import numpy as np
import matplotlib.pyplot as plt
import scipy
import sys
import caffe
import os
import leveldb
import gc
说明:numpy和leveldb,这两个库需要读者自己安装;
leveldb的下载、安装、使用链接:https://github.com/rjpower/py-leveldb
numpy安装:请百度
2 指定相应文件的目录
eval_image_dir=caffe_root+'sloanqin/data/godpool/eval_image/'#输入图片的路径
feature_dir='./feature/' #提取特征的路径
featureStr_dir='./featureStr/'#提取特征的路径
ps:这里我给了两个特征提取输出的路径,后面会说明为什么我要这样做;
3 创建相应的目录
<pre name="code" class="python">if(os.path.isdir(feature_dir)):
os.system('rm -r '+feature_dir)
os.system('mkdir '+feature_dir)
if(os.path.isdir(featureStr_dir)): # this for us to view
os.system('rm -r '+featureStr_dir)
os.system('mkdir '+featureStr_dir)
说明:如果路径已经存在了,我们删除掉;然后创建新的路径;
这样做的目的主要是删除程序上次运行产生的文件;
4 caffe网络设置
######################################################################
caffe.set_mode_gpu()
net = caffe.Net(caffe_root + 'sloanqin/data/godpool/deploy.prototxt',
caffe_root + 'sloanqin/data/godpool/caffenet_train_iter_201000.caffemodel',
caffe.TEST)
# input preprocessing: 'data' is the name of the input blob == net.inputs[0]
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
transformer.set_transpose('data', (2,0,1))
transformer.set_mean('data', np.load(caffe_root + 'python/caffe/imagenet/ilsvrc_2012_mean.npy').mean(1).mean(1)) # mean pixel
transformer.set_raw_scale('data', 255) # the reference model operates on images in [0,255] range instead of [0,1]
transformer.set_channel_swap('data', (2,1,0)) # the reference model has channels in BGR order instead of RGB
# set net to batch size of 50
net.blobs['data'].reshape(50,3,227,227)
######################################################################
说明:这里设置的含义读者自己应该很容易看出来;
至于为什么可以这样设置,需要看caffe的源码,看作者设计的数据结构;不过现在并没有必要这样做,我们知道就可以了;但是caffe的源码还是很值得学习的;
5 循环读取图片,存储提取得到的特征
<pre name="code" class="python">######################################################################
files = os.listdir(eval_image_dir) #打开图片路径
i=0
j=0
classnumMax=0
fileNameNum=np.arange(0,50,1).reshape(50,-1) # 数组,用来存储图片名称
fileHandle=open(eval_classify_txt_dir,'a') # txt文件,存储每一张图片预测的分类结果
# 打开leveldb文件,用来存储特征
dbDir=feature_dir+'db'
tempDb=leveldb.LevelDB(dbDir)
# this string help us to view
dbDirStr=featureStr_dir+'db'
tempDbStr=leveldb.LevelDB(dbDirStr)
for f in files:
if(os.path.isfile(eval_image_dir + f)):
if(i == 50):
i=0
j=j+1
# now we get 50 image data input
# we will forward compute it
# and extract features
out = net.forward()
fc7Data = net.blobs['fc7'].data
probData=(net.blobs['prob'].data)
predict=np.argmax(probData,axis=1).reshape(50,-1)
for k in range(0,50):
classnum=predict[k][0]
feature=fc7Data[k].reshape(1,-1)
tempData=feature.tobytes() # 将特征数组,转换成byte类型
tempDb.Put(str(fileNameNum[k][0]),tempData) # 存入特征
tempDataStr=str(feature) # 将特征数组,转换成string类型,存为string目的是为了方便观察
tempDbStr.Put(str(fileNameNum[k][0]),tempDataStr) # 存入特征
fileHandle.write(str(fileNameNum[k][0])+'.jpg '+str(classnum)+'\n') #存储每一张图片预测的分类结果
print '@_@ have extracted ',j*50,' images '
# save file name
# read file to data
# index + 1
fileNameNum[i]=float(f[0:12])
net.blobs['data'].data[i,:,:,:] = transformer.preprocess('data', caffe.io.load_image(eval_image_dir + f))
i=i+1
# for the rest images less than 50
# here i equals the rest images
print '@_@ extracted the rest',i,' images '
out = net.forward()
fc7Data = net.blobs['fc7'].data
probData=(net.blobs['prob'].data)
predict=np.argmax(probData,axis=1).reshape(50,-1)
for k in range(0,i):
classnum=predict[k][0]
feature=fc7Data[k].reshape(1,-1)
tempData=feature.tobytes()
tempDb.Put(str(fileNameNum[k][0]),tempData)
tempDataStr=str(feature)
tempDbStr.Put(str(fileNameNum[k][0]),tempDataStr)
fileHandle.write(str(fileNameNum[k][0])+'.jpg '+str(classnum)+'\n')
#print 'save feature of image : ',int(fileNameNum[k][0]),'.jpg'
# at the end,close the file
fileHandle.close()
print 'sum of classCnt is : ',sum(sum(classCnt))
print 'classnumMax is : ',classnumMax
print '@_@ extracted ',j*50+i,' images '
print '.Done'
######################################################################
说明:我们的batchsize是50,所以caffe每次处理50张图片;对于最后输入的几张没有被50整除的图片,我们单独做了处理;所以上面的存储特征的代码才有两个部分是雷同的
6 运行得到结果
说明:运行后会不断提取特征,并输出相应的信息;在工程目录下面会有feature文件夹出现,里面有leveldb格式的特征数据;
读者可使用leveldb的get函数,读取指定图片名称的特征值,fc7层的特征是4096维的;