首頁 > 軟體

opencv深入淺出瞭解機器學習和深度學習

2022-03-17 13:01:15

機器學習

kNN演演算法

kNN演演算法將找出k個距離最近的鄰居作為目標的 同一類別

圖解kNN演演算法

使用OpenCV的ml模組中的kNN演演算法的基本步驟如下。

(1)呼叫cv2.mL.KNearest_ create()函數建立kNN分類器。

(2)將訓練資料和標誌作為輸入,呼叫kNN分類器的train()方法訓練模型。

(3)將待分類資料作為輸入,呼叫kNN分類器的findNearest()方法找出K個最近鄰居,返回 分類結果的相關資訊。

下面的程式碼在影象中隨機選擇20個點,為每個點隨機分配標誌( 0或1 );影象中用矩形表示 標誌0,用三角形表示標誌1;再隨機新增一個點,用kNN演演算法找出其鄰居,並確定其標誌(即完 成分類)。

import cv2
import numpy as np
import matplotlib.pyplot as plt
points = np. random. randint(0,100, (20,2))                        #隨機選擇20個點
labels = np. random. randint(0,2,(20,1))                           #為隨機點隨機分配標誌
label0s = points[labels.ravel()==0]                                #分出標誌為0的點
plt. scatter(label0s[:,0],label0s[:,1],80,'b','s')                 #將標誌為0的點繪製為藍色矩形
label1s = points[labels.ravel()==1]                                #分出標誌為1的點
plt. scatter(label1s[:,0],label1s[:,1],80,'r','^')                 #將標誌為1的點繪製為紅色三角形
newpoint = np.random.randint(0,100,(1,2))                          #隨機選擇一個點,下面確定其分類
plt.scatter(newpoint[:,0],newpoint[:,1],80,'g','o')                #將待分類新點繪製為綠色圓點
plt.show()                                                         #進一步使用kNN演演算法確認待分類新點的類別、3個最近鄰居和距離
knn = cv2.ml.KNearest_create()                                     #建立kNN分類器
knn.train(points.astype(np.float32).cv2.ml.ROW_SAMPLE,labels.astype(np. float32))  #訓練模型
ret,results,neighbours,dist = knn.findNearest(newpoint.astype(np.float32), 3)      #找出3個最近鄰居
print("新點標誌: %s" % results)
print("鄰居: %s" % neighbours)
print("距離: %s" % dist)

新點標誌: [[1.]]
鄰居: [[0. 1. 1.]]
距離: [[ 80. 296. 424.]]

因為三個最近鄰居有兩個是紅色三角,所以他的標誌為一

用kNN演演算法實現手寫數位識別

用下列圖片用來訓練。

先把下面分割為每個數位大小都是20*20的影象,用於訓練模型。

然後將手寫的數位進行反二值化閾值處理轉換成黑白影象,用畫素值作為特徵向量進行測試

import cv2
import numpy as np
import matplotlib.pyplot as plt
gray = cv2. imread('img/a.png',0)     #讀入手寫數位的灰度影象
digits = [np.hsplit(r,100) for r in np.vsplit(gray,50)]    #分解數位: 50行、100 列
np_digits = np.array(digits )      #轉換為NumPy陣列
#準備訓練資料,轉換為二維陣列,每個影象400個畫素
train_data = np_digits.reshape(-1, 400). astype(np. float32)
train_labels = np.repeat(np. arange(10),500)[:,np.newaxis]    #定義標誌
knn = cv2.ml.KNearest_create()             #建立kNN分類器
knn.train(train_data, cv2.ml.ROW_SAMPLE,train_labels)     #訓練模型
#用繪圖工具建立的手寫數位5影象(大小為20x 20 )進行測試
test= cv2.imread('img/a5.png',0)        #開啟影象
test_data=test.reshape(1,400).astype(np.float32)     #轉換為測試資料
ret,result,neighbours,dist = knn. findNearest(test_data,k=3)     #執行測試
print(result.ravel())        #輸出測試結果
print(neighbours.ravel())
#將對手寫數位9拍攝所得影象的大小轉換為20 x 20進行測試
img2=cv2. imread('img/d3.png',0)
ret,img2=cv2. threshold(img2,150, 255, cv2. THRESH_BINARY_INV)     #反二值化閾值處理
test_data=img2.reshape(1,400).astype(np. float32)       #轉換為測試資料
ret,result,neighbours,dist = knn. findNearest(test_data,k=3)                 #執行測試
print(result.ravel())                                                               #輸出測試結果
print(neighbours .ravel())

