配置Json环境

       使用Jsoncpp包中的.cpp和 .h文件
       解压上面下载的 Jsoncpp 文件,把 jsoncpp-src-0.5.0文件拷贝到工程目录下, 将 jsoncpp-src-0.5.0\jsoncpp-src-0.5.0\include\json 和 jsoncpp-src-0.5.0\jsoncpp-src-0.5.0\src\lib_json 目录里的文件包含到VS工程中,在VS工程的属性C/C++下General中 Additional Include Directories 包含头文件目录 .\jsoncpp-src-0.5.0\include 。在使用的cpp文件中 包含json头文件即可,如: #include "json/json.h" 。将 json_reader.cpp、 json_value.cpp和 json_writer.cpp三个文件的Precompiled Header属性设置为 Not Using Precompiled Headers, 否则编译会出现错误。

试了很多方法,上述方法亲测可用。

准备工作

读图解析Json文件及声明变量

    Mat src = imread(".//images//chessboard.jpg");//声明一些存储直线点的变量int i=0;vector < vector<Point2d> > Points;vector<Point2d> XZ_line, YZ_line, XY_line, XZ_line1, YZ_line1, XY_line1;Points.push_back(XZ_line);Points.push_back(YZ_line);Points.push_back(XY_line);Points.push_back(XZ_line1);Points.push_back(YZ_line1);Points.push_back(XY_line1);Point2d orignPoint;//第一步先解析Json数据//用来判断是线还是交点的点string shape_type = "line";//用来区分线条的类型vector<string> linetype;string c = ",";linetype.push_back("XZ_line");linetype.push_back("YZ_line");linetype.push_back("XY_line");linetype.push_back("XZ_line'");linetype.push_back("YZ_line'");linetype.push_back("XY_line'");//声明读取Json文件变量Json::Reader reader;Json::Value root;ifstream in(".//labelme_data//chessboard_line.json", ios::binary);if (!in.is_open()){cout << "打开文件错误\n";return 0;}if (reader.parse(in,root)){int temp = root["shapes"].size();for (int m =0; m < temp; m++){string shapetype = root["shapes"][m]["shape_type"].asString();//判断是否为直线点,还是交点if (shapetype == shape_type){string templinetype = root["shapes"][m]["label"].asString();for (; i < linetype.size(); i++){if (templinetype == linetype[i]){//得到points标签下的数据(此时为string类型)int temppointsize = root["shapes"][m]["points"].size();for (int j = 0; j < temppointsize; j++){string strpoint = root["shapes"][m]["points"][j].toStyledString();//对读取到的字符串进行处理,删除[]和空格字符strpoint.erase(strpoint.find(' '),1);strpoint.erase(strpoint.find('['), 1);strpoint.erase(strpoint.find(' '), 1);strpoint.erase(strpoint.find(']'), 1);//将该字符串按逗号分割vector<string> res;SplitString(strpoint, res, c);//将字符串转为doublePoint2d temppoint;temppoint.x = atof(res[0].c_str());temppoint.y = atof(res[1].c_str());Points[i].push_back(temppoint);}}}i = 0;}//原点位置else if (shapetype == "point"){//得到points标签下的数据(此时为string类型)string strpoint = root["shapes"][m]["points"].toStyledString();//对读取到的字符串进行处理,删除[]和空格字符strpoint.erase(strpoint.find(' '), 1);strpoint.erase(strpoint.find('['), 1);strpoint.erase(strpoint.find('['), 1);strpoint.erase(strpoint.find(' '), 1);strpoint.erase(strpoint.find(']'), 1);strpoint.erase(strpoint.find(']'), 1);//将该字符串按逗号分割vector<string> res;SplitString(strpoint, res, c);//将字符串转为doubleorignPoint.x = atof(res[0].c_str());orignPoint.y = atof(res[1].c_str());}}in.close();}

读取到的图像如下:

