【图像处理】——Python实现图像特征提取BP神经网络实现图像二分类
目錄
?
一、圖像特征提取
二、BP實現圖像二分類
1、輸入層、隱層、輸出層結點個數設置
(1)one hot碼(假設是n分類問題)
(2)一個輸出,輸出層結點為1
一、圖像特征提取
圖像具有灰度特征、GLCM特征、Huments不變矩特征、LBP特征,具體可參考我主頁的其他博客
import cv2 import numpy as np from numpy import histogram#灰度特征 def GrayFea(faultness):''':param faultness: 灰度圖像:return: list->(4)'''hist0 = cv2.calcHist([faultness], [0], None, [256], [0, 255])h, w = faultness.shapehist = hist0 / (h * w)# 灰度平均值mean_gray = 0for i in range(len(hist)):mean_gray += i * hist[i]# 灰度方差var_gray = 0for i in range(len(hist)):var_gray += hist[i] * (i - mean_gray) ** 2# 能量##歸一化max_ = np.max(hist)min_ = np.min(hist)hist_ = (hist - min_) / (max_ - min_)##求解能量energy = 0for i in range(len(hist_)):energy += hist_[i] ** 2#灰度對比度con = np.max(faultness)-np.min(faultness)gray_fea = [mean_gray[0], var_gray[0], energy[0],con]return gray_fea#計算不變矩特征 def huMoments(faultness):'''opencv_python自帶求矩以及不變矩的函數:param faultness: 灰度圖像,對于二值圖像來說就只有兩個灰度0和255:return: 返回以10為底對數化后的hu不變矩,(7*1)'''moments = cv2.moments(faultness)#返回的是一個字典,三階及以下的幾何矩(mpq)、中心矩(mupq)和歸一化的矩(nupq)humoments = cv2.HuMoments(moments)#根據幾何矩(mpq)、中心矩(mupq)和歸一化的矩(nupq)計算出hu不變矩# 因為直接計算出來的矩可能很小或者很大,因此取對數好比較,這里的對數底數為e,通過對數除法的性質將其轉換為以10為底的對數humoment = (np.log(np.abs(humoments)))/np.log(10)humoment = -humoment.ravel()#將其變為一維的return humoment#灰度共生矩陣GLCM from skimage.feature import greycomatrix, greycoprops import cv2image = cv2.imread(r'E:bpPackage\colorful_lena.jpg',0)def GLCM(grayImg):''':param grayImg: 灰度圖像:return: list->(24),因為GLCM特征有6個,每個特征取了四個方向的特征,因此共有24個特征值'''GLCMFeas = []#這一步類似于數據壓縮,因為8位圖像含有256個灰度級,這樣會導致計算灰度共生矩陣是的計算量過大,因此將其進行壓縮成16級,將灰度進行分區bins = np.array([0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255]) #16-bitinds = np.digitize(grayImg, bins)#返回的是一個和image大小一樣的矩陣,只是矩陣元素表示的是image中元素在bins中的區間位置,小于0為0,0-16為1,以此類推max_value = inds.max()+1matrix_coocurrence = greycomatrix(inds, #需要進行共生矩陣計算的numpy矩陣[1],#步長[0, np.pi/4, np.pi/2, 3*np.pi/4],#方向角度levels=max_value, #共生矩陣階數normed=False, symmetric=False)print(matrix_coocurrence)#P[i,j,d,theta]返回的是一個四維矩陣,各維代表不同的意義# GLCM properties#對比度CON# [[2.26653266 3.03593344 1.1861809 2.33115325]]返回的是一個數組,要將其元素求出來,首先進行取0元素然后再進行extend加入列表中contrast = greycoprops(matrix_coocurrence,'contrast')GLCMFeas.extend(contrast[0])#差異性DISLdissimilarity = greycoprops(matrix_coocurrence,'dissimilarity')GLCMFeas.extend(dissimilarity[0])#反差分矩陣HOMOhomogeneity = greycoprops(matrix_coocurrence,'homogeneity')GLCMFeas.extend(homogeneity[0])#熵ENTenergy = greycoprops(matrix_coocurrence, 'energy')GLCMFeas.extend(energy[0])#相關性CORcorrelation = greycoprops(matrix_coocurrence, 'correlation')GLCMFeas.extend(correlation[0])#角二階矩(能量)ASMasm = greycoprops(matrix_coocurrence, 'ASM')GLCMFeas.extend(asm[0])print(GLCMFeas)return GLCMFeas#LBP特征 from skimage import feature as skft def LBPFeas(grayimg):''':param grayimg: 灰度圖像:return: 返回list->(256)'''#uniform,nri_uniform,varlbp = skft.local_binary_pattern(grayimg,P=8,R=1,method='nri_uniform')#將原圖分割成256個小子圖像,得到每個小區域的LBP十進制直方圖,然后將256個直方圖進行疊加得到全局直方圖lbp = lbp.astype(np.uint8)max_bins = int(lbp.max() + 1) # 得到圖片中最大的灰度級別# hist size:256#對圖像的256個子圖像的LBP值進行統計LBPHist,_ = np.histogram(lbp, bins=max_bins, range=(0, max_bins),density=False) # 繪制每一個小區域的直方圖return list(LBPHist.ravel())#求得一個圖像的所有特征 def CalAllFeas(img):''':param img: 灰度圖像:return: 返回一個含有所有特征的列表,4+7+24+256'''##存放全部特征Allfeas = []##加入灰度特征grayFeas = GrayFea(img)Allfeas.extend(grayFeas)##加入不變矩特征HuMomentFeas = huMoments(img)Allfeas.extend(HuMomentFeas)##加入共生矩陣特征GlcmFeas = GLCM(img)Allfeas.extend(GlcmFeas)##加入LBP紋理特征LbpFeas = LBPFeas(img)Allfeas.extend(LbpFeas)return Allfeas#進行特征特取以及標簽標記 def main():'''特征標記規則:渣點圖像標記為1,其余標記為0:return: 返回含標記的數據集,第一位是圖片編號,編號規則:渣點圖像編號從1-102,非渣點從103-203'''dataSets = []#數據集PosImgDatasets = []#渣點圖像數據集NegImgDatasets = []#非渣點圖像數據集for i in range(1,103):img = cv2.imread(r'E:bpPackage\PositiveImg\ObjImg{}.jpg'.format(i),0)PosAllFeas = [i]#加入圖片編號PosAllFeas.extend(CalAllFeas(img))PosAllFeas.append(1)PosImgDatasets.append(PosAllFeas)dataSets.extend(PosImgDatasets)for i in range(1,101):img = cv2.imread(r'E:bpPackage\NegativeImg\NoObjImg{}.jpg'.format(i),0)NegAllFeas = [i+len(dataSets)]NegAllFeas.extend(CalAllFeas(img))NegAllFeas.append(0)NegImgDatasets.append(NegAllFeas)dataSets.extend(NegImgDatasets)dataSets = np.array(dataSets)#將數組以元素為浮點數的形式寫入TXT文件中,元素間用\t進行分割np.savetxt(r"E:dataSets94.txt", dataSets, fmt='%f', delimiter='\t')if __name__ == '__main__':main()二、BP實現圖像二分類
1、輸入層、隱層、輸出層結點個數設置
參考:《BP神經網絡的隱含層,輸入層,輸出層的節點數確定》
《神經網絡隱藏層節點數最少可以是多少個?》
輸入層結點個數等于一個樣本的特征個數
隱層結點個數一般是輸入層結點個數開根號取整+1
輸出層結點取決于你分類的方式
(1)one hot碼(假設是n分類問題)
??????? 可以實現多分類的輸出,對于一個樣本來說,最終會得到n個輸出值,輸出值是樣本歸屬于每一類的概率,我們最后將其歸類到概率最大的那一類中,這種規則叫做通吃規則,這時候為了方便,我們將最大概率的值設置為1,其余的設置為0,這樣對于每一個樣本的分類都對應一個行向量,[0 0 0 0 ... 1 0 0 0 ... 0 0],這里1所對應的類別就是樣本的類別,要是有m個樣本,則得到的將會是nXm的一個分類矩陣
關于one hot在實例中如何實現的可以參考:Python 基于BP神經網絡的鳶尾花分類
關鍵代碼:
# 結果的維度n_rows = y_test.shape[0]n_cols = y_test.shape[1]# 預測值結果存儲output = np.empty(shape=(n_rows, n_cols), dtype=int)for i in range(n_rows):for j in range(n_cols):if a2[i][j] > 0.5:output[i][j] = 1else:output[i][j] = 0(2)一個輸出,輸出層結點為1
這個就是直接將輸出的結果作為標簽,以三分類為準,輸出0為類別一,輸出1為類別二,輸出2為類別三
本案例就是通過這種方式進行分類的
import pandas as pd import numpy as np import datetime from sklearn.utils import shuffle#####################################BP神經網絡模型創建######################################### # 1.初始化參數 def initialize_parameters(n_x, n_h, n_y):#n_x = 94一個樣本具有的特征個數,n_h = 10,n_y = 1np.random.seed(2)# 權重和偏置矩陣w1 = np.random.randn(n_h, n_x) * 0.01#(10,94)b1 = np.zeros(shape=(n_h, 1))#(10,1)w2 = np.random.randn(n_y, n_h) * 0.01#(1,10)b2 = np.zeros(shape=(n_y, 1))#(1,1)# 通過字典存儲參數parameters = {'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2}return parameters# 2.前向傳播 def forward_propagation(X, parameters):w1 = parameters['w1']#(10,94)b1 = parameters['b1']#(10,1)w2 = parameters['w2']#(1,10)b2 = parameters['b2']#(1,1)# 通過前向傳播來計算a2,x(94,141)z1 = np.dot(w1, X) + b1 #(10,141) # 這個地方需注意矩陣加法:雖然(w1*X)和b1的維度不同,但可以相加a1 = 1 / (1 + np.exp(-z1)) #(10,141) # 使用tanh作為第一層的激活函數z2 = np.dot(w2,a1) + b2 #(1,141)a2 = 1 / (1 + np.exp(-z2)) #(1,141) 使用sigmoid作為第二層的激活函數# 通過字典存儲參數cache = {'z1': z1, 'a1': a1, 'z2': z2, 'a2': a2}return a2, cache# 3.計算代價函數 def compute_cost(a2, Y, parameters):''':param a2: (1,141)最后一層經過激活函數處理的:param Y: (1,141)標簽:param parameters: :return: '''m = Y.shape[1] #Y(1,141) Y的列數即為總的樣本數# 采用交叉熵(cross-entropy)作為代價函數logprobs = np.multiply(np.log(a2), Y) + np.multiply((1 - Y), np.log(1 - a2))cost = - np.sum(logprobs) / mreturn cost# 4.反向傳播(計算代價函數的導數) def backward_propagation(parameters, cache, X, Y):m = Y.shape[1]w2 = parameters['w2']a1 = cache['a1']a2 = cache['a2']# 反向傳播,計算dw1、db1、dw2、db2dz2 = a2 - Ydw2 = (1 / m) * np.dot(dz2, a1.T)db2 = (1 / m) * np.sum(dz2, axis=1, keepdims=True)dz1 = np.multiply(np.dot(w2.T, dz2), 1 - np.power(a1, 2))dw1 = (1 / m) * np.dot(dz1, X.T)db1 = (1 / m) * np.sum(dz1, axis=1, keepdims=True)grads = {'dw1': dw1, 'db1': db1, 'dw2': dw2, 'db2': db2}return grads# 5.更新參數 def update_parameters(parameters, grads, learning_rate=0.0075):w1 = parameters['w1']b1 = parameters['b1']w2 = parameters['w2']b2 = parameters['b2']dw1 = grads['dw1']db1 = grads['db1']dw2 = grads['dw2']db2 = grads['db2']# 更新參數w1 = w1 - dw1 * learning_rateb1 = b1 - db1 * learning_ratew2 = w2 - dw2 * learning_rateb2 = b2 - db2 * learning_rateparameters = {'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2}return parameters# 建立神經網絡 def nn_model(X, Y, n_h, n_input, n_output, num_iterations=100000, print_cost=False):np.random.seed(3)n_x = n_input # 輸入層節點數n_y = n_output # 輸出層節點數# 1.初始化參數parameters = initialize_parameters(n_x, n_h, n_y)# 梯度下降循環for i in range(0, num_iterations):# 2.前向傳播a2, cache = forward_propagation(X, parameters)# 3.計算代價函數cost = compute_cost(a2, Y, parameters)# 4.反向傳播grads = backward_propagation(parameters, cache, X, Y)# 5.更新參數parameters = update_parameters(parameters, grads)# 每1000次迭代,輸出一次代價函數if print_cost and i % 1000 == 0:print('迭代第%i次,代價函數為:%f' % (i, cost))return parameters# 對模型進行測試 def predict(parameters, x_test, y_test):''':param parameters: 神經網絡參數,權重和偏置:param x_test: 用于測試的樣本集:param y_test: 用于測試的樣本集對應的真實標簽分類:return: 返回的是對測試數據集預測的標簽output以及預測的正確率acc'''w1 = parameters['w1']b1 = parameters['b1']w2 = parameters['w2']b2 = parameters['b2']z1 = np.dot(w1, x_test) + b1a1 = 1 / (1 + np.exp(-z1))z2 = np.dot(w2, a1) + b2a2 = 1 / (1 + np.exp(-z2))# 結果的維度n_rows = y_test.shape[0]#1n_cols = y_test.shape[1]#61# 預測值結果存儲output = np.empty(shape=(n_rows, n_cols), dtype=int)# 取出每條測試數據的預測結果,大于0.5的設置為1,小于0.5的設置為0for i in range(n_cols):for j in range(n_rows):if a2[j,i] > 0.5:output[j][i] = 1else:output[j][i] = 0# print('預測結果:')# print(output)# print('真實結果:')# print(y_test)count = 0for k in range(0, n_cols):if output[0][k] == y_test[0][k]:count = count + 1acc = count / int(y_test.shape[1]) * 100# print('準確率:%.2f%%' % acc)return output,acc#數據集處理 def createdataset(path):''':param path: TXT文件路徑:return: 返回的是數據集->list'''#通過utf-8格式打開含有中文的TXT文件datasets = open(path,encoding='utf-8')#按行讀取文件,得到的是一個列表,每一個元素是將一行作為一個字符串lines = datasets.readlines()#遍歷列表dataSets = []for line in lines:#通過去除首位空格和根據逗號來分割字符串,將一串字符串分割成了多個字符組成的列表line = line.strip().split('\t')line = list(map(float,line))#將字符串數字轉化為浮點型數據dataSets.append(line)#將之前的數據集規整化為一個列表return dataSets#劃分數據集 def splitDatasets(dataSets,trainingSize):''':param dataSets: 數據集,第一列是編號,最后一列是類別:param trainingSize: 訓練集樣本占比,小數表示一般為0.7:return: 返回訓練集和測試集trainDatas(141,94),trainLabels(141,1),testDatas(61,94),testLabels(61,1)'''numOfData = len(dataSets)numOfTrainData = int(numOfData*trainingSize)trainSets = []testSets = []trainSets.extend(dataSets[0:numOfTrainData])testSets.extend(dataSets[numOfTrainData:])#劃分數據集,將數據集進行轉置,數據集通過轉置來實現,標簽集通過reshape來實現trainDatas = (np.array(trainSets)[:,1:-1]).TtestDatas = (np.array(testSets)[:,1:-1]).TtrainLabels = (np.array(trainSets)[:,-1]).reshape(1,numOfTrainData)testLabels = (np.array(testSets)[:,-1]).reshape(1,numOfData-numOfTrainData)return trainDatas,trainLabels,testDatas,testLabelsif __name__ == "__main__":# 讀取數據start_time1 = datetime.datetime.now()path = r'E:bpPackage\dataSets94.txt'accSum = 0.0for i in range(10):print("------------------------第%d次------------------------------------"%i)dataSets = createdataset(path)#102個正樣本,100個負樣本dataSets = shuffle(dataSets) # 打亂數據,這樣保證了數據的隨機性#劃分數據集,訓練樣本特征、訓練樣本標簽、測試樣本特征、測試樣本標簽trainDatas, trainLabels, testDatas, testLabels = splitDatasets(dataSets,trainingSize=0.7)# print(trainDatas)# print(testDatas.shape)# 開始訓練start_time = datetime.datetime.now()# 輸入94個節點,隱層6個節點,輸出1個節點,迭代100000次parameters = nn_model(trainDatas, trainLabels, n_h=10, n_input=94, n_output=1, num_iterations=100000, print_cost=True)end_time1 = datetime.datetime.now()print("訓練模型用時:" + str((end_time1 - start_time).seconds) + 's' + str(round((end_time1 - start_time).microseconds / 1000)) + 'ms')# 對模型進行測試,隨機測試100次,取正確率的平均值output,acc = predict(parameters, testDatas, testLabels)accSum += accaccMean = accSum/10print("正確率:",accMean)end_time2 = datetime.datetime.now()print("總用時:" + str((end_time2 - start_time1).seconds) + 's' + str(round((end_time2 - start_time).microseconds / 1000)) + 'ms')上述可以調的超參數是:迭代次數:num_iterration,循環次數:10
總結
以上是生活随笔為你收集整理的【图像处理】——Python实现图像特征提取BP神经网络实现图像二分类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 题目一:给出一个n,代表有从1到n的数字
- 下一篇: 【项目实战】——Python打包正装换底