OpenCV連續數字識別—可運行驗證

前言

? 文章開始,瞎說一點其他的東西,真的是很離譜,找了至少兩三個小時,就一個簡單的需求:

1、利用OpenCV 在Windows進行抓圖

2、利用OpenCV 進行連續數字的檢測。

3、使用C++,Qt

3、將檢測的結果顯示出來

? 就這么簡單的需求,結果網上找了各種版本硬是找不到,要是代碼可能沒啥問題,但是運行不了,你這運行不了,我怎么知道你到底能不能用,我代碼調半天能用了,結果你跟我說最后效果不好,為啥呢?

? 因為圖像識別這種東西,很取決于你的外部環境的,一定你的外部環境變量,你的數字的背景啥的變了,那么你的代碼肯定就要做相應的調整,這種不像深度學習能夠自己學習的,實際只能靠你自己一步一步的去調試驗證效果怎么樣,最終得到適合你的。

? 所以,我下面會給出我這個程序的打包的可直接驗證效果的版本,你如果不是一個想調代碼的人,或是你不是一個有耐心的人,或者你跟我的識別環境不一致, 那么我估計我的代碼你也用不了,也不必去下載了。可繼續找下一個了。

? 但如果你說,只要我代碼能讓你運行起來,那么你就能夠花精力把它調出來,實在不行,你讓AI 幫你把它調出來,這都是沒問題的,因為目前的運行方式很簡單,只要你確保環境跟我一致,基本就沒啥問題。

環境:

Windows 10

Qt 12.8 MSVC2015

OpenCV 4.5.5(我帶的這個opencv 是用VS2015編譯出來的,如果沒有MSVC2015 ,那么就只能靠你自己去下載一個MinGW 之類的,或是你自己對應版本的OpenCV了)

運行現象:
在這里插入圖片描述

因為這個是采用那個SVM首先進行模型訓練的,我的模型,每個數字只放了一張或是兩張,訓練量太小了,出來的效果就比較不好,而且,若要進行這個識別,肯定要注意以下幾點:

1、攝像頭與數字的距離一定是固定的,然后外部光源也是固定的,不能說一會亮一會不亮的,這是不合理的。

2、需要拍攝更多組的照片以及數字來進行訓練,甚至該模型可以采用自訓練的方式,來進行優化,但我這個版本就沒有做到這個點了,這個點有需要的可以來進行優化。后面對這個方面如果我有進行優化,我會來跟貼的。

3、可以對捕抓到的數字再進行一些處理,增大SVM訓練的量,這樣可能效果就會穩定很多了,我上面這個攝像頭是手拿著的,所以會一直飄,我覺得應該也是比較正常的,畢竟只用了一天時間,搞出了這個demo,那效果肯定會有差強人意的地方。

可運行程序

通過網盤分享的文件:NumberRecognitionTool.zip
鏈接: https://pan.baidu.com/s/1hr8VqU2x17pIQ561hy8nQw?pwd=1111 提取碼: 1111

我有試了一下,是可以運行的,如果不能運行可以留言下,我看下是什么原因。

如下,我會把我的核心代碼給貼上去,如果有環境的,直接改一改運行就可以了。如果還覺得有點懶的話,可以直接下載我上傳的資源文件,那里面我會把dll,啥的,都給你打包好,直接運行即可。不過要花費點積分就是了,如果又沒有積分的話,可以加我qq,或者私信我,我可以直接發你。qq在主頁有。

https://download.csdn.net/download/qq_43211060/90468759?spm=1001.2014.3001.5501

我也下載了好一些往上的資源,我也不知道有沒有用,反正我沒用上,如果有需要的話,也可以一起發給你們。希望能對你們有幫助。

正文

一、代碼

處理的核心代碼:

