opencv画虚线_(四十四)OpenCV中的机器学习-SVM
時間為友,記錄點滴。
本來還想在特征點檢測的道路上再走一走,學習一下Harr級聯或者HOG什么的,但總有些概念感覺繞不過去。擇日不如撞日,撞日不如今日。我們先揭開機器學習中的一個小角,看看大熱的機器學習到底是什么東西。
啥是機器學習?
如今機器學習在中國的大熱,還是要感謝2016年Alpha Go和李世石的那場人機圍棋對決。外行人人談AI,內行深度神經網絡大紅大紫。
人工智能,機器學習,深度學習的關系從關系上看,機器學習僅僅是實現人工智能的其中一種方式。所謂機器學習,我更愿意把機器擬人化,跟人類學習一樣,可以從經驗(數據)中去成長(學習),然后可以解決實際的問題。這個過程就是學習。人的過程就是人的學習,計算機的過程就是機器學習。
我們可以用這么定義:
機器學習=數據+算法+硬件
機器學習的分類
硬件:
我們結合上面的公式,先來看看硬件:
CPU GPU 專用芯片- 最開始的機器學習當然是寫成程序運行在CPU通用處理器上了;
- 但是隨著深度學習的發展,人們發現GPU的架構更適合做深度神經網絡這種大量的簡單運算(要么NVIDIA的股票biubiu地飛);
- 后來,人們發現可以為某個算法單獨設計一款ASIC,這樣的運算能效比比GPU更高(要么Bitcoin能挖這么快);
數據和算法:
為什么把數據和算法放一塊呢?因為他們總是相輔相成,特定的數據就需要有更優的算法來匹配。
在機器學習的算法世界里,如OpenCV的傳統算法一樣,浩如煙海,如果真的有人想要搞懂大部分的算法,一定是驚為天人了。聽說下面這個哥們用numpy手寫了好多。
ddbourgin/numpy-ml?github.comOpenCV中的機器學習
OpenCV的ml模塊實現了很多算法,包括樸素貝葉斯、K近鄰、SVM、決策樹、Boosting、GBT、隨機森林、神經網絡等。其大多繼承自同一基類,訓練和預測的接口都是train(),predict(),使用較為方便。
我們進入到代碼里面瞅一瞅:
在源碼的opencv-4.1.1opencv-4.1.1modulesmlincludeopencv2ml.hpp文件中有提到:
ml.hpp里面包含的內容SVM(Support Vector Machines)
如果之前沒接觸過機器學習,那么越說多越迷糊;如果之前就聽過NG大神的課,那多說就是廢話。我們既然不是以機器學習算法研究推導為主題,那么就讓我們在OpenCV中感受一個比較簡單的算法,這樣可以對機器學習的認識再向前前進一小步。
拿誰開刀呢?SVM!
SVM(Support Vector Machines)中文翻譯是支持向量機,SVM算法在在1995年正式發表,在針對中小型數據規模的分類任務上有著卓越的效果,同時有著完整的理論證明,在20世紀末的幾年和21世紀初的10年完勝神經網絡,直到深度學習的興起。但即便這樣,現在SVM算法依舊被廣泛的使用。
1、SVM要解決什么問題?
如果要搞清楚SVM是什么東西,還是要從我們為什么要引入SVM說起。
SVM主要用于解決模式識別領域中的數據分類問題,屬于有監督學習算法的一種。SVM要解決的問題可以用一個經典的二分類問題加以描述。
我們把需求簡化一下,兩個數據在笛卡爾直角平面坐標系中分別被標定成紅色點和藍色點,那么我顯然可以通過一條直線把兩個數據區分開(在數字圖像中,可以把兩個點理解成特征點和背景,所以區分數據就是提取特征點的過程)
那么問題來了,這條線該怎么畫?SVM就是來解決如何劃線的問題。
監督:人為規定此球(數據)為紅色,彼球(數據)為藍色的過程。分類:就是把紅球和籃球分開;
2、SVM中如何畫線?
如何判斷上圖中的三條線,哪條比較好?直覺是紅色的那條,為什么呢?因為當數據變多時,紅色的線是最大可能分區數據的那條。
可以畫一條虛線連接兩個圓的圓心作為輔助線,紅線距離兩個圓的圓心都比較遠嗯,感覺好有道理,這和SVM有什么關系呢?
我們知道,在計算機的世界里,所有的點都是離散的,比如下圖:
如何區分上圖的眾多紅球和籃球的過程中,你可以畫一條A這樣的線,也可以畫一條B這樣的線,他們都可以把紅球和籃球區分開,但是哪個是最優的呢?
可不可以借鑒兩個圓連接圓心求最大距離的思路呢?當然可以!
我們取(b)圖放大,此時A就是此時的分界線,專業稱為“決策線”。
所以,找線的問題就轉變成求解支持向量到決策線的垂直距離d最大的問題。
在SVM支持向量中,所有的這些數據在空間中的表達式就是一個向量,而用于直接支持確定決策線的這些點,就叫做支持向量。因此,這個算法被叫做支持向量機。
- 數據即向量;
- 支持確立決策線的數據即支持向量;
- 通過支持向量求決策線的算法即支持向量機;
好了,我們今天了解了支持向量機能做什么以及為什么叫他支持向量機。至于公式推導SVM如何做到這一切的就留給明天吧,我們今天先來看看OpenCV中官方的SVM怎么使用的。
官方文件目錄:opencv-4.1.1samplescpptutorial_codemlintroduction_to_svmintroduction_to_svm.cpp
C++
這里面的三個關鍵點:
1、數據和標簽
int labels[4] = {1, 1, -1, -1};float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };- trainingData為四個數據點(可以認為是球的圓心坐標)。
- labels為對應數據的標簽(監督,可以認為1為紅球,-1為籃球)
2、訓練
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);如下是OpenCV中train的函數原型:
/** @brief Trains the statistical model@param samples training samples@param layout See ml::SampleTypes.@param responses vector of responses associated with the training samples.*/CV_WRAP virtual bool train( InputArray samples, int layout, InputArray responses );其中:
- Sample表示訓練樣本數據
- Layout 有兩種組織方式ROW_SAMPLE與COL_SAMPLE
- Responses 每個輸入樣本的標簽
這里其實就是尋找決策線的過程。
3、分類
float response = svm->predict(sampleMat);如下是OpenCV的predict原型
@param samples The input samples, floating-point matrix@param results The optional output matrix of results.@param flags The optional flags, model-dependent. See cv::ml::StatModel::Flags.*/CV_WRAP virtual float predict( InputArray samples, OutputArray results=noArray(), int flags=0 ) const = 0;其中:
- samples:表示輸入樣本,供SVM判定。
- OutputArray :表示輸出矩陣
- flag:表示支持模式
返回值為設定的標簽值(這里是1或者-1),由此可以判定當前輸入應該被分到哪一類中(也可以理解成是分在決策線的哪一邊。)
#include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/highgui.hpp> #include <opencv2/ml.hpp>using namespace cv; using namespace cv::ml;int main(int, char**) {// Set up training data//! [setup1]int labels[4] = {1, 1, -1, -1};float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };//! [setup1]//! [setup2]Mat trainingDataMat(4, 2, CV_32F, trainingData);Mat labelsMat(4, 1, CV_32SC1, labels);//! [setup2]// Train the SVM//! [init]Ptr<SVM> svm = SVM::create();svm->setType(SVM::C_SVC);svm->setKernel(SVM::LINEAR);svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));//! [init]//! [train]svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);//! [train]// Data for visual representationint width = 512, height = 512;Mat image = Mat::zeros(height, width, CV_8UC3);// Show the decision regions given by the SVM//! [show]Vec3b green(0,255,0), blue(255,0,0);for (int i = 0; i < image.rows; i++){for (int j = 0; j < image.cols; j++){Mat sampleMat = (Mat_<float>(1,2) << j,i);float response = svm->predict(sampleMat);if (response == 1)image.at<Vec3b>(i,j) = green;else if (response == -1)image.at<Vec3b>(i,j) = blue;}}//! [show]// Show the training data//! [show_data]int thickness = -1;circle( image, Point(501, 10), 5, Scalar( 0, 0, 0), thickness );circle(image, Point(255, 10), 5, Scalar(0, 0, 0), thickness);circle( image, Point(501, 255), 5, Scalar(255, 255, 255), thickness );circle( image, Point( 10, 501), 5, Scalar(255, 255, 255), thickness );//! [show_data]// Show support vectors//! [show_vectors]thickness = 2;Mat sv = svm->getUncompressedSupportVectors();for (int i = 0; i < sv.rows; i++){const float* v = sv.ptr<float>(i);circle(image, Point( (int) v[0], (int) v[1]), 6, Scalar(0, 0, 255), thickness);}//! [show_vectors]imwrite("result.png", image); // save the imageimshow("SVM Simple Example", image); // show it to the userwaitKey();return 0; }有了上面的監督數據+訓練+預測,代碼就好理解多了。直接看結果吧:
代碼我稍作了修改,主要是修改了標簽值。讀者也可以自己改一下標簽紙,感受一下支持向量和決策邊界的移動。
總結
以上是生活随笔為你收集整理的opencv画虚线_(四十四)OpenCV中的机器学习-SVM的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 自后向前截取函数_【转载】S
- 下一篇: spark executor内存分配_二