用一張繪圖圖片和手寫圖片用來測試

輸出結果:

[5.]
[5. 5. 5.]
[3.]
[3. 5. 3.]

SVM演演算法

可使用一條直線將線性可分離的資料分為兩組,這條直線在SVM演演算法中稱為“決策邊界”; 非線性可分離的資料轉換為高維資料後可稱為線性可分離資料。這是SVM演演算法的理論基礎。

圖解SVM演演算法

下面的程式碼在影象中選擇了五個點,分為兩類,類別標誌分別為0和1。將五個點和標誌作為已知分類資料訓練SVM模型;然後用模型對影象中的所有點進行分類,根據分類結果設定影象顏色,從而直觀顯示影象畫素的分類結果。

import cv2
import numpy as np
import matplotlib.pyplot as plt#準備訓練資料,假設影象高240,寬320,在其中選擇5個點
traindata=np.matrix([[140,60],[80, 120],[16,10],[166,190],[248, 180]],dtype = np.float32)
#5個點,前3個點為一類,標誌為8;後2個點為一類,標誌為1
labels = np.array([0,0,0,1,1])
svm = cv2.ml.SVM_create()             #建立SVM分類器
svm. setGamma(0.50625)                 #設定相關引數
svm. setC(12.5)
svm. setKernel(cv2.ml.SVM_LINEAR)
svm.setType(cv2.ml.SVM_C_SVC)
svm. setTermCriteria((cv2. TERM_CRITERIA_MAX_ITER, 100, 1e-6))
svm.train(traindata, cv2.ml. ROW_SAMPLE, labels)        #訓練模型
img = np.zeros((240,320,3),dtype="uint8" )           #建立影象
colors = {0:(102,255,204),1:(204,204,102)}
#用SVM分類器對影象畫素進行分類,根據分類結果設定畫素顏色
for i in range(240):
    for j in range(320):
        point = np.matrix([[j,i]], dtype=np.float32)       #將畫素座標轉換為測試資料
        label = svm.predict(point)[1].ravel()              #執行預測,返回結果
        img[i,j] = colors[label[0]]              #根據預測結果設定畫素顏色
svm_vectors = svm. getUncompressedSupportVectors() #獲得SVM向量
for i in range(svm_vectors.shape[0]):           #在影象中繪製SVM向量(紅色圓)
    cv2.circle(img,(int(svm_vectors[i,0]),int(svm_vectors[i,1])),8,(0,0,255),2)
#在影象中繪製訓練資料點,類別標誌0使用藍色,類別標誌1使用綠色
cv2.circle(img, (140, 60),5,(255,0,0),-1)
cv2.circle(img, (80,120),5,(255,0,0),-1)
cv2.circle(img, (160,110),5,(255,0,0),-1)
cv2.circle(img, (160,190),5,(0,255,0),-1)
cv2.circle(img, (240,180),5,(0,255,0),-1)
img = cv2. cvtColor(img, cv2.COLOR_BGR2RGB)   #轉換為RGB格式
plt. imshow(img)
plt. show()        #顯示結果

如圖中三個藍點為一類,下面兩個訓練點為一類,兩顏色交界位置為決策邊界

使用SVM演演算法識別手寫資料

kMM演演算法使用了畫素值作為特徵向量。 svm演演算法可使用影象的定向梯度直方圖作為特徵向量來對影象進行分類 梯度直方圖

用svm識別數位和knn的區別在於他會使用影象的定向梯度直方圖作為特徵向量來對影象進行分類。

下面程式碼步驟:

1.定義了HOG描述符的計算函數,用於將單個數位影像計算HOG描述符,再轉換成一維陣列(特徵描述符就是通過提取影象的有用資訊,並且丟棄無關資訊來簡化影象的表示)

2.分解圖片,計算每張圖片對應的HOG描述符

3.建立svm分類器,用這些圖片進行訓練模型

4.用繪製的影象測試

import cv2
import numpy as np
def hog(img): #定義HOG描述符的計算函數
    hog = cv2.HOGDescriptor((20,20),(8,8),(4,4),(8,8),9,1,-1,0,0.2,1,64,True)    #定義HOGDescriptor物件
    hog_descriptor=hog.compute(img)            #計算HOG描述符
    hog_descriptor=np.squeeze(hog_descriptor)  #轉換為一維陣列
    return hog_descriptor                       #返回HOG描述符,144 位
