手寫數(shù)字識別是一種經(jīng)典的模式識別和圖像處理問題,旨在通過計算機自動識別用戶手寫的數(shù)字。
本文將教會你如何使用基于RV1106的 LockAI視覺識別模塊進行手寫數(shù)字識別。
源代碼:https://gitee.com/LockzhinerAI/LockzhinerVisionModule/tree/master/Cpp_example/D02_DigitHandRecog
1. 基本知識講解
1.1 手寫數(shù)字識別簡介
手寫數(shù)字識別是一種利用計算機視覺和機器學習技術自動識別手寫數(shù)字的過程。它通過圖像預處理、特征提取和模型訓練來實現(xiàn)高效準確的數(shù)字識別。被廣泛應用于銀行支票處理、郵政編碼識別及考試評分等場景。這項技術不僅提高了數(shù)據(jù)處理的速度和準確性,還極大地簡化了輸入流程,為金融、郵政和教育等行業(yè)帶來了顯著的便利。
1.2 手寫數(shù)字識別常用方法
目前,實現(xiàn)手寫數(shù)字識別方法有很多,常用的方法如下:
卷積神經(jīng)網(wǎng)絡(CNN):最流行的方法之一,能夠自動從圖像中學習特征。適用于復雜背景和不同書寫風格的手寫數(shù)字識別。
支持向量機(SVM):一種傳統(tǒng)的機器學習方法,通過提取圖像的特征(如HOG特征)進行分類,適合處理較為規(guī)范的手寫數(shù)字。
K近鄰算法(KNN):基于相似度的分類方法,通過比較待識別數(shù)字與訓練樣本的距離來進行分類,簡單但計算成本較高。
2. C++ API文檔
2.1 PaddleClas類
2.1.1 頭文件
#include
作用:用于聲明PaddleClas類,使得PaddleClas類可以在當前源文件中使用。
2.1.2 構造類函數(shù)
lockzhiner_vision_module::PaddleClasmodel;
作用:用于實現(xiàn)手寫數(shù)字識別。
參數(shù)說明:
無
返回值:
無
2.1.3 Predict函數(shù)
autoresult=model.Predict(input_mat);
作用:PaddleClas類中的一個函數(shù),用于實現(xiàn)手寫數(shù)字識別。
參數(shù)說明:
input_mat:要識別的圖像。
返回值:
返回一個包含手寫數(shù)字分類結果的對象。該Result對象包含預測得分(score)和對應的標簽ID(label_id),即識別出的手寫數(shù)字。
2.2 Visualize函數(shù)
2.2.1 頭文件
#include
作用:用于聲明Visualize函數(shù),使得Visualize函數(shù)可以在當前源文件中使用。
2.2.2 結果可視化
lockzhiner_vision_module::Visualize(input_mat,output_image,result);
參數(shù)說明:
input_mat:表示原始輸入圖像。
output_image:用于存儲帶有可視化結果的輸出圖像。
result:輸入?yún)?shù),表示手寫數(shù)字識別的結果。該Result對象包含預測得分(score)和對應的標簽ID(label_id)。
返回值:
無
3. 綜合代碼解析
3.1 流程圖
3.2 核心代碼解析
初始化分類模型
lockzhiner_vision_module::PaddleClasmodel;
自定義函數(shù)參數(shù)如下
圖片手寫數(shù)字識別
intTestImage(conststd::string&image_path)
參數(shù)說明:
image_path:輸入?yún)?shù),表示包含手寫數(shù)字的圖像文件路徑。
返回值:
返回0表示成功執(zhí)行,并保存執(zhí)行結果為"cls_result.png"。
攝像頭實時手寫數(shù)字識別
intTestCapture()
參數(shù)說明:
無
返回值:
返回0表示執(zhí)行成功,并將檢測結果繪制在原始圖像上。程序會持續(xù)從攝像頭讀取幀并進行處理,直到手動終止程序。
3.3 完整代碼實現(xiàn)
#include#include#include#include#include#include#include#includeusingnamespacestd::chrono;lockzhiner_vision_module::PaddleClas model;intTestCapture(){ // 初始化 edit 模塊 lockzhiner_vision_module::Edit edit; if(!edit.StartAndAcceptConnection()) { std::cerr <"Error: Failed to start and accept connection."?<< std::endl;? ? return?EXIT_FAILURE;? }? std::cout <"Device connected successfully."?<< std::endl;? cv::VideoCapture cap;?? // 設置攝像頭長寬? cap.set(cv::CAP_PROP_FRAME_WIDTH,?640);? cap.set(cv::CAP_PROP_FRAME_HEIGHT,?480);? cap.open(0);? if?(!cap.isOpened())? {? ? std::cerr <"Error: Could not open camera."?<< std::endl;? ? return?EXIT_FAILURE;? }? cv::Mat input_mat;? while?(true)? {? ? int?read_index =?0;? ? int?time_ms =?0;? ? for?(int?i =?0; i 30; i++)? ? {? ? ? // 獲取當前時間點作為開始時間? ? ? high_resolution_clock::time_point start_time =? ? ? ? ? high_resolution_clock::now();? ? ? cap >> input_mat; if(input_mat.empty()) { continue; } // 使用 model 對象的 Predict 方法對輸入圖像進行預測 autoresult = model.Predict(input_mat); // 獲取當前時間點作為結束時間 high_resolution_clock::time_point end_time = high_resolution_clock::now(); autotime_span =duration_cast(end_time - start_time); time_ms += time_span.count(); read_index +=1; std::cout <"score is "?<< result.score <";label_id is "? ? ? ? ? ? ? ? << result.label_id << std::endl;? ? ? cv::Mat output_image;? ? ? lockzhiner_vision_module::Visualize(input_mat, output_image,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result);? ? ? // 使用 edit 模塊處理幀? ? ? edit.Print(output_image);? ? }? ? std::cout <"Frames per second: "?<1000.0?/ time_ms * read_index? ? ? ? ? ? ? << std::endl;? }? cap.release();? return?0;}int?TestImage(const?std::string &image_path){? cv::Mat input_image = cv::imread(image_path);? auto?result = model.Predict(input_image);? std::cout <"score is "?<< result.score <";label_id is "?<< result.label_id? ? ? ? ? ? << std::endl;? cv::Mat output_image;? lockzhiner_vision_module::Visualize(input_image, output_image,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result);? cv::imwrite("cls_result.png", output_image);? return?0;}int?main(int?argc,?char?*argv[]){? if?(argc !=?3)? {? ? std::cerr <"Usage: Test-PaddleClas model_path "? ? ? ? ? ? ? << std::endl;? ? return?1;? }? if?(!model.Initialize(argv[1]))? {? ? std::cout <"Failed to initialize model."?<< std::endl;? ? return?1;? }? std::string?argument(argv[2]);? if?(argument ==?"Capture")? {? ? return?TestCapture();? }? else? {? ? return?TestImage(argument);? }? return?0;}
4. 編譯調(diào)試
4.1 編譯環(huán)境搭建
請確保你已經(jīng)按照開發(fā)環(huán)境搭建指南正確配置了開發(fā)環(huán)境。
同時已經(jīng)正確連接開發(fā)板。
4.2 Cmake介紹
cmake_minimum_required(VERSION3.10)project(test_DigitHandRecog)set(CMAKE_CXX_STANDARD17)set(CMAKE_CXX_STANDARD_REQUIRED ON)# 定義項目根目錄路徑set(PROJECT_ROOT_PATH"${CMAKE_CURRENT_SOURCE_DIR}/../..")message("PROJECT_ROOT_PATH = "${PROJECT_ROOT_PATH})include("${PROJECT_ROOT_PATH}/toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake")# 定義 OpenCV SDK 路徑set(OpenCV_ROOT_PATH"${PROJECT_ROOT_PATH}/third_party/opencv-mobile-4.10.0-lockzhiner-vision-module")set(OpenCV_DIR"${OpenCV_ROOT_PATH}/lib/cmake/opencv4")find_package(OpenCV REQUIRED)set(OPENCV_LIBRARIES"${OpenCV_LIBS}")# 定義 LockzhinerVisionModule SDK 路徑set(LockzhinerVisionModule_ROOT_PATH"${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk")set(LockzhinerVisionModule_DIR"${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module")find_package(LockzhinerVisionModule REQUIRED)add_executable(Test-DigitHandRecogDigitHandRecog.cc)target_include_directories(Test-DigitHandRecogPRIVATE${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS})target_link_libraries(Test-DigitHandRecogPRIVATE${OPENCV_LIBRARIES}${LOCKZHINER_VISION_MODULE_LIBRARIES})install( TARGETSTest-DigitHandRecog RUNTIME DESTINATION . )
4.3 編譯項目
使用 Docker Destop 打開 LockzhinerVisionModule 容器并執(zhí)行以下命令來編譯項目
# 進入Demo所在目錄cd/LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/Cpp_example/D02_DigitHandRecog# 創(chuàng)建編譯目錄rm-rf build &&mkdirbuild &&cdbuild# 配置交叉編譯工具鏈exportTOOLCHAIN_ROOT_PATH="/LockzhinerVisionModuleWorkSpace/arm-rockchip830-linux-uclibcgnueabihf"# 使用cmake配置項目cmake ..# 執(zhí)行編譯項目make -j8 && make install
在執(zhí)行完上述命令后,會在build目錄下生成可執(zhí)行文件。
5. 例程運行示例
5.1 運行前準備
請確保你已經(jīng)下載了凌智視覺模塊手寫數(shù)字分類模型
5.2 運行過程
在凌智視覺模塊輸入以下命令:
chmod777Test-DigitHandRecog# 調(diào)用攝像頭實時識別./Test-DigitHandRecogLZ-DigitHandRecog.rknn Capture# 單張圖像識別./Test-DigitHandRecogLZ-DigitHandRecog.rknn image_path
5.3 運行效果
圖像識別效果圖
- 攝像頭實時識別效果圖
6. 總結
通過上述內(nèi)容,我們成功的實現(xiàn)了一個手寫數(shù)字識別系統(tǒng),包括:
獲取并加載包含手寫數(shù)字的圖像。
進行手寫數(shù)字的檢測和分類,返回檢測和分類后的結果。
可視化包含手寫數(shù)字圖像的識別結果。
-
AI
+關注
關注
88文章
35168瀏覽量
280156 -
視覺識別
+關注
關注
3文章
107瀏覽量
17071 -
數(shù)字識別
+關注
關注
2文章
21瀏覽量
10254
發(fā)布評論請先 登錄
基于LockAI視覺識別模塊:C++條碼識別
基于LockAI視覺識別模塊:C++人臉識別
基于分數(shù)本征特征的手寫數(shù)字識別
基于分數(shù)本征特征的手寫數(shù)字識別
基于MNIST的手寫數(shù)字識別系統(tǒng)

基于LockAI視覺識別模塊:C++使用圖像的統(tǒng)計信息

基于LockAI視覺識別模塊:C++目標檢測

評論