攝像頭單目測距原理及實現


攝像頭單目測距原理及實現

一.測距原理

空間的深度或距離等數據的攝像頭。

人的眼睛長在頭部的前方,兩只眼的視野范圍重疊,兩眼同時看某一物體時,產生的視覺稱為雙眼視覺。

雙眼視覺的優點是可以彌補單眼視野中的盲區缺損,擴大視野,並產生立體視覺。

也就是說,假如只有一只眼睛,失去立體視覺后,人判斷距離的能力將會下降。

這也就是單目失明的人不能考取駕照的原因。

 

 

 單純的單目視覺測距,必須已知一個確定的長度。

 

 

 f為攝像頭的焦距,c為鏡頭光心。物體發出的光經過相機的光心,然后成像於圖像傳感器或者也可以說是像平面上,如果設物體所在平面與相機平面的距離為d,物體實際高度為H,在傳感器上的高度為h,H一定要是已知的,我們才能求得距離d。

假設我們有一個寬度為 W 的目標或者物體。然后我們將這個目標放在距離我們的相機為 D 的位置。我們用相機對物體進行拍照並且測量物體的像素寬度 P 。這樣我們就得出了相機焦距的公式:

F = (P x D) / W

例如,假設現在我們有一張A4紙(8.27in x 11.69in), in代表英寸,1in = 25.4mm。紙張寬度W=11.69in,相機距離紙張的距離D = 32in,此時拍下的照片中A4紙的像素寬度為P=192px(我的相機實際測量得到的值)。
此時我們可以算出焦距F=(192x30)/11.69。
當我們將攝像頭遠離或者靠近A4紙時,就可以用相似三角形得到相機距離物體的距離。
此時的距離: D’ = (W’ x F ) / P’。
(注意:這里測量的距離是相機到物體的垂直距離,產生夾角,測量的結果就不准確了。)

二.測距步驟

1.  使用攝像機采集道路前方的圖像;

2.  在道路區域對物體進行檢測,通過矩形框將物體形狀框出來。

3.  結合矩形框信息,找到該矩形框底邊的兩個像平面坐標,分別記為(u1,v1)和(u2,v2);

4.  使用幾何關系推導法,由像平面坐標點(u1, v1)、(u2, v2)推導出道路平面坐標(x1,y1)、(x2, y2);(投影到地面上,z軸為0)

5.  通過歐氏距離公式計算出d。

三.難點整理:

1.圖像畸變矯正模型的理解;

(標定參數,內參矩陣,畸變矩陣,外參矩陣(平移、旋轉向量矩陣))

2.像素坐標與世界坐標公式的推導及驗證;

3.測距方法,對於檢測物體在攝像頭前方、左側、右側的判別思路;

4.弄清反畸變;對於畸變矯正后的圖像中的檢測框中的點進行反畸變處理。

四.相機鏡頭畸變矯正-->得到相機的內外參數、畸變參數矩陣

1.  外參數矩陣。世界坐標經過旋轉和平移,然后落到另一個現實世界點(攝像機坐標)上。

2.  內參數矩陣。告訴你上述那個點在1的基礎上,是如何繼續經過攝像機的鏡頭、並通過針孔成像和電子轉化而成為像素點的。

3.  畸變矩陣。告訴你為什么上面那個像素點並沒有落在理論計算該落在的位置上,還產生了一定的偏移和變形.

 五.實現代碼

#!/usr/bin/python3

# -*- coding: utf-8 -*-

# Date: 18-10-29

 import numpy as np      # 導入numpy庫

import cv2              # 導入Opencv庫

 NOWN_DISTANCE = 32   # 這個距離自己實際測量一下

 KNOWN_WIDTH = 11.69     # A4紙的寬度

KNOWN_HEIGHT = 8.27

IMAGE_PATHS = ["Picture1.jpg", "Picture2.jpg", "Picture3.jpg"]   # 將用到的圖片放到了一個列表中

# 定義目標函數

def find_marker(image):

    gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 將彩色圖轉化為灰度圖

    gray_img = cv2.GaussianBlur(gray_img, (5, 5), 0)    # 高斯平滑去噪

    edged_img = cv2.Canny(gray_img, 35, 125)     # Canny算子閾值化

    cv2.imshow("降噪效果圖", edged_img)          # 顯示降噪后的圖片

    # 獲取紙張的輪廓數據

    img, countours, hierarchy = cv2.findContours(edged_img.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

    # print(len(countours))

    c = max(countours, key=cv2.contourArea)    # 獲取最大面積對應的點集

    rect = cv2.minAreaRect(c)       # 最小外接矩形

    return rect

 # 定義距離函數

def distance_to_camera(knownWidth, focalLength, perWidth):

    return (knownWidth * focalLength) / perWidth

 # 計算攝像頭的焦距(內參)

def calculate_focalDistance(img_path):

    first_image = cv2.imread(img_path)      # 這里根據准備的第一張圖片,計算焦距

    # cv2.imshow('first image', first_image)

    marker = find_marker(first_image)       # 獲取矩形的中心點坐標,長度,寬度和旋轉角度

    focalLength = (marker[1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH  # 獲取攝像頭的焦距

    # print(marker[1][0])

    print('焦距(focalLength) = ', focalLength)        # 打印焦距的值

    return focalLength

 # 計算攝像頭到物體的距離

def calculate_Distance(image_path, focalLength_value):

    image = cv2.imread(image_path)

    # cv2.imshow("原圖", image)

    marker = find_marker(image)     # 獲取矩形的中心點坐標,長度,寬度和旋轉角度, marke[1][0]代表寬度

    distance_inches = distance_to_camera(KNOWN_WIDTH, focalLength_value, marker[1][0])

    box = cv2.boxPoints(marker)

    # print("Box = ", box)

    box = np.int0(box)

    print("Box = ", box)

    cv2.drawContours(image, [box], -1, (0, 255, 0), 2)      # 繪制物體輪廓

    cv2.putText(image, "%.2fcm" % (distance_inches * 2.54), (image.shape[1] - 300, image.shape[0] - 20),

                cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 255, 0), 3)

    cv2.imshow("單目測距", image)

 if __name__ == "__main__":

    img_path = "Picture1.jpg"

    focalLength = calculate_focalDistance(img_path)

     for image_path in IMAGE_PATHS:

        calculate_Distance(image_path, focalLength)

        cv2.waitKey(0)

    cv2.destroyAllWindows()

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM