【问题标题】:Basic space carving algorithm基本空间雕刻算法
【发布时间】:2018-01-14 09:56:32
【问题描述】:

我有如下问题如图。我有点云和由四面体算法生成的网格。我将如何使用该算法雕刻网格?地标是点云吗?

算法伪代码:

for every 3D feature point
 convert it 2D projected coordinates

for every 2D feature point
cast a ray toward the polygons of the mesh 
get intersection point
if zintersection < z of 3D feature point
for ( every triangle vertices )
cull that triangle.

这是Guru Spektre提到的算法的后续实现:)

更新算法代码:

 int i;
        for (i = 0; i < out.numberofpoints; i++)
        {
            Ogre::Vector3 ray_pos = pos; // camera position);
            Ogre::Vector3 ray_dir = (Ogre::Vector3 (out.pointlist[(i*3)], out.pointlist[(3*i)+1], out.pointlist[(3*i)+2]) - pos).normalisedCopy();  // vertex - camea pos ;

            Ogre::Ray ray;
            ray.setOrigin(Ogre::Vector3( ray_pos.x, ray_pos.y, ray_pos.z));
            ray.setDirection(Ogre::Vector3(ray_dir.x, ray_dir.y, ray_dir.z));
            Ogre::Vector3 result;
            unsigned int u1;
            unsigned int u2;
            unsigned int u3;
            bool rayCastResult = RaycastFromPoint(ray.getOrigin(), ray.getDirection(), result, u1, u2, u3);

            if ( rayCastResult )
            {
                Ogre::Vector3 targetVertex(out.pointlist[(i*3)], out.pointlist[(3*i)+1], out.pointlist[(3*i)+2]);
                float distanceTargetFocus = targetVertex.squaredDistance(pos);
                float distanceIntersectionFocus = result.squaredDistance(pos);
                if(abs(distanceTargetFocus) >= abs(distanceIntersectionFocus))
                {
                    if ( u1 != -1 && u2 != -1 && u3 != -1)
                    {
                        std::cout << "Remove index "<< "u1 ==> " <<u1 << "u2 ==>"<<u2<<"u3 ==> "<<u3<< std::endl;
                        updatedIndices.erase(updatedIndices.begin()+ u1);
                        updatedIndices.erase(updatedIndices.begin()+ u2);
                        updatedIndices.erase(updatedIndices.begin()+ u3);

                    }
                }
            }

            }


            if ( updatedIndices.size() <= out.numberoftrifaces)
            {
                std::cout << "current face list===> "<< out.numberoftrifaces << std::endl;

                std::cout << "deleted face list===> "<< updatedIndices.size() << std::endl;
                manual->begin("Pointcloud", Ogre::RenderOperation::OT_TRIANGLE_LIST);

                for (int n = 0; n < out.numberofpoints; n++)
                {
                    Ogre::Vector3 vertexTransformed = Ogre::Vector3( out.pointlist[3*n+0], out.pointlist[3*n+1], out.pointlist[3*n+2]) - mReferencePoint;
                    vertexTransformed *=1000.0 ;
                    vertexTransformed = mDeltaYaw * vertexTransformed;

                    manual->position(vertexTransformed);

                }

                for (int n = 0 ; n < updatedIndices.size(); n++)
                {
                     int n0 = updatedIndices[n+0];
                     int n1 = updatedIndices[n+1];
                     int n2 = updatedIndices[n+2];

                    if ( n0 < 0 || n1 <0 || n2 <0 )
                    {
                        std::cout<<"negative indices"<<std::endl;
                        break;
                    }
                    manual->triangle(n0, n1, n2);

                }

                manual->end();

跟进算法:

我现在有两个版本,一个是三角版,另一个是雕刻版。

这不是表面网格。 这是两个文件 http://www.mediafire.com/file/cczw49ja257mnzr/ahmed_non_triangulated.obj http://www.mediafire.com/file/cczw49ja257mnzr/ahmed_triangulated.obj

【问题讨论】:

  • 我在 cmets 中写的东西至少需要我 2 周的全职编码(因为我过去没有做任何类似的事情,需要从头开始编码)我没有也没有时间,也没有心情。这就是为什么您的另一个问题被标记为关闭太宽泛。生成的代码将远大于 30Kb 的限制,解释它的文字可能会填满整本书。除非使用计算着色器,否则 OpenGL 和 DirecX 对此没有多大帮助,但调试会花费更多时间,所以我强烈建议在 CPU 端执行此操作,并且仅在工作端口到 GPU 时执行此操作
  • 点云的加载和可视化没什么,可以很快编码。您缺少的是 Raycasting 和 Mesh CSG 之类的数学,大量的试验和错误来设置会有所帮助的视图(可能从 6 个基本视图开始不会有多大好处)看看这些 stackoverflow.com/a/48092685/2521214 @ 987654324@ 并将它们移植到 CPU
  • 您需要实现射线三角形相交(在第二个链接中),然后您需要从网格中实现面移除。因为我不知道你用什么结构......只能猜测。
  • 为此我需要更多关于您的图像和世界坐标系的信息,其中 (0,0,0) 以及哪个方向指向哪个轴
  • 通过比较距离 .... |target_vertex-focus| &gt;= |face_ray_intersection-focus| 表示您在目标顶点之前击中面部并且应该被移除。为了提高速度,您不需要sqrt 可以比较它们的长度...

标签: algorithm graphics 3d computer-vision 3d-reconstruction


【解决方案1】:

我是这样看的:

因此,您从具有已知 matrixFOV 和焦距的相机获取图像。

从中您可以知道焦点的确切位置以及图像在相机芯片上的位置(Z_near 平面)。所以任何顶点,其对应的像素和焦点都在同一条线上。

所以对于从焦点到点云的每个 可见 顶点的每个视图 cas 射线。并在击中包含目标顶点的面之前测试网格的任何面是否命中。如果是,请将其删除,因为它会阻碍可见性。

在这种情况下,

Landmark 只是点云中与 vertex 对应的特征点。它可以是任何可检测到的东西(强度、颜色、图案等的变化),通常 SIFT/SURF 用于此目的。您应该已经将它们定位,因为这是点云生成的输入。如果不是,您可以查看每个顶点对应的像素并测试背景颜色。

不知道在没有输入图像的情况下您想如何做到这一点。为此,您需要决定从哪个侧面/视图可以看到哪个顶点。可能以某种方式从附近的顶点形成是可行的(例如使用顶点密度点或对平面的对应...),或者以某种方式更改算法以找到网格内未使用的顶点。

要投射光线,请执行以下操作:

ray_pos=tm_eye*vec4(imgx/aspect,imgy,0.0,1.0);
ray_dir=ray_pos-tm_eye*vec4(0.0,0.0,-focal_length,1.0);

其中tm_eye 是相机直接变换矩阵,imgx,imgy 是标准化为&lt;-1,+1&gt; 的图像中的二维像素位置,其中(0,0) 是图像的中间位置。 focal_length决定了相机的FOV,纵横比是图像分辨率的比例image_ys/image_xs

射线三角形相交方程可以在这里找到:

如果我提取它:

vec3 v0,v1,v2; // input triangle vertexes
vec3 e1,e2,n,p,q,r;
float t,u,v,det,idet;
//compute ray triangle intersection
e1=v1-v0;
e2=v2-v0;
// Calculate planes normal vector
p=cross(ray[i0].dir,e2);
det=dot(e1,p);
// Ray is parallel to plane
if (abs(det)<1e-8) no intersection;
idet=1.0/det;
r=ray[i0].pos-v0;
u=dot(r,p)*idet;
if ((u<0.0)||(u>1.0)) no intersection;
q=cross(r,e1);
v=dot(ray[i0].dir,q)*idet;
if ((v<0.0)||(u+v>1.0)) no intersection;
t=dot(e2,q)*idet;
if ((t>_zero)&&((t<=tt))  // tt is distance to target vertex
    {
    // intersection
    }              

跟进:

要在规格化图像(imgx,imgy) 和原始图像(rawx,rawy) 坐标之间移动尺寸为(imgxs,imgys) 的图像,其中(0,0) 是左上角,(imgxs-1,imgys-1) 是右下角:

imgx = (2.0*rawx / (imgxs-1)) - 1.0
imgy = 1.0 - (2.0*rawy / (imgys-1))

rawx = (imgx + 1.0)*(imgxs-1)/2.0
rawy = (1.0 - imgy)*(imgys-1)/2.0

[进度更新 1]

我终于到了可以编译示例测试输入数据的地步了(因为您根本无法共享有效数据):

我用硬编码的 table 网格(灰色)和点云(浅绿色)和简单的相机控制创建了小型应用。我可以保存任意数量的视图(屏幕截图+相机直接矩阵)。当加载回来时,它与网格本身对齐(黄色光线穿过图像中的水色点,也穿过表格网格)。蓝线从相机焦点投射到其角落。这将模拟您获得的输入。应用程序的第二部分将仅使用这些带有点云的图像和矩阵(不再使用网格表面)对其进行四边形化(已经完成)现在只需将光线投射到每个视图中的每个地标(水色点)并移除目标顶点之前的所有四边形在点云中被击中(这个东西甚至还没有开始,可能在周末)......最后只存储表面三角形(很容易使用所有只使用一次的三角形也已经完成,除了保存部分,但要从这很容易......)。

[进度更新 2]

我添加了地标检测和点云匹配

如您所见,仅投射有效光线(在图像上可见的光线),因此点云上的某些点不会投射光线(奇异的水色点))。所以现在只有射线/三角形相交和从列表中删除四面体是缺少的......

【讨论】:

  • @andreahmed q(x,y,z,w) = Inverse(tm_eye)*pnt(x,y,z,1) 会将您的 3D 点转换为相机本地空间,现在您需要反向应用透视,例如 x = q.x*focal_length/q.z , y = q.y*focal_length/q.z +/- 如果您的相机坐标系未标准化为 @ 则有一些偏移987654345@你应该目视检查...
  • @andreahmed 所有二维特征点的垂直距离等于焦距(因为它们都投影到芯片平面(小星图)上。相机空间中焦点的垂直距离为Z 坐标,所以不需要任何方程....您只需通过应用逆相机矩阵将 3D 顶点转换为相机空间
  • @andreahmed 简而言之,你做对了,但你应该只对可见顶点执行此操作。因此,当您将顶点转换为 2D 以决定它是否也是地标(或图像中的特征点)时,像素不能是背景。它也应该是一个特征点(筛选冲浪或点云计算过程中曾经使用过的东西)如果不是(图像上附近没有这样的点),那么不要为它投射光线(该点是从不同的图像/视点)
  • 如何判断像素是否不是背景?
  • @andreahmed 分割...但是为此您需要一些关于它的知识,例如颜色...或者您可以分割相似的区域(基于颜色、图案、纹理或照明条件)和一个触摸边框通常是背景。正如我写的那样,这比你乍一看要多得多……而且如果没有正确的输入,就会丢失更多……
猜你喜欢
  • 2013-03-17
  • 1970-01-01
  • 2020-11-20
  • 1970-01-01
  • 1970-01-01
  • 2012-11-17
  • 1970-01-01
  • 2011-11-23
相关资源
最近更新 更多