图像处理中的caffe

2019-11-19 16:30:01 niaolianjiulin 阅读数 254

caffe读取图像

使用caffe.io.Transform类操作:

1、设定图片的shape格式为网络data层格式
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
2、改变维度顺序,由原始图片维度(h, w, c)变为(c, h, w)
transformer.set_transpose('data', (2,0,1)) 
3、减去图像均值,注意要先将binaryproto格式均值文件转换为npy格式
transformer.set_mean('data', np.load(mean_file_path).mean(1).mean(1))
或者通道均值
transformer.set_mean('data', [b_v, g_v, r_v] )
4、缩放到[0,255]之间
transformer.set_raw_scale('data', 255)
5、交换通道,将C通道由RGB变为BGR
transformer.set_channel_swap('data', (2,1,0))
6、加载图片
im=caffe.io.load_image(img)
7、执行上面设置的图片预处理操作,并将图片载入到blob中
net.blobs['data'].data[...] = transformer.preprocess('data', im)

opencv读图

1、上述采用caffe.io.load_image读图,数据格式是RGB,数值范围0~1,因此会有4、5步的操作。
当采用opencv读图时,有2个区别:
(1)数据格式是BGR
(2)数值范围0~255

2、
利用imread函数读图时,shape格式为:H W C
利用resize函数缩放时,注意shape设为:W H

3、注意区分2个变换:
(1)transformer.set_transpose(‘data’, (2,0,1)) 这个是将HWC->CHW,不管是caffe.io读图,还是opencv读图,这步操作都是需要的。
(2)transformer.set_channel_swap(‘data’, (2,1,0))这个是将C通道的RGB->BGR。该操作只是在caffe.io读图时需要做下。opencv读图时本身就已经是BGR了。

2018-01-05 15:31:36 oJiMoDeYe12345 阅读数 3216

Caffe2 - 图像加载与预处理

举例说明从图像文件或图像 url 加载图像,以及相应的 Caffe2 用到的必要的图像预处理.

必要的 python 包:

sudo pip install scikit-image scipy matplotlib
import skimage
import skimage.io as io
import skimage.transform 
import sys
import numpy as np
import math
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
print("Required modules imported.")

1. Image Load

Caffe 使用的是 OpenCV 的 Blue-Green-Red (BGR),而不是通用的 Red-Green-Blue (RGB).

Caffe2 也使用 BGR.

IMAGE_File = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1515142841038&di=56e548070fdf3ed09c1dc95a0ee2204f&imgtype=0&src=http%3A%2F%2Fimg6.ph.126.net%2FEfFAh8rDic7haOAZAQ83ag%3D%3D%2F2497527468371353486.jpg'
img = skimage.img_as_float(skimage.io.imread(IMAGE_File)).astype(np.float32)

# show the original image
plt.figure()
plt.subplot(1,2,1)
plt.imshow(img)
plt.axis('on')
plt.title('Original image = RGB')

# show the image in BGR - just doing RGB->BGR temporarily for display
imgBGR = img[:, :, (2, 1, 0)]
#plt.figure()
plt.subplot(1,2,2)
plt.imshow(imgBGR)
plt.axis('on')
plt.title('OpenCV, Caffe2 = BGR')
plt.show()

这里写图片描述

Caffe 的 CHW 是指:

  • H: Height
  • W: Width
  • C: Channel (as in color)

GPU 采用 CHW;而 CPU 往往是 HWC.

cuDNN 使用来对 GPUs 加速计算的工具,只支持 CHW.

因此,采用 CHW 的原因在于其速度更快.


2. Image Mirror 和 Rotate

# Flip, Mirror
imgMirror = np.fliplr(img)
plt.figure()
plt.subplot(1,2,1)
plt.imshow(imgMirror)
plt.axis('off')
plt.title('Mirror image')

# Rotate
imgRotated = np.rot90(img)
plt.subplot(1,2,2)
plt.imshow(imgRotated)
plt.axis('off')
plt.title('Rotated image')
plt.show()

这里写图片描述


3. Image Resize

resize 是图像预处理很重要的一部分.

Caffe2 要求图片是方形(square)的,需要 resize 到标准的 height 和 width. 这里将图片 resize 为 256×256,然后 crop 出 224×224 的尺寸大小. 即为网络输入的图片 input_height 和 input_width.

input_height, input_width = 224, 224
print("Model's input shape is %dx%d") % (input_height, input_width)
img256 = skimage.transform.resize(img, (256, 256))
plt.figure()
plt.imshow(img256)
plt.axis('on')
plt.title('Resized image to 256x256')
print("New image shape:" + str(img256.shape))
plt.figure()

Model’s input shape is 224x224
New image shape:(256, 256, 3)

这里写图片描述


4. Image Rescale

由于图片尺度因素,在 resize 和 crop 时需要考虑 rescaling.

比如,原始图片尺寸 1920×1080 ,crop 尺寸 224×224,如果不进行 rescaling,则 crop 出的部分可能丢失图片的重要信息及意义.