img = cv2.imread('img/a.png',0)
digits=[np.hsplit(row,100) for row in np.vsplit(img, 50)]  #分解影象,50行、100列
labels = np.repeat(np. arange(10),500)[:,np.newaxis]   #定義對應的標記
hogdata = [list(map(hog,row)) for row in digits]        #計算影象的HOG描述符
trainData = np. float32(hogdata) . reshape(-1, 144)    #轉換為測試資料
svm = cv2.ml.SVM_create( )      #建立SVM分類器
#設定相關引數
svm. setKernel(cv2.ml. SVM_LINEAR)
svm. setType(cv2.ml.SVM_C_SVC)
svm. setC(2.67)
svm. setGamma(5.383)
svm. train(trainData, cv2.ml. ROW_SAMPLE, labels)
#訓練模型
#用繪圖工具建立的手寫數位5影象(大小為20 x 20 )進行測試
test= cv2.imread('img/d5.jpg',0)
#開啟影象
test_data=hog(test)
test_data=test_data.reshape(1, 144) . astype(np. float32)
#轉換為測試資料
result = svm. predict(test_data)[1]
print( '識別結果: ',np. squeeze(result))
#用繪圖工具建立的手寫數位8影象(大小為20 x20 )進行測試
test= cv2. imread('img/d7.jpg' ,0)
test_data=hog(test)
test_data=test_data.reshape(1,144).astype(np .float32)
#轉換為測試資料
result = svm. predict(test_data)[1]
print('識別結果:',np.squeeze(result))

k均值聚類演演算法

k均值聚類演演算法的基本原理是根據資料的密集程度尋找相對密集資料的質心,再根據質心完成資料分類

圖解k均值聚類演演算法

下面程式碼在大小為240*320的影象中選擇3組資料點,不同顏色顯示分類資料和質心

import cv2
import numpy as np
from matplotlib import pyplot as plt
#建立聚類資料,3個類別,每個類別包含20個點
data = np.vstack((np.random. randint(10,90, (20,2)),np. random. randint(80,170, (20, 2)),np.random.randint(160,250, (20, 2))))
data=data.astype(np.float32)
#定義演演算法終止條件
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 1.0)
#使用k均值聚類演演算法執行分類操作,k=3,返回結果中label用於儲存標誌,center 用於儲存質心
ret,label,center=cv2. kmeans(data,3,None, criteria,10,cv2.KMEANS_RANDOM_CENTERS)
#根據運算結果返回的標誌將資料分為3組,便於繪製影象
data1 = data[label.ravel() == 0]
data2 = data[label.ravel() == 1]
data3 = data[label.ravel() == 2]
plt. scatter(data1[:,0], data1[:,1], c='r')
#繪製第1類資料點,紅色
#繪製第2類資料點,綠色
plt.scatter(data2[:,0],data2[:,1],c='g')
#繪製第3類資料點,藍色
plt.scatter(data3[:,0], data3[:,1], c='b')
plt.scatter(center[:,0],center[:,1],100,['#CC3399'],'s')
#繪製質心,顏色為#CC3399
#顯示結果
plt. show()

使用k均值聚類演演算法量化影象顏色

使用k均值聚類演演算法量化影象顏色,即將質心作為影象新的畫素,從而減少影象中的顏色值 K均值聚類步驟:

第一步:確定K值,聚類成K個類簇。

第二步:從資料中隨機選擇(或按照某種方式)K個資料點作為初始分類的中心。

第三步:分別計算資料中每個點到每個中心的距離,將每個點劃分到離中心最近的類中

第四步:當每個中心都劃分了一些點後,去每個類的均值,選出新的中心。

第五步:比較新的中心和之前的中心,如果新的中心和之前的中心之間的距離小於某閾值,或迭代次數超過某閾值,認為聚類已經收斂,終止。

第六步:否則繼續迭代執行第三到五步,直到第五步滿足。

import cv2
import numpy as np
img = cv2.imread('img/qwe.jpg')
#開啟影象

