您好我正在尝试使用Mayavi和vtk的Python绑定将纹理映射到3d网格。我正在想象一个.obj波前。这个obj是脸的3D照片。纹理图像是三张2D照片的合成。
网格中的每个节点在图像中都有一个(uv)坐标,用于定义其颜色。网格的不同区域从图像的不同部分绘制它们的颜色。为了说明这一点,我用这个替换了实际的纹理图像:
并将其映射到网格。
我所面临的问题在鼻子周围被说明了。在红色和绿色之间的边界处有一个蓝色的轮廓。在线框模式下对该区域的仔细检查表明,它不是uv映射的问题,而是vtk如何在两个节点之间插入颜色。出于某种原因,它在两个节点之间添加了一块蓝色,其中一个是红色,一个是绿色。
使用真实纹理进行可视化时,这会导致严重问题
有没有办法强制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)
答案 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会容易得多,但是我找不到合适的方式来更新单元格。