代码原版台湾版

摘要:本文通過圖文詳細介紹如何利用支持向量機對圖像進行分類,經過上篇文章對原理的介紹,這裏介紹利用MATLAB編程實現。後續章節將介紹的主要部分有:

  • 圖片數據集整理
  • 特徵提取
  • SVM訓練與測試
  • 分類結果評價
  • 結果顯示

點我下載:SVM圖像分類的MATLAB完整程序及圖片集文件


1. 前言

機器學習是人工智能研究發展到一定階段的必然產物。二十世紀八十年代是機器學習成爲一個獨立學科的學科領域、各種機器學習技術百花綻放的時期。支持向量機於1995年正式發表[Cortes and Vapnik,1995],由於在文本分類任務中的卓越性能[Joachims,1998],很快成爲機器學習的主流技術,並直接掀起了“統計學習”(statistical learning)在2000年前後的高潮。——《機器學習》 周志華

2010年前後,隨着計算能力的迅猛提升和大數據的涌現,神經網絡研究在“深度學習”的名義下又重新崛起,並迎來又一次發展高潮。近年研究SVM的論文少了很多,SVM的風頭很多時候確實已被強勢崛起的深度學習浪潮所淹沒,95年的SVM比我們年齡還大,有點彷彿英雄遲暮的感覺。不過在我看來,實現簡單而且非常強大的分類算法SVM仍然有其研究價值,與神經網絡相比SVM亦有過人之處,如特徵維數多於樣本數的情況,而小樣本學習至今仍是深度學習的一大難題。

當淺層神經網絡效果不佳時,人們將目光轉向支持向量機,而支持向量機亦不負衆望,以不錯的成績讓人們對機器學習重拾信心。感謝支持向量機,感謝在神經網絡幾經起落的時候,支持向量機繼往開來、自成一脈,填補了機器學習的一段空窗期,讓這條曲折向上的研究之路綿延至今迎來了現在人工智能百花齊放的時代!

接下來就通過簡單的圖片分類問題,通過MATLAB程序理解認識一下這一簡單而強大的分類算法——支持向量機.


2. 圖片數據集整理

首先需要準備好分類的數據集,數據的整理是機器學習中的重要一環。這裏我們自行整理一個用於分類的圖片集,圖片集有四類圖片,分別爲車、貓、花、魚。從百度上下載這四種圖片,並分別存放在四個文件夾中,如下圖所示

四類圖片每類分別下載100張左右的圖片,這四百張圖片作爲分類的數據集,以7:3的比例將其分爲訓練圖片集和測試圖片集,分別放到picturestestPictures兩個文件夾中。這兩個文件夾下同上圖一樣都有car、cat、flw、fsh四個文件夾,值得注意的是測試樣本的圖片應可能不出現在訓練集圖片庫中。做好以上工作,用於分類的圖片集就準備完畢了。

(當然用於分類的圖片集常用的是cafir10圖片集,這個數據集是寫論文或研究時普遍用到的,可能會在後面的文章中介紹其用法,這裏就暫時不使用cafir了。)

爲了便於後面的特徵提取等對每張圖片進行的操作,這裏在程序中有必要將圖片文件的存儲位置、數量、類別等信息整理到一個數據結構中,新建一個m文件,程序代碼如下

dir=('D:\pictures');
testdir=('D:\testPictures\test');
trainingSet = imageSet(dir,'recursive');
testSet = imageSet(testdir,'recursive');

以上代碼中用到imageSet( )函數是一個圖片集整理的函數(MATLAB R2016b及以上版本支持),返回的是dir文件路徑下文件夾內的文件信息。例如得到的trainingSet爲一個1*4的imageSet變量,每個imageSet變量由Description、ImageLocation、Count三個屬性組成,分別代表對子文件的描述、文件存儲位置和圖片數量。如下圖所示是testSet(1)內部情況


3. 主要步驟

和深度學習的算法相比,傳統的機器學習在進行圖片分類時輸入的不是原始圖片而是先進行一個特徵提取的步驟。在上篇中已經介紹了特徵提取的相關內容,這裏用的是方向梯度直方圖(HOG)以及灰度共生矩陣(GLCM)。

3.1 GLCM提取