#顯示原圖
img2 = img.reshape((-1,3)). astype(np. float32)
#轉換為nx 3的浮點型別陣列,n=影象畫素的總數一3
#定義演演算法終止條件
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K=8
ret,label,center=cv2.kmeans(img2,K,None, criteria,10,cv2.KMEANS_RANDOM_CENTERS)
center = np.uint8(center)             #將質心轉換為整型
img3 = center[label.ravel()]          #轉換為一維陣列
img3 = img3.reshape((img.shape))        #恢復為原影象陣列形狀
cv2.imshow('K=8',img3)
K=12
ret,label,center=cv2. kmeans(img2,K,None, criteria,10,cv2.KMEANS_RANDOM_CENTERS)
center = np.uint8(center)             #將質心轉換為整型
img3 = center[label.ravel()]          #轉換為一維陣列
img3 = img3.reshape((img.shape))        #恢復為原影象陣列形狀
cv2.imshow('K=12',img3)
cv2.waitKey(0)
  • 將原圖的二維(寬,高)三通道的圖片轉換成了一維(一列)三通道的陣列
  • 根據誤差和迭代次數定義演演算法終止的條件
  • 將一維三通道的值根據K分成的類別替換為質心的值
  • 將這個陣列再轉換為原影象的陣列形狀

下圖分別是原圖、k=4、k=8、k=12的圖

深度學習

機器學習通常包含輸入、特徵提取、分類和輸出四個步驟

深度學習通常分為輸入、特徵提取與分類和輸出3個步驟,它將機器學習中的特徵提取和分類和並在同一個步驟中完成

基於深度學習的影象識別

影象識別是將影象內容作為一個物件來識別其型別。使用OpenCV中的深度學習預訓練模型進行影象識別的基本步驟如下。

  • 從組態檔和預訓練模型檔案中載入模型。
  • 將影象檔案處理為塊資料( blob )。
  • 將影象檔案的塊資料設定為模型的輸入。
  • 執行預測。
  • 處理預測結果。

基於AlexNet和Caffe模型進行影象識別

1.從文字中獲取每個類別的名稱

2.載入Caffe模型

3.開啟用於識別分類的影象

4.建立影象塊資料,將影象塊資料作為神經網路輸入

5.執行預測,返回的是一個1*1000的陣列,是按照順序對應1000種類別的可信度

6.輸出排名第一的預測結果

import cv2
import numpy as np
from matplotlib import pyplot as plt
from PIL import ImageFont,ImageDraw, Image
#讀入文字檔案中的類別名稱,共0種類到每行為一個類到,從第11個字元開始為名稱
#基本格式如下
# n01440764 tench, Tinca tinca
# n01443537 goldfish, Carassius auratus
file=open('classes.txt' )
names=[r.strip() for r in file.readlines()]
file.close()
classes = [r[10:] for r in names]
#獲取每個類別的名稱
#從檔案中載入Caffe模型
net = cv2.dnn.readNetFromCaffe("AlexNet_deploy.txt", "AlexNet_CaffeModel.dat")
image = cv2. imread("img/qwe.jpg")
#開啟影象,用於識別分類
#建立影象塊資料,大小為(224,224),顏色通道的均值縮減比例因子為(104, 117, 123)
blob = cv2.dnn. blobFromImage(image, 1, (224,224), (104, 117, 123))
net. setInput(blob)
#將影象塊資料作為神經網路輸入
#執行預測,返回結果是一個 1x 1000的陣列,按順序對應1000種類別的可信度
result = net. forward()
ptime, x = net. getPerfProfile()
#獲得完成預測時間
print('完成預測時間: %.2f ms' % (ptime * 1000.0 / cv2.getTickFrequency(0)))
sorted_ret = np. argsort(result[0])
#將預測結果按可信度由高到低排序
top5 = sorted. ret[::-1][:5]
#獲得排名前5的預測結果
ctext = "類別: "+classes[top5[0]]
ptext = "可信度: {:.2%}" . format(result[0][top5[0]])
#輸出排名前5的預測結果
for (index, idx) in enumerate(top5):
    print("t).類別: {},可信度: (:2%)" .format(index + 1, classes[idx], result[0][idx]))
#在影象中輸出排名第1的預測結果
fontpath = "STSONG. TTF"
font = ImageFont . truetype( fontpath, 80)        #載入中文字型,設定字號
img_pil = Image. fromarray(image)
draw = ImageDraw.Draw(img_pil)
draw.text((10, 10),ctext, font = font,fill=(0,0,255)) #繪製文字
draw.text((10,100),ptext, font = font, fill=(0,0,255))
img = np.array(img_pil)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.axis('off')
plt.show()

基於深度學習的物件檢測

