自学SLAM(8)《第四讲:相机模型与非线性优化》作业

前言

在这里插入图片描述

小编研究生的研究方向是视觉SLAM,目前在自学,本篇文章为初学高翔老师课的第四次作业。

文章目录

  • 前言
  • 1.图像去畸变
  • 2.双目视差的使用
  • 3.矩阵微分
  • 4.高斯牛顿法的曲线拟合实验


1.图像去畸变

现实⽣活中的图像总存在畸变。原则上来说,针孔透视相机应该将三维世界中的直线投影成直线,但是当我们使⽤⼴⾓和鱼眼镜头时,由于畸变的原因,直线在图像⾥看起来是扭曲的。本次作业,你将尝试如何对⼀张图像去畸变,得到畸变前的图像。
在这里插入图片描述
在这里插入图片描述

对于畸变,用两张鲜明的照片来展示:
在这里插入图片描述
在这里插入图片描述
undistort_image.cpp:

//
// Created by ljh on 2023/11/5.
//#include <opencv2/opencv.hpp>
#include <string>using namespace std;string image_file = "/home/lih/video4_homework/homework1/test.png"; // 请确保路径正确int main(int argc, char **argv) {// 本程序需要你自己实现去畸变部分的代码。尽管我们可以调用OpenCV的去畸变,但自己实现一遍有助于理解。// 畸变参数double k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;// 内参double fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;cv::Mat image = cv::imread(image_file,0);   // 图像是灰度图,CV_8UC1int rows = image.rows, cols = image.cols;cv::Mat image_undistort = cv::Mat(rows, cols, CV_8UC1);   // 去畸变以后的图// 计算去畸变后图像的内容for (int v = 0; v < rows; v++)for (int u = 0; u < cols; u++) {double u_distorted = 0, v_distorted = 0;// TODO 按照公式,计算点(u,v)对应到畸变图像中的坐标(u_distorted, v_distorted) (~6 lines)// start your code here// 按照公式,计算点(u,v)对应到畸变图像中的坐标(u_distorted, v_distorted)
double x = (u-cx)/fx, y = (v-cy)/fy; // 计算图像点坐标到光心的距离;
double r = sqrt(x*x+y*y);// 计算投影点畸变后的点
double x_distorted = x*(1+k1*r+k2*r*r)+2*p1*x*y+p2*(r+2*x*x); 
double y_distorted = y*(1+k1*r+k2*r*r)+2*p2*x*y+p1*(r+2*y*y); // 把畸变后的点投影回去
u_distorted = x_distorted*fx+cx;
v_distorted = y_distorted*fy+cy;// end your code here// 赋值 (最近邻插值)if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < cols && v_distorted < rows) {image_undistort.at<uchar>(v, u) = image.at<uchar>((int) v_distorted, (int) u_distorted);} else {image_undistort.at<uchar>(v, u) = 0;}}// 画图去畸变后图像cv::imshow("image undistorted", image_undistort);cv::waitKey();return 0;
}

string image_file = “/home/lih/video4_homework/homework1/test.png”; // 填写你自己的图片路径

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)PROJECT(undistort_image)IF(NOT CMAKE_BUILD_TYPE) #(可选)如果没有指定cmake编译模式,就选择Relealse模式,必须写成三行SET(CMAKE_BUILD_TYPE Release)
ENDIF()MESSAGE("Build type: " ${CMAKE_BUILD_TYPE}) #终端打印cmake编译模式的信息set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}  -Wall  -O3 -march=native ") #添加c标准支持库
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall   -O3 -march=native") #添加c++标准支持库# Check C++11 or C++0x support #检查c++11或c++0x标准支持库
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")add_definitions(-DCOMPILEDWITHC11)message(STATUS "Using flag -std=c++11.")
elseif(COMPILER_SUPPORTS_CXX0X)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")add_definitions(-DCOMPILEDWITHC0X)message(STATUS "Using flag -std=c++0x.")
else()message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()find_package(OpenCV 3.0 QUIET) #find_package(<Name>)命令首先会在模块路径中寻找 Find<name>.cmake
if(NOT OpenCV_FOUND)find_package(OpenCV 2.4.3 QUIET)if(NOT OpenCV_FOUND)message(FATAL_ERROR "OpenCV > 2.4.3 not found.")endif()
endif()include_directories(${OpenCV_INCLUDE_DIRS})add_executable(image undistort_image.cpp)#链接OpenCV库
target_link_libraries(image ${OpenCV_LIBS})

