Skip to content

Commit dd0892a

Browse files
author
Ignacio Rocco Spremolla
committed
update to arXiv v2/CVPR18 camera ready
1 parent d41a1e3 commit dd0892a

File tree

2 files changed

+111
-81
lines changed

2 files changed

+111
-81
lines changed

data/pf_dataset.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class PFPascalDataset(Dataset):
103103
104104
"""
105105

106-
def __init__(self, csv_file, dataset_path, output_size=(240,240), transform=None, category=None):
106+
def __init__(self, csv_file, dataset_path, output_size=(240,240), transform=None, category=None, pck_procedure='scnet'):
107107

108108
self.category_names=['aeroplane','bicycle','bird','boat','bottle','bus','car','cat','chair','cow','diningtable','dog','horse','motorbike','person','pottedplant','sheep','sofa','train','tvmonitor']
109109
self.out_h, self.out_w = output_size
@@ -121,6 +121,7 @@ def __init__(self, csv_file, dataset_path, output_size=(240,240), transform=None
121121
self.transform = transform
122122
# no cuda as dataset is called from CPU threads in dataloader and produces confilct
123123
self.affineTnf = GeometricTnf(out_h=self.out_h, out_w=self.out_w, use_cuda = False)
124+
self.pck_procedure = pck_procedure
124125

125126
def __len__(self):
126127
return len(self.pairs)
@@ -135,7 +136,22 @@ def __getitem__(self, idx):
135136
point_B_coords = self.get_points(self.point_B_coords,idx)
136137

137138
# compute PCK reference length L_pck (equal to max bounding box side in image_A)
138-
L_pck = torch.FloatTensor([torch.max(point_A_coords.max(1)[0]-point_A_coords.min(1)[0])])
139+
N_pts = torch.sum(torch.ne(point_A_coords[0,:],-1))
140+
141+
if self.pck_procedure=='pf':
142+
L_pck = torch.FloatTensor([torch.max(point_A_coords[:,:N_pts].max(1)[0]-point_A_coords[:,:N_pts].min(1)[0])])
143+
elif self.pck_procedure=='scnet':
144+
#modification to follow the evaluation procedure of SCNet
145+
point_A_coords[0,0:N_pts]=point_A_coords[0,0:N_pts]*224/im_size_A[1]
146+
point_A_coords[1,0:N_pts]=point_A_coords[1,0:N_pts]*224/im_size_A[0]
147+
148+
point_B_coords[0,0:N_pts]=point_B_coords[0,0:N_pts]*224/im_size_B[1]
149+
point_B_coords[1,0:N_pts]=point_B_coords[1,0:N_pts]*224/im_size_B[0]
150+
151+
im_size_A[0:2]=torch.FloatTensor([224,224])
152+
im_size_B[0:2]=torch.FloatTensor([224,224])
153+
154+
L_pck = torch.FloatTensor([224.0])
139155

140156
sample = {'source_image': image_A, 'target_image': image_B, 'source_im_size': im_size_A, 'target_im_size': im_size_B, 'source_points': point_A_coords, 'target_points': point_B_coords, 'L_pck': L_pck}
141157

util/eval_util.py

+93-79
Original file line numberDiff line numberDiff line change
@@ -10,47 +10,8 @@
1010
from torch.autograd import Variable
1111
from geotnf.point_tnf import PointTnf, PointsToUnitCoords, PointsToPixelCoords
1212
from util.py_util import create_file_path
13+
from model.loss import WeakInlierCount, TwoStageWeakInlierCount
1314

14-
def theta_to_sampling_grid(out_h,out_w,theta_aff=None,theta_tps=None,theta_aff_tps=None,use_cuda=True,tps_reg_factor=0):
15-
affTnf = GeometricTnf(out_h=out_h,out_w=out_w,geometric_model='affine',use_cuda=use_cuda)
16-
tpsTnf = GeometricTnf(out_h=out_h,out_w=out_w,geometric_model='tps',use_cuda=use_cuda,tps_reg_factor=tps_reg_factor)
17-
18-
if theta_aff is not None:
19-
sampling_grid_aff = affTnf(image_batch=None,
20-
theta_batch=theta_aff.view(1,2,3),
21-
return_sampling_grid=True,
22-
return_warped_image=False)
23-
else:
24-
sampling_grid_aff=None
25-
26-
if theta_tps is not None:
27-
sampling_grid_tps = tpsTnf(image_batch=None,
28-
theta_batch=theta_tps.view(1,-1),
29-
return_sampling_grid=True,
30-
return_warped_image=False)
31-
else:
32-
sampling_grid_tps=None
33-
34-
if theta_aff is not None and theta_aff_tps is not None:
35-
sampling_grid_aff_tps = tpsTnf(image_batch=None,
36-
theta_batch=theta_aff_tps.view(1,-1),
37-
return_sampling_grid=True,
38-
return_warped_image=False)
39-
40-
# put 1e10 value in region out of bounds of sampling_grid_aff
41-
sampling_grid_aff = sampling_grid_aff.clone()
42-
in_bound_mask_aff=Variable((sampling_grid_aff.data[:,:,:,0]>-1) & (sampling_grid_aff.data[:,:,:,0]<1) & (sampling_grid_aff.data[:,:,:,1]>-1) & (sampling_grid_aff.data[:,:,:,1]<1)).unsqueeze(3)
43-
in_bound_mask_aff=in_bound_mask_aff.expand_as(sampling_grid_aff)
44-
sampling_grid_aff = torch.add((in_bound_mask_aff.float()-1)*(1e10),torch.mul(in_bound_mask_aff.float(),sampling_grid_aff))
45-
# put 1e10 value in region out of bounds of sampling_grid_aff_tps_comp
46-
sampling_grid_aff_tps_comp = F.grid_sample(sampling_grid_aff.transpose(2,3).transpose(1,2), sampling_grid_aff_tps).transpose(1,2).transpose(2,3)
47-
in_bound_mask_aff_tps=Variable((sampling_grid_aff_tps.data[:,:,:,0]>-1) & (sampling_grid_aff_tps.data[:,:,:,0]<1) & (sampling_grid_aff_tps.data[:,:,:,1]>-1) & (sampling_grid_aff_tps.data[:,:,:,1]<1)).unsqueeze(3)
48-
in_bound_mask_aff_tps=in_bound_mask_aff_tps.expand_as(sampling_grid_aff_tps_comp)
49-
sampling_grid_aff_tps_comp = torch.add((in_bound_mask_aff_tps.float()-1)*(1e10),torch.mul(in_bound_mask_aff_tps.float(),sampling_grid_aff_tps_comp))
50-
else:
51-
sampling_grid_aff_tps_comp = None
52-
53-
return (sampling_grid_aff,sampling_grid_tps,sampling_grid_aff_tps_comp)
5415

5516
def compute_metric(metric,model,dataset,dataloader,batch_tnf,batch_size,two_stage=True,do_aff=False,do_tps=False,args=None):
5617
# Initialize stats
@@ -81,6 +42,10 @@ def compute_metric(metric,model,dataset,dataloader,batch_tnf,batch_size,two_stag
8142
elif metric=='flow':
8243
metrics = ['flow']
8344
metric_fun = flow_metrics
45+
elif metric=='inlier_count':
46+
metrics = ['inlier_count']
47+
metric_fun = inlier_count
48+
model.return_correlation = True
8449
# initialize vector for storing results for each metric
8550
for key in stats.keys():
8651
for metric in metrics:
@@ -104,36 +69,43 @@ def compute_metric(metric,model,dataset,dataloader,batch_tnf,batch_size,two_stag
10469
theta_aff,theta_aff_tps,corr_aff,corr_aff_tps=model(batch)
10570
elif do_aff:
10671
theta_aff=model(batch)
72+
if isinstance(theta_aff,tuple):
73+
theta_aff=theta_aff[0]
10774
elif do_tps:
10875
theta_tps=model(batch)
109-
110-
if metric_fun is not None:
76+
if isinstance(theta_tps,tuple):
77+
theta_tps=theta_tps[0]
78+
79+
if metric=='inlier_count':
80+
stats = inlier_count(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,corr_aff,corr_aff_tps,stats,args)
81+
elif metric_fun is not None:
11182
stats = metric_fun(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,stats,args)
11283

11384
print('Batch: [{}/{} ({:.0f}%)]'.format(i, len(dataloader), 100. * i / len(dataloader)))
11485

86+
# Print results
87+
if metric == 'flow':
88+
print('Flow files have been saved to '+args.flow_output_dir)
89+
return stats
90+
11591
for key in stats.keys():
11692
print('=== Results '+key+' ===')
11793
for metric in metrics:
94+
# print per-class brakedown for PFPascal, or caltech
95+
if isinstance(dataset,PFPascalDataset):
96+
N_cat = int(np.max(dataset.category))
97+
for c in range(N_cat):
98+
cat_idx = np.nonzero(dataset.category==c+1)[0]
99+
print(dataset.category_names[c].ljust(15)+': ','{:.2%}'.format(np.mean(stats[key][metric][cat_idx])))
100+
101+
# print mean value
118102
results=stats[key][metric]
119103
good_idx = np.flatnonzero((results!=-1) * ~np.isnan(results))
120104
print('Total: '+str(results.size))
121105
print('Valid: '+str(good_idx.size))
122-
# import pdb; pdb.set_trace()
123106
filtered_results = results[good_idx]
124107
print(metric+':','{:.2%}'.format(np.mean(filtered_results)))
125-
if isinstance(dataset,CaltechDataset) and key=='aff_tps' and metric=='intersection_over_union':
126-
N_cat = int(np.max(dataset.category))
127-
for c in range(N_cat):
128-
cat_idx = np.nonzero(dataset.category==c+1)[0]
129-
print(dataset.category_names[c].ljust(15)+': ','{:.2%}'.format(np.mean(stats[key][metric][cat_idx])))
130-
131-
if isinstance(dataset,PFPascalDataset):
132-
N_cat = int(np.max(dataset.category))
133-
for c in range(N_cat):
134-
cat_idx = np.nonzero(dataset.category==c+1)[0]
135-
print(dataset.category_names[c].ljust(15)+': ','{:.2%}'.format(np.mean(stats[key][metric][cat_idx])))
136-
108+
137109
print('\n')
138110

139111
return stats
@@ -224,6 +196,17 @@ def point_dist_metric(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,st
224196

225197
return stats
226198

199+
def inlier_count(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,corr_aff,corr_aff_tps,stats,args,use_cuda=True):
200+
inliersComposed = TwoStageWeakInlierCount(use_cuda=torch.cuda.is_available(),dilation_filter=0,normalize_inlier_count=True)
201+
inliers_comp = inliersComposed(matches=corr_aff,theta_aff=theta_aff,theta_aff_tps=theta_aff_tps)
202+
current_batch_size=batch['source_im_size'].size(0)
203+
indices = range(batch_start_idx,batch_start_idx+current_batch_size)
204+
205+
stats['aff_tps']['inlier_count'][indices] = inliers_comp.unsqueeze(1).cpu().data.numpy()
206+
207+
return stats
208+
209+
227210
def pck_metric(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,stats,args,use_cuda=True):
228211
alpha = args.pck_alpha
229212
do_aff = theta_aff is not None
@@ -264,7 +247,7 @@ def pck_metric(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,stats,arg
264247
current_batch_size=batch['source_im_size'].size(0)
265248
indices = range(batch_start_idx,batch_start_idx+current_batch_size)
266249

267-
# import pdb; pdb.set_trace()
250+
# import pdb; pdb.set_trace()
268251

269252
if do_aff:
270253
pck_aff = pck(source_points.data, warped_points_aff.data, L_pck, alpha)
@@ -352,8 +335,7 @@ def pascal_parts_metrics(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps
352335
if do_aff_tps:
353336
warped_mask_aff_tps = F.grid_sample(source_mask, grid_aff_tps)
354337
stats['aff_tps']['intersection_over_union'][idx] = intersection_over_union(warped_mask_aff_tps,target_mask)
355-
# if idx==300:
356-
# import pdb; pdb.set_trace()
338+
357339
return stats
358340

359341
def area_metrics(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,stats,args,use_cuda=True):
@@ -362,6 +344,9 @@ def area_metrics(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,stats,a
362344
do_aff_tps = theta_aff_tps is not None
363345

364346
batch_size=batch['source_im_size'].size(0)
347+
348+
pt=PointTnf(use_cuda=use_cuda)
349+
365350
for b in range(batch_size):
366351
h_src = int(batch['source_im_size'][b,0].data.cpu().numpy())
367352
w_src = int(batch['source_im_size'][b,1].data.cpu().numpy())
@@ -376,30 +361,43 @@ def area_metrics(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,stats,a
376361
batch['source_polygon'][1][b],
377362
h_src,w_src,use_cuda=use_cuda)
378363

379-
grid_aff,grid_tps,grid_aff_tps=theta_to_sampling_grid(h_tgt,w_tgt,
380-
theta_aff[b,:] if do_aff else None,
381-
theta_tps[b,:] if do_tps else None,
382-
theta_aff_tps[b,:] if do_aff_tps else None,
383-
use_cuda=use_cuda,
384-
tps_reg_factor=args.tps_reg_factor)
385-
364+
grid_X,grid_Y = np.meshgrid(np.linspace(-1,1,w_tgt),np.linspace(-1,1,h_tgt))
365+
grid_X = torch.FloatTensor(grid_X).unsqueeze(0).unsqueeze(3)
366+
grid_Y = torch.FloatTensor(grid_Y).unsqueeze(0).unsqueeze(3)
367+
grid_X = Variable(grid_X,requires_grad=False)
368+
grid_Y = Variable(grid_Y,requires_grad=False)
369+
370+
if use_cuda:
371+
grid_X = grid_X.cuda()
372+
grid_Y = grid_Y.cuda()
373+
374+
grid_X_vec = grid_X.view(1,1,-1)
375+
grid_Y_vec = grid_Y.view(1,1,-1)
376+
377+
grid_XY_vec = torch.cat((grid_X_vec,grid_Y_vec),1)
378+
379+
def pointsToGrid (x,h_tgt=h_tgt,w_tgt=w_tgt): return x.contiguous().view(1,2,h_tgt,w_tgt).transpose(1,2).transpose(2,3)
380+
386381
idx = batch_start_idx+b
387382

388383
if do_aff:
384+
grid_aff = pointsToGrid(pt.affPointTnf(theta_aff[b,:].unsqueeze(0),grid_XY_vec))
389385
warped_mask_aff = F.grid_sample(source_mask, grid_aff)
390386
flow_aff = th_sampling_grid_to_np_flow(source_grid=grid_aff,h_src=h_src,w_src=w_src)
391387

392388
stats['aff']['intersection_over_union'][idx] = intersection_over_union(warped_mask_aff,target_mask)
393389
stats['aff']['label_transfer_accuracy'][idx] = label_transfer_accuracy(warped_mask_aff,target_mask)
394390
stats['aff']['localization_error'][idx] = localization_error(source_mask_np, target_mask_np, flow_aff)
395391
if do_tps:
392+
grid_tps = pointsToGrid(pt.tpsPointTnf(theta_tps[b,:].unsqueeze(0),grid_XY_vec))
396393
warped_mask_tps = F.grid_sample(source_mask, grid_tps)
397394
flow_tps = th_sampling_grid_to_np_flow(source_grid=grid_tps,h_src=h_src,w_src=w_src)
398395

399396
stats['tps']['intersection_over_union'][idx] = intersection_over_union(warped_mask_tps,target_mask)
400397
stats['tps']['label_transfer_accuracy'][idx] = label_transfer_accuracy(warped_mask_tps,target_mask)
401398
stats['tps']['localization_error'][idx] = localization_error(source_mask_np, target_mask_np, flow_tps)
402399
if do_aff_tps:
400+
grid_aff_tps = pointsToGrid(pt.affPointTnf(theta_aff[b,:].unsqueeze(0),pt.tpsPointTnf(theta_aff_tps[b,:].unsqueeze(0),grid_XY_vec)))
403401
warped_mask_aff_tps = F.grid_sample(source_mask, grid_aff_tps)
404402
flow_aff_tps = th_sampling_grid_to_np_flow(source_grid=grid_aff_tps,h_src=h_src,w_src=w_src)
405403

@@ -416,6 +414,8 @@ def flow_metrics(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,stats,a
416414
do_aff = theta_aff is not None
417415
do_tps = theta_tps is not None
418416
do_aff_tps = theta_aff_tps is not None
417+
418+
pt=PointTnf(use_cuda=use_cuda)
419419

420420
batch_size=batch['source_im_size'].size(0)
421421
for b in range(batch_size):
@@ -424,28 +424,42 @@ def flow_metrics(batch,batch_start_idx,theta_aff,theta_tps,theta_aff_tps,stats,a
424424
h_tgt = int(batch['target_im_size'][b,0].data.cpu().numpy())
425425
w_tgt = int(batch['target_im_size'][b,1].data.cpu().numpy())
426426

427-
grid_aff,grid_tps,grid_aff_tps=theta_to_sampling_grid(h_tgt,w_tgt,
428-
theta_aff[b,:] if do_aff else None,
429-
theta_tps[b,:] if do_tps else None,
430-
theta_aff_tps[b,:] if do_aff_tps else None,
431-
use_cuda=use_cuda,
432-
tps_reg_factor=args.tps_reg_factor)
433-
434-
if do_aff_tps:
435-
flow_aff_tps = th_sampling_grid_to_np_flow(source_grid=grid_aff_tps,h_src=h_src,w_src=w_src)
436-
flow_aff_tps_path = os.path.join(result_path,'aff_tps',batch['flow_path'][b])
437-
create_file_path(flow_aff_tps_path)
438-
write_flo_file(flow_aff_tps,flow_aff_tps_path)
439-
elif do_aff:
427+
grid_X,grid_Y = np.meshgrid(np.linspace(-1,1,w_tgt),np.linspace(-1,1,h_tgt))
428+
grid_X = torch.FloatTensor(grid_X).unsqueeze(0).unsqueeze(3)
429+
grid_Y = torch.FloatTensor(grid_Y).unsqueeze(0).unsqueeze(3)
430+
grid_X = Variable(grid_X,requires_grad=False)
431+
grid_Y = Variable(grid_Y,requires_grad=False)
432+
if use_cuda:
433+
grid_X = grid_X.cuda()
434+
grid_Y = grid_Y.cuda()
435+
436+
grid_X_vec = grid_X.view(1,1,-1)
437+
grid_Y_vec = grid_Y.view(1,1,-1)
438+
439+
grid_XY_vec = torch.cat((grid_X_vec,grid_Y_vec),1)
440+
441+
def pointsToGrid (x,h_tgt=h_tgt,w_tgt=w_tgt): return x.contiguous().view(1,2,h_tgt,w_tgt).transpose(1,2).transpose(2,3)
442+
443+
idx = batch_start_idx+b
444+
445+
if do_aff:
446+
grid_aff = pointsToGrid(pt.affPointTnf(theta_aff[b,:].unsqueeze(0),grid_XY_vec))
440447
flow_aff = th_sampling_grid_to_np_flow(source_grid=grid_aff,h_src=h_src,w_src=w_src)
441448
flow_aff_path = os.path.join(result_path,'aff',batch['flow_path'][b])
442449
create_file_path(flow_aff_path)
443450
write_flo_file(flow_aff,flow_aff_path)
444-
elif do_tps:
451+
if do_tps:
452+
grid_tps = pointsToGrid(pt.tpsPointTnf(theta_tps[b,:].unsqueeze(0),grid_XY_vec))
445453
flow_tps = th_sampling_grid_to_np_flow(source_grid=grid_tps,h_src=h_src,w_src=w_src)
446454
flow_tps_path = os.path.join(result_path,'tps',batch['flow_path'][b])
447455
create_file_path(flow_tps_path)
448456
write_flo_file(flow_tps,flow_tps_path)
457+
if do_aff_tps:
458+
grid_aff_tps = pointsToGrid(pt.affPointTnf(theta_aff[b,:].unsqueeze(0),pt.tpsPointTnf(theta_aff_tps[b,:].unsqueeze(0),grid_XY_vec)))
459+
flow_aff_tps = th_sampling_grid_to_np_flow(source_grid=grid_aff_tps,h_src=h_src,w_src=w_src)
460+
flow_aff_tps_path = os.path.join(result_path,'aff_tps',batch['flow_path'][b])
461+
create_file_path(flow_aff_tps_path)
462+
write_flo_file(flow_aff_tps,flow_aff_tps_path)
449463

450464
idx = batch_start_idx+b
451465
return stats

0 commit comments

Comments
 (0)