基于OpenCV的图形分析辨认05

目录

一、前言

二、实验目的

三、实验内容

四、实验过程


一、前言

编程语言:Python,编程软件:vscode或pycharm,必备的第三方库:OpenCV,numpy,matplotlib,os等等。

关于OpenCV,numpy,matplotlib,os等第三方库的下载方式如下:

第一步,按住【Windows】和【R】调出运行界面,输入【cmd】,回车打开命令行。

第二步,输入以下安装命令(可以先升级一下pip指令)。

pip升级指令:

python -m pip install --upgrade pip

 opencv库的清华源下载:

pip install opencv-python  -i https://pypi.tuna.tsinghua.edu.cn/simple

numpy库的清华源下载:

 pip install numpy  -i https://pypi.tuna.tsinghua.edu.cn/simple

matplotlib库的清华源下载:

pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple

os库的清华源下载:

pip install os  -i https://pypi.tuna.tsinghua.edu.cn/simple 

二、实验目的

1.了解不同人脸特征算法;

2.了解不同建模方式;

3.基于人脸特征及建模方式,建立不同人脸识别模型;

三、实验内容

1.使用脸部图片,建立人脸识别模型

(1)分别使用LBP/LDP建立Global/Local case(包含不同尺度)的人脸特征

(2)分别使用Template matching / Clustering / SVM对Global/Local case(包含不同尺度)的人脸特建立识别模型

(3)结果必须包含: (1)部份特征图可视化结果(2)不同识别模型识别正确率 (3)各种特征/识别模型的结果分析与探讨

四、实验过程

图像的素材有40个人像,每个人有10张照片,其中有7张作为训练集,另外3张作为测试集,在此基础上,分成训练集文件夹【train】和测试集文件夹【test】。

根据LBP和LDP的原理编写代码,之后用LBP和LDP处理【train】文件和【test】文件得到的每个人像的特征数据,保存在【txt】文件中,并编写了相应的代码去读取特征数据文件的文件名和具体的特征数据。代码文件命名为【Methods】,代码如下:

import numpy as np
import os
import cv2

def LBP(img):
    dst = np.zeros(img.shape, dtype = img.dtype)  # 创建一个全零的数组dst,形状和数据类型与img相同
    height, width = img.shape  # 获取img的高度和宽度

    for i in range(1, height - 1):  # 遍历img的每一行,除了第一行和最后一行
        for j in range(1, width - 1):  # 遍历img的每一列,除了第一列和最后一列
            center = img[i][j]  # 获取当前像素点的灰度值
            code = 0  # 初始化code为0
            code |= (img[i-1][j-1] >= center) << (np.uint8)(7)  # 判断上方左方的像素点是否大于等于center,如果大于等于,则将1左移7位后异或到code上
            code |= (img[i-1][j  ] >= center) << (np.uint8)(6)  # 判断上方的像素点是否大于等于center,如果大于等于,则将1左移6位后异或到code上
            code |= (img[i-1][j+1] >= center) << (np.uint8)(5)  # 判断上方右方的像素点是否大于等于center,如果大于等于,则将1左移5位后异或到code上
            code |= (img[i  ][j+1] >= center) << (np.uint8)(4)  # 判断右方的像素点是否大于等于center,如果大于等于,则将1左移4位后异或到code上
            code |= (img[i+1][j+1] >= center) << (np.uint8)(3)  # 判断下方右方的像素点是否大于等于center,如果大于等于,则将1左移3位后异或到code上
            code |= (img[i+1][j  ] >= center) << (np.uint8)(2)  # 判断下方的像素点是否大于等于center,如果大于等于,则将1左移2位后异或到code上
            code |= (img[i+1][j-1] >= center) << (np.uint8)(1)  # 判断下方左方的像素点是否大于等于center,如果大于等于,则将1左移1位后异或到code上
            code |= (img[i  ][j-1] >= center) << (np.uint8)(0)  # 判断左方的像素点是否大于等于center,如果大于等于,则将1左移0位后异或到code上
            dst[i][j] = code  # 将code的值赋给dst的对应位置
    
    return dst  # 返回处理后的dst数组

def LDP(img):
    dst = np.zeros(img.shape, dtype = img.dtype)  # 创建一个全零的数组dst,形状和数据类型与img相同
    height, width = img.shape  # 获取img的高度和宽度
    threshold, result = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) # 对img进行阈值处理,使用OTSU二值化算法确定阈值

    for i in range(1, height - 1): # 遍历img的每一行,除了第一行和最后一行
        for j in range(1, width - 1):  # 遍历img的每一列,除了第一列和最后一列
            center = img[i][j]  # 获取当前像素点的灰度值
            code = 0  # 初始化code为0
            # 判断上下左右四个像素点与中心点的灰度差是否大于阈值,并将结果按位存入code中
            code |= ((img[i-1][j-1] - center) > threshold) << (np.uint8)(7)  
            code |= ((img[i-1][j  ] - center) > threshold) << (np.uint8)(6)  
            code |= ((img[i-1][j+1] - center) > threshold) << (np.uint8)(5)  
            code |= ((img[i  ][j+1] - center) > threshold) << (np.uint8)(4)  
            code |= ((img[i+1][j+1] - center) > threshold) << (np.uint8)(3)  
            code |= ((img[i+1][j  ] - center) > threshold) << (np.uint8)(2)  
            code |= ((img[i+1][j-1] - center) > threshold) << (np.uint8)(1)  
            code |= ((img[i  ][j-1] - center) > threshold) << (np.uint8)(0)  
            dst[i][j] = code  # 将code的值赋给dst的对应位置

    return dst  # 返回处理后的dst数组

def train_txt_read(img_train_path):
    # 读取训练集文本文件,将内容存储到train_list中
    train_list = []

    with open(img_train_path, 'r') as f:
        for line in f.readlines():
            line = line.strip('\n')  # 去除每行末尾的换行符
            line = eval(line)  # 对line进行求值操作
            train = []
            for i in line[1]:
                i = int(i)  # 将每个元素转换为整数类型
                train.append(i)  # 将转换后的元素添加到train列表中
            train_list.append(train)  # 将train列表添加到train_list列表中
    
    return train_list  