然后
mkdir build
cd build
cmake …
make
./image
在这里插入图片描述

2.双目视差的使用

双⽬相机的⼀⼤好处是可以通过左右⽬的视差来恢复深度。课程中我们介绍了由视差计算深度的过程。本题,你需要根据视差计算深度,进⽽⽣成点云数据。本题的数据来⾃Kitti 数据集 [2]。 Kitti中的相机部分使⽤了⼀个双⽬模型。双⽬采集到左图和右图,然后我们可以通过左右视图恢复出深度。经典双⽬恢复深度的算法有 BM(Block Matching), SGBM(Semi-Global Matching)[3, 4]等,但本题不探讨⽴体视觉内容(那是⼀个⼤问题)。我们假设双⽬计算的视差已经给定,请你根据双⽬模型,画出图像对应的点云,并显⽰到 Pangolin 中。题给定的左右图见 code/left.png 和 code/right.png,视差图亦给定,见code/right.png。双⽬的参数如下:
fx= 718.856; fy = 718.856; cx =607.1928; cy = 185.2157
且双⽬左右间距(即基线)为:
d = 0.573 m
请根据以上参数,计算相机数据对应的点云,并显⽰到 Pangolin 中。程序请code/disparity.cpp ⽂件。
在这里插入图片描述

disparity.cpp:

// start your code here// 根据双目模型计算 point 的位置double x = (u - cx) / fx;double y = (v - cy) / fy;double depth = fx * b / (disparity.at<float>(v, u));point[0] = x * depth;point[1] = y * depth;point[2] = depth;// end your code here

double x和double y的计算方式和上一题一样,depth就算如下:
在这里插入图片描述
计算出depth后,那么point模仿课上五对图片那个实践仿写即可。只不过实践中的d(视差)没有给出,而此题中视差d已给,所以公式写出来略有不同。
CMakeLists.txt:

cmake_minimum_required( VERSION 2.8 )
project(stereoVision)
set( CMAKE_CXX_FLAGS "-std=c++11 -O3")include_directories("/usr/include/eigen3")
find_package(Pangolin REQUIRED)
include_directories( ${Pangolin_INCLUDE_DIRS} )find_package(OpenCV 3.0 QUIET) #find_package(<Name>)命令首先会在模块路径中寻找 Find<name>.cmake
if(NOT OpenCV_FOUND)find_package(OpenCV 2.4.3 QUIET)if(NOT OpenCV_FOUND)message(FATAL_ERROR "OpenCV > 2.4.3 not found.")endif()
endif()include_directories(${OpenCV_INCLUDE_DIRS})add_executable(disparity disparity.cpp)
target_link_libraries(disparity ${OpenCV_LIBRARIES})
target_link_libraries(disparity ${Pangolin_LIBRARIES})

然后就是编译五部曲:
mkdir build
cd build
cmake …
make
./disparity
在这里插入图片描述
如果你出现了这张图片,那就是你的disparity.cpp中的图片位置没有写对,找不到图片所导致的!!

运行成功如下:
在这里插入图片描述

3.矩阵微分

在这里插入图片描述

①第一问:如果大家有不理解的地方可以看看这个印度三哥的视屏,我认为讲的还是非常清晰的,至少我搜了很多国内的都没有这个讲得好,虽然语言不通,但是一点都不影响学习。高博的清华PPT还是不适合我这种人看。
链接:
矩阵求导讲解
在这里插入图片描述

②第二问:如果大家有不理解的地方可以看看这个印度三哥的视屏,我认为讲的还是非常清晰的,至少我搜了很多国内的都没有这个讲得好,虽然语言不通,但是一点都不影响学习。高博的清华PPT还是不适合我这种人看。
链接:
矩阵求导讲解
在这里插入图片描述

③第三问:
在这里插入图片描述

4.高斯牛顿法的曲线拟合实验

在这里插入图片描述

当然我觉得大家很有必要了解一下这一块的由来,我的上一篇博客讲述了海斯矩阵,凸函数等基本概念,大家看这个之前我认为很必要学习一下: 链接:
SLAM第四讲实践中的最优化知识

在做这道题之前我们非常有必要了解一下什么是牛顿法法,因为高斯牛顿法是牛顿法的改进,我以一道最优化的简单立体让你明白什么是牛顿法:
在这里插入图片描述
在这里插入图片描述
下来我们再看高斯牛顿法,我搜查了很多资料,很难找到一道高斯牛顿法的数学题来让大家理解,所以我只能找到一个更为详细点的高斯牛顿法的计算步骤让大家理解:
在这里插入图片描述

到这里,我们开始做题:
gaussnewton.cpp:

#include <iostream>
#include <chrono>
#include <opencv2/opencv.hpp>
#include <Eigen/Core>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;int main(int argc, char **argv) {double ar = 1.0, br = 2.0, cr = 1.0;         // 真实参数值double ae = 2.0, be = -1.0, ce = 5.0;        // 估计参数值int N = 100;                                 // 数据点double w_sigma = 1.0;                        // 噪声Sigma值double inv_sigma = 1.0 / w_sigma;cv::RNG rng;                                 // OpenCV随机数产生器vector<double> x_data, y_data;      // 数据for (int i = 0; i < N; i++) {double x = i / 100.0;x_data.push_back(x);y_data.push_back(exp(ar * x * x + br * x + cr) + rng.gaussian(w_sigma * w_sigma));}// 开始Gauss-Newton迭代int iterations = 100;    // 迭代次数double cost = 0, lastCost = 0;  // 本次迭代的cost和上一次迭代的costchrono::steady_clock::time_point t1 = chrono::steady_clock::now();for (int iter = 0; iter < iterations; iter++) {Matrix3d H = Matrix3d::Zero();             // Hessian = J^T W^{-1} J in Gauss-NewtonVector3d b = Vector3d::Zero();             // biascost = 0;for (int i = 0; i < N; i++) {double xi = x_data[i], yi = y_data[i];  // 第i个数据点double error = yi - exp(ae * xi * xi + be * xi + ce);//计算雅可比矩阵J(Xk)和误差f(Xk)Vector3d J; // 雅可比矩阵J[0] = -xi * xi * exp(ae * xi * xi + be * xi + ce);  // de/daJ[1] = -xi * exp(ae * xi * xi + be * xi + ce);  // de/dbJ[2] = -exp(ae * xi * xi + be * xi + ce);  // de/dcH += inv_sigma * inv_sigma * J * J.transpose();b += -inv_sigma * inv_sigma * error * J;cost += error * error;}// 求解线性方程 Hx=bVector3d dx = H.ldlt().solve(b);if (isnan(dx[0])) {cout << "result is nan!" << endl;break;}if (iter > 0 && cost >= lastCost) {cout << "cost: " << cost << ">= last cost: " << lastCost << ", break." << endl;break;}ae += dx[0];be += dx[1];ce += dx[2];lastCost = cost;cout << "total cost: " << cost << ", \t\tupdate: " << dx.transpose() <<"\t\testimated params: " << ae << "," << be << "," << ce << endl;}chrono::steady_clock::time_point t2 = chrono::steady_clock::now();chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);cout << "solve time cost = " << time_used.count() << " seconds. " << endl;cout << "estimated abc = " << ae << ", " << be << ", " << ce << endl;return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project(homework4)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS "-std=c++14 -O3")
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
# OpenCV
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
# Eigen
include_directories("/usr/include/eigen3")add_executable(homework4 gaussnewton.cpp)
target_link_libraries(homework4 ${OpenCV_LIBS})

然后老五套
mkdir build
cd build
cmake …
make
./homework4
在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/193047.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Load-balanced-online-OJ-system 负载均衡的OJ系统项目

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 本项目Github地址 - Load-balanced-o…

在Linux中nacos集群模式部署

一、安装 配置nacos 在Linux中建立一个nacos文件夹 mkdir nacos 把下载的压缩包拉入刚才创建好的nacos文件中 解压 tar -zxvf nacos-server-1.4.1\.tar.gz 修改配置文件 进入nacos文件中的conf文件的cluster.conf.example 修改cluster.conf.example文件 vim cluster.conf.exa…

Spring6(一):入门案例

文章目录 1. 概述1.1 Spring简介1.2 Spring 的狭义和广义1.3 Spring Framework特点1.4 Spring模块组成 2 入门2.1 构建模块2.2 程序开发2.2.1 引入依赖2.2.2 创建java类2.2.3 创建配置文件2.2.4 创建测试类测试 2.3 程序分析2.4 启用Log4j2日志框架2.4.1 引入Log4j2依赖2.4.2 加…

使用pixy计算群体遗传学统计量

1 数据过滤 过滤参数&#xff1a;过滤掉次等位基因频率&#xff08;minor allele frequency&#xff0c;MAF&#xff09;低于0.05、哈达-温伯格平衡&#xff08;Hardy– Weinberg equilibrium&#xff0c;HWE&#xff09;对应的P值低于1e-10或杂合率&#xff08;heterozygosit…

MacOS Ventura 13 优化配置(ARM架构新手向导)

一、系统配置 1、About My MacBook Pro 2、在当前标签打开新窗口 桌面上创建目录的文件夹&#xff0c;每次新打开一个目录&#xff0c;就会创建一个窗口&#xff0c;这就造成窗口太多&#xff0c;不太好查看和管理&#xff0c;我们可以改成在新标签处打开新目录。需要在&…

想买GPT4会员却只能排队?来看看背后的故事!

文章目录 &#x1f9d0; 为什么要进候选名单&#xff1f;&#x1f50d; 究竟发生了什么&#xff1f;&#x1f62e; IOS端还能买会员&#xff01;&#x1f914; 网页端为啥不能订会员&#xff1f;第一点&#xff1a;防止黑卡消费第二点&#xff1a;当技术巨头遇上资源瓶颈&#…

OpenGL的学习之路-3

前面1、2介绍的都是glut编程 下面就进行opengl正是部分啦。 1.绘制点 #include <iostream> #include <GL/gl.h> #include <GL/glu.h> #include <GL/glut.h>void myMainWinDraw();int main(int argc,char** argv) {glutInit(&argc,argv);glutIni…

求组合数(笔记)

//组合数2&#xff0c;取值在1e5 //Cab a! / (a - b)! * b! #include<iostream> using namespace std; using ll long long; const ll N 1e4 9, mod 1e9 7; ll fact[N], infact[N];//阶乘&#xff0c;逆元阶乘ll qmi(ll a, ll k, ll p)//逆元模板 {ll res 1;while…

LeetCode - 142. 环形链表 II (C语言,快慢指针,配图)

如果你对快慢指针&#xff0c;环形链表有疑问&#xff0c;可以参考下面这篇文章&#xff0c;了解什么是环形链表后&#xff0c;再做这道题会非常简单&#xff0c;也更容易理解下面的图片公式等。 LeetCode - 141. 环形链表 &#xff08;C语言&#xff0c;快慢指针&#xff0c;…

Spring6(三):面向切面AOP

文章目录 4. 面向切面&#xff1a;AOP4.1 场景模拟4.1.1 声明接口4.1.2 创建实现类4.1.3 创建带日志功能的实现类4.1.4 提出问题 4.2 代理模式4.2.1 概念4.2.2 静态代理4.2.3 动态代理4.2.4 测试 4.3 AOP概念4.3.1 相关术语①横切关注点②通知&#xff08;增强&#xff09;③切…

2023年【北京市安全员-B证】试题及解析及北京市安全员-B证证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 北京市安全员-B证试题及解析根据新北京市安全员-B证考试大纲要求&#xff0c;安全生产模拟考试一点通将北京市安全员-B证模拟考试试题进行汇编&#xff0c;组成一套北京市安全员-B证全真模拟考试试题&#xff0c;学员…

HDP集群Kafka开启SASLPLAINTEXT安全认证

hdp页面修改kafka配置 java代码连接kafka增加对应的认证信息 props.put("security.protocol","SASL_PLAINTEXT");props.put("sasl.mechanism","PLAIN");props.put("sasl.jaas.config","org.apache.kafka.common.securi…

CentOS to KeyarchOS 系统迁移体验

1. KOS(KeyarchOS)——云峦操作系统简介 KeyarchOS 即云峦操作系统(简称 KOS)是浪潮信息基于 Linux 内核、龙蜥等开源技术自主研发的一款服务器操作系统&#xff0c;支持x86、ARM 等主流架构处理器&#xff0c;广泛兼容传统 CentOS 生态产品和创新技术产品&#xff0c;可为用户…

【深度学习 | 核心概念】那些深度学习路上必经的核心概念,确定不来看看? (六)

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

毫米波雷达模块的目标检测与跟踪

毫米波雷达技术在目标检测与跟踪方面具有独特的优势&#xff0c;其高精度、不受光照影响等特点使其在汽车、军事、工业等领域广泛应用。本文深入探讨毫米波雷达模块在目标检测与跟踪方面的研究现状、关键技术以及未来发展方向。 随着科技的不断进步&#xff0c;毫米波雷达技术在…

短路语法 [SUCTF 2019]EasySQL1

打开题目 输入字符的时候啥也不回显。只有输入数字的时候页面有回显 但是当我们输入union&#xff0c;from&#xff0c;sleep&#xff0c;where&#xff0c;order等&#xff0c;页面回显nonono&#xff0c;很明显过滤了这些关键词 最开始我的思路是打算尝试双写绕过 1;ununion…

高效使用 PyMongo 进行 MongoDB 查询和插入操作

插入到集合中&#xff1a; 要将记录&#xff08;在MongoDB中称为文档&#xff09;插入到集合中&#xff0c;使用insert_one()方法。insert_one()方法的第一个参数是一个包含文档中每个字段的名称和值的字典。 import pymongomyclient pymongo.MongoClient("mongodb://l…

华为ensp:vrrp双机热备负载均衡

现在接口ip都已经配置完了&#xff0c;直接去配置vrrp r1上192.168.1.100 作为主 192.168.2.100作为副 r2上192.168.1.199 作为副 192.168.2.100作为主 这样就实现了负载均衡&#xff0c;如果两个都正常运行时&#xff0c;r1作为1.1的网关&#xff0c;r2作为2.1网关…

数据结构第三课 -----线性表之双向链表

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

Radiology 谈人工智能在放射学领域的10个预测方向 [文献阅读]

人工智能(AI)和信息学正在改变放射学。十年前&#xff0c;没有哪个专家会预测到今天放射人工智能行业的蓬勃发展&#xff0c;100多家人工智能公司和近400种放射人工智能算法得到了美国食品和药物管理局(FDA)的批准。 不到一年前&#xff0c;即使是最精明的预言家也不会相信这些…