目标物體識别及跟蹤
擷取圖像
由于架構搭建的時候是先用圖檔進行預處理,是以首先需要用OpenCV庫中的函數進行對圖檔的讀取,并正常顯示。具體代碼如下:
Mat img = imread("/home/hemingshan/圖檔/sonny.jpg",-1);namedWindow("example1_擷取圖像",cv::WINDOW_AUTOSIZE);imshow("example1_擷取圖像",img);
圖像資料預處理
1. 去噪
去噪也就是濾波,主要是為了實作對圖像噪聲的消除,增強圖像的效果。均值濾波器、高斯濾波器、中值濾波器、雙邊濾波器都可以進行使用。由于目标檢測過程中,不會像圖檔那樣非常平滑,會因為環境的變化參雜一些空間性的噪聲,是以推薦使用雙邊濾波器,因為雙邊濾波考慮了圖像的空間關系,也考慮圖像的灰階關系。雙邊濾波同時使用了空間高斯權重和灰階相似性權重,確定了邊界不會被模糊掉下去。
Mat img2;bilateralFilter(img,img2,9,75,75);namedWindow("example1_雙邊濾波",cv::WINDOW_AUTOSIZE);imshow("example1_雙邊濾波",img2);

從顯示的圖像上可以看出,整個人物形象邊緣以及輪廓都顯得沒有那麼尖銳,有一種“美顔”的感覺(我孫哥自帶美顔濾鏡,根本不需要美顔)。
2. HSV通道轉換
原來的圖像格式是RGB圖像格式,是通過三原色的混合來産生不同的顔色效果,三原色分别由8bit定義,在硬體實作中便于了解和處理。而HSV是通過色度hue, 亮度value,飽和度saturation來定義顔色,更接近人眼睛對顔色的定義(這是什麼顔色?深淺如何?明暗如何?)兩者之間的轉化需求來自于硬體實作和顯示效果調整兩個方面的需求,前者滿足具體處理過程中簡便高效實作,後者按照人眼識别特點進行調整,更容易達到人眼預期的、顯示效果的調整。
總的來說,RGB中都與顔色亮度相關,即我們無法将顔色資訊與亮度分開。HSV或色相飽和度值用于将圖像李娜高度與顔色資訊分開。這樣就使得我們在處理或需要圖像/幀的亮度時更容易。HSV還用于顔色描述騎着不可或缺的作用的情況。
3. 目标顔色檢測
Mat mask;inRange(imghsv,Scalar(hmin,smin,vmin),Scalar(hmax,smax,vmax),mask);//将紅顔色進行過濾出來imshow("提取",mask);
目标顔色檢測主要是為了将檢測物體和環境進行區分開來,通過變量的上下限來擷取目标物體的大緻範圍進行提取,之後完成後續處理。通過 inRange() 函數來完成目标顔色的分離與檢測。OpenCV中的inRange()函數可以實作二值化功能,更關鍵惡是可以同時針對多通道進行操作。
//Checks if array elements lie between the elements of two other arrays//檢查數組元素是否在兩外兩個數組元素值之間void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);
上面提到的數組也就是在OpenCV中常用到的矩陣Mat或向量。
由圖像可以看出該圖像除了人臉附近有紅色進行提取之外,有一小部分的LOGO帶有紅色部分的也被進行提取後進行二值化處理。是以,在這裡效果還算是可觀,接下來就是為了将環境噪聲進行去除進行下一步的圖像處理。
4. 形态學處理(腐蝕運算)
Mat out2;Mat element = getStructuringElement(MORPH_RECT,Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),Point(g_nStructElementSize,g_nStructElementSize));erode(mask,out2,element);imshow("腐蝕",out2);
首先getStructuringElement()函數可用于構造一個特定大小和形狀的結構元素,或指定形狀和尺寸的結構元素,用于圖像形态學處理。其函數具體說明為,
Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
腐蝕後有一大部分的紅色區域都被剔除掉了,而且最大的噪聲(LOGO)也被剔除了。是以有很大的效果,為之後的輪廓提取奠定了一定的基礎。
5. 高斯模糊
高斯模糊又叫高斯平滑,是廣泛使用的處理效果,通常用來減少圖像噪聲以及降低細節層次。這種模糊技術生成的圖像,其視覺效果就像是經過一個半透明螢幕在觀察圖像,這與鏡頭焦外成像效果散景以及普通照明陰影中的效果都明顯不同。高斯平滑也用于計算機視覺算法中的預先處理階段,以增強圖像在不同平滑比例大小下的圖像效果。從數學的角度來看,圖像的高斯模糊過程就是圖像與正态分布做卷積。由于正态分布又稱作“高斯分布”,是以這項技術就叫做高斯模糊。圖像與圓形方框模糊作卷積将生成更加精确的焦外成像效果。由于高斯函數的傅立葉變換是另外一個高斯函數,是以高斯模糊對于圖像來說就是一個低通濾波器。
//高斯模糊Mat gaussian;GaussianBlur(out2,gaussian,Size(g_nGaussianBlurValue*2+1,g_nGaussianBlurValue*2+1),0,0);//模糊化imshow("高斯模糊",gaussian); 代碼中最主要的函數是GaussianBlur()函數,其函數說明為,void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT );
其中Size ksize是高斯模糊中用到的平滑比例大小,不同平滑比例大小下的圖像所呈現的平滑處理都不同。
雖然該圖不太明顯,但是和上一張腐蝕後的圖像比較可以發現,圖像有所模糊化了。效果不高的原因是該圖檔沒有非常明顯的紅色區域,因為在HSV圖像基礎上進行提取的顔色是紅色,導緻體去除的紅色并不是太多。放到環境中取,特定識别一塊紅色物體還是有很明顯的效果。
6. 輪廓提取
//輪廓提取vector> contours;vectorhierarchy;Mat imgcontours;Point2f center;float radius;findContours(gaussian, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);double maxarea = 0;int maxareaidx = 0;for (int index = contours.size() - 1; index >= 0; index --)// find the maxarea return contour index { double tmparea = fabs(contourArea(contours[index])); if (tmparea > maxarea) { maxarea = tmparea; maxareaidx = index; }}minEnclosingCircle(contours[maxareaidx], center, radius);//using index ssearching the min circlecircle(img, static_cast(center), (int)radius, Scalar(255,0,0), 3);//using contour index to drawing circleimshow("輪廓", img);waitKey(0);
代碼中最重要的函數是findContours()函數,在OpenCV中通過使用該函數,簡單幾個步驟就可以檢測出物體的輪廓,很友善。其函數原型為,
void findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point());
第一個參數:image,單通道圖像矩陣,也就是可以是灰階圖、二值圖,但一般來說更常用的是二值圖。
第二個參數:contours,定義為vector> contours,是一個向量,并且是一個雙重向量,向量内每一個元素儲存了一組由連續的Point點構成的點的集合的向量,每一組Point點集就是一個輪廓。有多少輪廓,向量contours就有多少元素。
第三個參數:hierarchy,定義為vectorhierarchy,其定義了一個向量内每一個元素包含了4個int型變量的向量。向量hierarchy内的元素和輪廓向量contours内的元素是一一對應的,向量的容量相同。hierarchy向量内每一個元素的4個int型變量——hierarchy[i][0]~hierarchy[i][3],分别表示第i個輪廓的後一個輪廓、前一個輪廓、父輪廓、内嵌輪廓的索引編号。如果目前輪廓沒有對應的最後一個輪廓、前一個輪廓、父輪廓或内嵌輪廓的話,則hierarchy[i][0]~hierarchy[i][3]的相應位置被設定為預設值-1。
第四個參數:int型的mode,定義輪廓的檢索模式。其選擇有:
•CVRETREXTERNAL:隻檢測最外圍輪廓,包含在輪廓内的輪廓被忽略。
•CVRETRLIST:檢測所有的輪廓,包括内圍、外圍輪廓,但是檢測到的輪廓不建立等級關系,彼此之間獨立,意味着不存在父輪廓或内嵌輪廓。
•CVRETRCCOMP:檢測所有的輪廓,但所有的輪廓值建立兩個等級關系,外圍為頂層,内圍的所有輪廓歸屬于頂層。
•CVRETRTREE:檢測所有的輪廓,所有輪廓建立一個等級樹結構。
第五個參數:int型的method,定義輪廓的近似方法:
•CVCHAINAPPROX_NONE:儲存物體邊界上所有連續的輪廓點到contours向量内
•CVCHAINAPPROX_SIMPLE:僅儲存輪廓的拐點資訊,把所有輪廓拐點處的點儲存入contours向量内,拐點與拐點之間直線段上的資訊點不予保留。
•CVCHIANAPPROXTC89L1,CVCHIANAPPROXTC89KCOS使用teh-Chinl chain近似算法
第六個參數:Point偏移量,所有的輪廓資訊相對于院士圖像對應點的偏移量,相當于在每一個檢測出的輪廓點上加該偏移量。
然後往下的程式就是尋找最大的輪廓,簡單易懂,是以不加以贅述。運作結果如下圖所示
紅唇被标記出來了!!
之後就需要将該程式移植到Turtlebot3機器人的自帶攝像頭上面,主要用了其RGB攝像頭,深度攝像頭也可以用,但是沒有RGB攝像頭的效果好。
具體思路是:首先擷取攝像頭圖像,通過cvbridge轉換成OpenCV可以處理的Mat格式的資料,之後通過上述的識别算法,識别出Turtlebot31機器人,并且傳回其中心點和半徑,在這裡我将距離以半徑形式展現出來,也就是半徑越大,距離越近。
在控制部分由于第一次開發,是以就簡單來,就是Turtlebot31機器人在Turtlebot32機器人的攝像頭中的識别位置靠左邊,那麼我就通過對cmdvel進行資料釋出,使Turtlebot32向左轉,以此類推,如果距離遠了,那麼識别出來的半徑就會小,也就需要Turtlebot3_2向前移動靠近。
2020-08-03 07-22-31 的螢幕截圖
如果要運作,需要先在預先設計好的環境中運作兩個Turtlebot3模型,這個已經在launch檔案夾中已經編輯完畢,隻需要運作launch檔案即可。
$ roslaunch opencv_examples turtlebot3_follow.launch
然後運作目辨別别結點其結合了對第二個機器人的控制,具體運作
$ rosrun opencv_examples find_contours
之後,通過控制第一個機器人移動即可,驗證第二個機器人是否會跟随移動
$ rosrun turtlebot_teleop turtlebot3_1_teleop
其rqt_graph如下圖所示:
項目位址:GitHub'https://github.com/MingshanHe/Turtlebot3-Robot-based-target-recognition-and-tracking'
微信公衆号:小河和他的機器人