将Json文件里面标记的直线和点加载到图片上,并绘制出来可视化

    //点读取完毕,根据点将线条画在图上//复制一张图像//YZ_line, XY_line, XZ_line1, YZ_line1, XY_line1;Mat src1 = src.clone();for (int k = 0; k < Points.size(); k++){int tempSize = Points[k].size()/2;for (int n = 0; n < tempSize; n++){switch (k){case 0:line(src1, Points[k][2 * n], Points[k][2 * n + 1], Scalar(0, 0, 255), 1);XZ_line.push_back(Points[k][2 * n]);XZ_line.push_back(Points[k][2 * n+1]);break;case 1:line(src1, Points[k][2 * n], Points[k][2 * n + 1], Scalar(0, 255, 0), 1);YZ_line.push_back(Points[k][2 * n]);YZ_line.push_back(Points[k][2 * n + 1]);break;case 2:line(src1, Points[k][2 * n], Points[k][2 * n + 1], Scalar(255, 0, 0), 1);XY_line.push_back(Points[k][2 * n]);XY_line.push_back(Points[k][2 * n + 1]);break;case 3:line(src1, Points[k][2 * n], Points[k][2 * n + 1], Scalar(0, 255, 255), 1);XZ_line1.push_back(Points[k][2 * n]);XZ_line1.push_back(Points[k][2 * n + 1]);break;case 4:line(src1, Points[k][2 * n], Points[k][2 * n + 1], Scalar(255, 255, 0), 1);YZ_line1.push_back(Points[k][2 * n]);YZ_line1.push_back(Points[k][2 * n + 1]);break;case 5:line(src1, Points[k][2 * n], Points[k][2 * n + 1], Scalar(255, 0, 255), 1);XY_line1.push_back(Points[k][2 * n]);XY_line1.push_back(Points[k][2 * n + 1]);break;default:break;}}}

加载完,不同平面的直线用不同颜色绘制的直线和点如下图所示:

计算影消点

计算影消点,就是根据上面各个平面平行的直线,拟合出平行直线的交点。平行的直线本该没有交点,但经过摄影几何的透视变换,现实世界坐标系下的平行线都会相交于一点,这个点就是影消点,也就是世界坐标系里面的无穷远点,两条平行直线相交于无穷远处。但在摄影几何下,经过透视变换,无穷远点变为影消点,影消点在图像坐标系下可以求。

无穷远点变为影消点最直观的例子,拍摄一条火车铁轨,铁轨最终在图像里面一个点相交。

    //接下来求图像上的影消点//即计算两个平面平行线的交点//先计算XZ平面,两条平行线的交点//计算出来的line为Vec4f类型,即line[0-3]//斜率为line[1]/line[0],并过点(line[2],line[3])//先将其转为向量相乘的形式即l·x=0的形式,这里l其实为l的转置//l为(line[1],-line[0],-line[1]*line[2]+line[0]*line[3])vector<Vec3d> vecLineXZ;vector<Vec3d> vecLineYZ;vector<Vec3d> vecLineXY;vector<Vec3d> vecLineXZ1;vector<Vec3d> vecLineYZ1;vector<Vec3d> vecLineXY1;for (int i = 0; i < vecXZLine.size(); i++){Vec3d tempvec;tempvec[0] = vecXZLine[i][1];tempvec[1] = -vecXZLine[i][0];tempvec[2] = -vecXZLine[i][1] * vecXZLine[i][2] + vecXZLine[i][0] * vecXZLine[i][3];vecLineXZ.push_back(tempvec);}for (int i = 0; i < vecYZLine.size(); i++){Vec3d tempvec;tempvec[0] = vecYZLine[i][1];tempvec[1] = -vecYZLine[i][0];tempvec[2] = -vecYZLine[i][1] * vecYZLine[i][2] + vecYZLine[i][0] * vecYZLine[i][3];vecLineYZ.push_back(tempvec);}for (int i = 0; i < vecXYLine.size(); i++){Vec3d tempvec;tempvec[0] = vecXYLine[i][1];tempvec[1] = -vecXYLine[i][0];tempvec[2] = -vecXYLine[i][1] * vecXYLine[i][2] + vecXYLine[i][0] * vecXYLine[i][3];vecLineXY.push_back(tempvec);}for (int i = 0; i < vecXZ1Line.size(); i++){Vec3d tempvec;tempvec[0] = vecXZ1Line[i][1];tempvec[1] = -vecXZ1Line[i][0];tempvec[2] = -vecXZ1Line[i][1] * vecXZ1Line[i][2] + vecXZ1Line[i][0] * vecXZ1Line[i][3];vecLineXZ1.push_back(tempvec);}for (int i = 0; i < vecYZ1Line.size(); i++){Vec3d tempvec;tempvec[0] = vecYZ1Line[i][1];tempvec[1] = -vecYZ1Line[i][0];tempvec[2] = -vecYZ1Line[i][1] * vecYZ1Line[i][2] + vecYZ1Line[i][0] * vecYZ1Line[i][3];vecLineYZ1.push_back(tempvec);}for (int i = 0; i < vecXY1Line.size(); i++){Vec3d tempvec;tempvec[0] = vecXY1Line[i][1];tempvec[1] = -vecXY1Line[i][0];tempvec[2] = -vecXY1Line[i][1] * vecXY1Line[i][2] + vecXY1Line[i][0] * vecXY1Line[i][3];vecLineXY1.push_back(tempvec);}//求XZ平面的影消点Vec3d testVanishPoint = RobertColins(XZ_line, src.cols, src.rows);Vec3d pointvanishXZvec = vecLineXZ[0].cross(vecLineXZ[vecLineXZ.size() - 1]);//将齐次点形式转为欧式坐标Point2d pointvanishXZ = Point2d(pointvanishXZvec[0] / pointvanishXZvec[2], pointvanishXZvec[1] / pointvanishXZvec[2]);//将图片放大,将影消点可视化Mat dst(6060, 6060, CV_8UC3, Scalar(255, 255, 255));Rect roiRect = Rect(2827, 2827, src.cols, src.rows);src1.copyTo(dst(roiRect));//定义偏移量Point2d dispoint = Point2d(2828, 2828);line(dst, XZ_line[0] + dispoint, pointvanishXZ + dispoint, Scalar(0, 0, 255), 1);line(dst, XZ_line[XZ_line.size() - 1] + dispoint, pointvanishXZ + dispoint, Scalar(0, 0, 255), 1);//求YZ平面的影消点Vec3d pointvanishYZvec = vecLineYZ[0].cross(vecLineYZ[vecLineYZ.size() - 1]);Point2d pointvanishYZ = Point2d(pointvanishYZvec[0] / pointvanishYZvec[2], pointvanishYZvec[1] / pointvanishYZvec[2]);line(dst, YZ_line[1] + dispoint, pointvanishYZ + dispoint, Scalar(0, 255, 0), 1);line(dst, YZ_line[YZ_line.size() - 1] + dispoint, pointvanishYZ + dispoint, Scalar(0, 255, 0), 1);//求XY平面的影消点Vec3d pointvanishXYvec = vecLineXY[0].cross(vecLineXY[vecLineXY.size() - 1]);Point2d pointvanishXY = Point2d(pointvanishXYvec[0] / pointvanishXYvec[2], pointvanishXYvec[1] / pointvanishXYvec[2]);line(dst, XY_line[1] + dispoint, pointvanishXY + dispoint, Scalar(255, 0, 0), 1);line(dst, XY_line[XY_line.size() - 1] + dispoint, pointvanishXY + dispoint, Scalar(255, 0, 0), 1);//求XZ'平面的影消点Vec3d pointvanishXZ1vec = vecLineXZ1[0].cross(vecLineXZ1[vecLineXZ1.size() - 1]);Point2d pointvanishXZ1 = Point2d(pointvanishXZ1vec[0] / pointvanishXZ1vec[2], pointvanishXZ1vec[1] / pointvanishXZ1vec[2]);line(dst, XZ_line1[0] + dispoint, pointvanishXZ1 + dispoint, Scalar(0, 255, 255), 1);line(dst, XZ_line1[XZ_line1.size() - 1] + dispoint, pointvanishXZ1 + dispoint, Scalar(0, 255, 255), 1);//求YZ'平面的影消点Vec3d pointvanishYZ1vec = vecLineYZ1[0].cross(vecLineYZ1[vecLineYZ1.size() - 1]);Point2d pointvanishYZ1 = Point2d(pointvanishYZ1vec[0] / pointvanishYZ1vec[2], pointvanishYZ1vec[1] / pointvanishYZ1vec[2]);line(dst, YZ_line1[1] + dispoint, pointvanishYZ1 + dispoint, Scalar(255, 255, 0), 1);line(dst, YZ_line1[YZ_line1.size() - 1] + dispoint, pointvanishYZ1 + dispoint, Scalar(255, 255, 0), 1);//求XY'平面的影消点Vec3d pointvanishXY1vec = vecLineXY1[0].cross(vecLineXY1[vecLineXY1.size() - 1]);Point2d pointvanishXY1 = Point2d(pointvanishXY1vec[0] / pointvanishXY1vec[2], pointvanishXY1vec[1] / pointvanishXY1vec[2]);line(dst, XY_line1[1] + dispoint, pointvanishXY1 + dispoint, Scalar(255, 0, 255), 1);line(dst, XY_line1[XY_line1.size() - 1] + dispoint, pointvanishXY1 + dispoint, Scalar(255, 0, 255), 1);//至此,各个平面的影消点都已求出来//根据XZ、YZ、XY平面的影消点,进行相机内参标定,求解W矩阵vector<Point2d> vanishPointVec;vanishPointVec.push_back(pointvanishXZ);vanishPointVec.push_back(pointvanishYZ);vanishPointVec.push_back(pointvanishXY);return 0;
}