MATLAB中灰度共生矩陣的提取可以調用graycomatrix( )函數,不過這裏爲了取不同方向(0、45、90、135度)的灰度共生矩陣,通過循環計算各個方向的灰度共生矩陣並進行歸一化處理(計算對比度、逆差距、熵、自相關),然後取平均值和方差作爲最終提取的特徵。

新建一個m文件並命名爲getGLCMFeatures,輸入以下代碼

function [features] = getGLCMFeatures(image)
features_all  = [];
for i = 1:10
    glcm = graycomatrix(image, 'Offset', [0,i]);
    stats = graycoprops(glcm);
glcm45 = graycomatrix(image, <span class="hljs-string"><span class="hljs-string">'Offset'</span></span>, [-i,i]);
stats45 = graycoprops(glcm45);

glcm90 = graycomatrix(image, <span class="hljs-string"><span class="hljs-string">'Offset'</span></span>, [-i,<span class="hljs-number"><span class="hljs-number">0</span></span>]);
stats90 = graycoprops(glcm90);

glcm135 = graycomatrix(image, <span class="hljs-string"><span class="hljs-string">'Offset'</span></span>, [-i,-i]);
stats135 = graycoprops(glcm135);

stats7x4 = [stats.Contrast stats.Correlation stats.Energy stats.Homogeneity;
    stats45.Contrast stats45.Correlation stats45.Energy stats45.Homogeneity;
    stats90.Contrast stats90.Correlation stats90.Energy stats90.Homogeneity;
    stats135.Contrast stats135.Correlation stats135.Energy stats135.Homogeneity];
features_all = [features_all mean(stats7x4,<span class="hljs-number"><span class="hljs-number">1</span></span>) std(stats7x4,<span class="hljs-number"><span class="hljs-number">0</span></span>,<span class="hljs-number"><span class="hljs-number">1</span></span>)];

end
features = features_all;

新建的getGLCMFeatures函數輸入爲彩色圖像轉換後的灰度圖像矩陣,輸出爲提取後的灰度共生矩陣特徵。

3.2 合併特徵

自己編寫一個提取特徵的函數命名爲extractFeature,這個函數輸入爲整理過的訓練集和測試集,輸出爲訓練集的特徵、標籤和測試集的特徵、標籤。這個函數的功能是將HOG特徵和前面提取的GLCM特徵合併。

代碼第2到13行是爲了確定每張圖片提取特徵後得到的矩陣大小,以方便後面的操作同時也是爲了預分配空間以提高代碼效率。首先取第一張圖片進行灰度化以及閾值分割,將圖片大小調整在256*256的範圍(統一大小)分別進行HOG和GLCM的特徵提取,分別得到兩種特徵向量,取兩個向量的長度之和就是一張圖片特徵提取後的總長度了。