void CDataRecognitionMgr::InitSVM()
{srand((unsigned)time(0)); // 設置隨機數種子// 定義數字圖像尺寸:30x50digitWidth = 30;digitHeight = 50;hog = cv::HOGDescriptor(cv::Size(digitWidth, digitHeight), // winSizecv::Size(10, 10),                  // blockSizecv::Size(5, 5),                    // blockStridecv::Size(5, 5),                    // cellSize9                              // nbins);descriptorSize = (int)hog.getDescriptorSize();// ==========================// 1. 從外部加載模板圖像,并生成數據增強后的訓練樣本// ==========================vector<Mat> trainImages;vector<int> trainLabels;const int numAugmentations = 100; // 每個數字至少生成 100 個訓練樣本for (int digit = 0; digit < 10; digit++) {// 模板圖像存放在指定目錄下(根據需要調整路徑與圖片格式)string folderPattern = "./img/Mod/" + to_string(digit) + "/*.png";vector<String> files;glob(folderPattern, files, false);if (files.empty()) {cout << "未找到數字 " << digit << " 的模板圖片,請檢查文件夾: " << folderPattern << endl;continue;}// 生成數據增強樣本for (int i = 0; i < numAugmentations; i++) {// 隨機選擇一個模板圖片int idx = rand() % files.size();Mat img = imread(files[idx], IMREAD_GRAYSCALE);if (img.empty()) {cout << "加載圖片失敗: " << files[idx] << endl;continue;}// 對模板圖像進行增強處理Mat augImg = augmentImage(img, digitWidth, digitHeight);trainImages.push_back(augImg);trainLabels.push_back(digit);}}int totalSamples = (int)trainImages.size();if (totalSamples == 0) {cout << "未生成任何訓練樣本,請檢查模板圖像路徑與數據增強處理!" << endl;return;}cout << "生成的訓練樣本總數: " << totalSamples << endl;// ==========================// 2. 構造訓練數據矩陣// ==========================Mat trainingFeatures(totalSamples, descriptorSize, CV_32F);Mat trainingLabelsMat(totalSamples, 1, CV_32S);for (int i = 0; i < totalSamples; i++) {vector<float> descriptors;hog.compute(trainImages[i], descriptors);for (int j = 0; j < descriptorSize; j++) {trainingFeatures.at<float>(i, j) = descriptors[j];}trainingLabelsMat.at<int>(i, 0) = trainLabels[i];}// ==========================// 3. 使用 SVM(RBF 核)訓練分類器// ==========================svm = SVM::create();svm->setType(SVM::C_SVC);svm->setKernel(SVM::RBF);svm->setC(2.0);svm->setGamma(0.005);svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 1000, 1e-6));cout << "開始訓練 SVM..." << endl;svm->train(trainingFeatures, ml::ROW_SAMPLE, trainingLabelsMat);cout << "SVM 訓練完成。" << endl;
}void CDataRecognitionMgr::HandlerImage(const QImage &_oImg)
{
#if 1Mat mat = _ImageToMat(_oImg);Mat matGray;cvtColor(mat, matGray, COLOR_BGR2GRAY);Mat testImgThresh;threshold(matGray, testImgThresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
//    imshow("testImgThresh",testImgThresh);Mat struct1;struct1=getStructuringElement(0,Size(2,2));//矩形結構元素Mat erodeSrc;//存放腐蝕后的圖像erode(testImgThresh, erodeSrc,struct1);Mat morphKernel = getStructuringElement(MORPH_RECT, Size(3, 3));morphologyEx(erodeSrc, testImgThresh, MORPH_OPEN, morphKernel);morphologyEx(erodeSrc, testImgThresh, MORPH_CLOSE, morphKernel);vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(testImgThresh, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);qDebug() << "---> contours:"<<contours.size();if (contours.size() < 10){return;}vector<Rect> digitROIs;for (const auto& contour : contours) {Rect bbox = boundingRect(contour);// 根據尺寸過濾噪聲與無效區域qDebug() << "---> bbox.width:"<<bbox.width<<";bbox.height:"<<bbox.height;if (bbox.width > 20 && bbox.height > 20 && bbox.width < 200 && bbox.height < 200) {digitROIs.push_back(bbox);}}// 3. 分割粘連區域int avgWidth = 90; // 假設單個數字的平均寬度,可根據實際情況調整for (size_t i = 0; i < digitROIs.size(); i++) {if (digitROIs[i].width > 1.5 * avgWidth) { // 判斷是否為粘連區域// 提取粘連區域的二值圖像Mat roiImg = testImgThresh(digitROIs[i]);// 計算垂直投影Mat projection(1, roiImg.cols, CV_32F);reduce(roiImg, projection, 0, REDUCE_SUM, CV_32F);// 尋找分割點(局部最小值)int splitPos = -1;float minVal = numeric_limits<float>::max();for (int j = 1; j < projection.cols - 1; j++) {float val = projection.at<float>(0, j);if (val < projection.at<float>(0, j - 1) && val < projection.at<float>(0, j + 1) && val < minVal) {minVal = val;splitPos = j;}}// 根據分割點分割邊界框if (splitPos > 0) {Rect leftROI(digitROIs[i].x, digitROIs[i].y, splitPos, digitROIs[i].height);Rect rightROI(digitROIs[i].x + splitPos, digitROIs[i].y, digitROIs[i].width - splitPos, digitROIs[i].height);// 替換原始粘連區域digitROIs.erase(digitROIs.begin() + i);digitROIs.insert(digitROIs.begin() + i, leftROI);digitROIs.insert(digitROIs.begin() + i + 1, rightROI);i--; // 重新檢查新插入的區域}}}// 按 x 坐標排序(從左到右)sort(digitROIs.begin(), digitROIs.end(), [](const Rect& a, const Rect& b) {return a.x < b.x;});cout << "檢測到的輪廓數量: " << digitROIs.size() << endl;for (const auto& roi : digitROIs) {cout << "邊界框: " << roi << endl;}string recognized = "";for (const auto& roi : digitROIs) {Mat digitROI = testImgThresh(roi);Mat digitResized;resize(digitROI, digitResized, Size(digitWidth, digitHeight));vector<float> descriptors;hog.compute(digitResized, descriptors);Mat sample(1, descriptorSize, CV_32F);for (int j = 0; j < descriptorSize; j++) {sample.at<float>(0, j) = descriptors[j];}int predicted = (int)svm->predict(sample);recognized.push_back('0' + predicted);}QString str = QString::fromStdString(recognized);emit SIGNAL_DATA_NUM(str);cout << "識別結果1: " << recognized << endl;
#endif
}

