第十八屆全國大學生智能汽車競賽——攝像頭算法(附帶個人經驗)

文章目錄

  • 前言
  • 一、攝像頭圖像處理
    • 1、攝像頭圖像采集
    • 2、圖像二值化與大津算法
  • 二、左右邊界,中線掃描

前言

參加了第十六,十七和第十八屆全國大學生智能車競賽,對攝像頭的學習有部分心得,分享給大家,三屆車賽,車賽生涯也算是到了盡頭。打算從基礎的算法開始,給各位一些個人看法,也是對車賽的一次總結。

一、攝像頭圖像處理

閑話:其實攝像頭的算法有很多種,弄了兩年攝像頭,也只是學會了其中很小的一部分,但最終,作用都是大同小異的,也不必太過于追求算法上的完美。只需要達到能穩定提取特征,識別元素其實就夠用了。(個人用的是普通大津+二值化+八領域做邊界提取)

1、攝像頭圖像采集

打開攝像頭相關例程,可以發現其實最終攝像頭所采集的數據都存入了一個二維數組中,工作方式也很簡單:圖像采集,將圖像采集標志置一。手動清零,就可以達到重復采集的目的。(沒有相關例程的可以去找客服要,記得B站上也有逐飛的攝像頭攝像頭圖像采集視頻講解)

逐飛科技CH32V307攝像頭例程

2、圖像二值化與大津算法

智能車使用的攝像頭所采集的圖像一般都是灰度圖像,將圖像分割、數字化成一個個的數(一個個的像素點),0~255,像素點顏色越白數字越大。我們可以看出圖像信息很豐富,圖像處理方法自然也就多種多樣了,首先我們可以將圖像二值化

二值化就是將圖像上的灰度點分別設置為0,255(0xFF)(有點像二級分化)。圖像直觀上就會變為黑白圖像。我們該按照何種規則分黑和白呢?這時候就需要我們找出黑、白的分界值(也就是閾值)(大于閾值即為白,反之為黑),然后可以遍歷圖像數組中每一個像素點,大于閾值設為0XFF(白),反之設為0(黑)。(二值化有一個進階的思想:圖像每一個點都需要二值化嘛,我們能不能只將要使用的點二值化呢,這樣速度是不是就快了,這個其實開始沒有必要弄,有一張完整的二值化圖也方便我們理解)

:1,數組均從零開始。
2,二值化不能作用于攝像頭采集原圖上,應該重新定義一個同大小的數組,專門存放二值化后的圖像信息。(防止在進行圖像處理時,攝像頭重新采集數據,覆蓋之前數據)

?/*
mt9v03x_image_dvp : 原圖像   		 存放攝像頭灰度原圖
mt9v03x_image_baz :二值化圖像        用于存放圖像右邊界 
WHTIE  宏定義  替換作用 與0xff相同
*/
#define WHTIE 0xff //255
#define BLACK 0x00//使用宏 通過單詞代替抽象的數字 for(uint8_t i=0;i<MT9V03X_DVP_H;i++)             //MT9V03X_DVP_H:圖像高{for(uint8_t j=0;j<MT9V03X_DVP_W;j++)         //MT9V03X_DVP_W:圖像寬{if(mt9v03x_image_dvp[i][j]>=threshold )  //threshold:圖像閾值{mt9v03x_image_baz[i][j]=WHITE;}else{mt9v03x_image_baz[i][j]=BLACK;}}}?

后面就是確定圖像的閾值了,因為真實環境亮度是變化的,單純的給定閾值二值化就顯得不夠穩定,在圖像的基礎上動態的計算閾值適應性更強。我選擇的是大津算法,也是常用且基礎的一種了,缺點就是運算時間有點稍長。

大津算法的相關我就不說了,網上有很多相關介紹。(其實我理解的也不太透徹, 手動狗頭保命)

二、左右邊界,中線掃描

