目录
一、背景和挖掘目标
1、问题背景
2、水色分类
3、原始数据
4、挖掘目标
二、分析方法和过程
1、初步分析
2、总体流程
第1步:数据预处理——图像切割
第2步:特征提取
第3步:构建模型
第4步:水质评价
第5步:决策树模型对比实验
三、总结和思考
水色 | 浅绿色(清水或浊水) | 灰蓝色 | 黄褐色 | 茶褐色 (姜黄、茶褐、红褐、褐中带绿等) | 绿色 (黄绿、油绿、蓝绿、墨绿、绿中带褐等) |
水质类别 | 1 | 2 | 3 | 4 | 5 |
水产专家按水色判断水质分类,每个水质图片命名规则为“类别-编号.jpg”
请根据水质图片,利用图像处理技术,通过水色图像实现水质的自动评价。
采集到的水样图像包含盛水容器,容器的颜色与水体颜色差异较大,同时水体位于图像中央,为了提取水色的特征,需要提取水样图像中央部分具有代表意义的图像,具体实施方式是提取水样图像中央101*101像素的图像。
设原始图像 的大小是,则截取宽从第
个像素点到第
个像素点。
长从第个像素点到第
个像素点的子图像。
函数表示向0靠拢取整。
各阶颜色矩的计算公式:
1、一阶颜色矩:采用一阶原点矩,反映了图像的整体明暗程度。其中Ei是在第i个颜色通道的一阶颜色矩,对于RGB颜色空间的图像i=1,2,3,Pij是第j个像素的第i个颜色通道的颜色值。
2、二阶颜色矩:采用二阶中心距的平方根,反映了图像颜色的分布范围。其中Si是在第i个颜色通道的二阶颜色矩,Ei是在第i个颜色通道的一阶颜色矩。
3、三阶颜色矩:采用三阶中心距的立方根,反映了图像颜色分布的对称性。其中Si是在第i个颜色通道的二阶颜色矩,Ei是在第i个颜色通道的一阶颜色矩。
import numpy as np
import pandas as pd
from sklearn import preprocessing
from PIL import Image
import osdef PicManage(path,i):pic = Image.open(path)pic.c_x, pic.c_y = (int(i/2) for i in pic.size)box = (pic.c_x-50, pic.c_y-50, pic.c_x+50, pic.c_y+50)#从图片中提取中心100*100的子矩形region = pic.crop(box)#切分RGBr, g, b = np.split(np.array(region), 3, axis = 2)#计算一阶矩r_m1 = np.mean(r)g_m1 = np.mean(g)b_m1 = np.mean(b)#二阶矩r_m2 = np.std(r)g_m2 = np.std(g)b_m2 = np.std(b)#三阶矩r_m3 = np.mean(abs(r - r.mean())**3)**(1/3)g_m3 = np.mean(abs(g - g.mean())**3)**(1/3)b_m3 = np.mean(abs(b - b.mean())**3)**(1/3)#将数据标准化,区间在[-1,1]typ = np.array([i])arr = np.array([r_m1,g_m1,b_m1,r_m2,g_m2,b_m2,r_m3,g_m3,b_m3])#df = pd.DataFrame(preprocessing.minmax_scale(arr,feature_range=(-1,1))).Tdf = pd.DataFrame(arr).Tdn = pd.DataFrame(typ).Treturn df,dnresult = []
type_result = []
for i in os.listdir('images'):if i.endswith('.jpg'):df,dn = PicManage('images/'+i,int(i[0]))result.append(df)type_result.append(dn)data = pd.concat(result)
typ = pd.concat(type_result)
data = pd.DataFrame(preprocessing.normalize(data,norm='l2'))
data['type'] = typ.values
data.to_excel('picData.xls',index = False)
颜色矩特征提取后的数据集:
抽取80%作为训练样本,剩下的20%作为测试样本,用于水质评价检验。本案例采用支持向量机作为水质评价分类模型。
#-*- coding:utf-8 -*-
import pandas as pd#datapath = './data/moment.csv'
#data = pd.read_csv(datapath,encoding = 'gbk')
data = data.values#划分训练集和测试集
#cross_validation在sklearn0.20中改为model_selection
from sklearn.model_selection import train_test_split
train, test, train_target, test_target = train_test_split(data[:,0:],data[:,-1],test_size=0.2)
train_target = train_target.astype(int)
test_target = test_target.astype(int)#构建SVM模型
from sklearn import svm
model = svm.SVC()
model.fit(train*30,train_target)#save model
from sklearn.externals import joblib
joblib.dump(model,'svcmodel.pkl')#read model
model = joblib.load('svcmodel.pkl')#混淆矩阵
from sklearn import metrics
cm_train = metrics.confusion_matrix(train_target, model.predict(train*30))
cm_test = metrics.confusion_matrix(test_target, model.predict(test*30))train_accuracy = metrics.accuracy_score(train_target,model.predict(train*30))
test_accuracy = metrics.accuracy_score(test_target,model.predict(test*30))print("train accuracy: %f"% train_accuracy) #1.000
print("test accuracy: %f"% test_accuracy) #0.9756tr = pd.DataFrame(cm_train,index = range(1,6),columns = range(1,6)).to_excel('train.xls')
te = pd.DataFrame(cm_test,index = range(1,6),columns = range(1,6)).to_excel('test.xls')
由混淆矩阵,分类准确率为96.91%,分类效果较好,可应用模型进行水质评价。
预测值 实际值 | 1 | 2 | 3 | 4 | 5 |
1 | 41 | 1 | 1 | 0 | 0 |
2 | 0 | 34 | 0 | 0 | 0 |
3 | 0 | 0 | 59 | 0 | 0 |
4 | 0 | 0 | 1 | 20 | 0 |
5 | 0 | 1 | 0 | 1 |
取所有测试样本为输入样本,代入已构建好的LM神经网络模型,得到输出结果。
由混淆矩阵,分类准确率为95.12%,说明水质评价模型对于新增的水色图像的分类效果较好,可将模型应用到水质自动评价系统,实现水质评价。(注意,由于用随机函数来打乱数据,因此重复试验所得到的结果可能有所不同。)
预测值 实际值 | 1 | 2 | 3 | 4 | 5 |
1 | 7 | 0 | 1 | 0 | 0 |
2 | 0 | 10 | 0 | 0 | 0 |
3 | 0 | 0 | 19 | 0 | 0 |
4 | 0 | 0 | 0 | 3 | 0 |
5 | 0 | 0 | 0 | 1 | 0 |
import numpy as np
import os, re
from PIL import Imagedef get_ImgNames(path):"""获取图片名称:param path: 路径:return: 名称列表"""# os.listdir用于返回该路径下所包含的文件或文件夹的名字列表filenames = os.listdir(path=path)imgnames = []for i in filenames:# 在返回的文件名字中寻找正则表达式所匹配的所有字符串,如果不存在,返回空列表if re.findall('^\d_\d+\.jpg$', i) != []:imgnames.append(i)return imgnamesdef Var(data=None):"""获取三阶颜色矩:param p: 数据:return: 返回三阶颜色矩"""x = np.mean((data - data.mean()) ** 3)return np.sign(x) * np.abs(x) ** 1 / 3def imageCutting_FeatureExtraction(path, imgnames=None):"""图像切割与基于颜色矩进行特征提取:param path: 路径:param imgnames: 所有图片的名称:return: 返回特征提取后的9个分量,以及对应标签"""# 获取图片的数目n = len(imgnames)data = np.zeros((n, 9)) # 用来存放特征提取后的分量label = np.zeros((n)) # 用来存放样本标签# 对每一张图片进行图像分割,并计算9个分量for i in range(n):# 打开图像文件img = Image.open(path + imgnames[i])# 获取图片的尺寸M, N = img.size# 图像切割提取图样中间部分,img.crop返回图像的矩阵区域,参数为 (left, upper, right, lower)的元祖img = img.crop((M / 2 - 50, N / 2 - 50, M / 2 + 50, N / 2 + 50))# 将图像分割成3个通道,r, g, b = img.split()# 转化为数组数据并归一化,获得对应的像素矩阵rd = np.array(r, dtype=np.float32) / 255gd = np.array(g, dtype=np.float32) / 255bd = np.array(b, dtype=np.float32) / 255# 计算一阶颜色矩data[i, 0] = rd.mean()data[i, 1] = gd.mean()data[i, 2] = bd.mean()# 计算二阶颜色矩data[i, 3] = rd.std()data[i, 4] = gd.std()data[i, 5] = bd.std()# 计算三阶颜色矩data[i, 6] = Var(rd)data[i, 7] = Var(gd)data[i, 8] = Var(bd)# 获取样本标签-每个图片名的第一个数字代表类别label[i] = imgnames[i][0]return data, labelif __name__ == '__main__':# 获取所有图片的名称imgNames = get_ImgNames(path='images')# 图像切割与特征提取data, label = imageCutting_FeatureExtraction(path='images/', imgnames=imgNames)print(data)print(label)
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import confusion_matrix, accuracy_score# 划分数据集
# shuffle=True尽可能每一类别都取到或者采用分层抽样
data_tr, data_te, label_tr, label_te = train_test_split(data, label, test_size=0.2, shuffle=True)
model = DecisionTreeClassifier(random_state=1234)
model.fit(data_tr, label_tr)
# 预测
pred_te = model.predict(data_te)
# 混淆矩阵
cm = confusion_matrix(label_te, pred_te)
print('混淆矩阵为\n', cm)
# 准确率
acc = accuracy_score(label_te, pred_te)
print('准确率为\n', acc)
混淆矩阵和准确率:
参考:《python数据分析和数据挖掘》