????去年由奧比中光贊助的3D創新視覺賽落下帷幕,留下了令人印象深刻地一些作品(慚愧,雖然我也參加了,但是算法上面有些地方做地不好,就沒有參與到后續地評獎中,希望今年獲獎,哈哈哈哈哈),另外今年也幸運的當了社區的版主>.<,歡迎大家來投稿!
https://developer.orbbec.com.cn/forum.html
不過我發現論壇在長久的運營過程中其實留下了很多資料,但是缺乏系統的整理,所以我就準備整理一份開源的立體視覺資料出來,這里也希望大家給一些相關的建議。
在正式整理之前,我發現兩屆比賽出現了不少有用的方案,所以準備做一個系列的方案解讀。一方面是為了好的方案繼續發揮作用,二是為了他人的項目參考。

已完結~
那為什么會選定這樣一個方案來解讀呢?以下給出一封感興趣的讀者發來的郵件:

關鍵信息打碼了
可以看出,這個項目是完整的,以及有了實用性,其次是老師想選用這個案例用于教學和指導學生實踐學習。
我的文章并不簡明,內部大量充斥著口語,個人想法,其看起來更像是一份工作札記,但是文風這種東西改起來不是很容易,希望讀者理解。
項目緣起:

大哥在展會上面看到了這個東西

運行起來的樣子
So~就自己做一個!
功能目標:基于點云的軌跡引導,即無論待引導物體以何種位姿擺放(要求該位姿在機械臂的行程范圍內),視覺系統均能定位到該物體,并引導機械臂按需要的軌跡實現一定的工藝流程。
應用場景:需要軌跡引導的工業現場。
其實有人會問,那這個東西傳統的二維視覺做不了嗎?事實上是可以,但是它不太能滿足自由度多時機器人的引導,而加入了Depth會增加這種精度。

demo的樣子,kuka機器手臂一直在沿著鞋底的邊緣劃線

系統的硬件為相機,處理,執行器

安裝的位置如圖所示,右側的相機對工作平面進行解算,求出解算邊緣,而后給機械臂(這部分作者沒有寫,而且將處理數據輸入給機械臂的示教器)
奧比中光的Zora P1開發板:板子上跑的是armbian操作系統,部署的是點云采集和點云匹配程序,點云采集采用C++編寫,基于奧比中光官方提供的OpenNI2 SDK。
https://developer-orbbec-oss.oss-cn-shenzhen.aliyuncs.com/2021-05-26/public1/images/gather/deveban.jpg
這里是P1開發板的圖床位置,可以看到是阿里云的OBS,不知道買的啥套餐

板子一角

還是很豐富的接口
板子上面使用的armbian,就是基于Debiana適配的ARM開發板~
輕量級基于Debian或Ubuntu的Linux發行版,專門用于ARM開發板
每個系統均由Armbian Build Tools進行編譯,組裝和優化
它具有強大的構建和軟件開發工具,可以進行自定義構建
充滿活力的社區
其實就是一套完整的Linux系統,但是工具鏈齊全~文檔豐富

有著完整的文檔

就是使用的這個相機