InitSVM基本就是訓練的標準流程了,那么比較核心的還是下面這個函數,這個函數HandlerImage可能就需要你進行一些調整:
首先先進行基本的圖像處理,由于某些打印的會出現說數字粘在一起的情況,那么就得采用這個分割粘連區域進行局部處理,才能分割出來,我這份代碼試了兩種情況,都還可以,一個是會粘著的,一個是不會粘著的。

其他你需要更詳細的,可以將這兩個函數放到AI中幫忙解釋一下就可以了。

接下來,就到了我們的經典環節:
在這里插入圖片描述

在這里插入圖片描述

參考

1、opencv 數字識別 數碼管

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72904.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72904.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72904.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

shell的模擬實現 ─── linux第16課

在shell的命令行中輸入命令,會有兩種執行命令的途徑 shell自己執行 shell創建子進程(fork ,exit ,waitpid,exec) ,子進程去執行 shell自己執行的命令是自建命令(bulit command) 子進程執行的是非自建命令 第一版只能維護命令行參數表創建子進程, 執行非內建命令 我們先創…

MySQL創建數據庫和表,插入四大名著中的人物

一、登錄數據庫并創建數據庫db_ck 二、創建表t_hero 表屬性包括&#xff08;id&#xff0c;name&#xff0c;nickname&#xff0c;age&#xff0c;gender&#xff0c;address&#xff0c;weapon&#xff0c;types&#xff09; mysql> create table t_hero(-> id int,-…

靜態網頁的爬蟲(以電影天堂為例)

一、電影天堂的網址&#xff08;url&#xff09; 電影天堂_免費電影_迅雷電影下載_電影天堂網最好的迅雷電影下載網&#xff0c;分享最新電影&#xff0c;高清電影、綜藝、動漫、電視劇等下載&#xff01;https://dydytt.net/index.htm 我們要爬取這個頁面上的內容 二、代碼…

【C++】:STL詳解 —— 紅黑樹封裝map和set

目錄 紅黑樹的源代碼 正向迭代器的代碼 反向迭代器的代碼 set的模擬實現 map的模擬實現 紅黑樹的源代碼 #pragma once #include <iostream>using namespace std; // set ->key // map ->key/value// set ->key // map ->key/valueenum Colour {RED,BLAC…

MATLAB控制函數測試要點剖析

一、功能準確性檢驗 基礎功能核驗 針對常用控制函數&#xff0c;像用于傳遞函數建模的 tf 、構建狀態空間模型的 ss &#xff0c;以及開展階躍響應分析的 step 等&#xff0c;必須確認其能精準執行基礎操作。以 tf 函數為例&#xff0c;在輸入分子與分母系數后&#xff0c;理…

MoonSharp 文檔一

目錄 1.Getting Started 步驟1&#xff1a;在 IDE 中引入 MoonSharp 步驟2&#xff1a;引入命名空間 步驟3&#xff1a;調用腳本 步驟4&#xff1a;運行代碼 2.Keeping a Script around 步驟1&#xff1a;復現前教程所有操作 步驟2&#xff1a;改為創建Script對象 步驟…

ROS云課三分鐘-差動移動機器人導航報告如何撰寫-及格邊緣瘋狂試探

提示詞&#xff1a;基于如上所有案例并結合roslaunch teb_local_planner_tutorials robot_diff_drive_in_stage.launch和上面所有對話內容&#xff0c;設計一個差速移動機器人仿真實驗&#xff0c;并完成報告的全文撰寫。 差速移動機器人導航仿真實驗報告 一、實驗目的 驗證 T…

ACE協議學習1

在多核系統或復雜SoC&#xff08;System on Chip&#xff09;中&#xff0c;不同處理器核心或IP&#xff08;Intellectual Property&#xff09;模塊之間需要保持數據的一致性。常用的是ACE協議or CHI。 先對ACE協議進行學習 ACE協議&#xff08;Advanced Microcontroller Bu…

ajax之生成一個ajax的demo示例

目錄 一. node.js和express ?二. 使用express創建后端服務 三. 創建前端 一. node.js和express ajax是前端在不刷新的情況下訪問后端的技術&#xff0c;所以首先需要配置一個后端服務&#xff0c;可以使用node.js和express。 首先生成一個空項目&#xff0c;新建main目錄…

Java 字節碼操縱框架 -ASM

Java 字節碼操縱框架 -ASM 1.ASM 概述: ASM 是用于 Java 字節碼操縱的框架,可動態生成新類或增強現有類的功能。它既能直接產生二進制 class 文件,也能在類被加載到虛擬機之前動態改變類行為,通過讀取類文件信息來分析、修改類行為,甚至生成新類。許多流行框架如 cglib、…

kafka + flink +mysql 案例

假設你有兩個Kafka主題&#xff1a;user_activities_topic 和 product_views_topic&#xff0c;并且你希望將user_activities_topic中的數據寫入到user_activities表&#xff0c;而將product_views_topic中的數據寫入到product_views表。 maven <dependencies><!-- …

遠程登錄客戶端軟件 CTerm 發布了 v4.0.0

