1. 程式人生 > >[OpenCV3.4.3] KNN使用教程

[OpenCV3.4.3] KNN使用教程

// 參考資料:(建議先閱讀此處)
// https://blog.csdn.net/chaipp0607/article/details/77966888
// https://stackoverflow.com/questions/28035484/opencv-3-knn-implementation
#include <iostream>
#include <string>
#include <opencv2/ml.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>


void Init(
) { std::cout << "Init..." << std::endl; // 我們使用的訓練樣本是OpenCV自帶的一張圖,在\opencv\sources\samples\data目錄下 // 我把這張圖拷貝到我的桌面上了,大家可以自行修改路徑 auto Img = cv::imread(R"(C:\Users\Crablet\Desktop\digits.png)"); decltype(Img) Gray; cv::cvtColor(Img, Gray, CV_BGR2GRAY); constexpr auto
b = 20; const auto m = Gray.rows / b, n = Gray.cols / b; auto FileName = 0, FileNum = 0; for (int i = 0; i < m; ++i) { if (i % 5 == 0 && i != 0) { ++FileName; FileNum = 0; } const auto OffsetRow = i * b; for (int j =
0; j < n; ++j) { const auto OffsetCol = j * b; const auto Address = R"(C:\Users\Crablet\Desktop\Out\)" + std::to_string(FileName) + std::to_string(FileNum++) + R"(.jpg)"; decltype(Gray) Tmp; Gray(cv::Range(OffsetRow, OffsetRow + b), cv::Range(OffsetCol, OffsetCol + b)) .copyTo(Tmp); cv::imwrite(Address, Tmp); } } std::cout << "Init done.\n" << std::endl; } void TrainAndPredict(int k) { std::cout << "Training..." << std::endl; cv::Mat TrainData, TrainLabel; for (int i = 0; i < 10; ++i) { for (int j = 0; j < 400; ++j) { const auto Address = R"(C:\Users\Crablet\Desktop\Out\)" + std::to_string(i) + std::to_string(j) + R"(.jpg)"; const auto Src = cv::imread(Address).reshape(1, 1); TrainData.push_back(Src); TrainLabel.push_back(i); } } TrainData.convertTo(TrainData, CV_32F); // 這是新版OpenCV的介面,網上很多資料都舊了,所以我就寫一篇文章介紹一下新版介面的用法 // 建議先閱讀“參考資料”中的內容 auto KNN = cv::ml::KNearest::create(); KNN->setDefaultK(k); KNN->setIsClassifier(true); KNN->setAlgorithmType(cv::ml::KNearest::BRUTE_FORCE); KNN->train(TrainData, cv::ml::ROW_SAMPLE, TrainLabel); std::cout << "Predicting..." << std::endl; auto TestNum = 0, TrueNum = 0; for (int i = 0; i < 10; ++i) { for (int j = 400; j < 500; ++j) { ++TestNum; const auto Address = R"(C:\Users\Crablet\Desktop\Out\)" + std::to_string(i) + std::to_string(j) + R"(.jpg)"; auto TestData = cv::imread(Address).reshape(1, 1); TestData.convertTo(TestData, CV_32F); // 這個Dummy只是為了佔個位,我們並不需要它的內容,因為我們只想讀取KNN->findNearest的返回值而已 // 注意:“auto Response = KNN->findNearest(TestData, KNN->getDefaultK(), cv::Mat());”這樣寫是不行的 // 所以我們才需要這個Dummy cv::Mat Dummy; auto Response = KNN->findNearest(TestData, KNN->getDefaultK(), Dummy); if (static_cast<int>(Response) == i) { ++TrueNum; } } } std::cout << "K: " << k << std::endl; std::cout << "TrueNum: " << TrueNum << std::endl; std::cout << "TestNum: " << TestNum << std::endl; std::cout << "Result: " << 1.0 * TrueNum / TestNum << std::endl; std::cout << std::endl; } int main() { Init(); for (int i = 1; i <= 10; ++i) { TrainAndPredict(i); } return 0; }

效果圖: 效果圖