in lib/model/HGPIFuNetwNML.py [0:0]
def calc_normal(self, points, calibs, transforms=None, labels=None, delta=0.01, fd_type='forward'):
'''
return surface normal in 'model' space.
it computes normal only in the last stack.
note that the current implementation use forward difference.
args:
points: [B, 3, N] 3d points in world space
calibs: [B, 3, 4] calibration matrices for each image
transforms: [B, 2, 3] image space coordinate transforms
delta: perturbation for finite difference
fd_type: finite difference type (forward/backward/central)
'''
pdx = points.clone()
pdx[:,0,:] += delta
pdy = points.clone()
pdy[:,1,:] += delta
pdz = points.clone()
pdz[:,2,:] += delta
if labels is not None:
self.labels_nml = labels
points_all = torch.stack([points, pdx, pdy, pdz], 3)
points_all = points_all.view(*points.size()[:2],-1)
xyz = self.projection(points_all, calibs, transforms)
xy = xyz[:, :2, :]
im_feat = self.im_feat_list[-1]
sp_feat = self.spatial_enc(xyz, calibs=calibs)
point_local_feat_list = [self.index(im_feat, xy), sp_feat]
point_local_feat = torch.cat(point_local_feat_list, 1)
pred = self.mlp(point_local_feat)[0]
pred = pred.view(*pred.size()[:2],-1,4) # (B, 1, N, 4)
# divide by delta is omitted since it's normalized anyway
dfdx = pred[:,:,:,1] - pred[:,:,:,0]
dfdy = pred[:,:,:,2] - pred[:,:,:,0]
dfdz = pred[:,:,:,3] - pred[:,:,:,0]
nml = -torch.cat([dfdx,dfdy,dfdz], 1)
nml = F.normalize(nml, dim=1, eps=1e-8)
self.nmls = nml