print("Original image shape:" + str(img.shape) + " and remember it should be in H, W, C!")
print("Model's input shape is %dx%d") % (input_height, input_width)
aspect = img.shape[1]/float(img.shape[0])
print("Orginal aspect ratio: " + str(aspect))
if(aspect>1):
    # 宽图片 - width 较大
    res = int(aspect * input_height)
    imgScaled = skimage.transform.resize(img, (input_height, res))
if(aspect<1):
    # 长图片 - height 较大
    res = int(input_width/aspect)
    imgScaled = skimage.transform.resize(img, (res, input_width))
if(aspect == 1):
    imgScaled = skimage.transform.resize(img, (input_height, input_width))
plt.figure()
plt.imshow(imgScaled)
plt.axis('on')
plt.title('Rescaled image')
print("New image shape:" + str(imgScaled.shape) + " in HWC")
plt.show()

Original image shape:(607, 910, 3) and remember it should be in H, W, C!
Model’s input shape is 224x224
Orginal aspect ratio: 1.49917627677
New image shape:(224, 335, 3) in HWC

这里写图片描述


5. Image Crop

# Center crop on the original
print("Original image shape:" + str(img.shape) + " and remember it should be in H, W, C!")
def crop_center(img,cropx,cropy):
    y,x,c = img.shape
    startx = x//2-(cropx//2)
    starty = y//2-(cropy//2)    
    return img[starty:starty+cropy,startx:startx+cropx]

plt.figure()
# Original image
imgCenter = crop_center(img,224,224)
plt.subplot(1,3,1)
plt.imshow(imgCenter)
plt.axis('on')
plt.title('Original')

# Now let's see what this does on the distorted image
img256Center = crop_center(img256,224,224)
plt.subplot(1,3,2)
plt.imshow(img256Center)
plt.axis('on')
plt.title('Squeezed')

# Scaled image
imgScaledCenter = crop_center(imgScaled,224,224)
plt.subplot(1,3,3)
plt.imshow(imgScaledCenter)
plt.axis('on')
plt.title('Scaled')
plt.show()

这里写图片描述


6. Image Upscale

将小 square 的图片转换为较大的尺寸.

imgSmall128 = skimage.transform.resize(img, (128, 128))
print "Assume original image shape: ", imgSmall128.shape
imgBig224 = skimage.transform.resize(imgSmall128, (224, 224))
print "Upscaled image shape: ", imgBig224.shape
# Plot original
plt.figure()
plt.subplot(1, 2, 1)
plt.imshow(imgSmall128)
plt.axis('on')
plt.title('128x128')
# Plot upscaled
plt.subplot(1, 2, 2)
plt.imshow(imgBig224)
plt.axis('on')
plt.title('224x224')
plt.show()

Assume original image shape: (128, 128, 3)
Upscaled image shape: (224, 224, 3)

这里写图片描述

图片有一定的模糊.

imgSmallSlice = crop_center(imgSmall128, 128, 56)
# Plot original
plt.figure()
plt.subplot(1, 3, 1)
plt.imshow(imgSmall128)
plt.axis('on')
plt.title('Original')
# Plot slice
plt.subplot(1, 3, 2)
plt.imshow(imgSmallSlice)
plt.axis('on')
plt.title('128x56')
# Upscale?
print "Slice image shape: ", imgSmallSlice.shape
imgBigg224 = skimage.transform.resize(imgSmallSlice, (224, 224))
print "Upscaled slice image shape: ", imgBigg224.shape
# Plot upscaled
plt.subplot(1, 3, 3)
plt.imshow(imgBigg224)
plt.axis('on')
plt.title('224x224')
plt.show()

这里写图片描述

7. Image Preprocessing

imgCropped = crop_center(imgScaled,224,224)
print "Image shape before HWC --> CHW conversion: ", imgCropped.shape
# HWC -> CHW 
imgCropped = imgCropped.swapaxes(1, 2).swapaxes(0, 1)
print "Image shape after HWC --> CHW conversion: ", imgCropped.shape

plt.figure()
for i in range(3):
    plt.subplot(1, 3, i+1)
    plt.imshow(imgCropped[i])
    plt.axis('off')
    plt.title('RGB channel %d' % (i+1))

# RGB -> BGR
imgCropped = imgCropped[(2, 1, 0), :, :]
print "Image shape after BGR conversion: ", imgCropped.shape

# Subtract the mean image
# skimage loads image in the [0, 1] range so we multiply the pixel values first to get them into [0, 255].
# mean_file = os.path.join(CAFFE_ROOT, 'python/caffe/imagenet/ilsvrc_2012_mean.npy')
# mean = np.load(mean_file).mean(1).mean(1)
# img = img * 255 - mean[:, np.newaxis, np.newaxis]

plt.figure()
for i in range(3):
    plt.subplot(1, 3, i+1)
    plt.imshow(imgCropped[i])
    plt.axis('off')
    plt.title('BGR channel %d' % (i+1))
# Batch 
# Feed in multiple images
# Make sure image is of type np.float32
imgCropped = imgCropped[np.newaxis, :, :, :].astype(np.float32)
print 'Final input shape is:', imgCropped.shape
plt.show()

这里写图片描述
这里写图片描述

2014-10-14 22:16:59 deeplearninglc007 阅读数 38818

step 1.      首先,确保caffe已经正确安装,并且make runtest基本通过。

 

