Visual Hull是基于轮廓信息的三维重建,输入是序列图像以及对应序列图像的相机投影矩阵P。如果换成自己想要的序列图像,

相应的P矩阵也需要更换,因为P矩阵是相机标定后得到的。现在感觉自己作标定遇到了些许困难,不知是只作一次标定,还是

需要标定板也旋转一周,根据图像数量的多少旋转相应的角度,标定一周?我看过github上码主的视频,用的是激光标定板旋转一周作的标定,但是针对小物体,标定板也相对更小,镜头的焦距也相应变小,此时感觉这个办法就不是很通用了。不过可以放心的是,不论用什么办法标定,只要拿到每张图像对应的P矩阵,就能完成物体的三维重建。

开发环境:windows8.1,vs2010,opencv2.4.9,vtk;

完整代码我是在github上找到的,以松鼠模型为例子,代码原本有些错误,改了改之后,可以成功运行。

啥也不多说,直接贴代码吧。

// trySquirral.cpp : 定义控制台应用程序的入口点。
//
// Squirral.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/imgproc/imgproc.hpp>#include <vtkSmartPointer.h>
#include <vtkStructuredPoints.h>
#include <vtkPointData.h>
#include <vtkPLYWriter.h>
#include <vtkFloatArray.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkImageCast.h>
#include <vtkImageShiftScale.h>
#include <vtkMetaImageReader.h>
#include <vtkImageViewer2.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkMarchingCubes.h>
#include <vtkCleanPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <vtkAutoInit.h>
#include <vtkImageCanvasSource2D.h>VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle)
VTK_MODULE_INIT(vtkRenderingFreeType)using namespace cv;const int IMG_WIDTH = 1280;
const int IMG_HEIGHT = 960;
const int VOXEL_DIM = 128;
const int VOXEL_SIZE = VOXEL_DIM*VOXEL_DIM*VOXEL_DIM;
const int VOXEL_SLICE = VOXEL_DIM*VOXEL_DIM;
const int OUTSIDE = 0;struct voxel {float xpos;float ypos;float zpos;float res;float value;
};struct coord {int x;int y;
};struct startParams {float startX;float startY;float startZ;float voxelWidth;float voxelHeight;float voxelDepth;
};struct camera {cv::Mat Image;cv::Mat P;cv::Mat K;cv::Mat R;cv::Mat t;cv::Mat Silhouette;
};void exportModel(char *filename, vtkPolyData *polyData) {/* exports 3d model in ply format */vtkSmartPointer<vtkPLYWriter> plyExporter = vtkSmartPointer<vtkPLYWriter>::New();plyExporter->SetFileName(filename);plyExporter->SetInputData(polyData);plyExporter->Update();plyExporter->Write();
}coord project(camera cam, voxel v) {coord im;/* project voxel into camera image coords */float z =   cam.P.at<float>(2, 0) * v.xpos +cam.P.at<float>(2, 1) * v.ypos +cam.P.at<float>(2, 2) * v.zpos +cam.P.at<float>(2, 3);im.y =    (cam.P.at<float>(1, 0) * v.xpos +cam.P.at<float>(1, 1) * v.ypos +cam.P.at<float>(1, 2) * v.zpos +cam.P.at<float>(1, 3)) / z;im.x =    (cam.P.at<float>(0, 0) * v.xpos +cam.P.at<float>(0, 1) * v.ypos +cam.P.at<float>(0, 2) * v.zpos +cam.P.at<float>(0, 3)) / z;return im;
}void renderModel(float fArray[], startParams params) {/* create vtk visualization pipeline from voxel grid (float array) */vtkSmartPointer<vtkStructuredPoints> sPoints = vtkSmartPointer<vtkStructuredPoints>::New();sPoints->SetDimensions(VOXEL_DIM, VOXEL_DIM, VOXEL_DIM);sPoints->SetSpacing(params.voxelDepth, params.voxelHeight, params.voxelWidth);sPoints->SetOrigin(params.startZ, params.startY, params.startX);// sPoints->SetScalarTypeToFloat();vtkSmartPointer<vtkFloatArray> vtkFArray = vtkSmartPointer<vtkFloatArray>::New();vtkFArray->SetNumberOfValues(VOXEL_SIZE);vtkFArray->SetArray(fArray, VOXEL_SIZE, 1);sPoints->GetPointData()->SetScalars(vtkFArray);// sPoints->Update();/* create iso surface with marching cubes algorithm */vtkSmartPointer<vtkMarchingCubes> mcSource = vtkSmartPointer<vtkMarchingCubes>::New();mcSource->SetInputData(sPoints);mcSource->SetNumberOfContours(1);mcSource->SetValue(0,0.5);mcSource->Update();/* recreate mesh topology and merge vertices */vtkSmartPointer<vtkCleanPolyData> cleanPolyData = vtkSmartPointer<vtkCleanPolyData>::New();cleanPolyData->SetInputConnection(mcSource->GetOutputPort());cleanPolyData->Update();/* usual render stuff */vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();renderer->SetBackground(.45, .45, .9);renderer->SetBackground2(.0, .0, .0);renderer->GradientBackgroundOn();vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();renderWindow->AddRenderer(renderer);vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();interactor->SetRenderWindow(renderWindow);vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();mapper->SetInputConnection(cleanPolyData->GetOutputPort());vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();actor->SetMapper(mapper);/* visible light properties */actor->GetProperty()->SetSpecular(0.15);actor->GetProperty()->SetInterpolationToPhong();renderer->AddActor(actor);renderWindow->Render();interactor->Start();
}void carve(float fArray[], startParams params, camera cam) {cv::Mat silhouette, distImage;cv::Canny(cam.Silhouette, silhouette, 0, 255);cv::bitwise_not(silhouette, silhouette);//dst = ~srccv::distanceTransform(silhouette, distImage, CV_DIST_L2, 3);//Opencv中distanceTransform方法用于计算图像中每一个非零点距离//离自己最近的零点的距离,distanceTransform的第二个Mat矩阵参数dst保存了每一个点与最近的零点的距离信息,//图像上越亮的点,代表了离零点的距离越远。for (int i=0; i<VOXEL_DIM; i++) {for (int j=0; j<VOXEL_DIM; j++) {for (int k=0; k<VOXEL_DIM; k++) {/* calc voxel position inside camera view frustum */voxel v;v.xpos = params.startX + i * params.voxelWidth;v.ypos = params.startY + j * params.voxelHeight;v.zpos = params.startZ + k * params.voxelDepth;v.value = 1.0f;coord im = project(cam, v);float dist = -1.0f;/* test if projected voxel is within image coords */if (im.x > 0 && im.y > 0 && im.x < IMG_WIDTH && im.y < IMG_HEIGHT) {dist = distImage.at<float>(im.y, im.x);if (cam.Silhouette.at<uchar>(im.y, im.x) == OUTSIDE) {dist *= -1.0f;}}if (dist < fArray[i*VOXEL_SLICE+j*VOXEL_DIM+k]) {fArray[i*VOXEL_SLICE+j*VOXEL_DIM+k] = dist;}}}}}int main(int argc, char* argv[]) {/* acquire camera images, silhouettes and camera matrix */std::vector<camera> cameras;cv::FileStorage fs("C:/Users/cristina001/Desktop/有用代码/Voxel-Carving-squirral/Voxel-Carving-master/assets/viff.xml", cv::FileStorage::READ);for (int i=0; i<36; i++) {/* camera image */std::stringstream simg;simg << "C:/Users/cristina001/Desktop/有用代码/Voxel-Carving-squirral/Voxel-Carving-master/assets/image_" << i << ".jpg";cv::Mat img = cv::imread(simg.str());/* silhouette */cv::Mat silhouette;cv::cvtColor(img, silhouette, CV_BGR2HSV);cv::inRange(silhouette, cv::Scalar(0, 0, 30), cv::Scalar(255,255,255), silhouette);/* camera matrix */std::stringstream smat;smat << "viff" << std::setfill('0') << std::setw(3) << i << "_matrix";cv::Mat P;fs[smat.str()] >> P;/* decompose proj matrix to cam- and rot matrix and trans vect */cv::Mat K, R, t;cv::decomposeProjectionMatrix(P, K, R, t);//K = cv::Mat::eye(3, 3, CV_32FC1);//K.at<float>(0,0) = 1680.2631413061415; /* fx *///K.at<float>(1,1) = 1676.1202869984309; /* fy *///K.at<float>(0,2) = 621.59194200994375; /* cx *///K.at<float>(1,2) = 467.7223229477861; /* cy */camera c;c.Image = img;c.P = P;c.K = K;c.R = R;c.t = t;c.Silhouette = silhouette;cameras.push_back(c);}/* bounding box dimensions of squirrel */float xmin = -6.21639, ymin = -10.2796, zmin = -14.0349;float xmax = 7.62138, ymax = 12.1731, zmax = 12.5358;float bbwidth = std::abs(xmax-xmin)*1.15;float bbheight = std::abs(ymax-ymin)*1.15;float bbdepth = std::abs(zmax-zmin)*1.05;startParams params;params.startX = xmin-std::abs(xmax-xmin)*0.15;params.startY = ymin-std::abs(ymax-ymin)*0.15;params.startZ = 0.0f;params.voxelWidth = bbwidth/VOXEL_DIM;params.voxelHeight = bbheight/VOXEL_DIM;params.voxelDepth = bbdepth/VOXEL_DIM;/* 3 dimensional voxel grid */float *fArray = new float[VOXEL_SIZE];std::fill_n(fArray, VOXEL_SIZE, 1000.0f);/* carving model for every given camera image */for (int i=0; i<36; i++) {carve(fArray, params, cameras.at(i));// Mat segmented;//resize(cameras.at(i).Silhouette, segmented, cv::Size(640, 480));char save_file[200]; sprintf(save_file, "C:/Users/cristina001/Desktop/有用代码/Voxel-Carving-squirral/Voxel-Carving-master/assets/%d.jpg", i); imwrite(save_file,cameras.at(i).Silhouette);  }renderModel(fArray, params);///* show example of segmented image *///cv::Mat original, segmented;//cv::resize(cameras.at(1).Image, original, cv::Size(640, 480));//cv::resize(cameras.at(1).Silhouette, segmented, cv::Size(640, 480));//cv::imshow("Squirrel" , original);//cv::imshow("Squirrel Silhouette", segmented);//cvWaitKey();return 0;
}

