您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

一种简单的三维重现算法实现

时间:2022-06-23 10:50:35  来源:  作者:新缸中之脑

让我们从定义开始,三维重建 — 3d reconstruction — 是在长程数据处理的基础上开发对象的 3D 模型。可以使用多种原理进行三维重建:立体测量、立体光度测量、体积去除或运动数据。

本教程可以作为一个指南,解释了如何开发一个简单的应用程序来使用 GPU 重建对象的几何形状。

一种简单的三维重现算法实现

 

在上述原则中,我们选择了由Brian CurelessMark Levoy在其题为“ A Volumetric Method for Building Complex Models from Range Images ”的文章中提出的体积去除算法。

下图阐明了算法的基本原理。从一组图像中重建的3D对象显示在左侧。在处理图像时,该算法会移除位于对象前面的 3D 点(作者将结构光技术应用于深度映射)。第一次照片处理的结果显示在中心。使用从第二台相机获得的数据,程序删除额外的 3D 点。使用的角度越多,移除的额外 3D 点就越多;最后,只剩下属于该对象的点。

一种简单的三维重现算法实现

 

在应用程序中,我们实现了算法的简化版本,该算法仅删除图像中位于对象轮廓之外的点。继原文之后,我们将整个空间划分为一组立方元素(体素)。

为了确定体素是否属于 3D 对象,我们应用 GPU 渲染并将获得的投影与对象轮廓相匹配。

要获得投影,使用以下函数:

inline void	HComparator::render(HModel *model, const long long *voxel, HFrame *frame){
  pixelBuffer->makeCurrent();
  glClear(GL_COLOR_BUFFER_BIT);
  frame->setGL();
  float coords[3];
  model->position(voxel, coords);
  glTranslatef(coords[0], coords[1], coords[2]);
  double s = model->delta();
  glScalef(s, s, s);
  glCallList(voxelList);
  glFlush();
}

更详细地解释是,

pixelBuffer->makeCurrent () — 将绘图内容切换到屏幕外 QGLPixelBuffer缓冲区。

初始化输出缓冲区时,裁剪、深度测试和混合被禁用,因为唯一的目标是确定相对于对象的体素空间位置。

void	HComparator::initPixelBuffer(){
  pixelBuffer->makeCurrent();
  glDisable(GL_CULL_FACE);
  glDisable(GL_DEPTH_TEST);
  glDisable(GL_LIGHTING);
  glDisable(GL_BLEND);
  glEnable(GL_VERTEX_ARRAY);
  glClearColor(1, 1, 1, 1);
  glColor3f(0, 0, 0);
  createVoxelList();
}

切换HComparator::render中的内容后,清空输出缓冲区并设置投影参数。

  glClear(GL_COLOR_BUFFER_BIT);
  frame->setGL();
  float coords[3];
  model->position(voxel, coords);
  glTranslatef(coords[0], coords[1], coords[2]);
  double s = model->delta();
  glScalef(s, s, s);

为了渲染体素,调用glCallList(voxelList)函数来执行预先形成的命令列表。初始化函数为:

void	HComparator::createVoxelList(){
  float eps = 1e-4;
  static GLdouble vertices[]={
    0, 0, 0, 1, 0, 0,
    1, 1, 0, 0, 1, 0,
    0, 0, 1, 1, 0, 1,
    1, 1, 1, 0, 1, 1
  };
  for (int i = 0; i < 24; i++)
  {
    if (vertices[i] == 0)
    {
      vertices[i] -= eps;
    }
    if (vertices[i] == 1)
    {
      vertices[i] += eps;
    }
  }
  static GLubyte indices[]={
    0, 3, 2, 1, 2, 3, 7, 6,
    0, 4, 7, 3, 1, 2, 6, 5,
    4, 5, 6, 7, 0, 1, 5, 4
  };
  voxelList=glGenLists(1);
  glVertexPointer(3, GL_DOUBLE, 0, vertices);
  glMatrixMode(GL_MODELVIEW);
  glNewList(voxelList, GL_COMPILE);
  glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, indices);
  glEndList();
}

绘制后,使用HComparator::compareData函数确定相对于对象的体素空间位置。

char	HComparator::compareData(HModel *model, const long long *voxel, HFrame* frame){
  int min_x, min_y, max_x, max_y;
  long int width, _width, height;
  auto image=frame->data;
  getBounds(min_x, min_y, max_x, max_y, frame->width, frame->height);
  width=max_x-min_x;
  height=max_y-min_y;
  if ((width == 0) || (height == 0))
  {
    return 4;
  }
  _width=width;
  if(_width%4)
    _width+=4-_width%4;
  glReadPixels(min_x, min_y, width, height, GL_RED, GL_UNSIGNED_BYTE, currentData);
  char result=4;
  for(int j=0; j<height; j++){
    auto data_ptr = ¤tData[j*_width];
    auto image_ptr = &image[(min_y + j)*frame->width + min_x];
    for(auto i=0; i<width; i++){
      if(data_ptr[i] == 0){
        if(image_ptr[i] != 0){
          if(result==1)
            return 2;
          result=0;
        }
        else{
          if(result==0)
            return 2;
          result=1;
        }
      }
    }
  }
  return result;
}

compareData函数复制缓冲区内容并根据三个可能的选项将其与对象轮廓进行比较(见下图):

a) 体素完全位于对象内(代码 1);

b) 体素属于边界(代码2);

c) 体素完全位于对象之外(代码 0)。

一种简单的三维重现算法实现

 

用于开发 3D 模型的角度集由HReconstruction::process函数顺序处理。我们从每个体素都属于对象的假设开始。如果确定体素位置超出对象的某个角度,则其处理停止并从模型中移除。执行整个处理,直到考虑所有角度。最后,只剩下属于对象模型的体素。

void	HReconstruction::process() {
  int idle_counter = 0;
  _voxel[0] = _voxel[0]%_model->N();
  _voxel[1] = _voxel[1]%_model->N();
  _voxel[2] = _voxel[2]%_model->N();

  for (; _voxel[0] < _model->N(); _voxel[0]++) {
    for (; _voxel[1] < _model->N(); _voxel[1]++) {
      for (; _voxel[2] < _model->N(); _voxel[2]++) {
        char voxel_type = 1;
        for (auto &frame: _model->frames()) {
          char t=_comparator->compare(_model, _voxel, frame);
          if ((t == 0) || (t == 4)) {
            voxel_type = 0;
            break;
          }
        }
        _model->setStatus(_voxel, voxel_type);
        if(idle_counter++>idleValue)
          return;
      }
      _voxel[2] = 0;
    }
    _voxel[1] = 0;
  }
  workFlag=0;
}

为了匹配体素和对象轮廓,应该知道投影参数。它们由GL_PROJECTIONGL_MODELVIEW矩阵定义(参见setGL函数)。

void	HFrame::setGL(){
  glMatrixMode(GL_PROJECTION);
  glViewport(0, 0, width, height);
  glLoadMatrixd((double*)intrisicParameters.data);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glLoadMatrixd((double*)modelviewMatrix.data);
}

GL_PROJECTION矩阵由相机参数定义,特别是焦距和图像大小(
HFrame::loadIntrisicParameters函数)。

void HFrame::loadIntrisicParameters(const Mat &img, double focal_length)
{
  // http://kgeorge.Github.io/2014/03/08/calculating-opengl-perspective-matrix-from-opencv-intrinsic-matrix/
  Mat_<double> persp(4,4); persp.setTo(0);
  double f = focalLengthToPixels(focal_length, img.rows);
  double fx = f;
  double fy = f;
  double cx = img.cols/(double)2;
  double cy = img.rows/(double)2;
  persp(0,0) = fx/cx;
  persp(1,1) = fy/cy;
  double near = 0.01;
  double far = 1000;

  persp(2,2) = -(far+near)/(far-near);
  persp(2,3) = -2.0*far*near / (far-near);
  persp(3,2) = -1.0;

  persp = persp.t(); //to col-major for OpenGL

  intrisicParameters = persp.clone();
}

可以使用增强现实标记来确定相机的 3D 位置,我们从 aruco 库中获取它。标记是要打印在一张纸上的特殊图像(见下图)。

一种简单的三维重现算法实现

 

拍摄物体时,标记必须保持不动,并在每张物体照片中进入相机视野。

一种简单的三维重现算法实现

 

该库检测标记控制点,然后使用相机焦距计算标记 3D 位置(rvectvec)。

auto arucoDict = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
  auto grid = cv::aruco::GridBoard::create(6, 8, 0.04, 0.02, arucoDict);
  Mat gray;
  vector<Mat> board_corners;
  Mat board_ids;
  cvtColor(img_bgr, gray, COLOR_BGR2GRAY);
  cv::aruco::detectMarkers(gray, arucoDict, board_corners, board_ids);
  if (board_corners.empty())
  {
    return false;
  }
  double pixelsFocalLength = focalLengthToPixels(focalLength, img_bgra.rows);
  cameraMatrix = (Mat_<double>(3, 3)<< pixelsFocalLength, 0, img_bgra.cols*0.5, 0, pixelsFocalLength, img_bgra.rows*0.5, 0, 0, 1);

  cv::aruco::estimatePoseBoard(board_corners, board_ids, grid, cameraMatrix, Mat(), rvec, tvec);
  loadExtrisicParameters(rvec, tvec, modelviewMatrix);

rvec和tvec参数确定GL_MODELVIEW矩阵(参见HFrame ::loadExtrisicParameters函数)。

void HFrame::loadExtrisicParameters(const Mat &Rvec, const Mat &Tvec, Mat &modelview_matrix)
{
  // http://kgeorge.github.io/2014/03/08/calculating-opengl-perspective-matrix-from-opencv-intrinsic-matrix/
  CV_Assert(Rvec.rows == 3);
  CV_Assert(Tvec.rows == 3);
  Mat Rot(3,3,CV_32FC1);
  Rodrigues(Rvec, Rot);

  // [R | t] matrix
  Mat_<double> para = Mat_<double>::eye(4,4);
  Rot.convertTo(para(Rect(0,0,3,3)),CV_64F);
  Tvec.copyTo(para(Rect(3,0,1,3)));

  Mat cvToGl = Mat::zeros(4, 4, CV_64F);
  cvToGl.at<double>(0, 0) = 1.0f;
  cvToGl.at<double>(1, 1) = -1.0f; // Invert the y axis
  cvToGl.at<double>(2, 2) = -1.0f; // invert the z axis
  cvToGl.at<double>(3, 3) = 1.0f;

  para = cvToGl * para;

  Mat(para.t()).copyTo(modelview_matrix); // transpose to col-major for OpenGL
}

至此,我们学会了如何在图像平面上投影体素,确定体素相对于物体图像的位置,计算投影参数,并通过处理来自多个摄像机的数据来确定体素是否属于物体体;这是一种用于重建 3D 对象的简化但完整的技术,源代码可以在这里下载。

一种简单的三维重现算法实现

 


原文链接:
http://www.bimant.com/blog/simple-3d-reconstruction-implementation/



