《使用Qt Quick從零構建AI螺絲瑕疵檢測系統》——6. 傳統算法實戰:用OpenCV測量螺絲尺寸

目錄

  • 一、概述
    • 1.1 背景介紹:從“看見”到“看懂”
    • 1.2 學習目標
  • 二、圖像預處理:讓目標更突出
  • 三、輪廓發現與尺寸測量
  • 四、總結與展望

一、概述

1.1 背景介紹:從“看見”到“看懂”

在上一篇文章中,我們成功地為應用程序安裝了“眼睛”——集成了OpenCV并實現了圖像的加載與顯示。現在,我們的程序已經能夠“看見”螺絲了。然而,僅僅看見是不夠的,機器視覺的核心價值在于能像人一樣“看懂”圖像,從中提取出有用的信息。

本篇文章的核心任務,就是實現從“看見”到“看懂”的第一次跨越。我們將利用OpenCV強大的圖像處理能力,編寫第一個真正的視覺算法——自動測量螺絲的尺寸。這是一種經典的、非接觸式的測量應用,在工業生產中非常常見。通過這個實戰,讀者將直觀地感受到傳統視覺算法是如何通過一系列步驟,從像素中提取出幾何信息的。

1.2 學習目標

通過本篇的學習,讀者將能夠:

  1. 掌握圖像預處理的基本技術,如灰度轉換二值化,這是讓計算機能夠“理解”圖像的關鍵步驟。
  2. 學習并實踐OpenCV中一個核心的算法——輪廓發現(Contour Finding)
  3. 利用發現的輪廓,計算其最小外接矩形(Min Area Rect),從而精確地獲得螺絲的長度和寬度。
  4. 將計算出的尺寸信息和判定結果,通過信號傳遞回QML界面進行顯示。

二、圖像預處理:讓目標更突出

計算機不像人眼那樣智能,一張彩色的原始圖像對它來說只是一堆復雜的RGB像素值。為了讓計算機能夠輕松地識別出我們感興趣的目標(螺絲),必須先對圖像進行預處理,其核心目的就是簡化圖像,增強目標特征,減弱背景干擾

【例6-1】 圖像灰度化與二值化。

1. 修改Backend (backend.cpp)
我們將繼續在Backend::startScan()函數中進行修改。在加載圖像之后,增加灰度轉換和二值化的步驟。

// backend.cpp
#include "backend.h"
// ... (之前的include保持不變)// ... (matToQImage輔助函數保持不變)Backend::Backend(QObject *parent) : QObject(parent) {}void Backend::startScan()
{// ... (加載圖像的代碼保持不變)QString imagePath = QDir::currentPath() + "/../../dataset/screw/test/scratch_head/000.png";cv::Mat sourceMat = cv::imread(imagePath.toStdString());if (sourceMat.empty()) { /* ... 錯誤處理 ... */ return; }emit statusMessageChanged("圖像加載成功,開始預處理...");// --- 1. 灰度轉換 ---// 將BGR彩色圖像轉換為單通道的灰度圖像cv::Mat grayMat;cv::cvtColor(sourceMat, grayMat, cv::COLOR_BGR2GRAY);// --- 2. 二值化 ---// 將灰度圖像轉換為只有黑白兩種顏色的二值圖像// 此處使用OTSU方法自動尋找最佳閾值cv::Mat binaryMat;cv::threshold(grayMat, binaryMat, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);// 為了在UI上直觀展示處理結果,我們暫時只顯示二值化后的圖像QImage imageQ = matToQImage(binaryMat);if (imageQ.isNull()){ /* ... 錯誤處理 ... */ return; }m_imageProvider->updateImage(imageQ);emit imageReady("screw_processed");emit statusMessageChanged("圖像預處理完成!");
}

2. 運行結果
再次運行程序并點擊“開始檢測”,現在界面上顯示的不再是原始的彩色螺絲圖片,而是一張清晰的黑白輪廓圖。在這張圖中,螺絲主體是白色(像素值為255),背景是黑色(像素值為0),目標物被完美地凸顯了出來。
在這里插入圖片描述
關鍵代碼分析:
(1) cv::cvtColor(...): OpenCV中用于色彩空間轉換的函數。cv::COLOR_BGR2GRAY是一個預定義的常量,表示從BGR色彩空間轉換到灰度空間。
(2) cv::threshold(...): 二值化函數。它將圖像中所有像素值大于閾值的像素設為一個值(如255),小于等于閾值的設為另一個值(如0)。
(3) THRESH_BINARY_INV: 表示反向二值化。因為我們的螺絲比背景暗,普通二值化后螺絲會變黑。使用反向二值化,可以讓暗的螺絲變成白色,方便后續處理。
(4) THRESH_OTSU: 這是一個非常智能的標志。當使用它時,我們傳遞的閾值參數(這里是0)會被忽略,threshold函數會自動計算出一個最優的全局閾值來分割前景和背景。這對于光照不均的場景非常有效。

三、輪廓發現與尺寸測量

經過預處理后,圖像中的螺絲已經變成了一個清晰的白色區域。現在,我們可以讓OpenCV去“尋找”這個白色區域的邊界,這個邊界就是輪廓

【例6-2】 尋找輪廓并計算最小外接矩形。

1. 修改Backend (backend.cpp)
在二值化之后,加入輪廓發現和幾何計算的邏輯。

// backend.cpp
// ...
#include <vector> // C++標準庫,用于存儲輪廓// ... (matToQImage輔助函數)void Backend::startScan()
{// ... (加載圖像、灰度化、二值化的代碼保持不變) ...cv::Mat sourceMat = cv::imread(...);cv::Mat binaryMat;// ... cv::threshold(...) ...emit statusMessageChanged("預處理完成,開始尋找輪廓...");// --- 3. 輪廓發現 ---std::vector<std::vector<cv::Point>> contours;cv::findContours(binaryMat, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);// 假設最大輪廓就是我們的螺絲if (contours.empty()) {emit statusMessageChanged("錯誤:未在圖像中找到任何輪廓!");return;}// 尋找面積最大的輪廓double maxArea = 0;int maxAreaIdx = -1;for (int i = 0; i < contours.size(); i++) {double area = cv::contourArea(contours[i]);if (area > maxArea) {maxArea = area;maxAreaIdx = i;}}if (maxAreaIdx == -1) {// ... 錯誤處理return;}// --- 4. 尺寸測量 ---// 計算最大輪廓的最小外接矩形cv::RotatedRect rotatedRect = cv::minAreaRect(contours[maxAreaIdx]);// 獲取矩形的尺寸。注意:width和height不一定是物理的長和寬cv::Size2f rectSize = rotatedRect.size;float width = std::min(rectSize.width, rectSize.height);float length = std::max(rectSize.width, rectSize.height);qDebug() << "Measured dimensions (pixels): Length =" << length << ", Width =" << width;QString resultMessage = QString("測量結果: 長度= %1 px, 寬度= %2 px").arg(length, 0, 'f', 2).arg(width, 0, 'f', 2);// --- 5. 結果可視化 ---// 為了直觀展示,我們在原始彩色圖上把輪廓和矩形畫出來// 獲取矩形的四個頂點cv::Point2f vertices[4];rotatedRect.points(vertices);// 將輪廓和矩形畫在sourceMat上cv::drawContours(sourceMat, contours, maxAreaIdx, cv::Scalar(0, 255, 0), 2); // 綠色輪廓for (int i = 0; i < 4; i++) {cv::line(sourceMat, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 0, 255), 2); // 紅色矩形}// 將帶有繪制結果的圖像發送到UIQImage imageQ = matToQImage(sourceMat);m_imageProvider->updateImage(imageQ);emit imageReady("screw_processed");emit statusMessageChanged(resultMessage);
}

2. 運行結果
點擊“開始檢測”后,界面上將顯示原始的彩色螺絲圖片,但上面已經疊加了綠色的輪廓線和紅色的最小外接矩形。同時,狀態欄會顯示出計算出的像素尺寸。
在這里插入圖片描述
關鍵代碼分析:
(1) cv::findContours(...): OpenCV中用于尋找輪廓的核心函數。
- binaryMat: 輸入必須是二值圖像。
- contours: 輸出參數,一個存儲向量的向量集(std::vector<std::vector<cv::Point>>),用于存儲所有找到的輪廓。每個輪廓本身是一個由點(cv::Point)組成的向量。
- cv::RETR_EXTERNAL: 表示只檢測最外層的輪廓,忽略內部的孔洞,這對于我們的需求是最高效的。
- cv::CHAIN_APPROX_SIMPLE: 一種輪廓點的壓縮算法,只保留輪廓的端點,可以節省大量內存。
(2) cv::contourArea(...): 計算一個輪廓所包圍的面積。我們通過遍歷所有輪廓并比較面積,來找到最大的那個,并假定它就是我們的目標螺絲。
(3) cv::minAreaRect(...): 計算并返回一個包圍輪廓點的、面積最小的旋轉矩形(cv::RotatedRect)。這個矩形能夠緊密地貼合傾斜的目標。
(4) rotatedRect.size: cv::RotatedRect對象包含中心點、角度和尺寸(cv::Size2f)信息。sizewidthheight不保證哪個是長哪個是短,因此我們用std::minstd::max來獲取物理上的寬度和長度。
(5) cv::drawContours(...)cv::line(...): 用于在圖像上進行繪制的函數,非常適合在調試和結果展示時,將算法的中間結果可視化。

四、總結與展望

在本篇文章中,我們成功地實現了第一個真正的機器視覺算法。通過圖像預處理(灰度、二值化)、核心算法(輪廓發現)和 幾何計算(最小外接矩形)這一經典流程,我們讓程序從一張普通的圖片中精確地提取出了螺絲的像素尺寸。

我們不僅學習了幾個關鍵的OpenCV函數,更重要的是,我們建立了一套解決此類問題的思維框架。然而,讀者可能已經發現,這種方法雖然能測量尺寸,但對于識別表面劃痕、銹斑等紋理類、無固定形狀的瑕疵卻無能為力。

這正是傳統視覺算法的局限性所在,也為我們引入更強大的AI技術埋下了伏筆。在下一篇文章【《使用Qt Quick從零構建AI螺絲瑕疵檢測系統》——7. AI賦能(上):訓練你自己的YOLOv8瑕疵檢測模型】中,我們將進入深度學習領域,親手訓練一個能夠“認識”多種瑕疵的AI模型。

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

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

相關文章

《人性的弱點》重構【01】

手上有本《人性的弱點》&#xff08;韓文橋 譯&#xff0c;浙江文藝出版社&#xff0c;2017.1出版&#xff09;&#xff0c;前些年買的&#xff0c;近期翻出來看看。這門書雖成書于80多年前&#xff0c;但卡耐基對人性洞察之深刻&#xff0c;時至今日&#xff0c;并未覺得過時。…

k8s開啟審計日志

k8s默認是關閉審計功能的&#xff0c;想看的話需要到apiserver的pod中才可以。 開啟此功能是為了進行k8s審計日志的收集&#xff0c;方便我們查看k8s中用戶的各自操作。 開啟此功能之前&#xff0c;我們要先創建個審計策略文件audit-policy.yaml 例如以下的測驗文件 apiVersion…

Kafka MQ 消費者應用場景

Kafka MQ 消費者應用場景 1 消費者自動提交的時機 在 Kafka 中默認的消費位移的提交方式是自動提交,這個由消費者客戶端參數 enable.auto.commit 配置,默認值為 true。當然這個默認的自動提交不是每消費一條消息就提交一次,而是定期提交,這個定期的周期時間由客戶端參數 …

Git版本控制系統

Git作為目前最流行的分布式版本控制系統&#xff0c;已經成為開發者必備的技能之一。本文將全面介紹Git的核心概念、基本操作、分支管理以及與GitHub的協作開發&#xff0c;幫助讀者從零開始掌握Git的使用。 一、Git概述 1.1 Git發展歷史 Git誕生于2005年&#xff0c;由Linu…

如何編譯RustDesk(Unbuntu 和Android版本)

編譯Linux版本的RustDesk備注&#xff1a;官方文檔上&#xff0c;一邊都是基于sciter&#xff0c;這個在后面已經不建議使用了&#xff0c;但是依然可以編譯剛開始的時候看官方的文檔&#xff0c;涉及的東西比較多&#xff0c;也搞的一頭霧水&#xff0c;通過B站上一個視頻&…

Spring中的循環依賴:解密、破局與架構啟示

> 當兩個Bean緊緊相擁,Spring容器卻陷入死鎖——這是Java開發者的經典噩夢 某電商平臺凌晨上線時突然宕機,日志里反復滾動著`BeanCurrentlyInCreationException`的報錯。經排查,**優惠券服務與庫存服務在初始化時相互依賴**,形成致命閉環。這個價值百萬的故障案例,揭開…

DataFrame?(數據框)

一種二維表格型數據結構&#xff0c;類似于電子表格&#xff08;如 Excel&#xff09;或 SQL 表&#xff0c;由行&#xff08;記錄&#xff09;?和列&#xff08;字段&#xff09;?組成。它是數據分析、機器學習和科學計算中最常用的數據結構之一&#xff0c;尤其在 ?Python…

B站視頻評論數據爬取

爬取B站視頻評論數據爬取與分析 如果只要單純的腳本可以直接看項目結構里的b_comments.py 一、技術架構 1、環境配置 Python 3.8PyCharm 2、模塊配置 requests&#xff1a;用于發送HTTP請求time&#xff1a;用于處理時間相關的操作csv&#xff1a;用于讀寫CSV文件json&#xff…

OpenAI最新大模型GPT-4o體驗之Code Copilot AI編程大模型

一、前言GPT-4o&#xff08;"o"代表"全能"&#xff09;具備處理各種文本、聲音和圖像資料的能力&#xff0c;能夠輸出多種格式的文本、聲音和圖像。GPT-4o 的推出標志著 AI 技術的重大突破。它不再局限于單一媒介&#xff0c;而是首次實現了文本、語音和圖…

