OpenCV 單目測距實現

2021-09-05 08:45:58 字數 3830 閱讀 5247

最近要做乙個小專案,要完成相機的測距實現,最先考慮的是三角雷射測距,但是實現起來太麻煩了,基本要搭乙個簡易的雷射測距雷達...然後是雙目測距,然而乙個便宜的雙目工業相機也要四五百,而且以前也沒接觸過雙目測距...

於是就想試試單目測距的效果怎麼樣,通過參考網路上的各種資料,加上以前玩過三角雷射測距,所以也算比較順利的寫出來個簡易實現單目測距的**,精度還算差強人意。

原理大概是這樣的 :

這是三維情況下的小孔成像模型 :

我們把它簡化成更為直觀的二維平面模型(渣畫勿噴...):

這裡要說明下,這是乙個典型的小孔成像模型,與單目相機的成像原理類似。

中間通過紅藍的垂線是相機的主光軸,d是被測物體至鏡頭的距離,f為相機鏡頭的焦距,w為被測物體的實際寬度(高度),w'為物體在成像平面(感光元件)上的寬度(高度)。 

根據相似三角形公式可得:f / d = w' / w

由於f(相機鏡頭焦距)一般都是已知引數(買相機的時候總要選鏡頭焦距吧...),即使不清楚也可以通過計算得出,這裡就不具體說了,w(實際物體寬或高)則是可以實際測得的常量。           

重點說下怎麼通過計算得出w'(物像寬或高)。舉個栗子,假設你手上的相機是200w畫素捕獲畫面尺寸為1920*1080,感光元件尺寸為1/2.7'',寬高分別為5.3mm和4mm(估值),被測物體在畫面上的畫素寬高都為600 pixel,那麼w'(x) = (5.3 / 1920 * 600)(mm),同樣的,w'(y) = (4 / 1080 * 600)(mm)。關於感光元件尺寸和畫面尺寸可以通過檢視相機引數手冊獲得,而感光元件的寬和高可以通過其尺寸計算出來,這裡直接扔張感光元件靶面尺寸表作為參考,圖**自網路:

這樣,得知了 f,w,w' ,就可以根據上文提到的相似三角形公式計算得出d啦。

不過以上考慮的的是理想情況,前提是保證物像光線通過主光軸,相機是完全無畸變的,且被測物體平面要與相機成像平面保持平行狀態。在這裡我使用的相機是無畸變工業相機(低程度畸變,完全沒畸變的相機是不存在的...),如果是較為廉價的相機或者是廣角鏡頭相機都會存在較大程度的畫面畸變,可以通過軟體進行校正。準確來說這些情況都屬於無法完全消除的偏差,只能通過後期軟體來儘量減少這種偏差。

以上也就是為什麼單目測距的精度要比雙目測距差的多的原因,但是在所需測量精度不需要很精確的情況(偏差 < 10% ~ 15%),以及成本受限的情況下,單目測距依然是首選方案,何況其實現起來也十分簡單。

以下是**實現部分,使用 opencv 3.4.0

// 單目測距.cpp: 定義控制台應用程式的入口點。

//#include "stdafx.h"

#include "opencv2/opencv.hpp"

#include #include #include // 單位畫素寬/高(cm/pixel)

#define unit_pixel_w 0.0008234375

#define unit_pixel_h 0.000825

using namespace std;

int main(void)

for (;;)

cv::medianblur(frame, frame, 3);

cv::mat grayimage;

cv::cvtcolor(frame, grayimage, cv::color_bgr2gray);

// otsu 可以換用動態閾值

cv::threshold(grayimage, grayimage, null, 255, cv::thresh_binary | cv::thresh_otsu);

vector> contours;

vectormaxareacontour;

//cv::drawcontours(frame, contours, -1, cv::scalar(0, 0, 255), 2, 8);

// 提取面積最大輪廓

double maxarea = 0;

for (size_t i = 0; i < contours.size(); i++)

} // 輪廓外包正矩形

cv::rect rect = cv::boundingrect(maxareacontour);

cv::rectangle(frame, cv::point(rect.x, rect.y), cv::point(rect.x + rect.width, rect.y + rect.height), cv::scalar(255, 0, 0), 2, 8);

// 計算成像寬/高

double width = rect.width * unit_pixel_w;

double height = rect.height * unit_pixel_h;

// 分別以寬/高為標準計算距離

double distancew = w * f / width;

double distanceh = h * f / height;

char disw[50], dish[50];

sprintf_s(disw, "distancew : %.2fcm", distancew);

sprintf_s(dish, "distanceh : %.2fcm", distanceh);

cv::puttext(frame, disw, cv::point(5, 20), cv::font_hershey_complex_small, 1, cv::scalar(0, 255, 0), 1, 8);

cv::puttext(frame, dish, cv::point(5, 40), cv::font_hershey_complex_small, 1, cv::scalar(0, 255, 0), 1, 8);

cv::imshow("frame", frame);

cv::imshow("gray", grayimage);

if ((cv::waitkey(10) & 0xff) == 27) break;

} cv::destroyallwindows();

capture.release();

return exit_success;

}

這裡使用的相機感光元件尺寸 cmos 1/2.7'',捕獲畫面尺寸設定為640 * 480。

**分別使用了w'(x)和w'(y)作為引數進行測距。

實際測試結果:

實際距離15cm,計算距離14.40 ~ 14.57cm,偏差量0.43 ~ 0.60cm

實際距離7cm,計算距離6.83 ~ 6.85cm,偏差量0.15 ~ -0.17cm

實際距離20cm,計算距離18.86 ~ 19.12cm,偏差量0.88 ~ 1.14cm

可以看出,測距精度和實際距離呈反比,這裡的測試結果跟其他博主寫兩篇文章測出的結果情況一樣,都是偏小。另外,測量精度與畫面尺寸(相機畫素值)呈正比,如果用更高畫素的相機來測量會跟精確。

opencv雙目測距實現

開篇之前,首先要感謝maxwellsdemon和wobject,沒有和你們的討論,也就沒有此篇的成文。說到雙攝像頭測距,首先要複習一下測距原理,把learning opencv翻到416和418頁,可以看到下面兩幅圖 圖1.雙攝像頭模型俯檢視 圖2,雙攝像頭模型立體檢視 圖1解釋了雙攝像頭測距的原理...

opencv手冊 OpenCV之單目測距實現

最近要做乙個小專案,要完成相機的測距實現,最先考慮的是三角雷射測距,但是實現起來太麻煩了,基本要搭乙個簡易的雷射測距雷達.然後是雙目測距,然而乙個便宜的雙目工業相機也要四五百,而且以前也沒接觸過雙目測距.於是就想試試單目測距的效果怎麼樣,通過參考網路上的各種資料,加上以前玩過三角雷射測距,所以也算比...

Mobileye單目測距

其中 a是本車,前方車b和c,攝像頭p,焦距f,攝像頭高度h,和障礙物b c的距離分別是z1 z2,b c檢測框著地點在影象的投影是y1 y2。那麼按照相似三角形可以得出 y fh z,所以z fh y。首先假設路面是水平面,不考慮道路的坡度,實際上可以通過車道線的形狀計算出道路的坡度 如何確定車輛...