有時候我們需要遠程登錄到 Linux/Unix 服務器&#xff0c;這方面使用最廣泛的客戶端軟件是 PuTTY&#xff0c;不過它是全英文的&#xff0c;而且是單窗口的&#xff0c;有時候顯得不那么方便。 CTerm (Clever Terminal) 是一個 Windows 平臺下支持 Telnet 和 SSH 協議進行遠程…

從李佳琦團隊看新型用工:靈活就業如何重構組織架構?

2022年“雙11”期間&#xff0c;李佳琦直播間累計銷售額突破115億元&#xff08;來源&#xff1a;新腕數據《2022雙11直播電商戰報》&#xff09;&#xff0c;其背后團隊規模約400人&#xff0c;但全職員工僅占35%&#xff0c;其余65%為外包選品團隊、兼職客服、第三方MCN機構人…

微軟程序的打包格式MSIX

MSIX 微軟推出的MSIX格式是其為統一Windows應用程序打包和部署而設計的新一代安裝包格式&#xff0c;具有以下核心特點和進展&#xff1a; 1. 推出背景與時間線 MSIX最初于2018年在微軟Build大會上宣布&#xff0c;并在同年7月發布預覽版打包工具&#xff0c;10月正式版上線…

AFL++安裝

學習fuzzing也幾天了&#xff0c;今天記錄AFL的安裝及使用 一、實驗環境 虛擬機&#xff1a;ubuntu20.04 當然也可以uname -a去看自己的版本號 二、AFL安裝 1.先更新一下工具 sudo apt update2.安裝AFL必要的一些依賴&#xff0c;例如編譯工具&#xff08;如 build-essen…

【STM32】ADC功能-單通道多通道(學習筆記)

本章結合上一節內容復習更好理解【江協科技STM32】ADC數模轉換器-學習筆記-CSDN博客 一、ADC單通道 接線圖 ADC初始化 ①RCC開啟時鐘&#xff0c;包括ADC和GPIO的時鐘&#xff0c;另外ADCCLK的分頻器也要配置 ②配置GPIO,&#xff0c;把需要用的GPIO配置成模擬輸入模式&am…

基于YOLO11深度學習的運動品牌LOGO檢測與識別系統【python源碼+Pyqt5界面+數據集+訓練代碼】

《------往期經典推薦------》 一、AI應用軟件開發實戰專欄【鏈接】 項目名稱項目名稱1.【人臉識別與管理系統開發】2.【車牌識別與自動收費管理系統開發】3.【手勢識別系統開發】4.【人臉面部活體檢測系統開發】5.【圖片風格快速遷移軟件開發】6.【人臉表表情識別系統】7.【…

當前主流的大模型訓練與推理框架的全面匯總

以下是當前主流的大模型訓練與推理框架的全面匯總 以下是更新后包含 SGLang 的大模型訓練與推理框架列表&#xff0c;并對分類和示例進行了優化&#xff1a; 一、通用深度學習推理框架 TensorRT-LLM 特點&#xff1a;NVIDIA推出的針對Transformer類模型的優化框架&#xff0c;支…

Linux學習(八)(服務管理(檢查服務狀態,開始/停止服務,檢查服務日志,創建新服務))

服務管理 Linux 中的服務管理是指控制 Linux 在啟動和關閉計算機的過程中啟動和停止的服務&#xff08;或“守護程序”&#xff09;的系統。這些服務執行各種功能&#xff0c;并提供未附加到用戶界面的進程。 Linux 系統&#xff0c;尤其是系統管理員&#xff0c;通常需要管理…

ElasticSearch 分詞器介紹及測試:Standard(標準分詞器)、English(英文分詞器)、Chinese(中文分詞器)、IK(IK 分詞器)

ElasticSearch 分詞器介紹及測試&#xff1a;Standard&#xff08;標準分詞器&#xff09;、English&#xff08;英文分詞器&#xff09;、Chinese&#xff08;中文分詞器&#xff09;、IK&#xff08;IK 分詞器&#xff09; ElasticSearch 分詞器介紹及測試1. Standard Analyz…