把图片路径换成自己的就好~还有需要P矩阵文件viff.xml.

输入的36张松鼠序列图像

可以获取到获取松鼠的轮廓图像

最后是重建出的结果

Visual Hull基于序列图像的三维重建相关推荐

  1. 基于序列图像的三维体绘的视线投射算法

    基于序列图像的三维体绘的视线投射算法(Ray Casting) 一.体绘算法步骤   1.体数据的生成: 将序列图像的象素数据部分剥离出来(如果是JPG等压缩类型的数据,还需要先解压缩),按照相对的上 ...

  2. 基于点云的三维重建_香港科技大学王煜教授:深度学习在物体三维重建中的应用...

    基于单幅图像的物体三维重建是计算机视觉领域的一个重要问题, 近十年来得到了广泛地关注. 随着深度学习的不断发展, 近年来逐渐成为一个新的学术研究热点问题. 计算机视觉研究的主要目标之一是从二维图像复原 ...

  3. 谈谈基于深度相机的三维重建

    三维重建(3D Reconstruction)技术一直是计算机图形学和计算机视觉领域的一个热点课题.早期的三维重建技术通常以二维图像作为输入,重建出场景中的三维模型.但是,受限于输入的数据,重建出的三 ...

  4. 基于深度相机的三维重建技术

    /*************************************************************************************************** ...

  5. 基于图像的三维重建研究

    前言 三维重建,顾名思义就是对现实世界中的三维物体用计算机来进行模拟.目前主流的有两种手段:采用红外设备对物体进行测距.基于多张有关待测物体的二维图像进行三维重建.由于前者需要红外设备,成本比较昂贵且 ...

  6. (亲测可行)基于面绘制的MC算法以及基于体绘制的 Ray-casting 实现Dicom图像的三维重建(python实现)

    写在这里的初衷,一是备忘,二是希望得到高人指点,三是希望能遇到志同道合的朋友. 转载自 基于面绘制的MC算法以及基于体绘制的 Ray-casting 实现Dicom图像的三维重建(python实现) ...

  7. 研究生科研必备!!!2015-2020年各类国际会议基于图像的三维重建论文综述(1)——总览

    此文为2015-2020年各类国际会议与期刊基于图像的三维对象重建论文综述的第一部分,总览部分 本文涵盖总结了2015到2020年几百篇国际会议与期刊上的3d-reconstruction文章. 本系 ...

  8. 【MATLAB教程案例47】基于双目相机拍摄图像的三维重建matlab仿真

    欢迎订阅<FPGA学习入门100例教程>.<MATLAB学习入门100例教程> 本课程学习成果预览: 目录 1.软件版本 2.基于双目相机拍摄图像的三维重建原理概述

  9. 基于图像的三维重建——基于空间patch扩散的方法(PMVS)

    1.PMVS:多视图匹配经典算法简介 导语:常见的稠密重建方法主要有三种:基于体素的方法.基于深度图融合的方法以及基于3D patch扩张的方法.第一种基于体素的方法仅适用于小场景,单个物体,遮挡较少 ...

最新文章

  1. SpringMVC的form:form表单的使用
  2. 《Linux内核设计与实现》读书笔记(七)- 中断处理【转】
  3. 线程池框架_Java并发——Executor框架详解(Executor框架结构与框架成员)
  4. tomcat启动时,报java.io.EOFException
  5. 作为评审人完成了对其他小组第一阶段成果的评价
  6. Spring源码 (事务篇) - 整体流程
  7. java匹配字符串所在位置_Java:获取字符串中匹配项位置的方法?
  8. ORACLE常用数值函数、转换函数、字符串函数【转】
  9. 一个小型的中文文本分类系统(项目链接文末)——《ML算法原理和实践》学习笔记
  10. python文本文件对比工具_python实现比较文件内容异同
  11. Python:输入概率,计算信源熵
  12. 操作无法完成 因为文件已在system中打开
  13. 网易互娱的一道笔试题
  14. xpath获取不包含某一子标签的a标签
  15. 基于K-Means的文本聚类
  16. xp计算机无法正常启动,xp系统启动修复_两种方法修复XP系统无法正常启动进入不了计算机_xp系统启动修复工具...
  17. linux下tc、htb、iptables基础知识及openwrt 下qos使用介绍
  18. www.wolframalpha.com
  19. 修改macOS中程序坞的位置和图标大小
  20. C3P0数据库连接池的配置

热门文章

  1. 鸿蒙二部曲之一,网文封神之作,“鸿蒙二部曲”和“斗罗四部曲”你选择站哪边?...
  2. 51单片机矩阵键盘的控制原理-扫描及使用方式
  3. geotif 添加坐标_tiff和geotiff经度纬度高度值读取
  4. bigemap卫星地图下载器的优势
  5. 智能交通系统计算机技术应用,计算机技术在智能交通系统中的应用.docx
  6. AI(人工智能:一种现代的方法)学习之:无信息搜索(uninformed search)算法——广度优先搜索、深度优先搜索、Uniform-cost search
  7. 初入职场“荒野求生”,五条靠谱的生存指南
  8. 纯css动画-div从左到右出现
  9. 基于Python的新闻聚合网站设计与实现
  10. 卡尔卡西25首练习曲简析-音阶与音程训练