def test_txt_read(img_test_path):
    # 读取测试集文本文件,将内容存储到test_list中
    test_list = []

    with open(img_test_path, 'r') as f:
        for line in f.readlines():
            line = line.strip('\n')  # 去除每行末尾的换行符
            line = eval(line)  # 对line进行求值操作
            test = []
            for i in line[1]:
                i = int(i) # 将每个元素转换为整数类型
                test.append(i) # 将转换后的元素添加到test列表中
            test_list.append(test) # 将test列表添加到test_list列表中
    
    return test_list

def train_name_read(image_train_path):
    # 读取训练集路径下的所有图像文件,提取文件名并返回名称列表
    image_train_list = os.listdir(image_train_path)
    train_name = []
    
    for i in image_train_list:
        i = i.split('.')[0]
        train_name.append(i)
    
    return train_name

def test_name_read(image_test_path):
    # 读取测试集路径下的所有图像文件,提取文件名并返回名称列表
    image_test_list = os.listdir(image_test_path)
    test_name = []
    
    for i in image_test_list:
        i = i.split('.')[0]
        test_name.append(i)
    
    return test_name

Global Case:

先是利用LBP代码提取每一张图像的特征数据,然后绘制在txt文件中,对训练集和测试集的特征提取代码如下:

import cv2
import os
from Methods import *

def train_txt():
    # 训练集txt文件生成函数
    image_path = r"D:\Image\train"  # 图像路径
    image_list = os.listdir(image_path)  # 获取图像列表
    file = open(r"D:\Image\GC_LBP_train.txt", "w")  # 打开训练集txt文件

    for i in image_list:
        result_list = [[], []]  # 结果列表,每个图像分为两个列表:图像名和LBP直方图
        image_name = i.split(".")[0]  # 获取图像名
        result_list[0].append(image_name)  # 将图像名加入结果列表
        img_path = os.path.join(image_path, i)  # 图像完整路径
        img = cv2.imread(img_path)  # 读取图像
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图像
        img_LBP = LBP(img_gray)  # 计算LBP
        img_hist = cv2.calcHist([img_LBP], [0], None, [256], [0, 256])  # 计算LBP直方图
        for j in img_hist:
            result_list[1].append(int(j[0]))  # 将直方图中的每个像素值加入结果列表
        file.write(str(result_list) + "\n")  # 将结果写入txt文件
    
    print("train.txt已完成")  # 打印完成信息
    file.close()  # 关闭文件

def test_txt():
    # 测试集txt文件生成函数
    image_path = r"D:\Image\test"  # 图像路径
    image_list = os.listdir(image_path)  # 获取图像列表
    file = open(r"D:\Image\GC_LBP_test.txt", "w")  # 打开测试集txt文件

    for i in image_list:
        result_list = [[], []]  # 结果列表,每个图像分为两个列表:图像名和LBP直方图
        image_name = i.split(".")[0]  # 获取图像名
        result_list[0].append(image_name)  # 将图像名加入结果列表
        img_path = os.path.join(image_path, i)  # 图像完整路径
        img = cv2.imread(img_path)  # 读取图像
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图像
        img_LBP = LBP(img_gray)  # 计算LBP
        img_hist = cv2.calcHist([img_LBP], [0], None, [256], [0, 256])  # 计算LBP直方图
        for j in img_hist:
            result_list[1].append(int(j[0]))  # 将直方图中的每个像素值加入结果列表
        file.write(str(result_list) + "\n")  # 将结果写入txt文件
    
    print("test.txt已完成")  # 打印完成信息
    file.close()  # 关闭文件

train_txt()  # 调用train_txt函数生成训练集txt文件
test_txt()  # 调用test_txt函数生成测试集txt文件

生成如下的txt文件(训练集和测试集):

使用Template matching来检验识别的准确率:

代码如下:

import numpy as np
import os
from Methods import *

# 训练图片路径
img_train_path = r"D:\Image\GC_LBP_train.txt"
# 测试图片路径
img_test_path = r"D:\Image\GC_LBP_test.txt"
# 读取训练集文本文件
train_list = train_txt_read(img_train_path)
# 读取测试集文本文件
test_list = test_txt_read(img_test_path)

# 结果索引列表
result_index = []
# 遍历测试集
for i in test_list:
    # 差值列表
    diff_list = []
    # 遍历训练集
    for j in train_list:
        # 计算两个图片数组的差值
        diff = sum(abs(np.array(i) - np.array(j)))
        diff_list.append(diff)
    # 获取差值最小值的索引
    diff_min = min(diff_list)
    diff_min_index = diff_list.index(diff_min)
    # 将最小差值的索引添加到结果索引列表中
    result_index.append(diff_min_index)

# 读取训练集图片名称
train_name = train_name_read(r"D:\Image\train")
# 读取测试集图片名称
test_name = test_name_read(r"D:\Image\test")

# 结果列表
test_result = []
# 遍历结果索引列表
for i in result_index:
    # 获取与训练集图片名称匹配的索引值并添加到结果列表中
    test_result.append(train_name[i])

# 比较结果列表
compare_result = []
# 遍历测试结果
for i in range(len(test_result)):
    # 打印测试图片及对应训练图片
    print(f"测试图片:{test_name[i]}对应训练图片:{test_result[i]}")
    # 判断训练图片的名称是否与测试图片的名称的首个单词相同
    if test_result[i].split('_')[0] == test_name[i].split('_')[0]:
        compare_result.append(1)
    else:
        compare_result.append(0)

# 打印识别准确率
print(f"识别准确率:{(compare_result.count(1) / len(compare_result)) * 100}%")

运行效果如下:

为了直观的查看识别效果,编写代码用于将结果可视化,代码如下: 

import cv2
import numpy as np
import matplotlib.pyplot as plt
from Methods import *

