说明:想获取输入到网络模型的图片数据形状
步骤:
①将png图像转换为jpg格式,4通道变为3通道(RGBA→RGB);
②将jpg格式图像灰度化,3通道变为单通道;
③读取图像
代码如下:
###Convert_jpg_ok.py
import tkinter.filedialog as filedialog
import os
from PIL import Image
folderPath = filedialog.askdirectory(title = "./trainset1/")#能改完png图片,但是不能替换,可自行摸索替换的代码
for root, dirs, files in os.walk(folderPath, topdown=False):
for name in files:
print('os.path.join(root,name)为:',os.path.join(root, name))
if os.path.splitext(os.path.join(root, name))[1].lower() == ".png":
outfile = os.path.splitext(os.path.join(root, name))[0] + ".jpg"
try:
im = Image.open(os.path.join(root, name))
r,g,b,a=im.split()
im=Image.merge("RGB",(r,g,b)) #若没有这两行,会错误。png图像有RGBA四个通道,而BMP、JPG图像只有RGB三个通道,所以PNG转BMP、JPG时候程序不知道A通道怎么办,就会产生错误。
print ("Generating jpeg for %s" % name)
im.save(outfile, "JPG", quality=100)
except Exception as e:
print (e)
# os.remove(os.path.splitext(os.path.join(root, name))[1].lower() == ".png") #删png图nok
结果:
###Convert_gray_ok.py
需要依次替换输入文件名和保存文件名
#Caroline 2020/10/16 21:50
#将普通图转为灰度图,RGBA→RGB变为三通道,灰度图片存入**G/0,1...4文件夹
from skimage import io,transform,color
import numpy as np
def convert_gray(f,**args):#图片处理与格式化的函数
rgb=io.imread(f) #读取图片
gray=color.rgb2gray(rgb) #将彩色图片转换为灰度图片
dst=transform.resize(gray,(64,64)) #调整大小,图像分辨率为64*64
return dst
datapath='./testset1/0' #图片所在的路径 0,1,2,3,4
str=datapath+'/*.jpg' #识别.jpg的图像
coll = io.ImageCollection(str,load_func=convert_gray)#批处理
for i in range(len(coll)):
io.imsave(r'./testsetG/0/'+np.str(i)+'.jpg',coll[i]) #保存图片在'./testsetG/0/'...1,2,3,4#!需要手动建立数据集
结果:
照此方法建立训练集、测试集后读取
###read_imgs_n&c_ok.py
# 2020.09.01 Caroline
#定义读取图像及标签的函数read_imgs
# 1 导入模块
from __future__ import print_function
import numpy as np
from scipy import misc
import imageio
import scipy
import matplotlib.pyplot as plt
import glob #用于获取文件夹和文件信息
import re # 主要用于字符串匹配
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.callbacks import ModelCheckpoint #保存检查点
# 准备数据
num_classes = 5 #类别
batch_size = 120 #批量大小
epochs = 120 #训练次数
# 2 定义导入数据的函数,读取图片及标注
def loadImages(imgpath):
img = imageio.imread(imgpath)#imgpath:所有匹配的文件路径列表
if img is None:
return None
img = img.astype('float32') # 转成浮点32位数据类型
img /= 255 # 将图片归一化,加速模型训练速度
#print(img[1].shape)
return img
# 对图片进行维度变换
def changeDim(img):
img = np.expand_dims(img,axis=2) # 灰度图像为2D--change3 →(223, 28, 28) (223, 11)
img = np.expand_dims(img,axis=0) # 灰度图像前加一批量通道
return img
# 准备图像数据
def loadDataset( imgpath, pathtype):
images = loadImages(imgpath[0]) # 一幅图片的变维方法
images = changeDim(images)
for single in imgpath[1:]: # 用for循环处理多幅图片变维
img = loadImages(single)
img = changeDim(img)
images =np.append(images,img, axis = 0)
# 准备标记
labels = [] # 标签是数列
pattern = re.compile(pathtype+r"\\(\d{1,2})") # 用正则表达式,读取子文件夹名称;
# 匹配一个数字的"\\d"可以写成r"\d"; {m,n} 匹配前一个字符出现m到n次
for single in imgpath:
label = pattern.findall(single) # 搜索字符串,以列表类型返回全部能匹配的子串
labels.append(int(label[0]))#图片文件的名称是1的话对应图片写入的标签也为1
return images, labels # 返回图片的列表,标签列表
print('----------- 准备训练数据------------\n')
imgfiles = './trainsetG/*/*.jpg' # 准备训练数据
imgpath = glob.glob(imgfiles)#返回所有匹配的文件路径列表
images, labels = loadDataset(imgpath,'./trainsetG')
#print(imgpath) print(images) print(labels)---check
labels = keras.utils.to_categorical(labels, num_classes) #对标记进行转化,输出符合keras标记的类型
print(labels[0])
print(images.shape, labels.shape)
最终获取结果:
----------- 准备训练数据------------
[1. 0. 0. 0. 0.]
(350, 64, 64, 1) (350, 5)
----------- 准备测试数据------------
(105, 64, 64, 1) (105, 5)
读取数据完成!
输入到网络训练
# 2020.09.01 Caroline
#定义读取图像及标签的函数read_imgs
# 1 导入模块
from __future__ import print_function
import numpy as np
from scipy import misc
import imageio
import scipy
import matplotlib.pyplot as plt
import glob #用于获取文件夹和文件信息
import re # 主要用于字符串匹配
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.callbacks import ModelCheckpoint #保存检查点
# 准备数据
num_classes = 5 #类别
batch_size = 120 #批量大小
epochs = 120 #训练次数
# 2 定义导入数据的函数,读取图片及标注
def loadImages(imgpath):
img = imageio.imread(imgpath)#imgpath:所有匹配的文件路径列表
if img is None:
return None
img = img.astype('float32') # 转成浮点32位数据类型
img /= 255 # 将图片归一化,加速模型训练速度
#print(img[1].shape)
return img
# 对图片进行维度变换
def changeDim(img):
img = np.expand_dims(img,axis=2) # 灰度图像为2D--change3 →(223, 28, 28) (223, 11)
img = np.expand_dims(img,axis=0) # 灰度图像前加一批量通道
return img
# 准备图像数据
def loadDataset( imgpath, pathtype):
images = loadImages(imgpath[0]) # 一幅图片的变维方法
images = changeDim(images)
for single in imgpath[1:]: # 用for循环处理多幅图片变维
img = loadImages(single)
img = changeDim(img)
images =np.append(images,img, axis = 0)
# 准备标记
labels = [] # 标签是数列
pattern = re.compile(pathtype+r"\\(\d{1,2})") # 用正则表达式,读取子文件夹名称;
# 匹配一个数字的"\\d"可以写成r"\d"; {m,n} 匹配前一个字符出现m到n次
for single in imgpath:
label = pattern.findall(single) # 搜索字符串,以列表类型返回全部能匹配的子串
labels.append(int(label[0]))#图片文件的名称是1的话对应图片写入的标签也为1
return images, labels # 返回图片的列表,标签列表
print('----------- 准备训练数据------------\n')
imgfiles = './trainsetG/*/*.jpg' # 准备训练数据
imgpath = glob.glob(imgfiles)#返回所有匹配的文件路径列表
images, labels = loadDataset(imgpath,'./trainsetG')
#print(imgpath) print(images) print(labels)---check
labels = keras.utils.to_categorical(labels, num_classes) #对标记进行转化,输出符合keras标记的类型
print(labels[0])
print(images.shape, labels.shape) #(223, 28, 28, 1) (223, 11)// (350, 64, 64, 1) (350, 5)ok!10/17 10:44
print('----------- 准备测试数据------------\n')
imgfiles2 = './testsetG/*/*.jpg' # 准备测试数据
imgpath2 = glob.glob(imgfiles2) # print(imgpath)
images2, labels2 = loadDataset(imgpath2,'./testsetG')
labels2 = keras.utils.to_categorical(labels2, num_classes)
print(images2.shape, labels2.shape) #(50, 28, 28, 1) (50, 11)//(105, 64, 64, 1) (105, 5)
print("读取数据完成!")
# 2 搭建模型
def createModel(num_classes):
input_shape = (64, 64, 1)
model = Sequential()
model.add(Conv2D(6, kernel_size=(5, 5),
activation='relu',
padding = 'same',
input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(16, (5, 5), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(120, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
return model
# 4 设计、训练网络
model = createModel(num_classes)
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adam(),
metrics=['accuracy'])
# 设置检查点
checkpointer = ModelCheckpoint(filepath='./checkpoint/weights001.hdf5', verbose=1, save_best_only=True)
model.fit(images, labels,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(images2, labels2),callbacks=[checkpointer])
# 保存训练模型
model.save('./checkpoint/model001.h5') # 保存为h5文件,方便以后调用
# 5 测试模型
score = model.evaluate(images2, labels2, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
成功输入到网络训练!但是此网络对此数据测试准确率不高,建议更换网络
Epoch 00120: val_loss did not improve from 1.53760
Test loss: 4.73303690467562
Test accuracy: 0.20952380952380953
此次主要解决问题
如何将图像数据转成符合网络输入的格式?
下一步工作
用本次建立的数据集对不同网络进行测试分析,发掘效果好的网络模型
个人感悟:需要耐心也需要细致,好好咀嚼消化,沉下心来加油吧!
以上仅为自己个人理解的学习记录,望大佬们赐教!