求得影消点的图片如下图所示:

 计算影消点时,用到了柯林斯算法,该算法如下:

//罗伯特·柯林斯方法求影消点
//输入参数为直线的端点,图像的宽高
//输出为影消点的齐次坐标形式
Vec3d RobertColins(vector<Point2d> vecLinePoints,int cols,int rows)
{Vec3d vanishPoint;int size = vecLinePoints.size();//防止坐标点差异过大造成求解精度下降,进行偏移int offset = (cols + rows) / 4;//这里直线端点,以两个点为一组代表一条直线//因此size必为偶数//得出各条直线的方向向量vector <Vec3d> Lines;for (int i = 0; i < size/2; i++){Vec3d startPoint, endPoint;startPoint[0] = (vecLinePoints[2 * i].x-offset);startPoint[1] = (vecLinePoints[2 * i].y-offset);startPoint[2] = offset;endPoint[0] = (vecLinePoints[2 * i + 1].x - offset);endPoint[1] = (vecLinePoints[2 * i + 1].y - offset);endPoint[2] = offset;//两个点坐标向量的叉乘等于,过该两点的直线齐次坐标向量Lines.push_back(startPoint.cross(endPoint));}/*声明一个Mat M形成3×3的“二阶矩”矩阵M为[a_i*a_i        a_i*b_i        a_i*c_i]M = sum [a_i*b_i        b_i*b_i        c_i*b_i][a_i*c_i        b_i*c_i        c_i*c_i]其中取i = 1到n的和。注意,M是对称矩阵。*/Mat M = (Mat_<double>(3, 3)<<0,0,0,0,0,0,0,0,0);for (int i = 0; i < size / 2; i++){Mat tempM = (Mat_<double>(3, 3));tempM.at<double>(0, 0) = Lines[i][0] * Lines[i][0];tempM.at<double>(0, 1) = Lines[i][0] * Lines[i][1];tempM.at<double>(0, 2) = Lines[i][0] * Lines[i][2];tempM.at<double>(1, 0) = Lines[i][1] * Lines[i][0];tempM.at<double>(1, 1) = Lines[i][1] * Lines[i][1];tempM.at<double>(1, 2) = Lines[i][1] * Lines[i][2];tempM.at<double>(2, 0) = Lines[i][2] * Lines[i][0];tempM.at<double>(2, 1) = Lines[i][2] * Lines[i][1];tempM.at<double>(2, 2) = Lines[i][2] * Lines[i][2];M = M + tempM;}//对M矩阵进行特征值分解Mat eigenvector = (Mat_<double>(3, 3));Mat eigenvalue = (Mat_<double>(3, 1));eigen(M, eigenvalue, eigenvector);vanishPoint[0] = eigenvector.at<double>(0, 2)*(offset / (eigenvector.at<double>(0, 2))) + offset;vanishPoint[1] = eigenvector.at<double>(1, 2)*(offset / (eigenvector.at<double>(0, 2))) + offset;vanishPoint[2] = 1;return vanishPoint;
}

解析Json文件用到的字符串处理方法:

//分割points字符串类型的点
void SplitString(const string& s, vector<string>& v, const string& c)
{string::size_type pos1, pos2;pos2 = s.find(c);pos1 = 0;while (string::npos != pos2){v.push_back(s.substr(pos1, pos2 - pos1));pos1 = pos2 + c.size();pos2 = s.find(c, pos1);}if (pos1 != s.length())v.push_back(s.substr(pos1));
}