def LBP_example_GC():
    image = cv2.imread(r"D:\Image\test\44_0.jpg") # 读取图像
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 将彩色图像转为灰度图像
    image_LBP = LBP(image_gray) # 计算LBP图像
    hist = cv2.calcHist([image_LBP], [0], None, [256], [0, 256]) # 计算直方图
    print(hist.ravel())
    # 显示原始图像, 显示灰度图像, 显示LBP图像, 显示直方图
    plt.subplot(2, 2, 1), plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)), plt.title('Original Image'), plt.axis('off')
    plt.subplot(2, 2, 2), plt.imshow(image_gray, cmap = 'gray'), plt.title('Gray Image'), plt.axis('off')
    plt.subplot(2, 2, 3), plt.imshow(image_LBP, cmap = 'gray'), plt.title('LBP Image'), plt.axis('off')
    plt.subplot(2, 2, 4), plt.plot(hist, color = 'skyblue'), plt.title('Histogram')
    plt.tight_layout() # 调整子图布局
    plt.show() # 显示图像

def LDP_example_GC(): 
    image = cv2.imread(r"D:\Image\test\6_1.jpg") # 读取图像
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 将彩色图像转为灰度图像
    image_LDP = LDP(image_gray) # 计算LDP图像
    hist = cv2.calcHist([image_LDP], [0], None, [256], [0, 256]) # 计算直方图
    print(hist.ravel())
    # 显示原始图像, 显示灰度图像, 显示LDP图像, 显示直方图
    plt.subplot(2, 2, 1), plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)), plt.title('Original Image'), plt.axis('off')
    plt.subplot(2, 2, 2), plt.imshow(image_gray, cmap = 'gray'), plt.title('Gray Image'), plt.axis('off')
    plt.subplot(2, 2, 3), plt.imshow(image_LDP, cmap = 'gray'), plt.title('LDP Image'), plt.axis('off')
    plt.subplot(2, 2, 4), plt.plot(hist, color = 'skyblue'), plt.title('Histogram')
    plt.tight_layout() # 调整子图布局
    plt.show() # 显示图像

def LBP_example_LC():
    # 读取图像
    image = cv2.imread(r"D:\Image\train\12_0.png")
    # 将图像转为灰度图像
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 获取图像的高度和宽度
    height, width = image_gray.shape
    # 计算LBP图像
    image_LBP = LBP(image_gray)
    # 定义四个子图像的范围
    x1, x2, x3 = 0, int(width / 2), int(width)
    y1, y2, y3 = 0, int(height / 2), int(height)
    # 切割四个子图像
    image_LBP_1 = image_LBP[y1:y2, x1:x2]
    image_LBP_2 = image_LBP[y1:y2, x2:x3]
    image_LBP_3 = image_LBP[y2:y3, x1:x2]
    image_LBP_4 = image_LBP[y2:y3, x2:x3]
    # 计算四个子图像的直方图
    hist_1 = cv2.calcHist([image_LBP_1], [0], None, [256], [0, 256])
    hist_2 = cv2.calcHist([image_LBP_2], [0], None, [256], [0, 256])
    hist_3 = cv2.calcHist([image_LBP_3], [0], None, [256], [0, 256])
    hist_4 = cv2.calcHist([image_LBP_4], [0], None, [256], [0, 256])
    # 展示四个子图像和它们的直方图
    plt.subplot(2, 4, 1), plt.imshow(image_LBP_1, cmap='gray'), plt.axis('off')
    plt.subplot(2, 4, 2), plt.imshow(image_LBP_2, cmap='gray'), plt.axis('off')
    plt.subplot(2, 4, 3), plt.imshow(image_LBP_3, cmap='gray'), plt.axis('off')
    plt.subplot(2, 4, 4), plt.imshow(image_LBP_4, cmap='gray'), plt.axis('off')
    plt.subplot(2, 4, 5), plt.plot(hist_1)
    plt.subplot(2, 4, 6), plt.plot(hist_2)
    plt.subplot(2, 4, 7), plt.plot(hist_3)
    plt.subplot(2, 4, 8), plt.plot(hist_4)
    plt.tight_layout()
    plt.show()

def LDP_example_LC():
    # 读取图像
    image = cv2.imread(r"D:\Image\train\12_0.png")
    # 将图像转为灰度图像
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 获取图像的高度和宽度
    height, width = image_gray.shape
    # 计算LDP图像
    image_LDP = LDP(image_gray)
    # 定义四个子图像的范围
    x1, x2, x3 = 0, int(width / 2), int(width)
    y1, y2, y3 = 0, int(height / 2), int(height)
    # 切割四个子图像
    image_LDP_1 = image_LDP[y1:y2, x1:x2]
    image_LDP_2 = image_LDP[y1:y2, x2:x3]
    image_LDP_3 = image_LDP[y2:y3, x1:x2]
    image_LDP_4 = image_LDP[y2:y3, x2:x3]
    # 计算四个子图像的直方图
    hist_1 = cv2.calcHist([image_LDP_1], [0], None, [256], [0, 256])
    hist_2 = cv2.calcHist([image_LDP_2], [0], None, [256], [0, 256])
    hist_3 = cv2.calcHist([image_LDP_3], [0], None, [256], [0, 256])
    hist_4 = cv2.calcHist([image_LDP_4], [0], None, [256], [0, 256])
    # 展示四个子图像和它们的直方图
    plt.subplot(2, 4, 1), plt.imshow(image_LDP_1, cmap='gray'), plt.axis('off')
    plt.subplot(2, 4, 2), plt.imshow(image_LDP_2, cmap='gray'), plt.axis('off')
    plt.subplot(2, 4, 3), plt.imshow(image_LDP_3, cmap='gray'), plt.axis('off')
    plt.subplot(2, 4, 4), plt.imshow(image_LDP_4, cmap='gray'), plt.axis('off')
    plt.subplot(2, 4, 5), plt.plot(hist_1)
    plt.subplot(2, 4, 6), plt.plot(hist_2)
    plt.subplot(2, 4, 7), plt.plot(hist_3)
    plt.subplot(2, 4, 8), plt.plot(hist_4)
    plt.tight_layout()
    plt.show()

# LBP_example_GC()
# LDP_example_GC()
LBP_example_LC()
LDP_example_LC()

以上是作者从网上搜索到的图片,在清晰度上有欠缺。展示的用LBP算法提取的人脸特征数据。

使用Clustering检验识别的准确率,代码如下:

import cv2
import numpy as np
import os
from Methods import *

# 载入训练集和测试集的路径
img_train_path = r"D:\Image\GC_LBP_train.txt"
img_test_path = r"D:\Image\GC_LBP_test.txt"

# 读取训练集和测试集的文本文件,并转化为numpy数组
train_list = train_txt_read(img_train_path)  # 读取训练集文本文件
test_list = test_txt_read(img_test_path)  # 读取测试集文本文件
train_data = np.array(train_list)  # 将训练集转化为numpy数组
test_data = np.array(test_list)  # 将测试集转化为numpy数组

# 将训练集和测试集的数组重塑为指定的形状
train_data = train_data.reshape((-1, 256))  # 将训练集数组重塑为256列的矩阵
test_data = test_data.reshape((-1, 256))  # 将测试集数组重塑为256列的矩阵

# 将训练集和测试集的数组转换为float32类型
train_data = np.float32(train_data)  # 将训练集数组转换为float32类型
test_data = np.float32(test_data)  # 将测试集数组转换为float32类型

# 定义k-means算法的终止条件、分配新点到初始中心点的方法和迭代最大次数
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 1000, 0.001)
flags = cv2.KMEANS_RANDOM_CENTERS
K = 46

# 使用k-means算法对训练集进行聚类
ret, train_label, train_center = cv2.kmeans(train_data, K, None, criteria, 100, flags)

# 将训练集的标签按组进行重塑,并得到在每组中出现次数最多的标签
train_label_group = train_label.reshape(-1, 7)
frequent_result = []
for group in train_label_group:
    most_frequent_num = np.bincount(group).argmax()  # 在每组中找到出现次数最多的标签
    frequent_result.append(most_frequent_num)  # 将出现次数最多的标签添加到列表中

# 计算测试集与每个聚类中心的距离,并将测试集归一化到最接近的聚类中心
test_distances = np.sqrt(((test_data[:, np.newaxis] - train_center) ** 2).sum(axis=2))  # 计算测试集与每个聚类中心的距离
test_labels = np.argmin(test_distances, axis=1)  # 将测试集归一化到最接近的聚类中心

test_labels_three = test_labels.reshape(-1, 3)  # 将测试集标签按组进行重塑

# 比较测试集的标签和最频繁出现的标签,并计算识别准确率
compare_result = []
for i in range(len(test_labels_three)):
    test_label = test_labels_three[i]
    for j in test_label:
        if j == frequent_result[i]:
            compare_result.append(1)  # 测试集的标签与最频繁出现的标签相同,识别正确
        else:
            compare_result.append(0)  # 测试集的标签与最频繁出现的标签不同,识别错误

test_name = test_name_read(r"D:\Image\test")  # 读取测试集的文件名
for i in range(len(test_name)):
    print(f"测试图片:{test_name[i]} 对应最近邻聚类中心标签:{test_labels[i]}")  # 打印每张测试图片及其对应的最近邻聚类中心标签

print(f"识别准确率:{(compare_result.count(1) / len(compare_result)) * 100}%")  # 计算并打印识别准确率

代码运行结果:

利用LDP代码提取的特征数据如下,代码如下:

import cv2
import os
from Methods import *

def train_txt():
    # 训练集txt文件生成函数
    image_path = r"D:\Image\train"  # 图像路径
    image_list = os.listdir(image_path)  # 获取图像列表
    file = open(r"D:\Image\GC_LDP_train.txt", "w")  # 打开训练集txt文件

    for i in image_list:
        result_list = [[], []]  # 初始化结果列表
        image_name = i.split(".")[0]  # 获取图像文件名
        result_list[0].append(image_name)  # 将图像文件名加入结果列表的第一个元素
        img_path = os.path.join(image_path, i)  # 获取图像完整路径
        img = cv2.imread(img_path)  # 读取图像
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 将图像转为灰度图
        img_LDP = LDP(img_gray)  # 计算图像的LDP特征
        img_hist = cv2.calcHist([img_LDP], [0], None, [256], [0, 256])  # 计算LDP特征的直方图
        for j in img_hist:
            result_list[1].append(int(j[0]))  # 将直方图中的像素值加入结果列表的第二个元素
        file.write(str(result_list) + "\n")  # 将结果写入训练集txt文件
    
    print("train.txt已完成")  # 打印训练集txt文件已完成
    file.close()  # 关闭训练集txt文件

def test_txt():
    # 测试集txt文件生成函数
    image_path = r"D:\Image\test"  # 图像路径
    image_list = os.listdir(image_path)  # 获取图像列表
    file = open(r"D:\Image\GC_LDP_test.txt", "w")  # 打开测试集txt文件

    for i in image_list:
        result_list = [[], []]  # 初始化结果列表
        image_name = i.split(".")[0]  # 获取图像文件名
        result_list[0].append(image_name)  # 将图像文件名加入结果列表的第一个元素
        img_path = os.path.join(image_path, i)  # 获取图像完整路径
        img = cv2.imread(img_path)  # 读取图像
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 将图像转为灰度图
        img_LDP = LDP(img_gray)  # 计算图像的LDP特征
        img_hist = cv2.calcHist([img_LDP], [0], None, [256], [0, 256])  # 计算LDP特征的直方图
        for j in img_hist:
            result_list[1].append(int(j[0]))  # 将直方图中的像素值加入结果列表的第二个元素
        file.write(str(result_list) + "\n")  # 将结果写入测试集txt文件
    
    print("test.txt已完成")  # 打印测试集txt文件已完成
    file.close()  # 关闭测试集txt文件

train_txt()  # 调用train_txt函数
test_txt()  # 调用test_txt函数

运行效果如下:

使用Template matching来检验识别的准确率,代码如下:

import numpy as np
import os
from Methods import *

# 训练图片路径
img_train_path = r"D:\Image\GC_LDP_train.txt"
# 测试图片路径
img_test_path = r"D:\Image\GC_LDP_test.txt"
# 读取训练集文本文件,返回图片列表
train_list = train_txt_read(img_train_path)
# 读取测试集文本文件,返回图片列表
test_list = test_txt_read(img_test_path)