step 2.      准备训练集:

        在训练之前,要准备训练需要的训练集,为了验证训练的效果,最好也准备一定数量的测试集。由于caffe的数据集的输入是leveldb格式,因此在训练前需要将输入转为相应格式。

        在caffe_root/example 文件夹中,提供了一些例子,cifar10与imagenet均是将图片形式数据库转换为leveldb格式,mnist则是将其本身的数据集转换为leveldb格式。这就要求我们需要把自己的数据集转换成leveldb格式,需要自己编写程序实现。下面以jpg格式图片为例说明。

在此,假设数据库本身是以图片形式给出,并且给出了label或者同一类别的图片已经分类。这样我们就可以通过imagenet例子中给出的create_imagenet.sh 对我们自己的数据库进行转换,要求数据集图片格式为jpg以下为具体操作步骤:

        A.若数据集已经给出label则忽略此步骤。图片按照类别装在不同文件夹下的情况,自己编写mklabel.sh命令,对图片进行处理并标明label。具体操作参照mklabel.sh 程序说明。

<pre name="code" class="plain">mklabel.sh
#!/bin/sh

#----------------------------------------------------
#文件存放形式为
#	dir/subdir1/files...
#	dir/subdir2/files...
#	dir/subdir3/files...
#	dir/subdirX/files...

#用法:
#1.$ sh mklabel.sh dir startlabel ;dir 为目标文件夹名称
#2.$ chmod a+x mklabel.sh ;然后可以直接用文件名运行
#3.默认label信息显示在终端,请使用转向符'>'生成文本,例:
#		$ sh ./mklabel.sh  data/faces94/male  > label.txt
#4.确保文件夹下除了图片不含其他文件(若含有则需自行添加判断语句)
#-----------------------------------------------------

DIR=~/codes/mklabel.sh		#命令位置(无用)
label=1					#label起始编号(为数字,根据自己需要修改)
testnum=0				#保留的测试集大小

if test $# -eq 0;then	#无参数,默认为当前文件夹下,label=1
	$DIR . 0 $label
else
	if test $# -eq 1;then	#仅有位置参数,默认testnum=0,label=1
		$DIR $1 0 $label
	else
		if test $# -eq 2;then	#两个参数时,label=1
			$DIR $1 $2 $label
		else
			testnum=$2			#每个类别保留测试集大小
			label=$3			#自定义label起始
			
			cd $1				#转到目标文件夹
		
			if test $testnum -ne 0;then
				mkdir "testdata"	#建立测试集
			fi
		
			for i in * ; do
				exist=`expr "$i" != "testdata"`
				if test -d $i && test $exist -eq 1;then	#文件夹存在
					#echo 
					#echo 'DIR:' $i
				
					cd $i			#进入文件夹
						num=1		#图片数目
						for j in *
						do
							if test $num -gt $testnum;then
								echo  $j  $label
								mv $j ../
							fi
							num=`expr $num + 1`
						done
					cd ..			#回到上层目录
				
					if test $testnum -eq 0;then
						rmdir $i
					else
						mv $i ./testdata
					fi
				
					label=`expr $label + 1`
									#计算label
				fi	
			done
		fi
	fi
fi


        B.修改create_imagenet.sh 文件,使其中的图片源地址与标明label的txt文件对应到自己数据库的相应文件。其中的convert_imageset.cpp 函数的参数依次为图片文件夹位置,label.txt文本文件,目标数据集名称,是否随机存储图片与label(即打乱图片数据的读入顺序)。

若你所使用的数据集不是通过图片形式给出,为了方便,可以根据leveldb数据的存储格式,自己编写程序转换数据集。

 

        C.多通道图片需要用到meanfile,通过example/imagenet文件夹下的shell函数make_imagenet_mean.sh,更改相应函数,很轻松的得到binaryproto文件,在训练时可能需要用到。

step 3.      使用自己的数据进行训练:

        以最简单的mnist网络为例,因为数据集的不同则需要更改的参数也不同。在训练前最好在example下新建个文件夹命名为数据集的名称,然后把mnist下的5个文件:

        lenet.prototxt

        lenet_solver.prototxt

        lenet_train.prototxt

        lenet_test.prototxt

        train_lenet.sh

      复制到新文件夹下,以上5个文件为必需的文件。按顺序对以上文件进行修改,在忽略网络结构的情况下,需要修改的有:

        a.      lenet.prototxt:

input_dim: 64
input_dim: 1
input_dim: 28
input_dim: 28

        分别为一次导入的图片个数,channel,heigth ,width。

                      倒数第二层,即输入给softmax层数据的那层,其中的num_output需要更改为实际图片的label数,即图片类别数。否则在进行训练时,会出现错误。

                                   

 

        b.      lenet_solver.prototxt:

       如果之前文件名没改的话则不需要更改以上两项,否则改为对应文件。其他参数根据实际需要更改。

       

        c.      lenet_train.prototxt:

        需要把data层的数据源文件替换为自己的数据。

              

        在训练多通道图片时,此处最好需要有一个meanfile参数。例如cifar10

       

       num_output参数参照lenet.prototxt修改。

 

        d.      lenet_test.prototxt:

        参照lenet_train.prototxt 进行相应修改。

 

        e.      train_lenet.sh:

         lenet_solver.prototxt文件名未更改的话则不需要进行改动。

  

step 4.      使用自己的model进行分类:

        Reference: http://nbviewer.ipython.org/github/BVLC/caffe/blob/master/examples/classification.ipynb

         假设之前的所有步骤已经成功,并且已经训练出正确率还行的model,则现在就可以使用model对图片进行分类。

        a.      首先确保已经正确安装了pythonwrapper,以及caffe_root/python/文件夹下requirements.txt文件中所需要的组件。

        b.      另外,还需要meanfile的npy文件。即需要把数据对应的binaryproto文件转换到npy文件。Caffe_root/python/caffe/io.cpp文件中已经给了对应的API。

   


        具体参照:https://github.com/BVLC/caffe/issues/420

        需要对blobproto_to_array 进行修改,得到blobproto_to_array2.

        


        即删去了blob.num 项。

        通过调用此API进行处理,具体python函数如下:

        convert_bproto_to_npy.py

#!/usr/bin/python

import numpy as np
from caffe.io import blobproto_to_array2
from caffe.proto import caffe_pb2

blob = caffe_pb2.BlobProto()

filename = './imagenet_mean.binaryproto'

data = open(filename, "rb").read() 
blob.ParseFromString(data) 

nparray =blobproto_to_array2(blob) 
f = file("mean.npy","wb") 
np.save(f,nparray) 
f.close()

        c.      按照demo步骤进行分类:

        代码的主要部分参照

        classify.py

        classifymap.py

        输出部分的说明

        1)     Classify.py

        输出的是prediction[0],一维数组,以imagenet为例就是大小为1000的数组,每个值对应概率大小。

 

        处理部分代码:

preDict = {}
for i in xrange(len(prediction[0])):
	preDict[prediction[0][i]] = i
for i in xrange(5):
	val = sorted(preDict.keys())[-i -1]
	print("%d %f %s" %(preDict[val], val * 100, linecache.getline(SYNSET, preDict[val])))

        把数组的值和索引对应到字典中,值作为键,把数组值进行排序,再用前五个作为键,找出索引值,也就是对应的类别。

为了能够直观地显示数字所代表的类别名,需要输出synset_words.txt文件中对应行数的内容。这里用的是linecache.getline()函数,需要

        import caffe

        为了修改方便,把synset_words.txt的路径设为变量

        SYNSET = '../../data/ilsvrc12/synset_words.txt'

        

        (序号概率值(百分比)对应种类)

 

 

 

 

        2)     Classifymap.py

        输出的是

                     outMat =out['prob'][0].argmax(axis=0)

是一个二维矩阵,8*8大小,每个值对应的都是一种类别,出现的越多代表概率越高。

 


        处理部分代码:

h1, w1 = np.shape(outMat)
outList = list(np.reshape(outMat,h1 * w1))
#print(outList)
 
outSet = set(outList)
outdict = {}
for x in outSet:
  outdict[outList.count(x)]=x
 
appear = outdict.keys()
applen = len(appear)
if len <= 5:
    for i in xrange(applen):
        print('%d %d: %s'%(outdict[appear[-(i+1)]], appear[-(i+1)],linecache.getline(SYNSET,outdict[appear[-(i+1)]])))   
else:
    for i in xrange(5):
        print('%d %d: %s'%(outdict[appear[-(i+1)]], appear[-(i+1)], linecache.getline(SYNSET,outdict[appear[-(i+1)]])))   


        和上面的文件大致思路相同。但是需要先把矩阵展开成一维列表,用set()变成集合,也就是去掉重复元素,再一一对应到字典中,然后通过count()找到每个值在矩阵中出现的次数,进行排序即可。

        (序号出现次数对应种类)

        3)  源代码:

        Classiy.py

import numpy as np
import matplotlib.pyplot as plt
import pylab

import caffe

caffe_root = '../'

MODEL_FILE = '../imagenet/imagenet_deploy.prototxt'
PRETRAINED = '../imagenet/caffe_reference_imagenet_model'
IMAGE_FILE = '../images/cat.jpg'

#net = caffe.Classifier(MODEL_FILE, PRETRAINED, mean_file = caffe_root + '../python/caffe/imagenet/ilsvrc_2012_mean.npy', channel_swap = (2,1,0), input_scale = 255)

net = caffe.Classifier(MODEL_FILE, PRETRAINED, mean_file = caffe_root + 'mean2.npy', channel_swap = (2,1,0), input_scale = 255)

net.set_phase_test()
net.set_mode_gpu()

input_image = caffe.io.load_image(IMAGE_FILE)
pylab.ion()
plt.imshow(input_image)
#pylab.show()


prediction = net.predict([input_image])
print 'prediction shape:', prediction[0].shape
#print(prediction[0])
plt.plot(prediction[0])
#pylab.show()
preDict = {}
preList = list(prediction[0])
for i in preList:
    preDict[preList[i]] = i
preLen = len(preList)
for i in xrange(5):
print('%d %d: %s' %(preDict[preDict.keys[-(i+1)]], preDict.values[-(i+1)], linecache.getline(SYNSET,preDict.values[-(i+1)])))	