在二值化之后,我們得到了一個由黑和白組成的二維數組,而我們的目的是讓小車時刻處于賽道中間位置,也就是圖像中間位置。我們想要小車不出賽道,如果能讓賽道的中線始終貼合圖像數組的中間(此處圖像數組的中間我們可以想象為圖像的寬/2),那我們的小車是不是就不會出賽道了。圖像數組的中間就像PID中的理論值,實際賽道的中線就像實際值。這樣我們是不是就可以將圖像與PID聯系起來。
說回邊界掃描,想直接找賽道中線還是比較難的,主要是沒有明顯特征,我們不妨先尋找左右邊界(左右邊界黑白相夾),左右相加除二求得中線。這樣就得到比較真實的中線坐標,再對比理想中線坐標(圖像中間,也就是圖像寬/2),從而求出中線偏差,用于PID控制。思路大抵都是這樣,但找的方法就很多種多樣了。

基礎的方法就是從中間往兩邊找,缺點是遍歷了整幅圖像,消耗時間稍長,而進階的就有對普通兩邊找線方法的優化,(如:雙最長白列法)。再進一步稍微復雜一點的有八鄰域,迷宮法等等。

我們先來看看普通的兩邊找線法:
在這里插入圖片描述

基本思路就是從最下行往上 (利于對之后對中線的處理),每一行從中間往兩邊,分別尋找左右邊界(特征:黑白跳變),存入左右邊界數組。
同時存下中線坐標,用于下一行中線的掃描。(這樣減小運算量的同時還可以加大中線掃描時的連續性)左右邊界相加除2求出該行中線坐標,存入中線數組。
注:

/* last_mid:                   邊界掃描起始坐標 每行邊界從此開始 起始行為圖像寬/2 后為前一行圖像中線坐標MT9V03X_DVP_W:              圖像寬MT9V03X_DVP_H:              圖像高mt9v03x_image_baz[][]:      二值化圖像數組left_flag[] :               左邊界存在數組 左邊界存在 標志置1left_flag[] :               右邊界存在數組 右邊界存在 標志置1left_border[]:              左邊界數組 存放左邊界坐標right_border[]:             右邊界數組 存放右邊界坐標Mid_border[]:               中線左邊數組 存放中線坐標
*/last_mid = MT9V03X_DVP_W / 2;    
for (int i = MT9V03X_DVP_H - 1; i >= 0; i--)//從下往上掃描
{left_flag[i] = 1;right_flag[i] = 1;for (int j = last_mid; j > 1; j--)//中間往左邊掃描{if (mt9v03x_image_baz[i][j] == 0xff && mt9v03x_image_baz[i][j-1] == 0x00 &&  mt9v03x_image_baz[i][j-2]==0x00)//黑黑白認為找到左邊界{left_border[i] = j;                       //將左邊界存入左邊界數組left_flag[i] = 1;                         //左邊界找到,標志置0break; 				//跳出循環}}if (left_flag[i]==0) left_border[i]=0;              //補線標志未置一,此行左丟線,取圖像左邊界for (int j = last_mid; j < MT9V03X_DVP_W-2; j++)  //往右掃描{if (mt9v03x_image_baz[i][j]==0xff && mt9v03x_image_baz[i][j+1]==0x00 && mt9v03x_image_baz[i][j+2]==0x00)//白黑黑認為找到右邊界{right_border[i] = j;                        //將右邊界存入右邊界數組right_flag[i] = 1;                         //右邊界找到,標志置0break; 				//跳出循環}}if (right_flag[i]==0) right_border[i] = MT9V03X_DVP_W-1;           //補線標志未置一,此行右丟線,取圖像右邊界Mid_border[i] = (left_border[i] + right_border[i]) / 2;		//中線坐標mt9v03x_image_baz[i][left_border[i]-2] = BLACK; 	//左邊界涂黑mt9v03x_image_baz[i][Mid_border[i]] = BLACK; 	//中線涂黑mt9v03x_image_baz[i][right_border[i]+2] = BLACK; 	//右邊界涂黑       /* 注意  左右邊界-2 +2 很容易存在數組越界 導致程序卡住 如  左邊界點  left_border[i]=0;   [right_border[i]=MT9V03X_DVP_W-1自己使用時可以加個限制如mt9v03x_image_baz[i][(left_border[i]<2?2:left_border[i])-2] = BLACK; 	//左邊界涂黑*/last_mid = Mid_border[i];		//中線查找開始點,方便中線尋找
}

可以在圖像上把邊界顯示出來,方便后面觀察圖像,像這樣:
邊界顯示
后續給各位說說我對八領域的理解,歡迎大家關注!!!

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

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