Tags:算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
诱导付费、自动扣费……微短剧被质疑借助算法精准“围猎”老年人
诱导付费、自动扣费、重复收费&hellip;&hellip;聚焦身边的消费烦心事⑦丨一些微短剧被质疑借助算法精准“围猎”老年人中工网北京3月31日电(工人日报&mdash;中工网记者刘兵)...【详细内容】
2024-04-01  Search: 算法  点击:(11)  评论:(0)  加入收藏
分析网站SEO快速排名算法对网站具体的影响效果
亲爱的朋友们,今天我想和大家分享一个我们都关心的话题&mdash;&mdash;网站SEO快速排名算法对网站我们身处一个信息爆炸的时代,如何在海量的信息中脱颖而出,成为了一个我们不得...【详细内容】
2024-03-28  Search: 算法  点击:(20)  评论:(0)  加入收藏
当prompt策略遇上分治算法,南加大、微软让大模型炼成「火眼金睛」
近年来,大语言模型(LLMs)由于其通用的问题处理能力而引起了大量的关注。现有研究表明,适当的提示设计(prompt enginerring),例如思维链(Chain-of-Thoughts),可以解锁 LLM 在不同领域的...【详细内容】
2024-03-12  Search: 算法  点击:(20)  评论:(0)  加入收藏
谷歌宣布更新搜索算法:打击AI生成内容,提高搜索结果质量
IT之家 3 月 6 日消息,谷歌于当地时间 5 日发文宣布,针对用户对搜索结果质量下降的反馈,将对算法进行调整,旨在打击 AI 生成的内容以及内容农场等垃圾信息,使用户能够看到更多“...【详细内容】
2024-03-06  Search: 算法  点击:(42)  评论:(0)  加入收藏
小红书、视频号、抖音流量算法解析,干货满满,值得一看!
咱们中国现在可不是一般的牛!网上的网友已经破了十个亿啦!到了这个互联网的新时代,谁有更多的人流量,谁就能赢得更多的掌声哦~抖音、小红书、、视频号,是很多品牌必争的流量洼地...【详细内容】
2024-02-23  Search: 算法  点击:(18)  评论:(0)  加入收藏
雪花算法详解与Java实现:分布式唯一ID生成原理
SnowFlake 算法,是 Twitter 开源的分布式 ID 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 ID。在分布式系统中的应用十分广泛,且 ID 引入了时间戳...【详细内容】
2024-02-03  Search: 算法  点击:(54)  评论:(0)  加入收藏
简易百科之什么是搜索引擎的PageRank算法?
简易百科之什么是搜索引擎的PageRank算法?在互联网时代,搜索引擎是我们获取信息的重要工具。而PageRank算法则是搜索引擎的核心技术之一,它决定了网页在搜索结果中的排名。那么...【详细内容】
2024-01-24  Search: 算法  点击:(57)  评论:(0)  加入收藏
PageRank算法揭秘:搜索引擎背后的魔法师的工作原理
PageRank(PR)算法是由谷歌创始人之一的拉里&middot;佩奇LarryPage命名的一种衡量网站页面重要性的方法。根据谷歌的说法,PageRank通过计算页面链接的数量和质量来粗略估计分...【详细内容】
2024-01-23  Search: 算法  点击:(45)  评论:(0)  加入收藏
程序开发中常用的十种算法,你用过几种?
当编写程序时,了解和使用不同的算法对解决问题至关重要。以下是C#中常用的10种算法,每个算法都伴随着示例代码和详细说明。1. 冒泡排序 (Bubble Sort):冒泡排序是一种简单的比...【详细内容】
2024-01-17  Search: 算法  点击:(46)  评论:(0)  加入收藏
百度最新的搜索引擎算法是什么样的?
百度搜索引擎算法是百度用来决定网页排名的算法。它是百度搜索技术的核心,也是百度作为全球最大的中文搜索引擎的基石。随着互联网的发展和用户需求的不断变化,百度搜索引擎算...【详细内容】
2024-01-10  Search: 算法  点击:(92)  评论:(0)  加入收藏
▌简易百科推荐
小红书、视频号、抖音流量算法解析,干货满满,值得一看!
咱们中国现在可不是一般的牛!网上的网友已经破了十个亿啦!到了这个互联网的新时代,谁有更多的人流量,谁就能赢得更多的掌声哦~抖音、小红书、、视频号,是很多品牌必争的流量洼地...【详细内容】
2024-02-23  二手车小胖说    Tags:流量算法   点击:(18)  评论:(0)  加入收藏
雪花算法详解与Java实现:分布式唯一ID生成原理
SnowFlake 算法,是 Twitter 开源的分布式 ID 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 ID。在分布式系统中的应用十分广泛,且 ID 引入了时间戳...【详细内容】
2024-02-03   一安未来  微信公众号  Tags:雪花算法   点击:(54)  评论:(0)  加入收藏
程序开发中常用的十种算法,你用过几种?
当编写程序时,了解和使用不同的算法对解决问题至关重要。以下是C#中常用的10种算法,每个算法都伴随着示例代码和详细说明。1. 冒泡排序 (Bubble Sort):冒泡排序是一种简单的比...【详细内容】
2024-01-17  架构师老卢  今日头条  Tags:算法   点击:(46)  评论:(0)  加入收藏
百度推荐排序技术的思考与实践
本文将分享百度在推荐排序方面的思考与实践。在整个工业界的推广搜场景上,特征设计通常都是采用离散化的设计,需要保证两方面的效果,一方面是记忆,另一方面是泛化。特征都是通过...【详细内容】
2024-01-09  DataFunTalk  微信公众号  Tags:百度推荐   点击:(80)  评论:(0)  加入收藏
什么是布隆过滤器?如何实现布隆过滤器?
以下我们介绍了什么是布隆过滤器?它的使用场景和执行流程,以及在 Redis 中它的使用,那么问题来了,在日常开发中,也就是在 Java 开发中,我们又将如何操作布隆过滤器呢?布隆过滤器(Blo...【详细内容】
2024-01-05  Java中文社群  微信公众号  Tags:布隆过滤器   点击:(94)  评论:(0)  加入收藏
面向推荐系统的深度强化学习算法研究与应用
随着互联网的快速发展,推荐系统在各个领域中扮演着重要的角色。传统的推荐算法在面对大规模、复杂的数据时存在一定的局限性。为了解决这一问题,深度强化学习算法应运而生。本...【详细内容】
2024-01-04  数码小风向    Tags:算法   点击:(106)  评论:(0)  加入收藏
非负矩阵分解算法:从非负数据中提取主题、特征等信息
非负矩阵分解算法(Non-negativeMatrixFactorization,简称NMF)是一种常用的数据分析和特征提取方法,主要用于从非负数据中提取主题、特征等有意义的信息。本文将介绍非负矩阵分解...【详细内容】
2024-01-02  毛晓峰    Tags:算法   点击:(75)  评论:(0)  加入收藏
再谈前端算法,你这回明白了吗?
楔子 -- 青蛙跳台阶一只青蛙一次可以跳上一级台阶,也可以跳上二级台阶,求该青蛙跳上一个n级的台阶总共需要多少种跳法。分析: 当n=1的时候,①只需要跳一次即可;只有一种跳法,即f(...【详细内容】
2023-12-28  前端爱好者  微信公众号  Tags:前端算法   点击:(114)  评论:(0)  加入收藏
三分钟学习二分查找
二分查找是一种在有序数组中查找元素的算法,通过不断将搜索区域分成两半来实现。你可能在日常生活中已经不知不觉地使用了大脑里的二分查找。最常见的例子是在字典中查找一个...【详细内容】
2023-12-22  小技术君  微信公众号  Tags:二分查找   点击:(79)  评论:(0)  加入收藏
强化学习算法在资源调度与优化中的应用
随着云计算和大数据技术的快速发展,资源调度与优化成为了现代计算系统中的重要问题。传统的资源调度算法往往基于静态规则或启发式方法,无法适应动态变化的环境和复杂的任务需...【详细内容】
2023-12-14  职场小达人欢晓    Tags:算法   点击:(169)  评论:(0)  加入收藏
站内最新
站内热门
站内头条