classifymap.py
import caffe
import matplotlib.pyplot as plt
import pylab
import numpy as np
import linecache

IMAGE_FILE ='../images/dog.jpg'
SYNSET = '../../data/ilsvrc12/synset_words.txt'
# Load the original network and extract the fully-connected layers' parameters.

net = caffe.Net('../imagenet/imagenet_deploy.prototxt', '../imagenet/caffe_reference_imagenet_model')

params = ['fc6', 'fc7', 'fc8']

# fc_params = {name: (weights, biases)}

fc_params = {pr: (net.params[pr][0].data, net.params[pr][1].data) for pr in params}



#for fc in params:

    #print '{} weights are {} dimensional and biases are {} dimensional'.format(fc, fc_params[fc][0].shape, fc_params[fc][1].shape)

# Load the fully-convolutional network to transplant the parameters.

net_full_conv = caffe.Net('../imagenet/imagenet_full_conv.prototxt', '../imagenet/caffe_reference_imagenet_model')

params_full_conv = ['fc6-conv', 'fc7-conv', 'fc8-conv']

# conv_params = {name: (weights, biases)}

conv_params = {pr: (net_full_conv.params[pr][0].data, net_full_conv.params[pr][1].data) for pr in params_full_conv}



#for conv in params_full_conv:

    #print '{} weights are {} dimensional and biases are {} dimensional'.format(conv, conv_params[conv][0].shape, conv_params[conv][1].shape)

for pr, pr_conv in zip(params, params_full_conv):

    conv_params[pr_conv][1][...] = fc_params[pr][1]
for pr, pr_conv in zip(params, params_full_conv):

    out, in_, h, w = conv_params[pr_conv][0].shape

    W = fc_params[pr][0].reshape((out, in_, h, w))

    conv_params[pr_conv][0][...] = W

# net_full_conv.save('../imagenet/caffe_imagenet_full_conv')
# load input and configure preprocessing

im = caffe.io.load_image(IMAGE_FILE)

plt.imshow(im)
#pylab.show()

net_full_conv.set_mean('data', '../../python/caffe/imagenet/ilsvrc_2012_mean.npy')

net_full_conv.set_channel_swap('data', (2,1,0))

net_full_conv.set_input_scale('data', 255.0)

# make classification map by forward pass and show top prediction index per location

out = net_full_conv.forward_all(data=np.asarray([net_full_conv.preprocess('data', im)]))

outMat = out['prob'][0].argmax(axis=0)

h1, w1 = np.shape(outMat)
outList = list(np.reshape(outMat,h1 * w1))
#print(outList)

outSet = set(outList)
outdict = {}
for x in outSet:
	outdict[outList.count(x)]=x

appear = outdict.keys()
applen = len(appear)
if len <= 5:
    for i in xrange(applen):
        print('%d %d: %s' %(outdict[appear[-(i+1)]], appear[-(i+1)], linecache.getline(SYNSET,outdict[appear[-(i+1)]])))	
else:
    for i in xrange(5):
        print('%d %d: %s' %(outdict[appear[-(i+1)]], appear[-(i+1)], linecache.getline(SYNSET,outdict[appear[-(i+1)]])))	





在训练之前,要准备训练需要的训练集,为了验证训练的效果,最好也准备一定数量的测试集。由于caffe的数据集的输入是leveldb格式,因此在训练前需要将输入转为相应格式。

在caffe_root/example 文件夹中,提供了一些例子,cifar10与imagenet均是将图片形式数据库转换为leveldb格式,mnist则是将其本身的数据集转换为leveldb格式。这就要求我们需要把自己的数据集转换成leveldb格式,需要自己编写程序实现。下面以jpg格式图片为例说明。

在此,假设数据库本身是以图片形式给出,并且给出了label或者同一类别的图片已经分类。这样我们就可以通过imagenet例子中给出的create_imagenet.sh 对我们自己的数据库进行转换,要求数据集图片格式为jpg以下为具体操作步骤:

A.若数据集已经给出label则忽略此步骤。图片按照类别装在不同文件夹下的情况,自己编写mklabel.sh命令,对图片进行处理并标明label。具体操作参照mklabel.sh 程序说明。

<pre name="code" class="plain">mklabel.sh
#!/bin/sh

#----------------------------------------------------
#文件存放形式为
#	dir/subdir1/files...
#	dir/subdir2/files...
#	dir/subdir3/files...
#	dir/subdirX/files...

#用法:
#1.$ sh mklabel.sh dir startlabel ;dir 为目标文件夹名称
#2.$ chmod a+x mklabel.sh ;然后可以直接用文件名运行
#3.默认label信息显示在终端,请使用转向符'>'生成文本,例:
#		$ sh ./mklabel.sh  data/faces94/male  > label.txt
#4.确保文件夹下除了图片不含其他文件(若含有则需自行添加判断语句)
#-----------------------------------------------------

DIR=~/codes/mklabel.sh		#命令位置(无用)
label=1					#label起始编号(为数字,根据自己需要修改)
testnum=0				#保留的测试集大小

if test $# -eq 0;then	#无参数,默认为当前文件夹下,label=1
	$DIR . 0 $label
else
	if test $# -eq 1;then	#仅有位置参数,默认testnum=0,label=1
		$DIR $1 0 $label
	else
		if test $# -eq 2;then	#两个参数时,label=1
			$DIR $1 $2 $label
		else
			testnum=$2			#每个类别保留测试集大小
			label=$3			#自定义label起始
			
			cd $1				#转到目标文件夹
		
			if test $testnum -ne 0;then
				mkdir "testdata"	#建立测试集
			fi
		
			for i in * ; do
				exist=`expr "$i" != "testdata"`
				if test -d $i && test $exist -eq 1;then	#文件夹存在
					#echo 
					#echo 'DIR:' $i
				
					cd $i			#进入文件夹
						num=1		#图片数目
						for j in *
						do
							if test $num -gt $testnum;then
								echo  $j  $label
								mv $j ../
							fi
							num=`expr $num + 1`
						done
					cd ..			#回到上层目录
				
					if test $testnum -eq 0;then
						rmdir $i
					else
						mv $i ./testdata
					fi
				
					label=`expr $label + 1`
									#计算label
				fi	
			done
		fi
	fi
fi


B.修改create_imagenet.sh 文件,使其中的图片源地址与标明label的txt文件对应到自己数据库的相应文件。其中的convert_imageset.cpp 函数的参数依次为图片文件夹位置,label.txt文本文件,目标数据集名称,是否随机存储图片与label(即打乱图片数据的读入顺序)。

若你所使用的数据集不是通过图片形式给出,为了方便,可以根据leveldb数据的存储格式,自己编写程序转换数据集。

 

C.多通道图片需要用到meanfile,通过example/imagenet文件夹下的shell函数make_imagenet_mean.sh,更改相应函数,很轻松的得到binaryproto文件,在训练时可能需要用到。

step 3.      使用自己的数据进行训练:

以最简单的mnist网络为例,因为数据集的不同则需要更改的参数也不同。在训练前最好在example下新建个文件夹命名为数据集的名称,然后把mnist下的5个文件:

        lenet.prototxt

        lenet_solver.prototxt

        lenet_train.prototxt

        lenet_test.prototxt

        train_lenet.sh

      复制到新文件夹下,以上5个文件为必需的文件。按顺序对以上文件进行修改,在忽略网络结构的情况下,需要修改的有:

a.      lenet.prototxt:

input_dim: 64
input_dim: 1
input_dim: 28
input_dim: 28

分别为一次导入的图片个数,channel,heigth ,width。

                      倒数第二层,即输入给softmax层数据的那层,其中的num_output需要更改为实际图片的label数,即图片类别数。否则在进行训练时,会出现错误。

                                   

 

b.      lenet_solver.prototxt:

       如果之前文件名没改的话则不需要更改以上两项,否则改为对应文件。其他参数根据实际需要更改。

       

c.      lenet_train.prototxt:

        需要把data层的数据源文件替换为自己的数据。

              

        在训练多通道图片时,此处最好需要有一个meanfile参数。例如cifar10

       

       num_output参数参照lenet.prototxt修改。

 

d.      lenet_test.prototxt:

        参照lenet_train.prototxt 进行相应修改。

 

e.      train_lenet.sh:

         lenet_solver.prototxt文件名未更改的话则不需要进行改动。

  

step 4.      使用自己的model进行分类:

        Reference: http://nbviewer.ipython.org/github/BVLC/caffe/blob/master/examples/classification.ipynb

         假设之前的所有步骤已经成功,并且已经训练出正确率还行的model,则现在就可以使用model对图片进行分类。

        a.      首先确保已经正确安装了pythonwrapper,以及caffe_root/python/文件夹下requirements.txt文件中所需要的组件。

        b.      另外,还需要meanfile的npy文件。即需要把数据对应的binaryproto文件转换到npy文件。Caffe_root/python/caffe/io.cpp文件中已经给了对应的API。

   


        具体参照:https://github.com/BVLC/caffe/issues/420

        需要对blobproto_to_array 进行修改,得到blobproto_to_array2.

        


        即删去了blob.num 项。

        通过调用此API进行处理,具体python函数如下:

        convert_bproto_to_npy.py

#!/usr/bin/python

import numpy as np
from caffe.io import blobproto_to_array2
from caffe.proto import caffe_pb2

blob = caffe_pb2.BlobProto()

filename = './imagenet_mean.binaryproto'

data = open(filename, "rb").read() 
blob.ParseFromString(data) 

nparray =blobproto_to_array2(blob) 
f = file("mean.npy","wb") 
np.save(f,nparray) 
f.close()

        c.      按照demo步骤进行分类:

        代码的主要部分参照

        classify.py

        classifymap.py

        输出部分的说明

        1)     Classify.py

        输出的是prediction[0],一维数组,以imagenet为例就是大小为1000的数组,每个值对应概率大小。

 

        处理部分代码:

preDict = {}
for i in xrange(len(prediction[0])):
	preDict[prediction[0][i]] = i
