1. 程式人生 > >Ubuntu16.04 Python/Opencv實現雙目定位及測距

Ubuntu16.04 Python/Opencv實現雙目定位及測距

1、安裝Python以及jupyter

本平臺是Ubuntu16.04,需要安裝python環境,我安裝的是python3版本。

(1)首先安裝python3

sudo apt-get install python3
#若要安裝指定版本的python,這地方可以更改成你需要的版本,比如你要安裝3.6版本:
sudo apt-get install python3.6 python3.6-dev

(2)切換python優先順序

安裝好後會在 /usr/bin/ 下出現 python3.6 這個可執行檔案,現在需要切換版本(預設版本2.7) 如下就是設定python3.6的路徑,並設定優先順序為200

,預設優先順序最高的優先使用

sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.6 200

所以如果想要使用系統預設的2.7版本,需要鍵入

sudo update-alternatives –install /usr/bin/python python /usr/bin/python2.7 250 

並設定優先順序大於其他的版本 

(3)安裝pip

當前python版本為3.x,輸入如下命令:

sudo apt-get install python3-pip python3-dev

若python版本為2.7,則輸入如下命令:

sudo apt-get install python-pip python-dev

在裝tensorflow之前,不管是不是最新的pip版本,都要更新一下,具體命令如下:

python 2.7版本:
sudo pip install --upgrade pip
python 3.x版本:
sudo pip3 install --upgrade pip

(4)安裝jupyter以及相關依賴包

若是Python3,把pip換成pip3

pip install pillow
pip install lxml
pip install jupyter
pip install matplotlib

在終端執行:

jupyter notebook

 會出現一個網址,如下圖:

 開啟網址,便進入到網頁版的jupyter

注意:在哪個目錄開啟jupyter notebook,則該目錄為根目錄。 

2、安裝opencv-python

這裡不需要進入官網下載opencv原始碼進行繁瑣的安裝,安裝opencv直接在終端執行:

sudo pip install opencv-python

檢視opencv版本,執行:

pkg-config --modversion opencv

下圖表安裝成功 ,我的是3.3.1