相關文章

【C語言基礎】:深入理解指針(一)

文章目錄 一、內存和地址1. 內存2. 如何理解編址 二、指針變量和地址2.1 取地址操作符(&)2.2 指針變量和解引用操作符(*)2.2.1 指針變量2.2.2 如何拆解指針變量2.2.3 解引用操作符 2.3 指針變量的大小 三、指針變量類型的意義3.1 指針的解引用3.2 指針 - 整數3.3 void*指針…

HCIA-HarmonyOS設備開發認證V2.0-習題

目錄 習題一習題二&#xff08;待續...&#xff09;堅持就有收獲 習題一 # HarmonyOS簡介 1. 以下哪幾項屬于OpenHarmony的技術特性&#xff1f;&#xff08;&#xff09;A. 統一OS&#xff0c;彈性部署B. 一次開發&#xff0c;多端部署C. 硬件互助&#xff0c;資源共享2. Ope…

從零開始的Java知識(下)

從零開始的Java知識 雙列數據集合&#xff08;Day1&#xff09;Map 雙列數據集合&#xff08;Day1&#xff09; Map 注意點&#xff1a; Map一次加入一個key-value一個key對應一個valuekey與key之間是不重復的key-value被稱為鍵值對&#xff0c;鍵值對對象或者是entry對象 …

離散數學

(理解大于識記, 這么多公式我是記不住) 命題邏輯 P P P Q Q Q P \neg P P 否定/非 P ∧ Q P \wedge Q P∧Q 合取/與 P ∨ Q P \vee Q P∨Q 析取/或 P → Q P \to Q P→Q 蘊含 P ? Q P \leftrightarrow Q P?Q 等價0010011011011010001001101111 P → Q P\to Q P→Q 的自然語…

openssl 加密文件(支持大文件,對稱、非對稱)

一、非對稱加密&#xff08;小文件&#xff09; 生成 2048 位密鑰 openssl genrsa -out rsa2048.key 2048從 rsa2048.key 密鑰文件中提取出公鑰 pub2048.key openssl rsa -in rsa2048.key -pubout -out pub2048.key使用 pub2048.key 公鑰加密一個文件 (data.zip 為原始文件&…

C# WPF編程-創建項目

1.創建新項目 選擇“WPF應用程序”》“下一步” 2. 設置項目 設置項目名稱&#xff0c;保存位置等參數>下一步 3.選擇框架 4.項目創建成功 5.運行項目

兩張二值化圖像融合

python實現&#xff0c;已知兩張二值化圖像&#xff0c;對比兩張圖&#xff0c;將像素點一致的坐標保留原來顏色&#xff0c;不一致的坐標像素值變為128 讀取原圖 import cv2 import matplotlib.pyplot as plt import numpy as npcup_file_pathname"/home/wzc/zlt_self/…

vue-顯示數據

? v-text和v-html專門用來展示數據, 其作用和插值表達式類似。v-text和v-html可以避免插值閃爍問題. ? 當網速比較慢時, 使用{{}}來展示數據, 有可能會產生插值閃爍問題。 ? 插值閃爍: 在數據未加載完成時&#xff0c;頁面會顯示出原始的{{}}, 過一會才會展示正常數據.語法…

Opencv實戰(5)平滑處理與常見函數

平滑處理 Opencv實戰&#xff1a; Opencv(1)讀取與圖像操作 Opencv(2)繪圖與圖像操作 Opencv(3)詳解霍夫變換 Opencv(4)詳解輪廓 文章目錄 平滑處理1.均值濾波2.方框濾波3.高斯濾波4.中值濾波5.雙邊濾波 常見函數(1).createTrackbar()(2).SetMouseCallback() 圖像的平滑處理是…

細數Android開發者的艱辛歷程,android零基礎

首先我們來看一下組件化項目和傳統項目的區別: 在傳統的項目里 我們通常情況下會有一個commonLib的Libary模塊和一個app的application模塊&#xff0c;業務中的邏輯都寫在app中各個功能模塊放到不同的包下。這樣做有以下幾個主要的缺點&#xff1a; 1.無論分包做的再好&…

【Linux】USB Functionfs編程:libusb接口詳解

1、USB host_app代碼注釋 #include <libusb.h> libusb頭文件,編譯時鏈接庫:libusb-1.0#define VENDOR 0x1d6b 廠商:Linux Foundation #define PRODUCT 0x0105 設備:FunctionFS Gadge

Zynq—AD9238數據采集DDR3緩存千兆以太網發送實驗(一)

ACM9238 高速雙通道ADC模塊自助服務手冊AD9238 一、實驗目的 本次實驗通過電腦上的網絡調試助手&#xff0c;將命令幀進行發送&#xff0c;然后通過ACZ7015開發板上的以太網芯片接收&#xff0c;隨后將接收到的數據轉換成命令&#xff0c;從而實現對ACM9238模塊采樣頻率、數據…

JavaScript中的new Proxy()和Object.defineProperty使用詳細,Vue2和vue3中雙向數據綁定的原理

簡介&#xff1a; Object.defineProperty() 是 JavaScript 中一個強大且常用的方法&#xff0c;用于定義對象屬性&#xff0c;允許我們精確地控制屬性的行為&#xff0c;包括讀取、寫入和刪除等操作&#xff0c;是vue2中雙向數據綁定的原理&#xff1b; new Proxy() 是ES6中一…

Tomcat布署及優化

1.Tomcat簡介 Tomcat 是 Java 語言開發的&#xff0c;Tomcat 服務器是一個免費的開放源代碼的 Web 應用服務器&#xff0c;Tomcat 屬于輕量級應用服務器&#xff0c;在中小型系統和并發訪問用戶不是很多的場合下被普遍使用&#xff0c;是開發和調試 JSP 程序的首選。一般來說&…

在實訓云平臺上配置云主機

文章目錄 零、學習目標一、實訓云升級二、實訓云登錄&#xff08;一&#xff09;登錄實訓云&#xff08;二&#xff09;切換界面語言&#xff08;三&#xff09;規劃云主機實例 三、創建網絡三、創建路由器2024-2-29更新到此四、添加接口五、創建端口六、添加安全組規則七、創建…

反相輸入放大器與生俱來的坑

我們都知道反相放大器能將輸入的信號反相放大&#xff0c;這是很基本的知識&#xff0c;學過電路的一般都知道。反相放大器的公式為Vout -Vin*Rf/Rin&#xff08;運算放大器應用匯總&#xff09;。根據已知的公式&#xff0c;能很輕松的完成設計&#xff0c;但反相放大器與生俱…

每日一類:QString類深入講解

QString類是Qt框架中的一個核心組件&#xff0c;設計用于方便、高效地處理Unicode字符串。與標準C中的字符串處理方式相比&#xff0c;QString提供了更為豐富的API&#xff0c;支持國際化&#xff0c;并且內部使用UTF-16編碼&#xff0c;能夠處理世界上幾乎所有的語言文字。 設…

【PHP進階】Rabbitmq的實際使用

RabbitMQ是一個流行的消息隊列中間件&#xff0c;它提供了可靠的消息傳遞機制。在使用RabbitMQ時&#xff0c;有幾個重要的概念需要了解&#xff1a; 消息隊列&#xff08;Message Queue&#xff09;&#xff1a;RabbitMQ中的核心概念之一。它是消息的緩沖區&#xff0c;用于存…

容器安全工具使用指南:保障容器環境安全的利器

隨著容器技術的廣泛應用,容器安全成為關注的焦點。本文將深入介紹幾個流行的容器安全工具,我們將深入了解容器安全領域的Top 10工具,包括Trivy、veinmind-tools、Clair、Docker Bench for Security、Sysdig Falco、neuVector等,詳細講解它們的功能、原理、安裝和使用方法,…

【精簡版】Ubuntu/Linux Anaconda 命令行終端安裝

網上重復內容很多&#xff0c;大都啰里啰嗦&#xff0c;特作此筆記。 【精簡版】Ubuntu/Linux Anaconda 命令行安裝 1 下載安裝包1.1 尋找適配版本安裝包1.2 下載 2 運行安裝程序3 設置安裝路徑4 添加環境變量并運行4.1 環境變量4.2 運行 5 驗證安裝成功感謝及參考博文 1 下載…