朴素贝叶斯分类器与Fisher线性判别实践——水果识别为例

开篇:本次博客主要分享二分类水果实现案例 , 样本构造显然不具备泛化、大数量特性以及背景均为纯白色是为了方便目标提取 。大家若需要更好的水果样本 , 上有许多的优秀案例 。本次代码计算效率较低 , 代码有较多计算可改进的地方 。
一、朴素贝叶斯及线性判别识别
(一)朴素贝叶斯最大后验概率分类
(二)线性两类判别
在求解最佳w投影时 , 其实有两种方法可以实现 , 其分别为梯度下降法和拉格朗日乘子法 , 此处主要以拉格朗日乘子法为例 , 但是也会在代码中给出梯度下降法 , 从而来比较两种方法的差异 。
图一 拉格朗日乘子法
对于梯度而言 , 我们知道梯度的本意是一个向量(矢量) , 表示某一函数在该点处的方向导数沿着该方向取得的最大值 , 即函数在该点处沿着该方向(梯度方向)变化最大 , 变化率最大(梯度的模) 。然而 , 对于梯度下降来说 , 通常我们需要优化的损失函数是一个非凸函数 , 所以其通常会收敛到一个局部极值 , 它的收敛极值往往就和我们所选的变量初值有关 。当然 , 我们知道若一个函数是凸函数 , 那么通过梯度下降法它一定会收敛到全局极值 , 所以我们在解决问题时通常会选择构造一个损失凸函数 。
补充点:在二维曲面中 , 若一阶偏导等于零且二阶偏导大于零 , 那么此点一定是一个曲面极小值点 。
图二 梯度下降法
二、实验构造样本集及测试集
图三训练样本集
图四测试样本集
三、判别实现流程
图五最大后验概率贝叶斯判别流程图六 线性判别流程
四、实现代码
(一)判别法
# Fisher线性二分类(LDA)import osimport cv2import numpy as npimport mathdef preProcess(OriResize):# 转HSV颜色空间利用饱和度去除白色背景HSV = cv2.cvtColor(OriResize, cv2.COLOR_BGR2HSV)# 通过实验发现所使用背景可利用s_min=40的饱和度去除lower = np.array([0, 40, 0])upper = np.array([179, 255, 255])mask = cv2.inRange(HSV, lower, upper)# 进行高斯模糊blur = cv2.GaussianBlur(mask, (7, 7), 1)return blurdef DataGet(imgname, Binary, OriResize):DataList = []MultOJ = cv2.bitwise_and(OriResize, OriResize, mask=Binary)B, G, R = cv2.split(MultOJ)shape = OriResize.shapeheight = shape[0]width = shape[1]# 正式开始获取颜色特征fMB = 0fMG = 0fMR = 0Rcount = 0for i in range(height):for j in range(width):fMB += B[i, j]fMG += G[i, j]fMR += R[i, j]Rcount += 1fMB /= RcountfMG /= RcountfMR /= RcountDataList.append(fMB)DataList.append(fMG)DataList.append(fMR)if imgname.startswith("apple"):DataList.append(0)else:DataList.append(1)return DataListdef test(w, tpro0, tpro1):# 获取样本数据(B、G、R目标均值)SampleFiles1 = os.listdir(r"D:\ThirdGhomework\classification\BayesTest")# 图像目标预处理error = 0true = 0record = 0for imgname1 in SampleFiles1:# 对香蕉和苹果进行训练 , 其他滤过if not imgname1.startswith("apple") and not imgname1.startswith("banana"):continueimgpath1 = os.path.join(r"D:\ThirdGhomework\classification\BayesTest", imgname1)Img1 = cv2.imread(imgpath1)# 调整图片长宽像素比调整显示大小shape1 = Img1.shapeOriResize1 = cv2.resize(Img1, (shape1[0] // 2, shape1[1] // 2))binary1 = preProcess(OriResize1)L1 = DataGet(imgname, binary1, OriResize1)test1 = L1[0:3]testS = L1[3]testpro = np.matmul(w, np.array(test1).T)if abs(testpro - tpro0) > abs(testpro - tpro1):record = 1else:record = 0if record == testS:true += 1else:error += 1return true/(error + true)# 梯度算子(瑞利商函数对w求偏导 , 此处矩阵的对向量求偏导不熟练)def grad(w):# 申明全局变量Sb与Swglobal u0,u1,cov1,cov0# 瑞利商函数对w的偏导,设置学习率为10的-3次幂rate = 0.01Sb = np.outer(u0-u1,u0-u1)Sw = cov1 + cov0sw2 = w.dot(Sw).dot(w.T)sb2 = w.dot(Sb).dot(w.T)nw = w + rate/pow(sw2, 2) * (2 * sw2 * Sb.dot(w.T) + 2 * sb2 * Sw.dot(w.T))ruiliS1 = w.dot(Sb).dot(w.T)/w.dot(Sw).dot(w.T)ruiliS2 = nw.dot(Sb).dot(nw.T)/nw.dot(Sw).dot(nw.T)return nw,ruiliS1,ruiliS2# 获取样本数据(B、G、R目标均值)SampleFiles = os.listdir(r"D:\ThirdGhomework\classification\BayesSamples")# 图像目标预处理DataL = []for imgname in SampleFiles:# 对香蕉和苹果进行训练 , 其他滤过if not imgname.startswith("apple") and not imgname.startswith("banana"):continueimgpath = os.path.join(r"D:\ThirdGhomework\classification\BayesSamples", imgname)Img = cv2.imread(imgpath)# 调整图片长宽像素比调整显示大小shape = Img.shapeOriResize = cv2.resize(Img, (shape[0] // 2, shape[1] // 2))binary = preProcess(OriResize)L = DataGet(imgname, binary, OriResize)DataL.append(L)# 法一:Fisher二类线性判别(拉格朗日极值法)npl = np.array(DataL)A = npl.T[0:3]sign = npl.T[3]# 两类数据分类x0 = A.T[sign == 0]x1 = A.T[sign == 1]# 返回轴向平均值(aix=0表示对各列求平均值;aix=1表示对各行求平均值)u0 = x0.mean(axis=0)u1 = x1.mean(axis=0)# 求协方差矩阵cov0 = np.cov(x0, rowvar=False)cov1 = np.cov(x1, rowvar=False)# 求解wsw = cov1 + cov0wf = np.matmul(np.linalg.inv(sw), u0-u1)# 计算Fisher(LDA)两类均值的投影pro0 = np.matmul(wf, u0.T)pro1 = np.matmul(wf, u1.T)# 法二:梯度下降法(与拉格朗日极值法共用初次协方差与均值求取)# 初始化w投影向量Wgrad = np.ones(3)while True:Wgrad, s1, s2 = grad(Wgrad)if abs(s1-s2)