# 结果索引列表
result_index = []
# 对于测试集中的每一张图片
for i in test_list:
    # 差值列表
    diff_list = []
    # 对于训练集中的每一张图片
    for j in train_list:
        # 计算两张图片像素差值的绝对值之和
        diff = sum(abs(np.array(i) - np.array(j)))
        diff_list.append(diff)
    # 获取差值最小值的索引
    diff_min = min(diff_list)
    diff_min_index = diff_list.index(diff_min)
    # 将最小差值的索引添加到结果索引列表中
    result_index.append(diff_min_index)

# 读取训练集图片名称列表
train_name = train_name_read(r"D:\Image\train")
# 读取测试集图片名称列表
test_name = test_name_read(r"D:\Image\test")

# 结果列表
test_result = []
# 对于结果索引列表中的每个索引
for i in result_index:
    # 将对应索引训练集图片名称添加到结果列表中
    test_result.append(train_name[i])

# 比较结果列表
compare_result = []
# 对于结果列表中的每一张图片
for i in range(len(test_result)):
    # 打印测试图片名称和对应训练图片名称
    print(f"测试图片:{test_name[i]}对应训练图片:{test_result[i]}")
    # 如果训练图片名称与测试图片名称的前缀相同,则将比较结果添加为1,否则为0
    if test_result[i].split('_')[0] == test_name[i].split('_')[0]:
        compare_result.append(1)
    else:
        compare_result.append(0)

# 打印识别准确率
print(f"识别准确率:{(compare_result.count(1) / len(compare_result)) * 100}%")

 代码运行效果如下:

结果可视化可以使用上面的可视化代码,那个代码文件里较为齐全。 

使用Clustering检验识别的准确率,代码如下:

import cv2
import numpy as np
import os
from Methods import *

# 载入训练集和测试集的文件路径
img_train_path = r"D:\Image\GC_LDP_train.txt"
img_test_path = r"D:\Image\GC_LDP_test.txt"

# 读取训练集和测试集的文件,并将其转化为NumPy数组
train_list = train_txt_read(img_train_path)  # 读取训练集文件
test_list = test_txt_read(img_test_path)  # 读取测试集文件
train_data = np.array(train_list)  # 将训练集转化为NumPy数组
test_data = np.array(test_list)  # 将测试集转化为NumPy数组

# 将训练集和测试集的数组形状改变为指定的形状,这里将其改变为256行的形状
train_data = train_data.reshape((-1, 256))  # 调整训练集形状
test_data = test_data.reshape((-1, 256))  # 调整测试集形状

# 将训练集和测试集的数组转化为浮点数类型
train_data = np.float32(train_data)  # 转化为浮点数类型
test_data = np.float32(test_data)  # 转化为浮点数类型

# 定义K-means算法的停止条件和聚类中心的初始化方式
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 1000, 0.001)  # 停止条件
flags = cv2.KMEANS_RANDOM_CENTERS  # 聚类中心的初始化方式

# 选择要聚类的类别的个数
K = 46

# 使用K-means算法对训练集进行聚类,得到聚类结果和聚类中心
ret, train_label, train_center = cv2.kmeans(train_data, K, None, criteria, 100, flags)

# 将训练集的聚类结果reshape为7行的形状,得到每个样本的7个类别的标签
train_label_group = train_label.reshape(-1, 7)

# 初始化聚类结果的列表
frequent_result = []

# 遍历每个样本的7个类别标签,计算每个类别中出现频率最高的标签,并将其添加到frequent_result列表中
for group in train_label_group:
    most_frequent_num = np.bincount(group).argmax()
    frequent_result.append(most_frequent_num)

# 计算测试集与每个聚类中心的距离,并根据距离选择最近的聚类中心的标签
test_distances = np.sqrt(((test_data[:, np.newaxis] - train_center) ** 2).sum(axis=2))
test_labels = np.argmin(test_distances, axis=1)

# 将测试集的最近邻聚类中心标签reshape为3行的形状,得到每个样本的3个标签
test_labels_three = test_labels.reshape(-1, 3)

# 初始化识别结果的列表
compare_result = []

# 遍历每个样本的3个标签,将其与frequent_result中对应的7个标签进行比较,得到识别结果并添加到compare_result列表中
for i in range(len(test_labels_three)):
    test_label = test_labels_three[i]
    for j in test_label:
        if j == frequent_result[i]:
            compare_result.append(1)
        else:
            compare_result.append(0)

# 读取测试集的文件名,并输出每个测试图片的名称、最近邻聚类中心的标签
test_name = test_name_read(r"D:\Image\test")
for i in range(len(test_name)):
    print(f"测试图片:{test_name[i]} 对应最近邻聚类中心标签:{test_labels[i]}")

# 计算识别准确率并输出
print(f"识别准确率:{(compare_result.count(1) / len(compare_result)) * 100}%") 

代码运行效果如下:

Local Case:

Local Case是在Global Case的基础上增加了一个图像的分割,分别得到特征数据。

对于LBP算法和LDP算法的特征提取基本与上文一致,故在这里不做过多赘述,代码如下:

import cv2
import os
from Methods import *

def train_txt():
    # 训练集txt文件生成函数
    image_path = r"D:\Image\train"  # 图像路径
    image_list = os.listdir(image_path)  # 获取图像列表
    file = open(r"D:\Image\LC_LBP_train.txt", "w")  # 打开训练集txt文件

    for i in image_list:
        result_list = [[], []]  # 结果列表,每个图像分为两个列表:图像名和LBP直方图
        image_name = i.split(".")[0]  # 获取图像名
        result_list[0].append(image_name)  # 将图像名加入结果列表
        img_path = os.path.join(image_path, i)  # 图像完整路径
        img = cv2.imread(img_path)  # 读取图像
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图像
        img_LBP = LBP(img_gray)  # 计算LBP
        width, height = img_LBP.shape  # 获取图像的宽度和高度
        x1, x2, x3 = 0, int(width / 2), int(width)  # 计算三个边界点的x坐标
        y1, y2, y3 = 0, int(height / 2), int(height)  # 计算三个边界点的y坐标
        image_LBP_1 = img_LBP[y1:y2, x1:x2]  # 截取第一个子图像
        image_LBP_2 = img_LBP[y1:y2, x2:x3]  # 截取第二个子图像
        image_LBP_3 = img_LBP[y2:y3, x1:x2]  # 截取第三个子图像
        image_LBP_4 = img_LBP[y2:y3, x2:x3]  # 截取第四个子图像
        hist_1 = cv2.calcHist([image_LBP_1], [0], None, [256], [0, 256])  # 计算第一个子图像的直方图
        hist_2 = cv2.calcHist([image_LBP_2], [0], None, [256], [0, 256])  # 计算第二个子图像的直方图
        hist_3 = cv2.calcHist([image_LBP_3], [0], None, [256], [0, 256])  # 计算第三个子图像的直方图
        hist_4 = cv2.calcHist([image_LBP_4], [0], None, [256], [0, 256])  # 计算第四个子图像的直方图
        img_hist = hist_1 + hist_2 + hist_3 + hist_4  # 计算四个子图像的直方图总和
        for j in img_hist:
            result_list[1].append(int(j[0]))  # 将直方图中的每个像素值加入结果列表
        file.write(str(result_list) + "\n")  # 将结果写入txt文件
    
    print("train.txt已完成")  # 打印完成信息
    file.close()  # 关闭文件

def test_txt():
    # 测试集txt文件生成函数
    image_path = r"D:\Image\test"  # 图像路径
    image_list = os.listdir(image_path)  # 获取图像列表
    file = open(r"D:\Image\LC_LBP_test.txt", "w")  # 打开测试集txt文件

    for i in image_list:
        result_list = [[], []]  # 结果列表,每个图像分为两个列表:图像名和LBP直方图
        image_name = i.split(".")[0]  # 获取图像名
        result_list[0].append(image_name)  # 将图像名加入结果列表
        img_path = os.path.join(image_path, i)  # 图像完整路径
        img = cv2.imread(img_path)  # 读取图像
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图像
        img_LBP = LBP(img_gray)  # 计算LBP
        width, height = img_LBP.shape  # 获取图像的宽度和高度
        x1, x2, x3 = 0, int(width / 2), int(width)  # 计算三个边界点的x坐标
        y1, y2, y3 = 0, int(height / 2), int(height)  # 计算三个边界点的y坐标
        image_LBP_1 = img_LBP[y1:y2, x1:x2]  # 截取第一个子图像
        image_LBP_2 = img_LBP[y1:y2, x2:x3]  # 截取第二个子图像
        image_LBP_3 = img_LBP[y2:y3, x1:x2]  # 截取第三个子图像
        image_LBP_4 = img_LBP[y2:y3, x2:x3]  # 截取第四个子图像
        hist_1 = cv2.calcHist([image_LBP_1], [0], None, [256], [0, 256])  # 计算第一个子图像的直方图
        hist_2 = cv2.calcHist([image_LBP_2], [0], None, [256], [0, 256])  # 计算第二个子图像的直方图
        hist_3 = cv2.calcHist([image_LBP_3], [0], None, [256], [0, 256])  # 计算第三个子图像的直方图
        hist_4 = cv2.calcHist([image_LBP_4], [0], None, [256], [0, 256])  # 计算第四个子图像的直方图
        img_hist = hist_1 + hist_2 + hist_3 + hist_4  # 计算四个子图像的直方图总和
        for j in img_hist:
            result_list[1].append(int(j[0]))  # 将直方图中的每个像素值加入结果列表
        file.write(str(result_list) + "\n")  # 将结果写入txt文件
    
    print("test.txt已完成")  # 打印完成信息
    file.close()  # 关闭文件

train_txt()  # 调用train_txt函数生成训练集txt文件
test_txt()  # 调用test_txt函数生成测试集txt文件
import cv2
import os
from Methods import *

def train_txt():
    # 训练集txt文件生成函数
    image_path = r"D:\Image\train"  # 图像路径
    image_list = os.listdir(image_path)  # 获取图像列表
    file = open(r"D:\Image\LC_LDP_train.txt", "w")  # 打开训练集txt文件

    for i in image_list:
        result_list = [[], []]  # 结果列表,每个图像分为两个列表:图像名和LDP直方图
        image_name = i.split(".")[0]  # 获取图像名
        result_list[0].append(image_name)  # 将图像名加入结果列表
        img_path = os.path.join(image_path, i)  # 图像完整路径
        img = cv2.imread(img_path)  # 读取图像
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图像
        img_LDP = LDP(img_gray)  # 计算LDP
        width, height = img_LDP.shape  # 获取图像的宽度和高度
        x1, x2, x3 = 0, int(width / 2), int(width)  # 计算三个边界点的x坐标
        y1, y2, y3 = 0, int(height / 2), int(height)  # 计算三个边界点的y坐标
        image_LDP_1 = img_LDP[y1:y2, x1:x2]  # 截取第一个子图像
        image_LDP_2 = img_LDP[y1:y2, x2:x3]  # 截取第二个子图像
        image_LDP_3 = img_LDP[y2:y3, x1:x2]  # 截取第三个子图像
        image_LDP_4 = img_LDP[y2:y3, x2:x3]  # 截取第四个子图像
        hist_1 = cv2.calcHist([image_LDP_1], [0], None, [256], [0, 256])  # 计算第一个子图像的直方图
        hist_2 = cv2.calcHist([image_LDP_2], [0], None, [256], [0, 256])  # 计算第二个子图像的直方图
        hist_3 = cv2.calcHist([image_LDP_3], [0], None, [256], [0, 256])  # 计算第三个子图像的直方图
        hist_4 = cv2.calcHist([image_LDP_4], [0], None, [256], [0, 256])  # 计算第四个子图像的直方图
        img_hist = hist_1 + hist_2 + hist_3 + hist_4  # 计算四个子图像的直方图总和
        for j in img_hist:
            result_list[1].append(int(j[0]))  # 将直方图中的每个像素值加入结果列表
        file.write(str(result_list) + "\n")  # 将结果写入txt文件
    
    print("train.txt已完成")  # 打印完成信息
    file.close()  # 关闭文件