下面寫一個測試程式碼實現攝像頭實時捕捉: 

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
while(1):
    # get a frame
    ret, frame = cap.read()
    # show a frame
    cv2.imshow("capture", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows() 

 同樣在jupyter上點選run all,或者按Shift+Eenter,就會顯示出視訊流

3、對專案攝像機進行標定

首先得買個雙目攝像機吧!

我用的是matlab標定(棋盤格方法),我是先分別對左右兩個圖形一幅一幅的抓取,20*2=40張,然後按照官網步驟一步一步來,過程還是比較繁瑣,沒辦法!標定的好壞決定最後的精度。

下面是抓取一張圖片的程式碼,按q結束並抓拍一張圖片。

#讀取視訊,按q結束並抓拍一張圖片
import cv2
import numpy as np

cap = cv2.VideoCapture(0)
while(1):
    # get a frame
    ret, frame = cap.read()
    # show a frame
    cv2.imshow("capture", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        cv2.imwrite('camera1.jpg', frame)
        break
cap.release()
cv2.destroyAllWindows() 

緊接著,新建一個camera_configs.py檔案,裡面專門用來儲存兩個攝像頭標定好的引數。

import cv2
import numpy as np

#左攝像頭引數
left_camera_matrix = np.array([[1394.26663, 0, 343.36581],
                               [0, 1393.25572, 206.56092],
                               [0, 0, 1]])
left_distortion = np.array([[-0.66451, 0.84137, -0.01001, -0.00274, 0]])

#右攝像頭引數
right_camera_matrix = np.array([[1385.46346, 0, 344.38903],
                                [0, 1385.09596, 197.18927],
                                [0, 0, 1]])
right_distortion = np.array([[-0.63339, -0.68796, -0.00491, -0.00675, 0]])

om = np.array([0.00456, 0.01463, 0.00042])        # 旋轉關係向量
R = cv2.Rodrigues(om)[0]                           # 使用Rodrigues變換將om變換為R
T = np.array([-59.63351, -0.15514, -0.35781])      # 平移關係向量

size = (640, 360) # 影象尺寸

# 進行立體更正
R1, R2, P1, P2, Q, validPixROI1, validPixROI2 = cv2.stereoRectify(left_camera_matrix, left_distortion,
                                                                  right_camera_matrix, right_distortion, size, R,
                                                                  T)
# 計算更正map
left_map1, left_map2 = cv2.initUndistortRectifyMap(left_camera_matrix, left_distortion, R1, P1, size, cv2.CV_16SC2)
right_map1, right_map2 = cv2.initUndistortRectifyMap(right_camera_matrix, right_distortion, R2, P2, size, cv2.CV_16SC2)

4、利用BM匹配演算法實現雙目測距

程式碼:

import cv2
import numpy as np
import camera_configs

cv2.namedWindow("depth")
cv2.moveWindow("left", 0, 0)
cv2.moveWindow("right", 640, 0)
cv2.createTrackbar("num", "depth", 2, 10, lambda x: None)
cv2.createTrackbar("blockSize", "depth", 5, 255, lambda x: None)

# 新增點選事件,列印當前點的距離q
def callbackFunc(e, x, y, f, p):
    if e == cv2.EVENT_LBUTTONDOWN:        
        print (threeD[y][x])

cv2.setMouseCallback("depth", callbackFunc, None)

cap = cv2.VideoCapture(0)   

while True:
    ret1, frame = cap.read()
    #ret2, frame2 = camera2.read()
    #if not ret1 or not ret2:
    if ret1 != True:
        break
    cv2.resize(frame,(2560,360),interpolation=cv2.INTER_LINEAR)  
    dsize = (1280, 360)
    imagedst = cv2.resize(frame,dsize,interpolation=cv2.INTER_LINEAR)
    
    frame1 = imagedst[0:360,0:640]
    frame2 = imagedst[0:360,640:1280]

    # 根據更正map對圖片進行重構
    img1_rectified = cv2.remap(frame1, camera_configs.left_map1, camera_configs.left_map2, cv2.INTER_LINEAR)
    img2_rectified = cv2.remap(frame2, camera_configs.right_map1, camera_configs.right_map2, cv2.INTER_LINEAR)

    # 將圖片置為灰度圖,為StereoBM作準備
    imgL = cv2.cvtColor(img1_rectified, cv2.COLOR_BGR2GRAY)
    imgR = cv2.cvtColor(img2_rectified, cv2.COLOR_BGR2GRAY)

    # 兩個trackbar用來調節不同的引數檢視效果
    num = cv2.getTrackbarPos("num", "depth")
    blockSize = cv2.getTrackbarPos("blockSize", "depth")
    if blockSize % 2 == 0:
         blockSize += 1
    if blockSize < 5:
         blockSize = 5

     # 根據Block Maching方法生成差異圖(opencv裡也提供了SGBM/Semi-Global Block Matching演算法,有興趣可以試試)
    stereo = cv2.StereoBM_create(numDisparities = 16*num, 
                                  blockSize = 31)
    
    disparity = stereo.compute(imgL, imgR)

    disp = cv2.normalize(disparity, disparity, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
    # 將圖片擴充套件至3d空間中,其z方向的值則為當前的距離
    threeD = cv2.reprojectImageTo3D(disparity.astype(np.float32)/16., camera_configs.Q)

    cv2.imshow("left", img1_rectified)
    cv2.imshow("right", img2_rectified)
    cv2.imshow("depth", disp)

    key = cv2.waitKey(1)
    if key == ord("q"):
        break
    elif key == ord("s"):
        cv2.imwrite(path_BM_left, imgL)
        cv2.imwrite(path_BM_right, imgR)
        cv2.imwrite(path_BM_depth, disp)
cap.release()
cv2.destroyAllWindows()

注意:需要把 camera_configs.py檔案放在同一個目錄。

測試結果: