OpenCV—PnP单目测距

2023-05-16

OpenCV—PnP单目测距

使用单目相机结合OpenCV的pnp解算实现单目测距(需要知道物体的长宽)
开始用的opencv 自带的标定api 标定相机,但是标定结果和matlab的结果有出入,可能我没用对吧,后面就用的Matlab 标定工具箱的标定结果,大概误差1 ~2cm吧,毕竟近距离。

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;


void drawRotatedRect(cv::Mat &img, const cv::RotatedRect &rect, const cv::Scalar &color, int thickness)
{
    cv::Point2f Vertex[4];
         rect.points(Vertex);
         for(int i = 0 ; i < 4 ; i++)
         {
             cv::line(img , Vertex[i] , Vertex[(i + 1) % 4] , color , thickness);
         }
}
void getTarget2dPoints(cv::RotatedRect object_rect,std::vector<Point2f> &object2d_point)
{
    cv::Point2f vertices[4];
    object_rect.points(vertices);
    cv::Point2f lu, ld, ru, rd;
    std::sort(vertices, vertices + 4, [](const cv::Point2f & p1, const cv::Point2f & p2) { return p1.x < p2.x; });
    if (vertices[0].y < vertices[1].y) {
        lu = vertices[0];
        ld = vertices[1];
    } else {
        lu = vertices[1];
        ld = vertices[0];
    }
    if (vertices[2].y < vertices[3].y) {
        ru = vertices[2];
        rd = vertices[3];
    } else {
        ru = vertices[3];
        rd = vertices[2];
    }
    object2d_point.clear();
    object2d_point.push_back(lu);
    object2d_point.push_back(ru);
    object2d_point.push_back(rd);
    object2d_point.push_back(ld);
}
int iLowH = 156;
int iHighH = 180;
int iLowS = 43;
int iHighS = 255;
int iLowV = 46;
int iHighV = 255;
int main()
{
    VideoCapture cap;
    cap.open(1);
    Mat frame;
    Mat gray;
    Mat binImg;
    Mat hsv_img;
    Mat imgThresholded;
    while(true)
    {
        cap >>frame;
        cvtColor(frame,gray,COLOR_BGR2GRAY);
        threshold(gray,binImg,40,255,THRESH_BINARY_INV);
        vector<vector<cv::Point>> bin_contours;
        cvtColor(frame, hsv_img, COLOR_BGR2HSV);



        inRange(hsv_img, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), imgThresholded); //Threshold the image
//        blur(imgThresholded,imgThresholded,Size(5,5));
        //开操作 (去除一些噪点)  如果二值化后图片干扰部分依然很多,增大下面的size
        Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
        morphologyEx(imgThresholded, imgThresholded, MORPH_OPEN, element);

        //闭操作 (连接一些连通域)
        morphologyEx(imgThresholded, imgThresholded, MORPH_CLOSE, element);
        erode(imgThresholded,imgThresholded,element);

        binImg = imgThresholded;

        cv::findContours(binImg,bin_contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
        for (uint i = 0;i < bin_contours.size();i++)
        {
            cv::RotatedRect RRect = minAreaRect(bin_contours[i]);
            if (RRect.size.area()<200 || RRect.size.area()>100000)
                continue;
            if (max(RRect.size.width,RRect.size.height) / min(RRect.size.width,RRect.size.height) > 1.3)
                continue;
            drawRotatedRect(frame,RRect,cv::Scalar(255,0,0),2);//画出最小旋转矩形

            Mat rot_vector,translation_vector;
            vector<Point2f> object2d_point;
            getTarget2dPoints(RRect, object2d_point);

            std::vector<cv::Point3f> point3d;

            float half_x = 2.6f/2.0f;
            float half_y = 3.4f/2.0f;  //height_target / 2.0;

            point3d.push_back(Point3f(-half_x, half_y, 0));
            point3d.push_back(Point3f(half_x, half_y, 0));
            point3d.push_back(Point3f(half_x, -half_y, 0));
            point3d.push_back(Point3f(-half_x, -half_y, 0));
            cv::Mat rot;
            cv::Mat trans;
            Mat cam_matrix = (Mat_<double>(3,3)<<578.6274,0,334.7460, 0, 576.9578, 214.0938, 0, 0, 1);//1981.3, -6.2, 684, 0, 2006.7, 504, 0, 0, 1
            Mat distortion_coeff = (Mat_<double>(5,1)<<-0.4290,  0.2780,  0,  0,  0);//-0.1029, 0.0058, -0.0030, 0.0047,0
            cv::solvePnP(point3d, object2d_point, cam_matrix, distortion_coeff, rot, trans);
            double tx = trans.at<double>(0,0);
            double ty = trans.at<double>(1,0);
            double tz = trans.at<double>(2,0);
            double dis  =sqrt(tx*tx+ty*ty+ tz*tz);
            cout<<"dis:"<<dis<<endl;
            putText(frame,to_string(dis)+"cm",Point(50,50),1,2,Scalar(0,255,100),2);
        }
        imshow("1",frame);
        imshow("2",imgThresholded);
        if (waitKey(10)=='q')
            break;

    }
}

