需要安装anaconda
目的
对100种狗进行识别,本文为简化,只对2种狗进行识别。
数据组织
有100种狗
E:\bd\train\train\train 下面是所有训练集图片
E:\bd\train\val\test1 下是所有验证集图片
E:\bd\train\data_train_image.txt 中存放训练图片–种类信息(以数字表示),格式为:
图片名 种类 url
E:\bd\train\val.txt 中存放验证图片–种类信息,格式与data_train_image.txt相同
将图片按其种类复制到对应文件夹下
将图片按期类别移动到E:\bd\train\train1下的子文件夹下
"""
加载txt文件,生成字典
每行数据格式: 图片名 类型ID 图片url
"""
def loadData(filePath):
pic = {}
filePath = unicode(filePath, "utf8")
f = open(filePath)
line = f.readline()
while line:
line = line.split(' ')
data.append(line[0])
label.append(line[1])
pic[line[0]] = line[1]
line = f.readline()
return pic
# 批量生成文件夹
def genDir(path):
base = unicode(path, "utf8")
i = 0
for j in range(140):
file_name = base + str(i)
os.mkdir(file_name)
i=i+1
"""
将filePath文件下的图片保存在newFilePath文件夹下的相应子文件夹中
pic 是字典,存放每个图片要移到的子文件夹名
"""
def moveImg(filePath, newFilePath, pic):
filePath = unicode(filePath, "utf8")
newFilePath = unicode(newFilePath, "utf8")
for root, dirs, files in os.walk(filePath):
for f in files:
if pic.has_key(f[:-4]):
fl = filePath + '/' + f
img = Image.open(fl)
img.save(newFilePath + '/' + pic[f[:-4]] + '/' + f)
调用后结果如下:
调整图片大小
为了节省内存,缩小图片,统一调整为64*64。
这里只挑选2个文件夹:23, 50,将这2个文件夹复制到E:\bd\train\train2下,调整后保存在E:\bd\train\train3下
#按照指定图像大小调整尺寸
def resize_image(image, height, width):
top, bottom, left, right = (0, 0, 0, 0)
#获取图像尺寸
h, w, _ = image.shape
#对于长宽不相等的图片,找到最长的一边
longest_edge = max(h, w)
#计算短边需要增加多上像素宽度使其与长边等长
if h < longest_edge:
dh = longest_edge - h
top = dh // 2
bottom = dh - top
elif w < longest_edge:
dw = longest_edge - w
left = dw // 2
right = dw - left
else:
pass
#RGB颜色
BLACK = [0, 0, 0]
#给图像增加边界,是图片长、宽等长,cv2.BORDER_CONSTANT指定边界颜色由value指定
constant = cv2.copyMakeBorder(image, top , bottom, left, right, cv2.BORDER_CONSTANT, value = BLACK)
#调整图像大小并返回
return cv2.resize(constant, (height, width))
def read_path(path_name, newpath):
for dir_item in os.listdir(path_name):
#从初始路径开始叠加,合并成可识别的操作路径
full_path = os.path.abspath(os.path.join(path_name, dir_item))
if os.path.isdir(full_path): #如果是文件夹,继续递归调用
read_path(full_path)
else: #文件
if dir_item.endswith('.jpg'):
image = cv2.imread(full_path)
image = resize_image(image, 64, 64)
cv2.imwrite(newpath + '/' + dir_item, image)
调用后结果如下:
训练模型
由于训练集和测试集的每类各约有100张图片,数量太少,所以采用扩展的数据集训练模型,准确率约为90%
# 搭建模型
def cnn(weights):
model = Sequential()
model.add(Convolution2D(32, 3, 3, input_shape=(64, 64, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten()) # this converts our 3D feature maps to 1D feature vectors
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
if weights:
model.load_weights(weights)
return model
# 训练模型
def train():
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1./255)
# this is a generator that will read pictures found in
# subfolers of 'E:/bd/train/train3', and indefinitely generate
# batches of augmented image data
train_generator = train_datagen.flow_from_directory(
'E:/bd/train/train3', # this is the target directory
target_size=(64, 64), # all images will be resized to 150x150
batch_size=32,
class_mode='binary') # since we use binary_crossentropy loss, we need binary labels
# this is a similar generator, for validation data
validation_generator = test_datagen.flow_from_directory(
'E:/bd/train/val3',
target_size=(64, 64),
batch_size=32,
class_mode='binary')
model.fit_generator(
train_generator,
samples_per_epoch=200, # 当模型处理的样本数达到200时,开始下一个epoch
nb_epoch=30, # epoch总数
validation_data=validation_generator,
nb_val_samples=80) # 每个epoch所采用的验证集数量
model.save_weights('first_try.h5') # always save your weights after training or during
部分结果:
Epoch 27/30
6/6 [==============================] - 13s - loss: 0.1839 - acc: 0.9255 - val_loss: 0.1789 - val_acc: 0.9233
Epoch 28/30
6/6 [==============================] - 14s - loss: 0.2680 - acc: 0.8775 - val_loss: 0.1809 - val_acc: 0.9386
Epoch 29/30
6/6 [==============================] - 14s - loss: 0.1724 - acc: 0.9323 - val_loss: 0.1819 - val_acc: 0.9398
Epoch 30/30
6/6 [==============================] - 14s - loss: 0.2165 - acc: 0.9027 - val_loss: 0.1394 - val_acc: 0.9422
预测
偷懒,采用训练集中的图片作一下预测,结果输出:
[[ 0.]]
是正确的
def predict():
model = cnn1('first_try.h5')
img_path = 'E:/bd/train/train3/23/25435079,1084908304.jpg'
img = image.load_img(img_path, target_size=(64, 64))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
preds = model.predict(x)
print preds
参考
人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型
使用Keras面向小数据集进行图像分类