def test_txt():
    # 测试集txt文件生成函数
    image_path = r"D:\Image\test"  # 图像路径
    image_list = os.listdir(image_path)  # 获取图像列表
    file = open(r"D:\Image\LC_LDP_test.txt", "w")  # 打开测试集txt文件

    for i in image_list:
        result_list = [[], []]  # 结果列表,每个图像分为两个列表:图像名和LDP直方图
        image_name = i.split(".")[0]  # 获取图像名
        result_list[0].append(image_name)  # 将图像名加入结果列表
        img_path = os.path.join(image_path, i)  # 图像完整路径
        img = cv2.imread(img_path)  # 读取图像
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图像
        img_LDP = LDP(img_gray)  # 计算LDP
        width, height = img_LDP.shape  # 获取图像的宽度和高度
        x1, x2, x3 = 0, int(width / 2), int(width)  # 计算三个边界点的x坐标
        y1, y2, y3 = 0, int(height / 2), int(height)  # 计算三个边界点的y坐标
        image_LDP_1 = img_LDP[y1:y2, x1:x2]  # 截取第一个子图像
        image_LDP_2 = img_LDP[y1:y2, x2:x3]  # 截取第二个子图像
        image_LDP_3 = img_LDP[y2:y3, x1:x2]  # 截取第三个子图像
        image_LDP_4 = img_LDP[y2:y3, x2:x3]  # 截取第四个子图像
        hist_1 = cv2.calcHist([image_LDP_1], [0], None, [256], [0, 256])  # 计算第一个子图像的直方图
        hist_2 = cv2.calcHist([image_LDP_2], [0], None, [256], [0, 256])  # 计算第二个子图像的直方图
        hist_3 = cv2.calcHist([image_LDP_3], [0], None, [256], [0, 256])  # 计算第三个子图像的直方图
        hist_4 = cv2.calcHist([image_LDP_4], [0], None, [256], [0, 256])  # 计算第四个子图像的直方图
        img_hist = hist_1 + hist_2 + hist_3 + hist_4  # 计算四个子图像的直方图总和
        for j in img_hist:
            result_list[1].append(int(j[0]))  # 将直方图中的每个像素值加入结果列表
        file.write(str(result_list) + "\n")  # 将结果写入txt文件
    
    print("test.txt已完成")  # 打印完成信息
    file.close()  # 关闭文件

train_txt()  # 调用train_txt函数生成训练集txt文件
test_txt()  # 调用test_txt函数生成测试集txt文件

得到的txt文件如下:

对于Template matching和Clustering也和前文一致,在这里也不做过多赘述,运行相应的代码文件即可。

LBP下的Template matching和Clustering,代码如下:

import numpy as np
import os
from Methods import *

# 训练图片路径
img_train_path = r"D:\Image\LC_LBP_train.txt"
# 测试图片路径
img_test_path = r"D:\Image\LC_LBP_test.txt"
# 读取训练集文本文件
train_list = train_txt_read(img_train_path)
# 读取测试集文本文件
test_list = test_txt_read(img_test_path)

# 结果索引列表
result_index = []
# 遍历测试集
for i in test_list:
    # 差值列表
    diff_list = []
    # 遍历训练集
    for j in train_list:
        # 计算两个图片数组的差值
        diff = sum(abs(np.array(i) - np.array(j)))
        diff_list.append(diff)
    # 获取差值最小值的索引
    diff_min = min(diff_list)
    diff_min_index = diff_list.index(diff_min)
    # 将最小差值的索引添加到结果索引列表中
    result_index.append(diff_min_index)

# 读取训练集图片名称
train_name = train_name_read(r"D:\Image\train")
# 读取测试集图片名称
test_name = test_name_read(r"D:\Image\test")

# 结果列表
test_result = []
# 遍历结果索引列表
for i in result_index:
    # 获取与训练集图片名称匹配的索引值并添加到结果列表中
    test_result.append(train_name[i])

# 比较结果列表
compare_result = []
# 遍历测试结果
for i in range(len(test_result)):
    # 打印测试图片及对应训练图片
    print(f"测试图片:{test_name[i]}对应训练图片:{test_result[i]}")
    # 判断训练图片的名称是否与测试图片的名称的首个单词相同
    if test_result[i].split('_')[0] == test_name[i].split('_')[0]:
        compare_result.append(1)
    else:
        compare_result.append(0)

# 打印识别准确率
print(f"识别准确率:{(compare_result.count(1) / len(compare_result)) * 100}%")
import cv2
import numpy as np
import os
from Methods import *

# 载入训练集和测试集的路径
img_train_path = r"D:\Image\LC_LBP_train.txt"
img_test_path = r"D:\Image\LC_LBP_test.txt"

# 读取训练集和测试集的文本文件,并转化为numpy数组
train_list = train_txt_read(img_train_path)  # 读取训练集文本文件
test_list = test_txt_read(img_test_path)  # 读取测试集文本文件
train_data = np.array(train_list)  # 将训练集转化为numpy数组
test_data = np.array(test_list)  # 将测试集转化为numpy数组

# 将训练集和测试集的数组重塑为指定的形状
train_data = train_data.reshape((-1, 256))  # 将训练集数组重塑为256列的矩阵
test_data = test_data.reshape((-1, 256))  # 将测试集数组重塑为256列的矩阵

# 将训练集和测试集的数组转换为float32类型
train_data = np.float32(train_data)  # 将训练集数组转换为float32类型
test_data = np.float32(test_data)  # 将测试集数组转换为float32类型

# 定义k-means算法的终止条件、分配新点到初始中心点的方法和迭代最大次数
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 1000, 0.001)
flags = cv2.KMEANS_RANDOM_CENTERS
K = 46

# 使用k-means算法对训练集进行聚类
ret, train_label, train_center = cv2.kmeans(train_data, K, None, criteria, 100, flags)

# 将训练集的标签按组进行重塑,并得到在每组中出现次数最多的标签
train_label_group = train_label.reshape(-1, 7)
frequent_result = []
for group in train_label_group:
    most_frequent_num = np.bincount(group).argmax()  # 在每组中找到出现次数最多的标签
    frequent_result.append(most_frequent_num)  # 将出现次数最多的标签添加到列表中