物件檢測是指檢測出影象中的所有物件。並識別物件的型別。使用OpenCV中的深度學習預訓練模型進行物件檢測的基本步驟如下。

  • 從組態檔和預訓練模型檔案中載入模型。
  • 建立影象檔案的塊資料( blob )。
  • 將影象檔案的塊資料設定為模型的輸入。
  • 執行預測。
  • 處理預測結果。

基於YOLO和Darknet預訓練模型的物件檢測

1.從文字中獲取每個類別的名稱

2.載入預訓練的Darknet模型

3.開啟用於物件檢測的影象

4.建立影象塊資料,將影象塊資料作為神經網路輸入

5.執行預測,返回每層的預測結果

6.遍歷所有的輸出層,遍歷層的所有輸出預測結果,每個結果為一個邊框

7.篩選出概率大於50%的類別,獲取他們的座標

8.用非最大值抑制獲得要繪製的box(為最大值一直是為了消除重複邊框)

9.繪製邊框

import cv2
import numpy as np
from matplotlib import pyplot as plt
import matplotlib
from PIL import InageFont, Inagoraw, Image
#載入字型,以便顯示漢字
fontpath = "STSONG.TTF」
font = ImageFont.truetype(fontpath,20)     #載入字型,設定字號
font2 = {'family': 'STSONG', "size": 22}
matplotlib.rc('font', **font2)
#設定plt字型
#從檔案中載入已知的物件名稱,檔案儲存了80個類別的物件名稱,每行個
f=open(" object_names .txt",encoding=' utf-8')
object. names = [r.strip() for r in f.readlines()]
f.close()
#從檔案中載入預訓練的Darknet模型
mode = cv2. dnn. readNetFromDarknet("yolov3.cfg", "yolov3.weights")
image = cv2. imread(" objects. jpg")
#開啟影象檔案
imgH, imgW = image . shape[ :2]
ut_layers = mode. getLayerNames()
#獲得輸出層
out_layers = [out_layers[i[0] - 1] for i in mode.getUnconnectedOutLayers()]
blob = cv2.dnn. blobFromImage(image, 1/255.0, (416,416),swapRB=True, crop=False)  #建立影象塊資料
mode . setInput(blob)
#將影象塊資料設定為模型輸入
layer_results = mode . forward(out_layers)
#執行預測,返回每層的預測結果
ptime,_ = mode. getPerfProfile()
tilte_text='完成預測時間: %.2f ms' % (ptime* 1000/cv2. getTickFrequency())
result_boxes = []
result_scores = []
result_name_id = []
for layer in layer_results:        #遍歷所有輸出層
    for box in layer:              #遍歷層的所有輸出預測結果,每個結果為一個邊框
        #預測結果結構: x, y, w, h, confidence, 80 個類別的概率
        probs = box[5:]
        class_id = np.argmax(probs)     #找到概率最大的類別名稱
        prob = probs[class_id]          #找到最大的概率
        if prob > 0.5:
            #篩選出概率大於50%的類別
            #計算每個box在原影象中的絕對座標
            box = box[0:4]* np.array[imgW, imgH, imgW, imgH])
            (centerx, centery, width, heignt) = box.astype("int")
            x = int(centerX - (width / 2))
            y = int(centerY - (height / 2))
            result_boxes.append([x, y, int(width),int(height)])
            result_scores . append(float(prob))
            result_name_id. append(class_id)
#應用非最大值抑制消除重複邊框,獲得要繪製的box
draw_boxes = cv2.dnn. NMSBoxes(result_boxes, result_scores, 0.6, 0.3)
if len(draw_boxes) > 0:
    for i in draw_boxes.ravel():
        #獲得邊框座標
        (x, y) = (result_boxes[i][0], result_boxes[i][1])
        (w, h) = (result_boxes[i][2], result_boxes[i][3])
        #繪製邊框
        cv2.rectangle(image,(x,y), (x+w,y+h),(0,255,0),1)
        #輸出類別名稱和可信度
        text=object_names[result_name_id[i]] +"n{: .1%}". format(result_scores[i])
        img_pil = Image.fromarray(image)
        draw = ImageDraw.Draw(img_pil)
        draw.text((x+5,y), text, font = font,fill=(0,0,255))
        #繪製文字
        image = np.array(img_pil)
img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt. title(tilte_text)
plt. imshow(img)
plt.axis('off')
plt. show()

到此這篇關於opencv深入淺出瞭解機器學習和深度學習的文章就介紹到這了,更多相關opencv 機器學習 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com