然后就是精度真的困難是不夠用
在P1上面使用的是Armbian的系統,論壇里面有詳細的這個安裝的教程,我這里也沒有機器,我就不去做了,不過我覺得是jetson或者是樹莓派都可以去部署。
香橙派Armbian系統安裝之認識
香橙派Armbian系統安裝之燒錄
現在應該寫標定的東西,但是寫采集的也OK,為了流程一致,寫標定。
相機標定是視覺系統的基礎,工業級的相機標定需要碳纖維(或者玻璃等)的工業級標定板,保證平整度和角點精度。同時需要遮住激光器,并使用紅外光源,使得紅外相機能采集到清晰的標定板圖像。
但是,普通開發者通常不具備上述條件,面臨的情況常常是沒有標定板和紅外光源。為此,項目使用自制標定板,即通過代碼生成高分辨率的棋盤格圖像,并用打印機將其打印出來,貼在平板上。但是由于沒有紅外光源,紅外相機只能借助帶激光散斑的激光器的光源來拍攝標定板圖像,帶來的問題是部分角點檢測的誤差較大。為了解決這個問題,項目采用先執行一次相機標定,保留重投影誤差小的70%的點,再執行一次相機標定。這么做可以明顯降低重投影誤差、提高精度,使用此方法標定出的相機內外參通過深度圖和彩色圖的對齊來驗證,確實取得了良好的效果。
為什么這個標定過程要做這么多的工作?其實我們要知道一點,我們的計算理論都是完美無瑕的,光線很直,鏡頭沒有各種光學誤差,CCD和鏡頭的裝配也是沒有誤差。
但事實上,一切都“比較糟糕”,所以相機的設計處處都是對現實的妥協,幸好,我們可以將這些誤差算出來,做計算方法上面的補償。
現在用的比較多的是張正友博士的棋盤格標定法(hhhh,大佬也姓張)

也叫標定板
好,我們自己寫程序實現這個標定板的生成。

這里準備了C++和Python的版本
原版是C++的,但是改寫成Python的。

首先引入庫,注意OpenCV的安裝。后面三個參數是單個標定快的大小以及標定塊的數量。

板子單位格子的高和寬

參數計算,不符合就報錯
我們的圖像應該有一個容器來放它們:
cv::Mat image(resolution, CV_8UC1, cv::Scalar::all(255));搞個容器,初始化一下。后面參數Scalar 是個short型vector。指定這個能夠使用指定的定制化值來初始化矩陣。
CV_[The number of bits per item][Signed or Unsigned][Type?Prefix]C[The?channel?number]
這是這個函數的簽名。

這是核心部分(嚇死我,都不敢說是算法)。
這個填充是一開始都是黑色的,一個黑色的頁面,縱向的逐像素的掃描。

像素點的操作。

顯示+保存,CPP看累了嗎?可以看看Python~

SCALE是縮放的系數,可以控制大小,都使用元組防止篡改。

邏輯和CPP的一樣,這一段

生成一張全白的照片,我上面寫錯了

兩個步驟,先掃描紙面,然后按照邏輯填充黑點。

完事~
import cv2import numpy as npimport sysSCALE = 0.48perBoardPixel = int(100 * SCALE * 2)boardSize = (7, 10)resolution = (int(1400 * SCALE), int(2000 * SCALE))if __name__ == "__main__":basisHeight = (resolution[0] - perBoardPixel * boardSize[0]) // 2basisWidth = (resolution[1] - perBoardPixel * boardSize[1]) // 2if basisHeight < 0 or basisWidth < 0:print("Resolution doesn't match!")sys.exit(0)image = np.ones(resolution).astype(np.uint8) * 255flag = 0for j in range(0, boardSize[0]):for i in range(0, boardSize[1]):flag = (i + j) % 2if flag == 0:for n in range(j * perBoardPixel, (j + 1) * perBoardPixel):for m in range(i * perBoardPixel, (i + 1) * perBoardPixel):image[n + basisWidth, m + basisHeight] = 0cv2.imshow("chessBoard", image)cv2.waitKey(0)cv2.imwrite("chessBoard.bmp", image)
設置參數,直接運行。
https://github.com/appliedengdesign/vscode-gcode-syntax原作者鏈接
https://blog.csdn.net/dawudayudaxue/article/details/106339491標定算法
https://developer.orbbec.com.cn/forum_plate_module_details.html?id=830論壇的位置
https://github.com/3DCVdeveloper/Visual-guided-manipulator可能出于一些別的保護原因,這個方案的源碼和相關資料沒有全部在Github上面上傳,不過學習起來還是綽綽有余,如果有其它疑問,可以聯系小助手獲取。
https://docs.armbian.com/User-Guide_Basic-Troubleshooting/Armbian文檔位置
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/core/mat%20-%20the%20basic%20image%20container/mat%20-%20the%20basic%20image%20container.htmlOpenCV Doc

hhhh,春天來了