在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenCV—PnP单目测距 的相关文章

  • 工作中遇到的C中Sscanf 函数的用法详解

    1 首先 xff0c 看到sscanf时 xff0c 会想到scanf xff0c 唯一不同的是前者是以固定的字符串为输入源 xff1b 后者是以屏幕为输入源 2 sscanf函数的定义为 int sscanf const char str
  • C 语言中结构体中成员所占内存的大小

    在C99标准中 xff0c 对于内存对齐的细节没有作过多的描述 xff0c 具体的实现交由编译器去处理 xff0c 所以在不同的编译环境下 xff0c 内存对齐可能略有不同 xff0c 但是对齐的最基本原则是一致的 xff0c 对于结构体的
  • 工作中遇到的一些SVN恶心的问题处理方法,解决问题的小妙招来了!---致刚刚参加的工作的青涩的人

    1 如果你已经参加了工作 xff0c 难免而且一定要用户svn xff0c 很多公司都会选择它来管理公司的项目 xff0c 这时懂的svn的用法会让你的工作事半功倍的 相信你一定为遇到上传失败 更新失败 clean up 失败而烦恼 xff
  • 麻将胡牌的算法

    清一色是麻将的种类之一 xff0c 指有一种花色的序数牌组成的胡牌 数字1 9 xff0c 每个数字最多4张牌 xff1b 我们不考虑具体的花色 xff0c 我们只看数字 刻字 xff1a 三张一样的牌 xff1a 111 222 333
  • 进程和线程的区别、相同点

    1 首先是定义 进程 xff1a 是执行中一段程序 xff0c 即一旦程序被载入到内存中并准备执行 xff0c 它就是一个进程 进程是表示资源分配的的基本概念 xff0c 又是调度运行的基本单位 xff0c 是系统中的并发执行的单位 线程
  • ORACLE日期数据类型

    oracle数据类型看起来非常简单 xff0c 但用起来会发现有许多知识点 xff0c 本文是我对ORACLE日期数据类型的一些整理 xff0c 都是开发入门资料 xff0c 与大家分享 xff1a 注 xff1a 由于INTERVAL及T
  • linux中shmget函数

    xfeff xfeff shmget int shmget key t key size t size int flag key 标识符的规则 size 共享存储段的字节数 flag 读写的权限 返回值 xff1a 成功返回共享存储的id
  • linux 中常用的数据库命令

    xfeff xfeff 1 显示数据库 show databases 2 选择数据库 use 数据库名 3 显示数据库中的表 show tables 4 显示数据表的结构 describe 表名 5 显示表中记录 SELECT FROM 表
  • socket编程accept函数返回值的理解

    accept函数返回值成功时返回非负值 xff0c 失败时返回 1 accept函数接受一个客户端请求后会返回一个新的SOCKFD值 xff0c 当有不同的客户端同时有不同请求时 xff0c 会返回不同的SOCKFD的值 这个不同的值和建立
  • 【TEE自学随笔】keystone代码略读(长文多图)

    武大信安在读 xff0c 最近在自学Risc v架构的可信执行环境 本篇内容由队友和我总结而成 xff0c 如有错误欢迎指正交流 keystone是risc v架构的开源tee 利用risc v的pmp来隔离页表 xff0c 进一步缩小了可
  • 二维数组与指针、指针数组、数组指针的用法

    二维数组 和指针 用指针表示二维数组 元素 要用指针处理二维数组 xff0c 首先要解决从存储的角度对二维数组 的认识问题 我们知道 xff0c 一个二维数组 在计算机中存储时 xff0c 是按照先行后列的顺序依次存储的 xff0c 当把每
  • 深剖基类和派生类的虚函数表

    1 当派生类实现基类的虚函数时 xff0c 基类中虚函数表和虚函数地址和派生类中虚函数表和虚函数地址不同 xff1b 当派生类不实现基类的虚函数时 xff0c 基类中虚函数表和虚函数地址和派生类中虚函数表和虚函数的地址相同 1 派生类重新实
  • C语言中转义字符

    在字符集中 xff0c 有一类字符具有这样的特性 xff1a 当从键盘上输入这个字符时 xff0c 显示器上就可以显示这个字符 xff0c 即输入什么就显示什么 这类字符称为可显示字符 xff0c 如a b c 43 和空格符等都是可显示字
  • c++ 中map 的find 用法

    用find函数来定位数据出现位置 xff0c 它返回的一个迭代器 xff0c 当数据出现时 xff0c 它返回数据所在位置的迭代器 xff0c 如果map中没有要查找的数据 xff0c 它返回的迭代器等于end函数返回的迭代器 xff0c
  • 解决AndroidStudio控制台输出乱码

    方法一 xff1a Help gt Edit Custom VM Options 在最后一行换行加上 xff1a xff08 不要漏掉符号 加好之后重启AndroidStudio xff09 Dfile encoding 61 UTF 8
  • c++--UDP发送接收

    UDP发送接收 头文件 include lt Winsock2 h gt 库 pragma comment lib Ws2 32 lib 连接Sockets相关库 初始化Windows SOCKET WSADATA wsaData if W
  • Airsim Setting up PX4 Hardware-in-Loop 环境搭建教程(windows)

    Airsim Setting up PX4 Hardware in Loop 环境搭建教程 xff08 windows xff09 经过本教程 xff0c 能够通过PX4连接遥控器 xff0c 继而能够控制airsim UE4中四轴模型 目
  • 在PX4 v1.9.2替换姿态控制算法方法

    在PX4 v1 9 2替换姿态控制算法方法 目的是在model中写一个与mc att control类似的model加入自己的姿态控制算法并替换之 目录 姿态控制算法simlink搭建生成并简单说明 PX4 v1 9 2姿态控制接口简单介绍
  • 不必通宵挂机,飞速克隆PX4源码的方法

    不必通宵挂机 xff0c 飞速克隆PX4源码的方法 项目地址 国内github网速 xff0c 那是慢的没法说 xff0c 克隆个PX4源码要半天 xff0c 然后更新子模块 xff0c 那不得需要一夜的时间 xff0c 有时早上一来 xf
  • Simlink与PX4硬件在环仿真(HIL)实现

    Simlink与PX4硬件在环仿真 HIL 实现 介于涉及的知识比较多 xff0c 这里只是简单的介绍一下 xff0c 硬件在环HIL介绍 simlink与PX4通信实现 硬件在环HIL介绍 为来贯彻万物都可以用数学公式表示 xff0c 我

随机推荐