机器学习分类器——案例(opencv sklearn svm ann)

机器学习分类器——案例(opencv sklearn svm ann python)

ps:最近师姐给我们留了一个任务,记录一下从一开始的什么都不懂到现在把任务做出来,并从中学习到的东西吧。。。。
语言环境python3.7,用到的库

import os
import cv2
import math
import time
import numpy as np
import tqdm
from skimage.feature import hog
from sklearn import svm,datasets,metrics
import matplotlib.pyplot as plt
from skimage import  feature as ft
from  sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import *
from sklearn import tree,neighbors
from xgboost import XGBClassifier
from sklearn.base import TransformerMixin,BaseEstimator
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import CategoricalNB,GaussianNB
from sklearn.model_selection import cross_val_score
from yellowbrick.classifier.rocauc import roc_auc
import joblib

任务要求:给定数据集train和test文件夹,其中文件夹中包含四个文件夹(后来才知道是对应于多分类的四个类别),数据格式是图片(也是后来才知道已经灰度处理过了)

小插曲:本来想展示一下文件夹层及目录,奈何图片过多,效果并不好,记录一下获取文件结构图的方法吧。

1.win+R cmd

2.进入想要展示的文件夹内

3.输入tree/f>file.txt命令,在响应的文件夹下生成txt文件可以看到文件结构图。

数据集目录结构

pycharm目录结构

ps:一开始什么都不懂,后来读文献知道了处理问题的整体思路,先来说一下整体思路吧。

整体思路:

在这里插入图片描述

数据预处理

方法:我的理解是把图片的像素变成0和255,来分割目标区域(细胞核),后面特征提取可以用到。

知识点:(方法原理可进一步了解)

直方图均衡化( Histogram Equalization):一种增强图像对比度的方法。

滤波: 尽量保留图像细节特征的条件下对目标图像的噪声进行抑制 , 消除图像中的噪声成分叫作图像的平滑化或滤波操作 。种类:均值滤波、中值滤波

图像的阈值分割:基于区域的图像分割技术,原理是把图像像素点分为若干类。本次采用ostu法或者迭代法计算阈值(很多种方法)

程序代码

def ImgProcessing(img):
    imgHist = cv2.equalizeHist(img)  # 直方图均衡化,用于提高图像的质量
    imgblur = cv2.blur(imgHist, (5, 5))  # 均值滤波
    imgthre, ostu = cv2.threshold(imgblur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)  # otsu法聚类计算阈值
    # print(imgthre)
    ###最佳阈值imgthre=126(具体问题的值不一样)
    return ostu

path = "Resource\\train\\1_typical_epithelial_cell\\1_122.jpg"
img = cv2.imread(path, 0)#把图片读进来
thres  = ImgProcessing(imgcopy)
cv2.namedWindow("result",0)
    cv2.resizeWindow("result",600,300)
    result = cv2.hconcat([thres,img])
    cv2.imshow('result',result)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

效果演示:如果想得到目标是黑色背景是白色,修改cv2.threshold的参数即可,因为后面的轮廓检测要求传入的目标是白色,故这里目标选择白色。(也是采坑遇见错误查阅官方文档才知道。。。)

在这里插入图片描述

去燥效果演示:

在这里插入图片描述

将预处理后的图片保存到trainpro和testpro文件夹中

方法:传入文件路径,获取每张图片然后对每张图片处理后保存到文件夹中

在这里插入图片描述

程序代码:

def get_label_dir(path):
    for file_name in os.listdir(path):
        img_dir = os.path.join(path, file_name)
        # print(file_name)
        img = cv2.imread(img_dir,0)
        imgHist = cv2.equalizeHist(img)  # 直方图均衡化,用于提高图像的质量
        imgblur = cv2.blur(imgHist, (5, 5))  # 均值滤波
        bestyuzhi1 = diedai(imgblur)#迭代法求阈值
        ret1, th1 = cv2.threshold(imgblur, bestyuzhi1, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
        #file_name = '4'+file_name[1:]
        cv2.imwrite("Resource\\testpro\\6_garbage\\"+file_name,th1)
get_label_dir("Resource\\test\\6_garbage")#每次只需要修改路径即可

获取特征

本次计算11个基本特征值和Hog特征(还有很多特征可以自行查阅,具体问题具体分析)最后把特征保存到Features列表中,一个图片对应一个11长度的列表。

基本特征:(轮廓特征)周长、面积、长度、宽度、圆度、椭圆度、矩形度、规划形状因子;(纹理特征)均值、方差、平滑度、熵值、三阶矩;

Hog特征:一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度方向直方图来构成特征。 通过提取有用信息并扔掉多余的信息来简化图像 。 特征描述子将一张大小为width×height×3 (通道数)的图片化成一个长度为n的特征向量数组。以HOG特征为例,输入图像的大小是64×128×3,输出是一个长度为3780(假设)的特征向量 。本次提取756个特征。

程序代码:

def getContours(thres,Features):
    contours, hierarchy = cv2.findContours(thres, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnt = contours[0]
    # print(cv2. arcLength(contours,True)) #轮廓长度
    # print(cv2.contourArea(contours))#轮廓面积
    area = cv2.contourArea(contours[0])
    # print("轮廓的面积是:%f" % area)
    length = cv2.arcLength(contours[0],True)
    # print("轮廓的周长是:%f" % length)
    #圆度计算公式4*PI*Area/length^2
    a = area*4*math.pi
    b = math.pow(length,2)
    if b!=0:
       roundness = a/b
    else:
       roundness = 0
    # print("轮廓圆度是:%f" % roundness)
    #最小外接矩形框
    rect = cv2.minAreaRect(contours[0])
    wideth = rect[1][0]
    highth = rect[1][1]
    box = cv2.cv2.Boxpoint() if imutils.is_cv2() else cv2.boxPoints(rect)
    box = np.int0(box)
    minrectarea = np.int0(rect[1][0]*rect[1][1])
    #计算矩形度
    rect_degree = area/minrectarea
    # print("轮廓矩形度是:%f" % rect_degree)
    # cv2.drawContours(imgcopy, [box], 0, (255, 0, 0), 1)
    # cv2.drawContours(imgcopy, contours, -1, (0, 0, 255), 1)  # 画出轮廓
    #计算椭圆度
    for i in range(len(contours)):
        if len(contours[i]) >= 5:
            cv2.drawContours(thres, contours, -1, (150, 10, 255), 3)
            ellipse = cv2.fitEllipse(contours[i])
            ellipse_area = np.int0(ellipse[1][0] * ellipse[1][1])
            ellipse_degree = 4 * area / ellipse_area
            # Features.append(round(ellipse_degree, 3))
            # print("轮廓椭圆度%d是:%f" % (i,ellipse_degree))
            d1 = ellipse[1][0]
            d2 = ellipse[1][1]
            if d1 * d2 * length !=0:
               REF = area * (3 * (d1 + d2) - 2 * math.sqrt(d1 * d2)) / (d1 * d2 * length)
            else :
               REF =0
    # cv2.imshow("Perfectlyfittedellipses", thres)
    # cv2.waitKey(0)
    # ellipse = cv2.fitEllipse(contours[0])
    # ellipse_area = np.int0(ellipse[1][0]*ellipse[1][1])

    # ellipse_degree = 4*area/ellipse_area
    # # cv2.ellipse(imgcopy,ellipse,(0,255,255),1)#可视化椭圆轮廓
    # #规划形状因子

    # print("规划形状因子是:%f" % REF)
    wenli_gt = cv2.moments(contours[0])
    # print("三阶矩是:%f" % wenli_gt['mu02'])  # 三阶矩
    Features.append(round(wideth,3))
    Features.append(round(highth,3))
    Features.append(round(area,3))
    Features.append(round(length,3))
    Features.append(round(roundness,3))
    Features.append(round(rect_degree,3))
    Features.append(round(ellipse_degree,3))
    Features.append(round(REF,3))
    Features.append(round(wenli_gt['mu02'],3))
def grain_feature(img,Features):
    mean , stddv = cv2.meanStdDev(img)#图像均值和标准差(方差)
    # print("均值为%f 方差为%f " % (mean[0][0],stddv[0][0]))
    wenli_r = 1-1/(1+stddv*stddv)
    # print("平滑度为%f" % wenli_r)
    imagea = np.histogram(img.ravel(), bins=256)[0]
    wenli_s = skimage.measure.shannon_entropy(imagea,base=2)
    # print("熵值是:%f" % wenli_s)

    Features.append(round(wenli_r[0][0],6))
    Features.append(round(wenli_s,3))
def get_features(path):
    Features_set = []
    for file_name in os.listdir(path):
        Features = []
        img_dir = os.path.join(path, file_name)
        # print(file_name)
        img = cv2.imread(img_dir,0)
        imgcopy = img.copy()
        thres = ImgProcessing(imgcopy)
        getContours(thres,Features)  ###基本特征
        grain_feature(imgcopy,Features)  #####纹理特征
        # Features = np.array(Features)
        # print(type(Features),type(Features_sets))
        Features_set.append(Features)
    return Features_set 

获取Hog特征代码:

def get_hog_feat(path):
    Features = []
    try:
        for file_name in os.listdir(path):
            img_dir = os.path.join(path, file_name)
            img = cv2.imread(img_dir,0)
            imgcopy = cv2.resize(img,(32,64))
            features, hog_img = ft.hog(imgcopy, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), visualize=True)
            Features.append(features)
    except cv2.error:
        print(file_name)
    return Features

制作数据集准备传入模型中,将四类训练集的特征都放入X_train中,Y_train存放标签1,2,3,4(有的模型要求是0,1,2,3,代码中有体现)

path_train = "Resource\\train"
path_test = "Resource\\test"
###########制作训练集
def get_data(path):
    X = []
    Y = []
    cnt =0
    for file_name in os.listdir(path):
        Features = []
        img_dir = os.path.join(path, file_name)
        Features = get_hog_feat(img_dir)
        cnt = cnt + 1
        for i in Features:
            X.append(i)
            Y.append(cnt)
        # cnt = cnt + 1 #XGB要求0123
    return X,Y
X_train ,Y_train = get_data(path_train)
X_test,Y_test = get_data(path_test)

如果遇到传入数据有空值的错误可以使用以下代码

关于np.nan_to_num可查看官方文档https://numpy.org/doc/stable/reference/generated/numpy.nan_to_num.html

X_train = np.nan_to_num(X_train)
Y_train = np.nan_to_num(Y_train)
X_test = np.nan_to_num(X_test)
Y_test = np.nan_to_num(Y_test)

数据降维

特征向量的维数过高会增加计算的复杂度,数据降维消除特征之间的数量级。

使用sklearn中的from sklearn.preprocessing import StandardScaler,使用方法可查看官方文档,sklearn的文档做的很好,有很多example,嘻嘻嘻。

sc_X = StandardScaler()
X_trainscaled = sc_X.fit_transform(X_train)
X_testscaled = sc_X.fit_transform(X_test)
X_testscaled = np.nan_to_num(X_testscaled)

ps:数据准备好开始训练

分类器训练和模型衡量标准

本次训练包含svm支持向量机,ann人工神经网络(MLP多层感知机),Decision Tree决策树、XGBboost(种梯度提升决策树的实现)k-nn(K近邻),Naive Bayes(朴素贝叶斯),有很多方法可以使用,但是很多原理还需要进一步学习。。。

分类器的训练模型参数均保存到.dat文件中,可以节约每次训练的时间。

程序代码

###############SVM
linear = svm.SVC(kernel='linear',C=1,decision_function_shape='ovo').fit(X_train ,Y_train)
linear = svm.SVC(decision_function_shape='ovo').fit(X_train ,Y_train)
linear_pred = linear.predict(X_test)
linear = joblib.load("Hog_linear.dat")
accuracy_lin = linear.score(X_test,Y_test)
print("SVM-linear准确度为%.2f%%" % (accuracy_lin*100))
# joblib.dump(linear,"Hog_linear.dat")#保存模型
##############ANN
#MLP = MLPClassifier(solver='adam', alpha=1e-5,#256,128,64,32,hidden_layer_sizes=(30,30,30)random_state=100,activation='logistic').fit(X_trainscaled,Y_train)
MLP = MLPClassifier().fit(X_trainscaled,Y_train)
#joblib.dump(MLP,"Hog_MLP.dat")#保存模型
#MLP = joblib.load("Hog_MLP.dat")#加载模型
# MLP_pre = MLP.predict(X_testscaled)
accuracy_ANN = MLP.score(X_testscaled,Y_test)
print("Hog特征之ANN准确度%.2f%%" % (accuracy_ANN*100.0))

About SVM:kernel(核函数linear、rbf、poly、sigmoid),gamma值、惩罚系数c的选取都会影响最终的准确度的,由于是多分类, 逻辑回归和 SVM 等二元分类模型本身不支持多类分类,需要元策略 ,分类策略采用的是ovo,还有ovr。

关于分类策略ovo和ovr:

由于SVM本质上是二分类模型,多分类可以是二分类的延伸。例如给定多分类class 1,class 2,class 3,class4。

ovo(One-vs-One):

class1 vs class 2

class 1 vs class3 等总共有n(n-1)/2种(4*3/2=6)

ovr(One-vs-Rest)n种:

class 1 vs [class2,class3,class4]

class 2 vs [class1,class 3,class 4]

class 3 vs [class1,class 2 ,class4]

class4 vs [class1,class2,class3]

About ANN

ANN就是借鉴了神经突触机制,在结点中设置了函数,比如sigmoid或者tanh函数,来完成抑制或激活的目标。

衡量标准

计算准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1-Measure的数值、画AUC曲线和混淆矩阵。

准确率(Accuracy):1-错误率

精确率(Precision):有多少比例是好的

召回率(Recall):好的信息中有多少被检索出来

F1-Measure的数值:对查准率/查全率的重视程度

混淆矩阵:看出有多少个分类正确,有多少个被分类到其他的类中

ROC-AUC曲线:ROC曲线下的面积

###########衡量标准
target_names = ['class 1', 'class 2', 'class 3','class 4']
print(classification_report(Y_test, MLP_pre, target_names=target_names))
######混淆矩阵
disp = metrics.ConfusionMatrixDisplay.from_predictions(Y_test, MLP_pre)
disp.figure_.suptitle("confusion matrix")
print(f"confusion matrix:\n{disp.confusion_matrix}")
plt.show()
######ROC曲线和AUC
#model = RidgeClassifier()
#model = SVC()
model = MLPClassifier()
roc_auc(MLP, X_train, Y_train, X_test=X_test, y_test=Y_test, encoder={1:'typical',  2:'Lymphocyte', 3:'Single',4:'garbage'})

效果演示
在这里插入图片描述
在这里插入图片描述

其他的分类器

#####################Decision Trees  决策树

DTC = tree.DecisionTreeClassifier()
DTC.fit(X_trainscaled,Y_train)
# joblib.dump(DTC,"Hog_DTC.dat")
DTC = joblib.load("Hog_DTC.dat")
accuracy_DTC = DTC.score(X_testscaled,Y_test)
print("Hog特征之DTC准确度%.2f%%" % (accuracy_DTC*100.0))
# print(cross_val_score(DTC,X_train,Y_train,cv=10))
# tree.plot_tree(DT)#绘制树
#可以pip graphviz导出树到pdf
####################集成学习
######XGBoost是一种梯度提升决策树的实现
XGB = XGBClassifier().fit(X_trainscaled,Y_train)
# XGB = joblib.load("Hog_XGB.dat")
accuracy_XGB = XGB.score(X_testscaled,Y_test)
print("Hog特征之XGB准确度%.2f%%" % (accuracy_XGB*100.0))
# joblib.dump(XGB,"Hog_XGB.dat")

####################K-Nearest Neighbors  K近邻
n_neighbors = 20
h = 0.02
K_N = neighbors.KNeighborsClassifier(n_neighbors,weights="distance")
K_N.fit(X_trainscaled,Y_train)
# # K_N = joblib.load("Hog_KNN.dat")
accuracy_KNN = K_N.score(X_testscaled, Y_test)
print("Hog特征之KNN准确度%.2f%%" % (accuracy_KNN * 100.0))
# # joblib.dump(K_N,"Hog_KNN.dat")
##绘制accuracy和k取值的关系图
acc = []
for i in range(1,40):
    neigh = neighbors.KNeighborsClassifier(n_neighbors = i).fit(X_trainscaled,Y_train)
    yhat = neigh.predict(X_testscaled)
    acc.append(metrics.accuracy_score(Y_test, yhat))
plt.figure(figsize=(10,6))
plt.plot(range(1,40),acc,color = 'blue',linestyle='dashed',
         marker='o',markerfacecolor='red', markersize=10)
plt.title('accuracy vs. K Value')
plt.xlabel('K')
plt.ylabel('Accuracy')
print("Maximum accuracy:-",max(acc),"at K =",acc.index(max(acc)))
plt.show()

############ Naive Bayes 朴素贝叶斯(种类多):多项式朴素贝叶斯(离散)高斯朴素贝叶斯(连续)
NB_G = GaussianNB().fit(X_trainscaled,Y_train)
NB_G = joblib.load("Hog_NB_G.dat")
accuracy_NBG = NB_G.score(X_testscaled,Y_test)
print("Hog特征之NB_G准确度%.2f%%" % (accuracy_NBG*100.0))
# joblib.dump(NB_G,"Hog_NB_G.dat")

About DT

决策树通过递归地进行特征选择,将训练集数据 D 进行分类最终生成一颗由节点和有向边组成的树结构。其中结点分为两种类型:内部节点和叶节点,内部结点表示一个特征,叶结点表示一个类别。

About k-nn

即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例,这K个实例的多数属于某个类,就把该输入实例分类到这个类中。(这就类似于现实生活中少数服从多数的思想

在这里插入图片描述

ps:关于分类器的算法的原理和理解很浅,希望后期可以多看原理,多看背后的数学逻辑,对适合数据的参数选择能力还不够,加油吧。

  • 2
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
OpenCV中实现图像分类SVM(支持向量机)是一种基于机器学习的算法,它需要使用一组已经标记的图像来训练模型,然后使用该模型对未知图像进行分类。 以下是实现SVM进行图像分类的基本步骤: 1. 收集数据集,包括用于训练和测试的图像。 2. 对每个图像进行特征提取,例如计算每个图像的颜色直方图、纹理、边缘等特征。 3. 将特征向量作为输入,将训练图像标记为相应的类别。训练数据集的样本应该在同一类别内相似,而不同类别之间应该有显著差异。 4. 使用OpenCV中的SVM模块对训练数据集进行训练,并调整模型参数以提高准确性。 5. 对测试数据集中的每个图像进行特征提取,并使用训练好的模型进行分类。 6. 计算分类准确率和召回率,并根据需求调整参数,以提高模型的性能。 下面是示例代码来实现基于OpenCVSVM进行图像分类。 ``` python import cv2 import numpy as np # 读取数据集图像及其标签 train_images = [] train_labels = [] test_images = [] test_labels = [] for i in range(1, 5): for j in range(1, 6): img = cv2.imread("dataset/%d/%d.png" % (i, j), cv2.IMREAD_GRAYSCALE) # 读取灰度图像 if j < 4: # 训练集前3张图像 train_images.append(img) train_labels.append(i) else: # 测试集后2张图像 test_images.append(img) test_labels.append(i) # 提取图像特征 hog = cv2.HOGDescriptor() train_features = np.array([hog.compute(img) for img in train_images], dtype=np.float32) test_features = np.array([hog.compute(img) for img in test_images], dtype=np.float32) # 训练SVM分类器 svm = cv2.ml.SVM_create() svm.setType(cv2.ml.SVM_C_SVC) svm.setKernel(cv2.ml.SVM_LINEAR) svm.setTermCriteria((cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 1000, 0.01)) svm.train(train_features, cv2.ml.ROW_SAMPLE, np.array(train_labels)) # 测试SVM分类器 ret, pred = svm.predict(test_features) # 计算分类准确率和召回率 accuracy = np.mean(pred.squeeze() == np.array(test_labels)) recall = np.mean(pred.squeeze() == np.array(test_labels)[np.array(test_labels) == 1]) print("Accuracy: %.2f%%" % (accuracy * 100)) print("Recall: %.2f%%" % (recall * 100)) ``` 该示例代码演示了如何使用OpenCVSVM实现图像分类。它使用了一个简单的数据集,由四个类别的图像(数字1-4)构成。图像特征采用HOG描述符,SVM类型为C-SVC,核函数为线性核,迭代停止条件为1000次或0.01的精度。在测试过程中,计算了分类准确率和召回率两个指标,以评估分类器的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shan_shmily

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值