鲁鹏老师三维重建课程之单视图重建相关推荐

  1. 北邮鲁鹏老师三维重建课程之相机标定

    在看北邮鲁鹏老师的三维重建的课程过程中,去官网找到有三个作业.现将三个作业里面的第一个作业相机标定完成.总体来说,可以分为三个部分,即图像坐标点和世界坐标点的获取:映射矩阵的生成,相机内外参的求解三个 ...

  2. 【计算机视觉】计算机视觉与深度学习-北邮鲁鹏老师课程笔记

    计算机视觉与深度学习-北邮鲁鹏老师课程笔记 01-计算机视觉相关介绍 02-图像分类 03-全连接神经网络 04-图像去噪&卷积&边缘提取 05-纹理表示&卷积神经网络 06- ...

  3. 【计算机视觉】计算机视觉与深度学习-01-计算机视觉相关介绍-北邮鲁鹏老师课程笔记

    计算机视觉与深度学习-01-计算机视觉相关介绍 前言 图像处理 vs 计算机视觉 图像处理 计算机视觉 相关课程 计算机视觉简介 计算机视觉顶级会议 计算机视觉的目标 图像中的信息 三维场景的结构信息 ...

  4. 北邮 鲁鹏老师 视频笔记

    https://www.zhihu.com/people/xu-hao-68-3/posts https://blog.csdn.net/weixin_45562510/category_109604 ...

  5. 影消点、影消线与相机内参、平面法向量的推导—单视图重构

    影消点计算算法如下: 单视图几何Vanish Point(消失点/灭点)计算方法--Robert_T_Collins(罗伯特·柯林斯)算法https://blog.csdn.net/beyond951 ...

  6. 鲁鹏 计算机视觉与深度学习

    本笔记来自于鲁鹏老师的视频 https://www.bilibili.com/video/BV1V54y1B7K3?p=3&vd_source=4ddee6259222ad3b06bedffc ...

  7. DeepFusion:基于单视图深度和梯度预测的单目SLAM实时稠密三维重建

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 标题:DeepFusion: Real-Time Dense 3D Reconstruction fo ...

  8. 单视图测量 (2D变换、影消点线、单视图重构)

    写在前面:本篇Blog仅作为学习笔记,学习内容来自于北邮CV-XUEBA团队的三维重建(精简版,鲁鹏)课程. 回顾经典2D变换 等距变换 旋转矩阵(Rotate Matrix)的性质分析 证明:旋转矩 ...

  9. 鲁祥老师吉他课学习笔记

    鲁祥老师吉他课学习笔记 导语 参考教材: <吉他入门经典教程>李国标 <弹指之间>潘尚文 <吉他教本>好连得出版社 <吉他教程>杰瑞吉他学校 <伯 ...

最新文章

  1. Linux2.6内核 -- 编码风格(3)
  2. 怎么用python处理excel文件-用python处理excel文件有多轻松?工作从未如此简单
  3. 王者服务器维护7月九号,腾讯手游王者荣耀7月9号9点半版本更新,备受期待的S20赛季它来了...
  4. python库_计算机二级教程 Python语言程序设计,第10章python第三方库概览
  5. 黑马程序员pink老师前端入门教程,零基础必看的JavaScript基础语法视频教程(DOM)
  6. PythonWeb开发教程(一),开发之前需要准备什么
  7. Git初始化及仓库创建和操作
  8. Maven,在pom.xml配置JDK 9版本。
  9. Nginx多进程高并发、低时延、高可靠机制在缓存(redis、memcache)twemproxy代理中的应用...
  10. Python2.x 和 3.x 的区别
  11. PHPnow中ZendDebugger与ZendOptimizer 共存
  12. Python 错误记录(新手)
  13. linux日志按日期生成器,Cron表达式生成器
  14. window驱动备份与安装
  15. 原型工具axure7.0
  16. 沈寅鑫银行内训实战专家
  17. 电视直播(CCTV5)
  18. 软件测试的项目职责、分工、测试流程详细讲解
  19. 计算机体系结构的一知半解
  20. python 装饰器

热门文章

  1. python游戏csgo开挂_Python64位游戏读写--GTA锁血
  2. spring boot自带的page分页
  3. (程序设计逻辑)如何按生日的年月日计算年龄(周岁)
  4. 为table标签内的tbody添加滚动条
  5. restapi是什么意思_什么是REST 、RESTful 、RESTful API?
  6. Spring常用注解你知道有哪些吗?
  7. 学生信息管理系统错误集(5)
  8. 顶尖AI科技智能化货代航运智能化铁路货运智能化海关港区口岸,全球集装箱港航人工智能领军企业中集飞瞳,成熟港航AI产品全球规模应用
  9. 序列化,os,sys,hashlib,collections
  10. PowerDesigner反向工程并添加注释,导出表到word