单目测距原理与实现(代码可运行)

Opencv3实现单目视觉测距

一、前言

单目视觉测距:网上有很多关于单目测距的文章,主要借鉴的是OpenCV学习笔记(二十一)——简单的单目视觉测距尝试单目摄像机测距(python+opencv)两篇文章,在这里特别作出说明。

工作环境:Ubuntu16.04 + Opencv3.4.0 +Pycharm

单目相机:DFK AFUX236-M12

二、单目测距原理

单目相机测距常用或者说实用的方法就是相似三角形法,为了让大家更好地理解程序,这里简单说一下相似三角形法。

单目测距原理与实现(代码可运行)

F = (P x D) / W

举个例子,假设我在离相机距离 D = 24 英寸的地方放一张标准的 8.5 x 11 英寸的 A4 纸(横着放;W = 11)并且拍下一张照片。我测量出照片中 A4 纸的像素宽度为 P = 249 像素。

因此我的焦距 F 是:

F = (248px x 24in) / 11in = 543.45

当我继续将我的相机移动靠近或者离远物体或者目标时,我可以用相似三角形来计算出物体离相机的距离:

D’ = (W x F) / P

为了更具体,我们再举个例子,假设我将相机移到距离目标 3 英尺(或者说 36 英寸)的地方并且拍下上述的 A4 纸。通过自动的图形处理我可以获得图片中 A4 纸的像素距离为 170 像素。将这个代入公式得:

D’ = (11in x 543.45) / 170 = 35 英寸

或者约 36 英寸,合 3 英尺。

从以上的解释中,我们可以看到,要想得到距离,我们就要知道摄像头的焦距和目标物体的尺寸大小,这两个已知条件根据公式:

D’ = (W x F) / P

得出目标到摄像机的距离D,其中P是指像素距离,W是A4纸的宽度,F是摄像机焦距。

三、实现代码:

import cv2
import numpy as np

win_width = 1920
win_height = 1200
mid_width = int(win_width / 2)
mid_height = int(win_height / 2)

foc = 2810.0
real_wid = 11.69
font = cv2.FONT_HERSHEY_SIMPLEX
w_ok = 1

capture = cv2.VideoCapture(1)
capture.set(3, win_width)
capture.set(4, win_height)

while(True):
    ret, frame = capture.read()
    # frame = cv2.flip(frame, 1)
    if ret == False:
        break

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (5, 5), 0)
    ret, binary = cv2.threshold(gray, 127, 255, 0)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
    binary = cv2.dilate(binary, kernel, iterations=2) # 形态学膨胀
    contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    # cv2.drawContours(frame, contours, -1, (0, 255, 0), 2)
    for c in contours:
        if cv2.contourArea(c) < 2000: # &#x5BF9;&#x4E8E;&#x77E9;&#x5F62;&#x533A;&#x57DF;&#xFF0C;&#x53EA;&#x663E;&#x793A;&#x5927;&#x4E8E;&#x7ED9;&#x5B9A;&#x9608;&#x503C;&#x7684;&#x8F6E;&#x5ED3;&#xFF0C;&#x6240;&#x4EE5;&#x4E00;&#x4E9B;&#x5FAE;&#x5C0F;&#x7684;&#x53D8;&#x5316;&#x4E0D;&#x4F1A;&#x663E;&#x793A;&#x3002;&#x5BF9;&#x4E8E;&#x5149;&#x7167;&#x4E0D;&#x53D8;&#x548C;&#x566A;&#x58F0;&#x4F4E;&#x7684;&#x6444;&#x50CF;&#x5934;&#x53EF;&#x4E0D;&#x8BBE;&#x5B9A;&#x8F6E;&#x5ED3;&#x6700;&#x5C0F;&#x5C3A;&#x5BF8;&#x7684;&#x9608;&#x503C;
            continue

        x, y, w, h = cv2.boundingRect(c) # &#x8BE5;&#x51FD;&#x6570;&#x8BA1;&#x7B97;&#x77E9;&#x5F62;&#x7684;&#x8FB9;&#x754C;&#x6846;

        if x > mid_width or y > mid_height:
            continue
        if (x + w) < mid_width or (y + h) < mid_height:
            continue
        if h > w:
            continue
        if x == 0 or y == 0:
            continue
        if x == win_width or y == win_height:
            continue

        w_ok = w
        cv2.rectangle(frame, (x + 1, y + 1), (x + w_ok - 1, y + h - 1), (0, 255, 0), 2)

    dis_inch = (real_wid * foc) / (w_ok - 2)
    dis_cm = dis_inch * 2.54
    # os.system("cls")
    # print("Distance : ", dis_cm, "cm")
    frame = cv2.putText(frame, "%.2fcm" % (dis_cm), (5, 25), font, 0.8, (0, 255, 0), 2)
    frame = cv2.putText(frame, "+", (mid_width, mid_height), font, 1.0, (0, 255, 0), 2)

    cv2.namedWindow('res', 0)
    cv2.namedWindow('gray', 0)
    cv2.resizeWindow('res', win_width, win_height)
    cv2.resizeWindow('gray', win_width, win_height)
    cv2.imshow('res', frame)
    cv2.imshow('gray', binary)

    c = cv2.waitKey(40)
    if c ==27:
        break

cv2.destroyAllWindows()

程序效果图如下:

单目测距原理与实现(代码可运行)

Original: https://blog.csdn.net/qq_43010752/article/details/122320949
Author: 冰软
Title: 单目测距原理与实现(代码可运行)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/647717/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球