{"id":210,"date":"2009-12-16T16:09:26","date_gmt":"2009-12-16T16:09:26","guid":{"rendered":"https:\/\/blogs.mathworks.com\/loren\/2009\/12\/16\/carving-a-dinosaur\/"},"modified":"2019-10-23T10:53:26","modified_gmt":"2019-10-23T15:53:26","slug":"carving-a-dinosaur","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/loren\/2009\/12\/16\/carving-a-dinosaur\/","title":{"rendered":"Carving a Dinosaur"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <introduction>\r\n      <p>Today I&#8217;d like to introduce a guest blogger, Ben, who is consultant over in The MathWorks UK. Some of you may have come across\r\n         his customer projects and demos on image processing. He&#8217;s going to talk about one of those demos here.\r\n      <\/p>\r\n   <\/introduction>\r\n   <h3>Contents<\/h3>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"#1\">Demo Description<\/a><\/li>\r\n         <li><a href=\"#2\">Introduction<\/a><\/li>\r\n         <li><a href=\"#3\">Setup<\/a><\/li>\r\n         <li><a href=\"#4\">Load the Camera and Image Data<\/a><\/li>\r\n         <li><a href=\"#5\">Convert the Images into Silhouettes<\/a><\/li>\r\n         <li><a href=\"#6\">Create a Voxel Array<\/a><\/li>\r\n         <li><a href=\"#7\">Carve the Voxels Using the First Camera Image<\/a><\/li>\r\n         <li><a href=\"#8\">Add More Views<\/a><\/li>\r\n         <li><a href=\"#9\">Now Include All the Views<\/a><\/li>\r\n         <li><a href=\"#10\">Final Result<\/a><\/li>\r\n         <li><a href=\"#11\">Conclusion<\/a><\/li>\r\n         <li><a href=\"#12\">File Availability<\/a><\/li>\r\n         <li><a href=\"#13\">References<\/a><\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <h3>Demo Description<a name=\"1\"><\/a><\/h3>\r\n   <p>This is a demo of reconstructing a 3D shape from multiple images using a simple space-carving approach. This technique is\r\n      usually used when you need a 3D model of a small artefact which can be placed on a turntable, allowing dozens, even hundreds\r\n      of images to be captured from around the object. It has been used pretty successfully by museums and the like to create online\r\n      virtual galleries.\r\n   <\/p>\r\n   <p><i>Note: This demo requires the <a href=\"https:\/\/www.mathworks.com\/access\/helpdesk\/help\/releases\/R2009b\/toolbox\/images\"><tt>Image Processing Toolbox<\/tt><\/a>.<\/i><\/p>\r\n   <h3>Introduction<a name=\"2\"><\/a><\/h3>\r\n   <p>A little while ago (is it really four years?!) I was asked to prepare a demonstration for a customer visit. The customer had\r\n      some samples that they wanted to photograph in order to estimate the volume occupied before and after a chemical process.\r\n      These samples were smooth but irregularly shaped such that a simple \"volume of revolution\" calculation was inaccurate. They\r\n      wanted to know if accurate volume estimation from images was possible, and if so how you might do it.\r\n   <\/p>\r\n   <p>The demo I produced is enumerated below and is the most basic form of a technique called \"space carving\" or \"shape from silhouettes\",\r\n      where each image is just used as a mask. A lump of voxel \"clay\" is placed in the middle of the scene and from each image we\r\n      simply look and see what is outside the object silhouette. Anything outside is carved away. Obviously, this requires us to\r\n      know where the camera was relative to the object when the picture was taken, which is a whole separate problem.\r\n   <\/p>\r\n   <p>This technique has been refined over the last decade and can be done in some computationally and memory efficient ways. My\r\n      approach is neither of these - I went for simplicity over efficiency since my only aim was to explain the technique and show\r\n      it in MATLAB.\r\n   <\/p>\r\n   <p><b>Acknowledgements<\/b><\/p>\r\n   <p>The dinosaur images used here were provided by Wolfgang Niem at the University of Hannover.<\/p>\r\n   <p>The camera data used in this example was provided by <a href=\"http:\/\/research.microsoft.com\/en-us\/um\/people\/awf\"><tt>Dr A. W. Fitzgibbon<\/tt><\/a> and <a href=\"http:\/\/www.robots.ox.ac.uk\/~az\"><tt>Prof A. Zisserman<\/tt><\/a> from the <a href=\"http:\/\/www.robots.ox.ac.uk\"><tt>University of Oxford Robotics Research Group<\/tt><\/a>.\r\n   <\/p>\r\n   <p>The images and camera data can both be downloaded from the <tt>Visual Geometry Group web-pages<\/tt> at the <a href=\"http:\/\/www.robots.ox.ac.uk\"><tt>University of Oxford Robotics Research Group<\/tt><\/a>.\r\n   <\/p>\r\n   <h3>Setup<a name=\"3\"><\/a><\/h3>\r\n   <p>All functions for this demo are in the \"spacecarving\" package and the data in the \"DinosaurData\" folder.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">import <span style=\"color: #A020F0\">spacecarving.*<\/span>;\r\ndatadir = fullfile( fileparts( mfilename( <span style=\"color: #A020F0\">'fullpath'<\/span> ) ), <span style=\"color: #A020F0\">'DinosaurData'<\/span> );\r\nclose <span style=\"color: #A020F0\">all<\/span>;<\/pre><h3>Load the Camera and Image Data<a name=\"4\"><\/a><\/h3>\r\n   <p>This reads the \"Dinosaur\" directory, loading the camera definitions (internal and external calibration) and image file for\r\n      each camera. These calibrations have previously been determined from the images using an automatic process that we won't worry\r\n      about here.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">cameras = loadcameradata( datadir )\r\n\r\nmontage( cat( 4, cameras.Image ) );\r\nset( gcf(), <span style=\"color: #A020F0\">'Position'<\/span>, [100 100 600 600] )\r\naxis <span style=\"color: #A020F0\">off<\/span>;<\/pre><pre style=\"font-style:oblique\">cameras = \r\n1x36 struct array with fields:\r\n    Image\r\n    P\r\n    K\r\n    R\r\n    T\r\n    Silhouette\r\n    rawP\r\nWarning: Image is too big to fit on screen; displaying at 25% \r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/210\/space_carving_demo_01.png\"> <h3>Convert the Images into Silhouettes<a name=\"5\"><\/a><\/h3>\r\n   <p>The image in each camera is converted to a binary image using the blue-screen background and some morphological operators\r\n      to clean up the edges. This becomes the \"mask\" referred to above. Holes in this mask are particularly dangerous as they will\r\n      cause voxels to be carved away that shouldn't be - we can end up drilling a hole through the object! The Image Processing\r\n      Toolbox functions <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2009b\/toolbox\/images\/bwareaopen.html\"><tt>bwareaopen<\/tt><\/a> and <a href=\"https:\/\/www.mathworks.com\/help\/releases\/R2009b\/toolbox\/images\/imclose.html\"><tt>imclose<\/tt><\/a> are your friends for this job!\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">for<\/span> c=1:numel(cameras)\r\n    cameras(c).Silhouette = getsilhouette( cameras(c).Image );\r\n<span style=\"color: #0000FF\">end<\/span>\r\n\r\nfigure(<span style=\"color: #A020F0\">'Position'<\/span>,[100 100 600 300]);\r\n\r\nsubplot(1,2,1)\r\nimshow( cameras(c).Image );\r\ntitle( <span style=\"color: #A020F0\">'Original Image'<\/span> )\r\naxis <span style=\"color: #A020F0\">off<\/span>\r\n\r\nsubplot(1,2,2)\r\nimshow( cameras(c).Silhouette );\r\ntitle( <span style=\"color: #A020F0\">'Silhouette'<\/span> )\r\naxis <span style=\"color: #A020F0\">off<\/span>\r\n\r\nmakeFullAxes( gcf );<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/210\/space_carving_demo_02.png\"> <h3>Create a Voxel Array<a name=\"6\"><\/a><\/h3>\r\n   <p>This creates a regular 3D grid of elements ready for carving away. The input argument sets the half size (i.e., 50 means 101x101x101\r\n      voxels). Use 20 for a quick and dirty model, 50 for reasonable and 100+ if you want a detailed model (and have enough memory!).\r\n   <\/p>\r\n   <p>For \"real world\" implementations of space carving you certainly wouldn't create a uniform 3D matrix like this. OctTrees and\r\n      other refinement representations give much better efficiency, both in memory and computational time.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">voxels = makevoxels( 85 ); <span style=\"color: #228B22\">% 60 for faster evaluation, 80 for detailed<\/span>\r\nstarting_volume = numel( voxels.values );\r\n\r\n<span style=\"color: #228B22\">% Show the whole scene<\/span>\r\nfigure(<span style=\"color: #A020F0\">'Position'<\/span>,[100 100 600 400]);\r\nshowscene( cameras, voxels );<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/210\/space_carving_demo_03.png\"> <h3>Carve the Voxels Using the First Camera Image<a name=\"7\"><\/a><\/h3>\r\n   <p>The silhouette is projected onto the voxel array. Any voxels that lie outside the silhouette are carved away, leaving only\r\n      points inside the model. Using just one camera, we end up with a dinosaur-prism - a single camera provides no information\r\n      on depth.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">voxels = spacecarving.carve( voxels, cameras(1) );\r\n\r\n<span style=\"color: #228B22\">% Show Result<\/span>\r\nfigure(<span style=\"color: #A020F0\">'Position'<\/span>,[100 100 600 300]);\r\nsubplot(1,2,1)\r\nshowscene( cameras(1), voxels );\r\ntitle( <span style=\"color: #A020F0\">'1 camera'<\/span> )\r\nsubplot(1,2,2)\r\nshowsurface( voxels )\r\ntitle( <span style=\"color: #A020F0\">'Result after 1 carving'<\/span> )<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/210\/space_carving_demo_04.png\"> <h3>Add More Views<a name=\"8\"><\/a><\/h3>\r\n   <p>Adding more views refines the shape. If we include two more, we already have something recognisable, albeit a bit \"boxy\".<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">voxels = spacecarving.carve( voxels, cameras(4) );\r\nvoxels = spacecarving.carve( voxels, cameras(7) );\r\n\r\n<span style=\"color: #228B22\">% Show Result<\/span>\r\nfigure(<span style=\"color: #A020F0\">'Position'<\/span>,[100 100 600 300]);\r\nsubplot(1,2,1)\r\ntitle( <span style=\"color: #A020F0\">'3 cameras'<\/span> )\r\nshowscene( cameras([1 4 7]), voxels );\r\nsubplot(1,2,2)\r\nshowsurface(voxels)\r\ntitle( <span style=\"color: #A020F0\">'Result after 3 carvings'<\/span> )<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/210\/space_carving_demo_05.png\"> <h3>Now Include All the Views<a name=\"9\"><\/a><\/h3>\r\n   <p>In this case we have 36 views (roughly every 10 degrees). For a very detailed model and if you have an automatic capture rig\r\n      you would use far more - the only limit being time and disk-space. When using a computer controlled turn-table (as is done\r\n      in museums) storage is the only real limitation.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">for<\/span> ii=1:numel(cameras)\r\n    voxels = carve( voxels, cameras(ii) );\r\n<span style=\"color: #0000FF\">end<\/span>\r\nfinal_volume = numel( voxels.values );\r\nfprintf( <span style=\"color: #A020F0\">'Final volume is %d (%d%%)\\n'<\/span>, <span style=\"color: #0000FF\">...<\/span>\r\n    final_volume, round( 100 * final_volume \/ starting_volume ) )<\/pre><pre style=\"font-style:oblique\">Final volume is 168688 (3%)\r\n<\/pre><h3>Final Result<a name=\"10\"><\/a><\/h3>\r\n   <p>For online galleries and the like we would colour each voxel from the image with the best view, leading to a colour 3D model.\r\n      Maybe one day I'll have time to do that too, but for now here's the uniformly coloured surface.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">figure(<span style=\"color: #A020F0\">'Position'<\/span>,[100 100 600 700]);\r\nshowsurface(voxels)\r\naxis <span style=\"color: #A020F0\">off<\/span>\r\ntitle( <span style=\"color: #A020F0\">'Result after 36 carvings'<\/span> )<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/210\/space_carving_demo_06.png\"> <h3>Conclusion<a name=\"11\"><\/a><\/h3>\r\n   <p>Hopefully this demo has given you a taste for what is possible by simple image masking and space-carving. If this has whetted\r\n      your appetite, have a look at the references below. Converting each image to a binary mask throws away a lot of information.\r\n      Instead of using these silhouettes, we could use the image values (either greyscale or colour) and a photo-consistency constraint.\r\n      This is <b>much<\/b> harder to get right, but copes much better with concavities and holes in the model.\r\n   <\/p>\r\n   <p>Have you ever been asked about volume estimation from images? Do you fancy trying this at home? Perhaps you've implemented\r\n      a better way to do this? I'd love to hear from you <a href=\"https:\/\/blogs.mathworks.com\/loren\/?p=210#respond\">here<\/a>.\r\n   <\/p>\r\n   <h3>File Availability<a name=\"12\"><\/a><\/h3>\r\n   <p><b>UPDATE!<\/b>  The functions created for this demo are on the File Exchange. They are available <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/26160-carving-a-dinosaur\">here<\/a>.\r\nAs a reminder, there's a link above for getting the data.\r\n   <\/p>\r\n   <h3>References<a name=\"13\"><\/a><\/h3>\r\n   <p>Some good references for this (including the original paper that used these images) are:<\/p>\r\n   <div>\r\n      <ul>\r\n         <li><b>Automatic 3D model construction for turn-table sequences<\/b>, <i>A. W. Fitzgibbon, G. Cross, and A. Zisserman, In 3D Structure from Multiple Images of Large-Scale Environments, Springer LNCS\r\n               1506, pages 155--170, 1998<\/i><\/li>\r\n         <li><b>A Theory of Shape by Space Carving<\/b>, <i>K. N. Kutulakos &amp; S. M. Seitz, International Journal of Computer Vision 38(3), 199&#8211;218, 2000<\/i><\/li>\r\n         <li><b>Foundations of Image Understanding<\/b>, Chapter 16, <i>edited by L. S. Davis, Kluwer, 2001<\/i><\/li>\r\n      <\/ul>\r\n   <\/div><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_34b1fb98ea0845a9a11def85642817c0() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='34b1fb98ea0845a9a11def85642817c0 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 34b1fb98ea0845a9a11def85642817c0';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        author = 'Loren Shure';\r\n        copyright = 'Copyright 2009 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n      \r\n      d.title = title + ' (MATLAB code)';\r\n      d.close();\r\n      }   \r\n      \r\n-->\r\n<\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_34b1fb98ea0845a9a11def85642817c0()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n            the MATLAB code \r\n            <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; 7.9<br><\/p>\r\n<\/div>\r\n<!--\r\n34b1fb98ea0845a9a11def85642817c0 ##### SOURCE BEGIN #####\r\n%% Carving a Dinosaur\r\n% Today I\u00e2\u20ac&#x2122;d like to introduce a guest blogger, Ben, who is consultant over\r\n% in The MathWorks UK. Some of you may have come across his customer\r\n% projects and demos on image processing. He\u00e2\u20ac&#x2122;s going to talk about one of\r\n% those demos here.\r\n%% Demo Description\r\n% This is a demo of reconstructing a 3D shape from multiple images using a\r\n% simple space-carving approach. This technique is usually used when you\r\n% need a 3D model of a small artefact which can be placed on a turntable,\r\n% allowing dozens, even hundreds of images to be captured from around the\r\n% object. It has been used pretty successfully by museums and the like to\r\n% create online virtual galleries.\r\n%\r\n% _Note: This demo requires the\r\n% <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/releases\/R2009b\/toolbox\/images |Image Processing Toolbox|>._\r\n%\r\n%% Introduction\r\n% A little while ago (is it really four years?!) I was asked to prepare a\r\n% demonstration for a customer visit. The customer had some samples that\r\n% they wanted to photograph in order to estimate the volume occupied before\r\n% and after a chemical process. These samples were smooth but irregularly\r\n% shaped such that a simple \"volume of revolution\" calculation was\r\n% inaccurate. They wanted to know if accurate volume estimation from images\r\n% was possible, and if so how you might do it.\r\n%\r\n% The demo I produced is enumerated below and is the most basic form of a\r\n% technique called \"space carving\" or \"shape from silhouettes\", where each\r\n% image is just used as a mask. A lump of voxel \"clay\" is placed in the\r\n% middle of the scene and from each image we simply look and see what is\r\n% outside the object silhouette. Anything outside is carved away.\r\n% Obviously, this requires us to know where the camera was relative to the\r\n% object when the picture was taken, which is a whole separate problem.\r\n%\r\n% This technique has been refined over the last decade and can be\r\n% done in some computationally and memory efficient ways. My approach is\r\n% neither of these - I went for simplicity over efficiency since my only\r\n% aim was to explain the technique and show it in MATLAB.\r\n% \r\n% *Acknowledgements*\r\n%\r\n% The dinosaur images used here were provided by Wolfgang Niem at\r\n% the University of Hannover.\r\n%\r\n% The camera data used in this example was provided by\r\n% <http:\/\/research.microsoft.com\/en-us\/um\/people\/awf |Dr A. W. Fitzgibbon|>\r\n% and <http:\/\/www.robots.ox.ac.uk\/~az |Prof A. Zisserman|>\r\n% from the <http:\/\/www.robots.ox.ac.uk |University of Oxford Robotics Research Group|>. \r\n%\r\n% The images and camera data can both be downloaded from the <http:\/\/www.robots.ox.ac.uk\/~vgg\/data\/data-mview.html \r\n% |Visual Geometry Group web-pages|> at the <http:\/\/www.robots.ox.ac.uk\r\n% |University of Oxford Robotics Research Group|>.\r\n\r\n%% Setup\r\n% All functions for this demo are in the \"spacecarving\" package and the\r\n% data in the \"DinosaurData\" folder.\r\nimport spacecarving.*;\r\ndatadir = fullfile( fileparts( mfilename( 'fullpath' ) ), 'DinosaurData' );\r\nclose all;\r\n\r\n\r\n%% Load the Camera and Image Data\r\n% This reads the \"Dinosaur\" directory, loading the camera definitions\r\n% (internal and external calibration) and image file for each camera. These\r\n% calibrations have previously been determined from the\r\n% images using an automatic process that we won't worry about here.\r\ncameras = loadcameradata( datadir ) \r\n\r\nmontage( cat( 4, cameras.Image ) );\r\nset( gcf(), 'Position', [100 100 600 600] )\r\naxis off;\r\n\r\n%% Convert the Images into Silhouettes\r\n% The image in each camera is converted to a binary image using the\r\n% blue-screen background and some morphological operators to clean up the\r\n% edges. This becomes the \"mask\" referred to above. Holes in this mask are\r\n% particularly dangerous as they will cause voxels to be carved away that\r\n% shouldn't be - we can end up drilling a hole through the object! The\r\n% Image Processing Toolbox functions\r\n% <https:\/\/www.mathworks.com\/help\/releases\/R2009b\/toolbox\/images\/bwareaopen.html |bwareaopen|> \r\n% and <https:\/\/www.mathworks.com\/help\/releases\/R2009b\/toolbox\/images\/imclose.html |imclose|>\r\n% are your friends for this job!\r\nfor c=1:numel(cameras)\r\n    cameras(c).Silhouette = getsilhouette( cameras(c).Image );\r\nend\r\n\r\nfigure('Position',[100 100 600 300]);\r\n\r\nsubplot(1,2,1)\r\nimshow( cameras(c).Image );\r\ntitle( 'Original Image' )\r\naxis off\r\n\r\nsubplot(1,2,2)\r\nimshow( cameras(c).Silhouette );\r\ntitle( 'Silhouette' )\r\naxis off\r\n\r\nmakeFullAxes( gcf );\r\n\r\n\r\n%% Create a Voxel Array\r\n% This creates a regular 3D grid of elements ready for carving away. The\r\n% input argument sets the half size (i.e., 50 means 101x101x101 voxels).\r\n% Use 20 for a quick and dirty model, 50 for reasonable and 100+ if you\r\n% want a detailed model (and have enough memory!).\r\n%\r\n% For \"real world\" implementations of space carving you certainly wouldn't\r\n% create a uniform 3D matrix like this. OctTrees and other refinement\r\n% representations give much better efficiency, both in memory and\r\n% computational time.\r\nvoxels = makevoxels( 85 ); % 60 for faster evaluation, 80 for detailed\r\nstarting_volume = numel( voxels.values );\r\n\r\n% Show the whole scene\r\nfigure('Position',[100 100 600 400]);\r\nshowscene( cameras, voxels );\r\n\r\n%% Carve the Voxels Using the First Camera Image\r\n% The silhouette is projected onto the voxel array.\r\n% Any voxels that lie outside the silhouette are carved away, leaving only\r\n% points inside the model. Using just one camera, we end up with a\r\n% dinosaur-prism - a single camera provides no information on depth.\r\nvoxels = spacecarving.carve( voxels, cameras(1) );\r\n\r\n% Show Result\r\nfigure('Position',[100 100 600 300]);\r\nsubplot(1,2,1)\r\nshowscene( cameras(1), voxels );\r\ntitle( '1 camera' )\r\nsubplot(1,2,2)\r\nshowsurface( voxels )\r\ntitle( 'Result after 1 carving' )\r\n\r\n%% Add More Views\r\n% Adding more views refines the shape. If we include two more, we already\r\n% have something recognisable, albeit a bit \"boxy\".\r\nvoxels = spacecarving.carve( voxels, cameras(4) );\r\nvoxels = spacecarving.carve( voxels, cameras(7) );\r\n\r\n% Show Result\r\nfigure('Position',[100 100 600 300]);\r\nsubplot(1,2,1)\r\ntitle( '3 cameras' )\r\nshowscene( cameras([1 4 7]), voxels );\r\nsubplot(1,2,2)\r\nshowsurface(voxels)\r\ntitle( 'Result after 3 carvings' )\r\n\r\n\r\n%% Now Include All the Views\r\n% In this case we have 36 views (roughly every 10 degrees). For a very\r\n% detailed model and if you have an automatic capture rig you would use far\r\n% more - the only limit being time and disk-space. When using a computer\r\n% controlled turn-table (as is done in museums) storage is the only real\r\n% limitation.\r\nfor ii=1:numel(cameras)\r\n    voxels = carve( voxels, cameras(ii) );\r\nend\r\nfinal_volume = numel( voxels.values );\r\nfprintf( 'Final volume is %d (%d%%)\\n', ...\r\n    final_volume, round( 100 * final_volume \/ starting_volume ) )\r\n\r\n%% Final Result\r\n% For online galleries and the like we would colour each voxel from the\r\n% image with the best view, leading to a colour 3D model. Maybe one day\r\n% I'll have time to do that too, but for now here's the uniformly coloured\r\n% surface.\r\nfigure('Position',[100 100 600 700]);\r\nshowsurface(voxels)\r\naxis off\r\ntitle( 'Result after 36 carvings' )\r\n\r\n%% Conclusion\r\n% Hopefully this demo has given you a taste for what is possible by simple\r\n% image masking and space-carving. If this has whetted your appetite, have\r\n% a look at the references below. Converting each image to a binary mask\r\n% throws away a lot of information. Instead of using these silhouettes, we\r\n% could use the image values (either greyscale or colour) and a\r\n% photo-consistency constraint. This is *much* harder to get right, but \r\n% copes much better with concavities and holes in the model.\r\n%\r\n% Have you ever been asked about volume estimation from images? Do you\r\n% fancy trying this at home? Perhaps you've implemented a better way to do\r\n% this? I'd love to hear from you \r\n% <https:\/\/blogs.mathworks.com\/loren\/?p=210#respond here>.\r\n%\r\n%\r\n%% File Availability\r\n% The functions created for this demo will ultimately appear on the File Exchange.\r\n% Once they are available, we'll update this post.  As a reminder, there's a link\r\n% above for getting the data.\r\n%\r\n%% References\r\n% Some good references for this (including the original paper that used these images) are:\r\n%\r\n% * *Automatic 3D model construction for turn-table sequences*, _A. W. Fitzgibbon, G. Cross, and A. Zisserman, \r\n% In 3D Structure from Multiple Images of Large-Scale Environments, Springer LNCS 1506, pages 155REPLACE_WITH_DASH_DASH170, 1998_ \r\n% * *A Theory of Shape by Space Carving*, _K. N. Kutulakos & S. M. Seitz,\r\n% International Journal of Computer Vision 38(3), 199\u00e2\u20ac\u201c218, 2000_ \r\n% * *Foundations of Image Understanding*, Chapter 16, _edited by L. S. Davis,\r\n% Kluwer, 2001_\r\n\r\n##### SOURCE END ##### 34b1fb98ea0845a9a11def85642817c0\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   \r\n      Today I&#8217;d like to introduce a guest blogger, Ben, who is consultant over in The MathWorks UK. Some of you may have come across\r\n         his customer projects and demos on image... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/loren\/2009\/12\/16\/carving-a-dinosaur\/\">read more >><\/a><\/p>","protected":false},"author":39,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[33,21,27,15],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/210"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/comments?post=210"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/210\/revisions"}],"predecessor-version":[{"id":3476,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/210\/revisions\/3476"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/media?parent=210"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/categories?post=210"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/tags?post=210"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}