function [trainingFeatures,trainingLabels,testFeatures,testLabels]=extractFeature(trainingSet,testSet)
%% 確定特徵向量尺寸
img = read(trainingSet(1), 1);
%轉化爲灰度圖像
img=rgb2gray(img);
%轉化爲2值圖像
lvl = graythresh(img);
img = im2bw(img, lvl);
img=imresize(img,[256 256]);
cellSize = [4 4];
[hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
glcm_feature = getGLCMFeatures(img);
SizeOfFeature = length(hog_feature)+ length(glcm_feature);

%% 構建訓練樣本特徵向量和訓練樣本標籤
trainingFeatures =
[];
trainingLabels =
[];
for digit = 1:numel(trainingSet)
numImages = trainingSet(digit).Count;
features =
zeros(numImages, SizeOfFeature, ‘single’);%初始化特徵向量
% 遍歷每張圖片
for i = 1:numImages
img = read(trainingSet(digit), i);% 取出第i張圖片

    img=rgb2gray(img);                <span class="hljs-comment">% 轉化爲灰度圖像</span>
    glcm_feature = getGLCMFeatures(img);  <span class="hljs-comment">% 提取<span class="hljs-constant">GLCM</span>特徵</span>

    lvl = graythresh(img);            <span class="hljs-comment">% 閾值化</span>
    img = im2bw(img, lvl);            <span class="hljs-comment">% 轉化爲<span class="hljs-number">2</span>值圖像</span>
    img=imresize(img,<span class="hljs-matrix">[<span class="hljs-number"><span class="hljs-number">256</span></span> <span class="hljs-number"><span class="hljs-number">256</span></span>]</span>);
    <span class="hljs-comment">% 提取<span class="hljs-constant">HOG</span>特徵</span>
    <span class="hljs-matrix">[hog_feature, vis_hog]</span> = extractHOGFeatures(img,<span class="hljs-string"><span class="hljs-string">'CellSize'</span></span>,cellSize);
    <span class="hljs-comment">% 合併兩個特徵</span>
    features(<span class="hljs-built_in">i</span>, <span class="hljs-symbol">:</span>) = <span class="hljs-matrix">[hog_feature glcm_feature]</span>;
<span class="hljs-keyword"><span class="hljs-keyword">end</span></span>
<span class="hljs-comment">% 使用圖像描述作爲訓練標籤</span>
labels = <span class="hljs-built_in">repmat</span>(trainingSet(digit).<span class="hljs-constant">Description</span>, numImages, <span class="hljs-number"><span class="hljs-number">1</span></span>);  
<span class="hljs-comment">% 逐個添加每張訓練圖片的特徵和標籤</span>
trainingFeatures = <span class="hljs-matrix">[trainingFeatures; features]</span>;
trainingLabels   = <span class="hljs-matrix">[trainingLabels; labels]</span>;       

end

%% 提取測試圖片集的特徵向量
testFeatures =
[];
testLabels =
[];
for digit = 1:numel(testSet)

numImages = testSet(digit).Count;
</span><span class="hljs-comment"><span class="hljs-string">%</span>初始化特徵向量</span>
features  = <span class="hljs-built_in">zeros</span>(numImages, <span class="hljs-constant">SizeOfFeature</span>, <span class="hljs-string"><span class="hljs-string">'single'</span></span>);

<span class="hljs-keyword"><span class="hljs-keyword">for</span></span> <span class="hljs-built_in">i</span> = <span class="hljs-number"><span class="hljs-number">1</span></span><span class="hljs-symbol">:numImages</span>

    img = read(testSet(digit), <span class="hljs-built_in">i</span>);
    <span class="hljs-comment">%轉化爲灰度圖像</span>
    img=rgb2gray(img);
    glcm_feature = getGLCMFeatures(img);
    <span class="hljs-comment">%轉化爲<span class="hljs-number">2</span>值圖像</span>
    lvl = graythresh(img);
    img = im2bw(img, lvl);
    img=imresize(img,<span class="hljs-matrix">[<span class="hljs-number"><span class="hljs-number">256</span></span> <span class="hljs-number"><span class="hljs-number">256</span></span>]</span>);
    <span class="hljs-matrix">[hog_4x4, vis4x4]</span> = extractHOGFeatures(img,<span class="hljs-string"><span class="hljs-string">'CellSize'</span></span>,cellSize);
    features(<span class="hljs-built_in">i</span>, <span class="hljs-symbol">:</span>) = <span class="hljs-matrix">[hog_4x4 glcm_feature]</span>;
<span class="hljs-keyword"><span class="hljs-keyword">end</span></span>

<span class="hljs-comment">% 使用圖像描述作爲訓練標籤</span>
labels = <span class="hljs-built_in">repmat</span>(testSet(digit).<span class="hljs-constant">Description</span>, numImages, <span class="hljs-number"><span class="hljs-number">1</span></span>);

testFeatures = <span class="hljs-matrix">[testFeatures; features]</span>;
testLabels=<span class="hljs-matrix">[testLabels; labels]</span>;

end
end

代碼18-41行是構建訓練樣本特徵向量和訓練樣本標籤,與前面步驟相似,只不過現在是遍歷訓練集每一張圖片,對其進行灰度化、閾值化、調整大小,然後進行特徵提取,將HOG特徵和GLCM特徵合併成一個向量作爲特徵矩陣的一行即一張圖片的特徵向量。樣本的標籤構建則將每張圖片所處的文件夾的名字作爲該圖片的標籤,並與特徵向量順序相對應。

第47-73行是構建測試樣本特徵向量和訓練樣本標籤,這裏將圖片集換成了測試集,而步驟與訓練集是一致的。

3.3 SVM訓練與測試

調用前面的特徵提取函數得到訓練和測試用的特徵向量與對應的標籤,便可以進行SVM的訓練和測試。MATLAB自帶的訓練svm函數可以用fitcecoc函數,測試可以用predict函數預測結果,訓練和測試的代碼如下

% 訓練一個svm分類器
% fitcecoc 使用1對1的方案
classifier = fitcecoc(trainingFeatures, trainingLabels);
save classifier.mat classifier;

% 使用測試圖像的特徵向量預測樣本標籤
predictedLabels = predict(classifier, testFeatures);

代碼中classifier爲訓練得到的SVM分類器,利用該分類器以及測試集特徵向量預測測試集的標籤predictLabels。後面可以將predictLabels與實際的測試標籤進行對比即可評估分類好壞。

3.4 分類結果評價

在上一篇文章中提到過了,爲了評價分類的好壞可以通過混淆矩陣,通過計算混淆矩陣對角線上的值佔每行總數的比值得出分類正確率,其實現代碼如下

%% 評估分類器
% 使用沒有標籤的圖像數據進行測試,生成一個混淆矩陣表明分類效果
confMat=confusionmat(testLabels, predictedLabels)
accuracy=(confMat(1,1)/sum(confMat(1,:))+confMat(2,2)/sum(confMat(2,:))+...
    confMat(3,3)/sum(confMat(3,:))+confMat(4,4)/sum(confMat(4,:)))/4

其結果如下圖所示

3.5 結果顯示

儘管以上代碼能得到分類正確率,但我們希望更直觀的看到輸入一張圖片後SVM分類器的分類結果,這裏編寫一個函數通過圖形窗口顯示預測結果。新建一個m文件命名爲Predict,輸入如下代碼

function [] = Predict(imageurl)
load classifier.mat;
figure;
img = imread(imageurl);
imshow(img);

%提取圖像的特徵向量
%轉化爲灰度圖像
img=rgb2gray(img);
glcm_feature = getGLCMFeatures(img);
%轉化爲2值圖像
lvl = graythresh(img);
img = im2bw(img, lvl);

% imshow(img);
% figure
img=imresize(img,[256 256]);
[hog_4x4, ~] = extractHOGFeatures(img,‘CellSize’,[4 4]);
testFeature = [hog_4x4 glcm_feature];

% 使用測試圖像的特徵向量預測樣本標籤
predictedLabel = predict(classifier, testFeature);

str = [‘分類結果:’ predictedLabel];
dim = [0.25 0.0004 0.2 0.2];
annotation(‘textbox’, dim, ‘string’, str, ‘fontsize’, 20, ‘color’, ‘g’,‘edgecolor’, ‘none’);

函數輸入爲圖片的存儲路徑,調用函數則會通過圖形窗口顯示圖片及分類結果,如在命令窗口輸入如下代碼

Predict('D:\testPictures\test\car\car9.jpg');

輸出結果如下圖


4. 完整代碼

爲了方便使用這裏貼出完整代碼

主函數:

clear;
dir=('D:\pictures');
testdir=('D:\testPictures\test');
trainingSet = imageSet(dir,'recursive');
testSet = imageSet(testdir,'recursive');

[trainingFeatures,trainingLabels,testFeatures,testLabels]=extractFeature(trainingSet,testSet);
%%
%訓練一個svm分類器
%fitcecoc 使用11的方案
classifier = fitcecoc(trainingFeatures, trainingLabels);
save classifier.mat classifier;

% 使用測試圖像的特徵向量預測樣本標籤
predictedLabels = predict(classifier, testFeatures);

%% 評估分類器
%使用沒有標籤的圖像數據進行測試,生成一個混淆矩陣表明分類效果
confMat=confusionmat(testLabels, predictedLabels)
accuracy=(confMat(1,1)/sum(confMat(1,:))+confMat(2,2)/sum(confMat(2,:))+…
confMat(3,3)/sum(confMat(3,:))+confMat(4,4)/sum(confMat(4,:)))/4

Predict(‘D:\testPictures\test\car\car9.jpg’);

getGLCMFeatures.m:

function [features] = getGLCMFeatures(image)
features_all  = [];
for i = 1:10
    glcm = graycomatrix(image, 'Offset', [0,i]);
    stats = graycoprops(glcm);
glcm45 = graycomatrix(image, <span class="hljs-string"><span class="hljs-string">'Offset'</span></span>, <span class="hljs-matrix">[-i,i]</span>);
stats45 = graycoprops(glcm45);

glcm9<span class="hljs-number">0</span> = graycomatrix(image, <span class="hljs-string"><span class="hljs-string">'Offset'</span></span>, <span class="hljs-matrix">[-i,<span class="hljs-number"><span class="hljs-number">0</span></span>]</span>);
stats9<span class="hljs-number">0</span> = graycoprops(glcm9<span class="hljs-number">0</span>);

glcm135 = graycomatrix(image, <span class="hljs-string"><span class="hljs-string">'Offset'</span></span>, <span class="hljs-matrix">[-i,-i]</span>);
stats135 = graycoprops(glcm135);

stats7x4 = <span class="hljs-matrix">[stats.<span class="hljs-constant">Contrast</span> stats.<span class="hljs-constant">Correlation</span> stats.<span class="hljs-constant">Energy</span> stats.<span class="hljs-constant">Homogeneity</span>;
    stats45.<span class="hljs-constant">Contrast</span> stats45.<span class="hljs-constant">Correlation</span> stats45.<span class="hljs-constant">Energy</span> stats45.<span class="hljs-constant">Homogeneity</span>;
    stats9<span class="hljs-number">0</span>.<span class="hljs-constant">Contrast</span> stats9<span class="hljs-number">0</span>.<span class="hljs-constant">Correlation</span> stats9<span class="hljs-number">0</span>.<span class="hljs-constant">Energy</span> stats9<span class="hljs-number">0</span>.<span class="hljs-constant">Homogeneity</span>;
    stats135.<span class="hljs-constant">Contrast</span> stats135.<span class="hljs-constant">Correlation</span> stats135.<span class="hljs-constant">Energy</span> stats135.<span class="hljs-constant">Homogeneity</span>]</span>;
features_all = <span class="hljs-matrix">[features_all mean(stats7x4,<span class="hljs-number"><span class="hljs-number">1</span></span>) std(stats7x4,<span class="hljs-number"><span class="hljs-number">0</span></span>,<span class="hljs-number"><span class="hljs-number">1</span></span>)]</span>;

end
features = features_all;

extractFeature.m:

function [trainingFeatures,trainingLabels,testFeatures,testLabels]=extractFeature(trainingSet,testSet)
%% 確定特徵向量尺寸
img = read(trainingSet(1), 1);
%轉化爲灰度圖像
img=rgb2gray(img);
%轉化爲2值圖像
lvl = graythresh(img);
img = im2bw(img, lvl);
img=imresize(img,[256 256]);
cellSize = [4 4];
[hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
glcm_feature = getGLCMFeatures(img);
SizeOfFeature = length(hog_feature)+ length(glcm_feature);

%% 構建訓練樣本特徵向量和訓練樣本標籤
trainingFeatures =
[];
trainingLabels =
[];
for digit = 1:numel(trainingSet)
numImages = trainingSet(digit).Count;
features =
zeros(numImages, SizeOfFeature, ‘single’);%初始化特徵向量
% 遍歷每張圖片
for i = 1:numImages
img = read(trainingSet(digit), i);% 取出第i張圖片

    img=rgb2gray(img);                <span class="hljs-comment">% 轉化爲灰度圖像</span>
    glcm_feature = getGLCMFeatures(img);  <span class="hljs-comment">% 提取<span class="hljs-constant">GLCM</span>特徵</span>

    lvl = graythresh(img);            <span class="hljs-comment">% 閾值化</span>
    img = im2bw(img, lvl);            <span class="hljs-comment">% 轉化爲<span class="hljs-number">2</span>值圖像</span>
    img=imresize(img,<span class="hljs-matrix">[<span class="hljs-number"><span class="hljs-number">256</span></span> <span class="hljs-number"><span class="hljs-number">256</span></span>]</span>);
    <span class="hljs-comment">% 提取<span class="hljs-constant">HOG</span>特徵</span>
    <span class="hljs-matrix">[hog_feature, vis_hog]</span> = extractHOGFeatures(img,<span class="hljs-string"><span class="hljs-string">'CellSize'</span></span>,cellSize);
    <span class="hljs-comment">% 合併兩個特徵</span>
    features(<span class="hljs-built_in">i</span>, <span class="hljs-symbol">:</span>) = <span class="hljs-matrix">[hog_feature glcm_feature]</span>;
<span class="hljs-keyword"><span class="hljs-keyword">end</span></span>
<span class="hljs-comment">% 使用圖像描述作爲訓練標籤</span>
labels = <span class="hljs-built_in">repmat</span>(trainingSet(digit).<span class="hljs-constant">Description</span>, numImages, <span class="hljs-number"><span class="hljs-number">1</span></span>);  
<span class="hljs-comment">% 逐個添加每張訓練圖片的特徵和標籤</span>
trainingFeatures = <span class="hljs-matrix">[trainingFeatures; features]</span>;
trainingLabels   = <span class="hljs-matrix">[trainingLabels; labels]</span>;       

end

%% 提取測試圖片集的特徵向量
testFeatures =
[];
testLabels =
[];
for digit = 1:numel(testSet)

numImages = testSet(digit).Count;
</span><span class="hljs-comment"><span class="hljs-string">%</span>初始化特徵向量</span>
features  = <span class="hljs-built_in">zeros</span>(numImages, <span class="hljs-constant">SizeOfFeature</span>, <span class="hljs-string"><span class="hljs-string">'single'</span></span>);

<span class="hljs-keyword"><span class="hljs-keyword">for</span></span> <span class="hljs-built_in">i</span> = <span class="hljs-number"><span class="hljs-number">1</span></span><span class="hljs-symbol">:numImages</span>

    img = read(testSet(digit), <span class="hljs-built_in">i</span>);
    <span class="hljs-comment">%轉化爲灰度圖像</span>
    img=rgb2gray(img);
    glcm_feature = getGLCMFeatures(img);
    <span class="hljs-comment">%轉化爲<span class="hljs-number">2</span>值圖像</span>
    lvl = graythresh(img);
    img = im2bw(img, lvl);
    img=imresize(img,<span class="hljs-matrix">[<span class="hljs-number"><span class="hljs-number">256</span></span> <span class="hljs-number"><span class="hljs-number">256</span></span>]</span>);
    <span class="hljs-matrix">[hog_4x4, vis4x4]</span> = extractHOGFeatures(img,<span class="hljs-string"><span class="hljs-string">'CellSize'</span></span>,cellSize);
    features(<span class="hljs-built_in">i</span>, <span class="hljs-symbol">:</span>) = <span class="hljs-matrix">[hog_4x4 glcm_feature]</span>;
<span class="hljs-keyword"><span class="hljs-keyword">end</span></span>

<span class="hljs-comment">% 使用圖像描述作爲訓練標籤</span>
labels = <span class="hljs-built_in">repmat</span>(testSet(digit).<span class="hljs-constant">Description</span>, numImages, <span class="hljs-number"><span class="hljs-number">1</span></span>);

testFeatures = <span class="hljs-matrix">[testFeatures; features]</span>;
testLabels=<span class="hljs-matrix">[testLabels; labels]</span>;

end
end

Predict.m:

function [] = Predict(imageurl)
load classifier.mat;
figure;
img = imread(imageurl);
imshow(img);

%提取圖像的特徵向量
%轉化爲灰度圖像
img=rgb2gray(img);
glcm_feature = getGLCMFeatures(img);
%轉化爲2值圖像
lvl = graythresh(img);
img = im2bw(img, lvl);

% imshow(img);
% figure
img=imresize(img,[256 256]);
[hog_4x4, ~] = extractHOGFeatures(img,‘CellSize’,[4 4]);
testFeature = [hog_4x4 glcm_feature];

% 使用測試圖像的特徵向量預測樣本標籤
predictedLabel = predict(classifier, testFeature);

str = [‘分類結果:’ predictedLabel];
dim = [0.25 0.0004 0.2 0.2];
annotation(‘textbox’, dim, ‘string’, str, ‘fontsize’, 20, ‘color’, ‘g’,‘edgecolor’, ‘none’);


5. 結束語

本博文的完整MATLAB程序文件與圖片集文件已經上傳,下載即可運行(注意根據實際修改程序中的圖片路徑哦)下載地址如下

點我下載:SVM的圖像分類MATLAB完整程序及圖片集文件

由於編者能力有限,代碼即使經過了多次校對,也難免會有疏漏之處。希望您能熱心指出其中的錯誤,以便下次修改時能以一個更完美更嚴謹的樣子,呈現在大家面前。同時如果有更好的實現方法也請您不吝賜教。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值