# 计算测试集与每个聚类中心的距离,并将测试集归一化到最接近的聚类中心
test_distances = np.sqrt(((test_data[:, np.newaxis] - train_center) ** 2).sum(axis=2))  # 计算测试集与每个聚类中心的距离
test_labels = np.argmin(test_distances, axis=1)  # 将测试集归一化到最接近的聚类中心

test_labels_three = test_labels.reshape(-1, 3)  # 将测试集标签按组进行重塑

# 比较测试集的标签和最频繁出现的标签,并计算识别准确率
compare_result = []
for i in range(len(test_labels_three)):
    test_label = test_labels_three[i]
    for j in test_label:
        if j == frequent_result[i]:
            compare_result.append(1)  # 测试集的标签与最频繁出现的标签相同,识别正确
        else:
            compare_result.append(0)  # 测试集的标签与最频繁出现的标签不同,识别错误

test_name = test_name_read(r"D:\Image\test")  # 读取测试集的文件名
for i in range(len(test_name)):
    print(f"测试图片:{test_name[i]} 对应最近邻聚类中心标签:{test_labels[i]}")  # 打印每张测试图片及其对应的最近邻聚类中心标签

print(f"识别准确率:{(compare_result.count(1) / len(compare_result)) * 100}%")  # 计算并打印识别准确率

LDP下的Template matching和Clustering,代码如下:

import numpy as np
import os
from Methods import *

# 训练图片路径
img_train_path = r"D:\Image\LC_LDP_train.txt"
# 测试图片路径
img_test_path = r"D:\Image\LC_LDP_test.txt"
# 读取训练集文本文件
train_list = train_txt_read(img_train_path)
# 读取测试集文本文件
test_list = test_txt_read(img_test_path)

# 结果索引列表
result_index = []
# 遍历测试集
for i in test_list:
    # 差值列表
    diff_list = []
    # 遍历训练集
    for j in train_list:
        # 计算两个图片数组的差值
        diff = sum(abs(np.array(i) - np.array(j)))
        diff_list.append(diff)
    # 获取差值最小值的索引
    diff_min = min(diff_list)
    diff_min_index = diff_list.index(diff_min)
    # 将最小差值的索引添加到结果索引列表中
    result_index.append(diff_min_index)

# 读取训练集图片名称
train_name = train_name_read(r"D:\Image\train")
# 读取测试集图片名称
test_name = test_name_read(r"D:\Image\test")

# 结果列表
test_result = []
# 遍历结果索引列表
for i in result_index:
    # 获取与训练集图片名称匹配的索引值并添加到结果列表中
    test_result.append(train_name[i])

# 比较结果列表
compare_result = []
# 遍历测试结果
for i in range(len(test_result)):
    # 打印测试图片及对应训练图片
    print(f"测试图片:{test_name[i]}对应训练图片:{test_result[i]}")
    # 判断训练图片的名称是否与测试图片的名称的首个单词相同
    if test_result[i].split('_')[0] == test_name[i].split('_')[0]:
        compare_result.append(1)
    else:
        compare_result.append(0)

# 打印识别准确率
print(f"识别准确率:{(compare_result.count(1) / len(compare_result)) * 100}%")
import cv2
import numpy as np
import os
from Methods import *

# 载入训练集和测试集的路径
img_train_path = r"D:\Image\LC_LDP_train.txt"
img_test_path = r"D:\Image\LC_LDP_test.txt"

# 读取训练集和测试集的文本文件,并转化为numpy数组
train_list = train_txt_read(img_train_path)  # 读取训练集文本文件
test_list = test_txt_read(img_test_path)  # 读取测试集文本文件
train_data = np.array(train_list)  # 将训练集转化为numpy数组
test_data = np.array(test_list)  # 将测试集转化为numpy数组

# 将训练集和测试集的数组重塑为指定的形状
train_data = train_data.reshape((-1, 256))  # 将训练集数组重塑为256列的矩阵
test_data = test_data.reshape((-1, 256))  # 将测试集数组重塑为256列的矩阵

# 将训练集和测试集的数组转换为float32类型
train_data = np.float32(train_data)  # 将训练集数组转换为float32类型
test_data = np.float32(test_data)  # 将测试集数组转换为float32类型

# 定义k-means算法的终止条件、分配新点到初始中心点的方法和迭代最大次数
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 1000, 0.001)
flags = cv2.KMEANS_RANDOM_CENTERS
K = 46

# 使用k-means算法对训练集进行聚类
ret, train_label, train_center = cv2.kmeans(train_data, K, None, criteria, 100, flags)

# 将训练集的标签按组进行重塑,并得到在每组中出现次数最多的标签
train_label_group = train_label.reshape(-1, 7)
frequent_result = []
for group in train_label_group:
    most_frequent_num = np.bincount(group).argmax()  # 在每组中找到出现次数最多的标签
    frequent_result.append(most_frequent_num)  # 将出现次数最多的标签添加到列表中

# 计算测试集与每个聚类中心的距离,并将测试集归一化到最接近的聚类中心
test_distances = np.sqrt(((test_data[:, np.newaxis] - train_center) ** 2).sum(axis=2))  # 计算测试集与每个聚类中心的距离
test_labels = np.argmin(test_distances, axis=1)  # 将测试集归一化到最接近的聚类中心

test_labels_three = test_labels.reshape(-1, 3)  # 将测试集标签按组进行重塑

# 比较测试集的标签和最频繁出现的标签,并计算识别准确率
compare_result = []
for i in range(len(test_labels_three)):
    test_label = test_labels_three[i]
    for j in test_label:
        if j == frequent_result[i]:
            compare_result.append(1)  # 测试集的标签与最频繁出现的标签相同,识别正确
        else:
            compare_result.append(0)  # 测试集的标签与最频繁出现的标签不同,识别错误

test_name = test_name_read(r"D:\Image\test")  # 读取测试集的文件名
for i in range(len(test_name)):
    print(f"测试图片:{test_name[i]} 对应最近邻聚类中心标签:{test_labels[i]}")  # 打印每张测试图片及其对应的最近邻聚类中心标签

print(f"识别准确率:{(compare_result.count(1) / len(compare_result)) * 100}%")  # 计算并打印识别准确率

以上就是全部内容,方法和代码的应用都是类似的。

都看到最后了,不点个赞吗?

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值