for i in xrange(5):
	val = sorted(preDict.keys())[-i -1]
	print("%d %f %s" %(preDict[val], val * 100, linecache.getline(SYNSET, preDict[val])))

        把数组的值和索引对应到字典中,值作为键,把数组值进行排序,再用前五个作为键,找出索引值,也就是对应的类别。

为了能够直观地显示数字所代表的类别名,需要输出synset_words.txt文件中对应行数的内容。这里用的是linecache.getline()函数,需要

        import caffe

        为了修改方便,把synset_words.txt的路径设为变量

        SYNSET = '../../data/ilsvrc12/synset_words.txt'

        

        (序号概率值(百分比)对应种类)

 

 

 

 

        2)     Classifymap.py

        输出的是

                     outMat =out['prob'][0].argmax(axis=0)

是一个二维矩阵,8*8大小,每个值对应的都是一种类别,出现的越多代表概率越高。

 


        处理部分代码:

h1, w1 = np.shape(outMat)
outList = list(np.reshape(outMat,h1 * w1))
#print(outList)
 
outSet = set(outList)
outdict = {}
for x in outSet:
  outdict[outList.count(x)]=x
 
appear = outdict.keys()
applen = len(appear)
if len <= 5:
    for i in xrange(applen):
        print('%d %d: %s'%(outdict[appear[-(i+1)]], appear[-(i+1)],linecache.getline(SYNSET,outdict[appear[-(i+1)]])))   
else:
    for i in xrange(5):
        print('%d %d: %s'%(outdict[appear[-(i+1)]], appear[-(i+1)], linecache.getline(SYNSET,outdict[appear[-(i+1)]])))   


        和上面的文件大致思路相同。但是需要先把矩阵展开成一维列表,用set()变成集合,也就是去掉重复元素,再一一对应到字典中,然后通过count()找到每个值在矩阵中出现的次数,进行排序即可。

(序号出现次数对应种类)

3)  源代码:

Classiy.py

import numpy as np
import matplotlib.pyplot as plt
import pylab

import caffe

caffe_root = '../'

MODEL_FILE = '../imagenet/imagenet_deploy.prototxt'
PRETRAINED = '../imagenet/caffe_reference_imagenet_model'
IMAGE_FILE = '../images/cat.jpg'

#net = caffe.Classifier(MODEL_FILE, PRETRAINED, mean_file = caffe_root + '../python/caffe/imagenet/ilsvrc_2012_mean.npy', channel_swap = (2,1,0), input_scale = 255)

net = caffe.Classifier(MODEL_FILE, PRETRAINED, mean_file = caffe_root + 'mean2.npy', channel_swap = (2,1,0), input_scale = 255)

net.set_phase_test()
net.set_mode_gpu()

input_image = caffe.io.load_image(IMAGE_FILE)
pylab.ion()
plt.imshow(input_image)
#pylab.show()


prediction = net.predict([input_image])
print 'prediction shape:', prediction[0].shape
#print(prediction[0])
plt.plot(prediction[0])
#pylab.show()
preDict = {}
preList = list(prediction[0])
for i in preList:
    preDict[preList[i]] = i
preLen = len(preList)
for i in xrange(5):
print('%d %d: %s' %(preDict[preDict.keys[-(i+1)]], preDict.values[-(i+1)], linecache.getline(SYNSET,preDict.values[-(i+1)])))	

classifymap.py
import caffe
import matplotlib.pyplot as plt
import pylab
import numpy as np
import linecache

IMAGE_FILE ='../images/dog.jpg'
SYNSET = '../../data/ilsvrc12/synset_words.txt'
# Load the original network and extract the fully-connected layers' parameters.

net = caffe.Net('../imagenet/imagenet_deploy.prototxt', '../imagenet/caffe_reference_imagenet_model')

params = ['fc6', 'fc7', 'fc8']

# fc_params = {name: (weights, biases)}

fc_params = {pr: (net.params[pr][0].data, net.params[pr][1].data) for pr in params}



#for fc in params:

    #print '{} weights are {} dimensional and biases are {} dimensional'.format(fc, fc_params[fc][0].shape, fc_params[fc][1].shape)

# Load the fully-convolutional network to transplant the parameters.

net_full_conv = caffe.Net('../imagenet/imagenet_full_conv.prototxt', '../imagenet/caffe_reference_imagenet_model')

params_full_conv = ['fc6-conv', 'fc7-conv', 'fc8-conv']

# conv_params = {name: (weights, biases)}

conv_params = {pr: (net_full_conv.params[pr][0].data, net_full_conv.params[pr][1].data) for pr in params_full_conv}



#for conv in params_full_conv:

    #print '{} weights are {} dimensional and biases are {} dimensional'.format(conv, conv_params[conv][0].shape, conv_params[conv][1].shape)

for pr, pr_conv in zip(params, params_full_conv):

    conv_params[pr_conv][1][...] = fc_params[pr][1]
for pr, pr_conv in zip(params, params_full_conv):

    out, in_, h, w = conv_params[pr_conv][0].shape

    W = fc_params[pr][0].reshape((out, in_, h, w))

    conv_params[pr_conv][0][...] = W

# net_full_conv.save('../imagenet/caffe_imagenet_full_conv')
# load input and configure preprocessing

im = caffe.io.load_image(IMAGE_FILE)