社交電商推客系統全棧開發指南:SpringCloud+分潤算法+Flutter跨端

一、推客系統概述與市場背景推客系統&#xff08;TuiKe System&#xff09;是一種基于社交關系的營銷推廣平臺&#xff0c;通過用戶分享商品或服務鏈接&#xff0c;實現裂變式傳播和精準營銷。近年來&#xff0c;隨著社交電商的蓬勃發展&#xff0c;推客系統已成為企業獲客的重…

網安-中間件-Redis未授權訪問漏洞

目錄 Redis Redis持久化 動態修改配置 使用反彈連接的情況 常見監聽端口的方式 常見建立反彈連接的方式 流程 Linux crontab cron文件存儲路徑 利用Redis實現攻擊 1.webshell提權案例 2.定時任務shell反彈案例 3.SSH Key getshell案例 ?編輯Redis其他利用方式 …

【c++深入系列】:萬字詳解棧和隊列和deque(附模擬實現的源碼)

&#x1f525; 本文專欄&#xff1a;c &#x1f338;作者主頁&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客勵志語錄&#xff1a; 石頭能被水滴穿&#xff0c;不是因為水有多強&#xff0c;而是因為它從未停過。 ★★★ 本文前置知識&#xff1a; 模版 棧 那么棧這個…

速通python加密之RSA加密

RSA加密 RSA加密是一種非對稱加密算法&#xff08;與AES等對稱加密不同&#xff09;&#xff0c;由羅納德李維斯特&#xff08;Ron Rivest&#xff09;、阿迪薩莫爾&#xff08;Adi Shamir&#xff09;和倫納德阿德曼&#xff08;Leonard Adleman&#xff09;于1977年提出&…

Java BeanUtils 類詳解:作用、語法與示例

一、BeanUtils 的核心作用BeanUtils 是 Apache Commons 和 Spring Framework 提供的工具類&#xff0c;主要用于簡化 JavaBean 的操作。核心功能包括&#xff1a;屬性拷貝&#xff1a;對象間同名屬性自動復制動態訪問&#xff1a;通過字符串名稱操作屬性類型轉換&#xff1a;自…

PyCharm高效開發全攻略

安裝與基礎配置下載PyCharm專業版或社區版&#xff08;免費&#xff09;并完成安裝。首次啟動時選擇默認設置或自定義主題、字體大小等界面偏好。配置Python解釋器路徑&#xff08;推薦使用虛擬環境&#xff09;&#xff0c;確保項目依賴隔離。快捷鍵與導航熟悉核心快捷鍵能大幅…

Pycharm 給 python 程序打包EXE的配置和方法

前言: Python 語言的設計變得越來越簡單,它有很多可以使用的庫,所以尤其在人工智能時代,Python語言被廣泛應用。但是Python語言和windows系統的兼容性稍微偏弱,如何生成windows可以執行的exe文件。是要一個很復雜的配置過程,本文就會做一個介紹。 本文,通過一個Python…

【Linux | 網絡】傳輸層(UDP和TCP)

目錄一、再談端口號1.1 端口號1.2 端口號的范圍劃分1.3 常見知名端口號1.4 netstat 命令1.5 進程與端口號的關系1.6 pidof 命令二、UDP協議2.1 UDP協議段格式2.2 如何理解UDP報頭和UDP報文2.2.1 UDP報頭2.2.2 UDP報文和UDP報文的管理2.2.3 UDP封裝過程2.3 UDP的特點2.4 UDP的緩…

mybatisX的自定義模板生成

在idea中使用mybtais的自定義模板生成&#xff0c;可以幫我們省去很多重復的代碼。 打開一個項目&#xff0c;我們要修改的主要就兩個文件&#xff0c;一個是生成的mapper接口&#xff0c;另一個是xml文件&#xff1a; 相應的mapper接口模板為&#xff1a; package ${mapper…

miniz:一個輕量級、高性能的開源壓縮庫

目錄 1.簡介 2.核心特性 3.基本使用示例 4.與 ZLIB 的對比 5.使用場景 6.注意事項 1.簡介 miniz 是一個輕量級、高性能的開源壓縮庫&#xff0c;專注于提供 ZLIB/GZIP 兼容的壓縮和解壓縮功能。它的核心優勢在于體積小巧&#xff08;單文件實現&#xff09;、跨平臺支持和…

Jenkins接口自動化測試(構建)平臺搭建

Python接口自動化測試零基礎入門到精通&#xff08;2025最新版&#xff09;自動化測試流程 在進行平臺搭建前&#xff0c;我們首先要問自己&#xff1a;我需要搭建的平臺的功能是什么&#xff0c;要實現什么目標&#xff1f; 在我的理解中&#xff0c;自動化構建平臺的執行流…