在将纹理映射到网格时,Vtk在节点之间插入不正确的颜色

时间:2016-08-25 05:33:31

标签: python vtk texture-mapping wavefront

您好我正在尝试使用Mayavi和vtk的Python绑定将纹理映射到3d网格。我正在想象一个.obj波前。这个obj是脸的3D照片。纹理图像是三张2D照片的合成。

enter image description here

网格中的每个节点在图像中都有一个(uv)坐标,用于定义其颜色。网格的不同区域从图像的不同部分绘制它们的颜色。为了说明这一点,我用这个替换了实际的纹理图像:

enter image description here

并将其映射到网格。

enter image description here

我所面临的问题在鼻子周围被说明了。在红色和绿色之间的边界处有一个蓝色的轮廓。在线框模式下对该区域的仔细检查表明,它不是uv映射的问题,而是vtk如何在两个节点之间插入颜色。出于某种原因,它在两个节点之间添加了一块蓝色,其中一个是红色,一个是绿色。

enter image description here

使用真实纹理进行可视化时,这会导致严重问题

enter image description here

有没有办法强制vtk为它们之间的颜色选择一个或其他相邻节点的颜色?我试过转动"边缘夹紧"在,但这没有取得任何成果。

我正在使用的代码如下,您可以从此处访问相关文件https://www.dropbox.com/sh/ipel0avsdiokr10/AADmUn1-qmsB3vX7BZObrASPa?dl=0 但我希望这是一个简单的解决方案。

from numpy import *
from mayavi import mlab
from tvtk.api import tvtk
import os
from vtk.util import numpy_support

def  obj2array(f):
    """function for reading a Wavefront obj"""
    if type(f)==str:
            if os.path.isfile(f)==False:
                    raise ValueError('obj2array: unable to locate file ' + str(f))
            f =open(f)

    vertices = list()
    connectivity = list()
    uv = list()
    vt = list()


    fcount = 0


    for l in f:
                line = l.rstrip('\n')

                data = line.split()
                if len(data)==0:
                        pass
                else:

                        if data[0] == 'v':
                            vertices.append(atleast_2d(array([float(item) for item in data[1:4]])))

                        elif data[0]=='vt':
                            uv.append(atleast_2d(array([float(item) for item in data[1:3]])))


                        elif data[0]=='f':

                            nverts = len(data)-1 # number of vertices comprising each face

                            if fcount == 0:    #on first face establish face format

                                fcount = fcount + 1
                                if data[1].find('/')==-1:  #Case 1
                                    case = 1

                                elif data[1].find('//')==True:
                                    case = 4
                                elif len(data[1].split('/'))==2:
                                    case = 2
                                elif len(data[1].split('/'))==3:
                                    case = 3



                            if case == 1:
                                f = atleast_2d([int(item) for item in data[1:len(data)]])
                                connectivity.append(f)

                            if case == 2:
                                splitdata = [item.split('/') for item in data[1:len(data)]]
                                f = atleast_2d([int(item[0]) for item in splitdata])

                                connectivity.append(f)

                            if case == 3:
                                splitdata = [item.split('/') for item in data[1:len(data)]]
                                f = atleast_2d([int(item[0]) for item in splitdata])
                                connectivity.append(f)


                            if case == 4:
                                splitdata = [item.split('//') for item in data[1:len(data)]]
                                f = atleast_2d([int(item[0]) for item in splitdata])

                                connectivity.append(f)


    vertices = concatenate(vertices, axis = 0)
    if len(uv)==0:
        uv=None
    else:
        uv = concatenate(uv, axis = 0)

    if len(connectivity) !=0:
            try:
                    conarray = concatenate(connectivity, axis=0)
            except ValueError:
                    if triangulate==True:
                            conarray=triangulate_mesh(connectivity,vertices)

                    else:
                            raise ValueError('obj2array: not all faces triangles?')
            if conarray.shape[1]==4:
                    if triangulate==True:
                            conarray=triangulate_mesh(connectivity,vertices)



    return vertices, conarray,uv



# load texture image
texture_img = tvtk.Texture(interpolate = 1,edge_clamp=1)
texture_img.input = tvtk.BMPReader(file_name='HM_1_repose.bmp').output

#load obj
verts, triangles, uv = obj2array('HM_1_repose.obj')

# make 0-indexed
triangles = triangles-1

surf = mlab.triangular_mesh(verts[:,0],verts[:,1],verts[:,2],triangles)

tc=numpy_support.numpy_to_vtk(uv)

pd = surf.mlab_source.dataset._vtk_obj.GetPointData()
pd.SetTCoords(tc)
surf.actor.actor.mapper.scalar_visibility=False
surf.actor.enable_texture = True
surf.actor.actor.texture = texture_img
mlab.show(stop=True)

2 个答案:

答案 0 :(得分:1)

您可以关闭所有插值(在示例中将interpolate = 1更改为interpolate = 0),但是无法在仅插入子图像的位置处关闭插值。纹理 - 至少在没有编写自己的片段着色器的情况下。这看起来很粗糙。

另一种解决方案是在每个位置创建3个纹理图像,其中透明纹理像素不是演员脸部的一部分。然后使用相同的纹理坐标渲染相同的几何体,但每次渲染一个不同的图像(即,每个具有相同的多边形但具有不同纹理图像的3个演员)。

答案 1 :(得分:0)

我也碰到了这个确切的问题,发现发生这种情况的原因是因为VTK假定渲染角色和相关的vtkTexture时,多数据中的点与uv坐标之间存在1对1的关系。但是,就我和OP而言,有相邻的三角形映射到图像的不同部分,因此它们具有非常不同的uv坐标。共享这些相邻面的点只能具有一个uv坐标(或Tcoord)关联,但实际上它们需要2个(或更多,取决于您的情况)。

我的解决方案是遍历并复制位于接缝/边界上的这些点,并使用带有这些重复的pointId的三角形创建一个新的vtkCellArray。然后,我只是用新的三角形替换了vtkPolyData Polys()列表。复制点并为每个需要它的三角形更新现有的pointIds会容易得多,但是我找不到合适的方式来更新单元格。