日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

讓我們從定義開始,三維重建 — 3d reconstruction — 是在長程數(shù)據(jù)處理的基礎(chǔ)上開發(fā)對象的 3D 模型。可以使用多種原理進(jìn)行三維重建:立體測量、立體光度測量、體積去除或運(yùn)動數(shù)據(jù)。

本教程可以作為一個指南,解釋了如何開發(fā)一個簡單的應(yīng)用程序來使用 GPU 重建對象的幾何形狀。

一種簡單的三維重現(xiàn)算法實(shí)現(xiàn)

 

在上述原則中,我們選擇了由Brian CurelessMark Levoy在其題為“ A Volumetric Method for Building Complex Models from Range Images ”的文章中提出的體積去除算法。

下圖闡明了算法的基本原理。從一組圖像中重建的3D對象顯示在左側(cè)。在處理圖像時,該算法會移除位于對象前面的 3D 點(diǎn)(作者將結(jié)構(gòu)光技術(shù)應(yīng)用于深度映射)。第一次照片處理的結(jié)果顯示在中心。使用從第二臺相機(jī)獲得的數(shù)據(jù),程序刪除額外的 3D 點(diǎn)。使用的角度越多,移除的額外 3D 點(diǎn)就越多;最后,只剩下屬于該對象的點(diǎn)。

一種簡單的三維重現(xiàn)算法實(shí)現(xiàn)

 

在應(yīng)用程序中,我們實(shí)現(xiàn)了算法的簡化版本,該算法僅刪除圖像中位于對象輪廓之外的點(diǎn)。繼原文之后,我們將整個空間劃分為一組立方元素(體素)。

為了確定體素是否屬于 3D 對象,我們應(yīng)用 GPU 渲染并將獲得的投影與對象輪廓相匹配。

要獲得投影,使用以下函數(shù):

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();
}

更詳細(xì)地解釋是,

pixelBuffer->makeCurrent () — 將繪圖內(nèi)容切換到屏幕外 QGLPixelBuffer緩沖區(qū)。

初始化輸出緩沖區(qū)時,裁剪、深度測試和混合被禁用,因?yàn)槲ㄒ坏哪繕?biāo)是確定相對于對象的體素空間位置。

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中的內(nèi)容后,清空輸出緩沖區(qū)并設(shè)置投影參數(shù)。

  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);

為了渲染體素,調(diào)用glCallList(voxelList)函數(shù)來執(zhí)行預(yù)先形成的命令列表。初始化函數(shù)為:

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函數(shù)確定相對于對象的體素空間位置。

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函數(shù)復(fù)制緩沖區(qū)內(nèi)容并根據(jù)三個可能的選項(xiàng)將其與對象輪廓進(jìn)行比較(見下圖):

a) 體素完全位于對象內(nèi)(代碼 1);

b) 體素屬于邊界(代碼2);

c) 體素完全位于對象之外(代碼 0)。

一種簡單的三維重現(xiàn)算法實(shí)現(xiàn)

 

用于開發(fā) 3D 模型的角度集由HReconstruction::process函數(shù)順序處理。我們從每個體素都屬于對象的假設(shè)開始。如果確定體素位置超出對象的某個角度,則其處理停止并從模型中移除。執(zhí)行整個處理,直到考慮所有角度。最后,只剩下屬于對象模型的體素。

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;
}

為了匹配體素和對象輪廓,應(yīng)該知道投影參數(shù)。它們由GL_PROJECTIONGL_MODELVIEW矩陣定義(參見setGL函數(shù))。

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矩陣由相機(jī)參數(shù)定義,特別是焦距和圖像大小(
HFrame::loadIntrisicParameters函數(shù))。

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();
}

可以使用增強(qiáng)現(xiàn)實(shí)標(biāo)記來確定相機(jī)的 3D 位置,我們從 aruco 庫中獲取它。標(biāo)記是要打印在一張紙上的特殊圖像(見下圖)。

一種簡單的三維重現(xiàn)算法實(shí)現(xiàn)

 

拍攝物體時,標(biāo)記必須保持不動,并在每張物體照片中進(jìn)入相機(jī)視野。

一種簡單的三維重現(xiàn)算法實(shí)現(xiàn)

 

該庫檢測標(biāo)記控制點(diǎn),然后使用相機(jī)焦距計(jì)算標(biāo)記 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參數(shù)確定GL_MODELVIEW矩陣(參見HFrame ::loadExtrisicParameters函數(shù))。

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
}

至此,我們學(xué)會了如何在圖像平面上投影體素,確定體素相對于物體圖像的位置,計(jì)算投影參數(shù),并通過處理來自多個攝像機(jī)的數(shù)據(jù)來確定體素是否屬于物體體;這是一種用于重建 3D 對象的簡化但完整的技術(shù),源代碼可以在這里下載。

一種簡單的三維重現(xiàn)算法實(shí)現(xiàn)

 


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

分享到:
標(biāo)簽:算法
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定