plt.imshow(im)
#pylab.show()

net_full_conv.set_mean('data', '../../python/caffe/imagenet/ilsvrc_2012_mean.npy')

net_full_conv.set_channel_swap('data', (2,1,0))

net_full_conv.set_input_scale('data', 255.0)

# make classification map by forward pass and show top prediction index per location

out = net_full_conv.forward_all(data=np.asarray([net_full_conv.preprocess('data', im)]))

outMat = out['prob'][0].argmax(axis=0)

h1, w1 = np.shape(outMat)
outList = list(np.reshape(outMat,h1 * w1))
#print(outList)

outSet = set(outList)
outdict = {}
for x in outSet:
	outdict[outList.count(x)]=x

appear = outdict.keys()
applen = len(appear)
if len <= 5:
    for i in xrange(applen):
        print('%d %d: %s' %(outdict[appear[-(i+1)]], appear[-(i+1)], linecache.getline(SYNSET,outdict[appear[-(i+1)]])))	
else:
    for i in xrange(5):
        print('%d %d: %s' %(outdict[appear[-(i+1)]], appear[-(i+1)], linecache.getline(SYNSET,outdict[appear[-(i+1)]])))	






2017-01-14 17:19:29 Xiongchao99 阅读数 712

以下均以caffe根目录和mnist例子为准(前提是mnist图片已下载且train/test.txt已生成,若未完成,请参考从以下文章:http://www.cnblogs.com/denny402/p/5083300.html):

(1)使用caffe自带的convert_imageset可执行文件将图片格式转化为lmdb格式(自带的下载文件已经转化好了,这里是指将自己的训练图片转化格式的方法)命令:

sudo ./build/tools/convert_imageset --shuffle=true /home/xxx/caffe/examples/mnist/ 
./examples/mnist/train/train.txt examples/mnist/train/train_lmdb


参数:可执行文件地址  参数组 图片数据地址  train.txt地址  格式转化数据的保存地址

(以上是train图片,test图片更改相应目录地址就可以)


(2)使用caffe自带compute_image_mean可执行文件生成mnist手写字的均值文件命令:

sudo ./build/tools/compute_image_mean examples/mnist/train/train_lmdb examples/mnist/mnist_mean.binaryproto

参数:可执行文件地址 转化格式后的训练数据地址 均值文件包保存地址


(3)使用caffe自带的caffe可执行文件生成mnist训练模型命令:

sudo ./build/tools/caffe train --solver=examples/mnist/solver.prototxt

参数:可执行文件地址 参数  配置文件地址



(4)使用caffe自带的mnist模型训练好后,使用该模型测试手写字识别精度的命令:

sudo ./build/tools/caffe test --model=examples/mnist/lenet_train_test.prototxt -weights=examples/mnist/lenet_iter_10000.caffemodel

参数:可执行文件地址 网络模型地址 训练模型地址


(5)使用caffe的CPP版本的calssification.bin对单张手写字进行分类命令:

sudo ./build/examples/cpp_classification/classification.bin \
examples/mnist/deploy.prototxt \
examples/mnist/lenet_iter_10000.caffemodel \
examples/mnist/mnist_mean.binaryproto \
examples/mnist/synset_words.txt \
examples/mnist/4.jpeg

(4.JPEG是自己的待测图片,复制到mnist/下即可)

注意:上述有两个文件未解释,分别是deploy.prototxt和synset_works.txt。


deploy.prototxt是根据我们训练模型时使用模型文件修改首尾部而来,我是用的训练模型文件是lenet_train_test.prototxt,可如下修改,

1)将原文件首部的如下两个数据层删除,然后添加自己的数据输入层:

layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/train/train_lmdb"
    batch_size: 64
    backend: LMDB
  }
}
layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/test/test_lmdb"
    batch_size: 100
    backend: LMDB
  }
}
添加(我的测试图片是3通道的,所以第二个dim是3):

layer {
  name: "data"
  type: "Input"
  top: "data"
  input_param { shape:{ dim: 1 dim: 3 dim: 28 dim: 28 } }
}

2)删除尾部的Accuracy和loss层,如下:

layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "ip2"
  bottom: "label"
  top: "accuracy"
  include {
    phase: TEST
  }
}
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "ip2"
  bottom: "label"
  top: "loss"
}

添加:

layer {
  name: "prob"
  type: "Softmax"
  bottom: "ip2"
  top: "prob"
}

synset_works.txt文件就是examples/mnist/test/labels.txt文件,内容为:

0
1
2
3
4
5
6
7
8
9

到此为止,测试单张图片的文件都准备完了,使用上述./build/examples/cpp_classification/classification.bin命令就可以进行测试。



2016-01-30 16:18:11 Quincuntial 阅读数 3074

首先要编译compute_image_mean.cpp文件,生成compute_image_mean.exe文件,具体生成方式类似于

http://blog.csdn.net/quincuntial/article/details/50611459中的生成Convert.exe文件。

在用上面连接生成lmdb文件后,写个批处理文件ComputImageMean.bat,内容为

ComputeImageMean.exe traindb mean.binaryproto
pause

运行后,会生成一个mean.binaryproto文件,里面就是图像的均值。