├── .gitignore ├── Network.py ├── ReadMe.md ├── datasets ├── __init__.py ├── custom_transforms.py ├── pdefined_anchor.pkl └── proposal_data_transforms.py ├── demo_new.py ├── example_images ├── farm1_100_276822098_cbe498842d.jpg ├── farm1_104_273169537_7227f34eed.jpg ├── farm1_12_16181736_f6db921ae0.jpg ├── farm1_158_332074945_ef8b72bb83.jpg ├── farm1_159_341058164_555a9dd582.jpg └── farm1_161_360215948_4ed3ff39f6_b.jpg ├── project_utils.py ├── py_utils ├── __init__.py ├── bboxes.py ├── dir_utils.py ├── file_utils.py ├── generate_SlideWindow.py └── load_utils.py ├── tf_utils ├── __init__.py └── utils.py └── view_results.py /.gitignore: -------------------------------------------------------------------------------- 1 | unsupervised_image_list.txt 2 | *.pth.tar 3 | *.pyc 4 | .idea/workspace.xml 5 | snapshots/ 6 | train_logs/ 7 | vgg_v1.txt 8 | .DS_Store 9 | nohup.out 10 | *.h5 11 | Baselines/models 12 | Baselines/tf_implementation/models 13 | Baselines/tf_implementation_old/models 14 | params/ 15 | visualizations/ 16 | .idea/vcs.xml 17 | ProposalResults/ 18 | DrawResults/ 19 | CropTest/ 20 | ProposalNetEvaluation/ 21 | *.zip 22 | weights/ 23 | .ideas/ 24 | .idea/ 25 | -------------------------------------------------------------------------------- /Network.py: -------------------------------------------------------------------------------- 1 | # saves all the utils of the ssd network 2 | import tensorflow as tf 3 | import tensorflow.contrib.slim as slim 4 | # import ndcg_recsys 5 | 6 | def base_net_arg_scope(): 7 | with slim.arg_scope([slim.conv2d, slim.fully_connected], 8 | activation_fn=tf.nn.relu, 9 | weights_regularizer=slim.l2_regularizer(0.0005), 10 | weights_initializer=tf.contrib.layers.xavier_initializer(), 11 | biases_initializer=tf.zeros_initializer()): 12 | with slim.arg_scope([slim.conv2d, slim.max_pool2d], 13 | padding='SAME') as sc: 14 | return sc 15 | 16 | 17 | def base_net(inputs, 18 | num_classes=400, 19 | rois=None, 20 | bbox_regression=False, 21 | is_training=True, 22 | dropout_keep_prob=0.5, 23 | reuse=None, 24 | scope='ssd_300_vgg'): 25 | with slim.arg_scope(base_net_arg_scope()): 26 | end_points = {} 27 | with tf.variable_scope(scope, 'ssd_300_vgg', [inputs], reuse=reuse): 28 | # Original VGG-16 blocks. 29 | net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1') 30 | end_points['block1'] = net 31 | net = slim.max_pool2d(net, [2, 2], scope='pool1') 32 | # Block 2. 33 | net = slim.repeat(net, 2, slim.conv2d, 128, [3, 3], scope='conv2') 34 | end_points['block2'] = net 35 | net = slim.max_pool2d(net, [2, 2], scope='pool2') 36 | # Block 3. 37 | net = slim.repeat(net, 3, slim.conv2d, 256, [3, 3], scope='conv3') 38 | end_points['block3'] = net 39 | net = slim.max_pool2d(net, [2, 2], scope='pool3') 40 | # Block 4. 41 | net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv4') 42 | end_points['block4'] = net 43 | net = slim.max_pool2d(net, [2, 2], scope='pool4') 44 | # Block 5. 45 | net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv5') 46 | end_points['block5'] = net 47 | net = slim.max_pool2d(net, [3, 3], stride=1, scope='pool5') 48 | 49 | # Block 6: let's dilate the hell out of it! 50 | net = slim.conv2d(net, 1024, [3, 3], rate=6, scope='conv6') 51 | end_points['block6'] = net 52 | # Block 7: 1x1 conv. 53 | net = slim.conv2d(net, 1024, [1, 1], scope='conv7') 54 | tf.summary.histogram('block7_hist', net) 55 | end_points['block7'] = net 56 | 57 | # Block 8. 58 | end_point = 'block8' 59 | with tf.variable_scope(end_point): 60 | net = slim.conv2d(net, 256, [1, 1], scope='conv1x1') 61 | net = slim.conv2d(net, 512, [3, 3], stride=2, scope='conv3x3', padding='VALID') 62 | tf.summary.histogram('block8', net) 63 | end_points[end_point] = net 64 | 65 | # prediction part 66 | end_point = 'prediction' 67 | with tf.variable_scope(end_point): 68 | net = end_points['block8'] 69 | net = slim.dropout(net, dropout_keep_prob, is_training=is_training, scope='dropout1') 70 | tf.summary.histogram('block8_dp', net) 71 | net = slim.conv2d(net, 1024, [9, 9], padding='VALID', scope='conv9x9') 72 | tf.summary.histogram('pred9x9', net) 73 | net = tf.reduce_mean(net, axis=[1, 2], keep_dims=True) 74 | net = slim.dropout(net, dropout_keep_prob, is_training=is_training, scope='dropout2') 75 | net = slim.conv2d(net, num_classes, [1, 1], scope='fc') 76 | end_points[end_point] = net 77 | prediction = tf.squeeze(net, [1, 2], name='squeezed') 78 | 79 | if not (rois is None): 80 | #todo: assume the batch size is 1 81 | end_point = 'fast_rcnn' 82 | with tf.variable_scope(end_point): 83 | net = end_points['block8'] 84 | net = tf.image.resize_images(net, [32, 32]) 85 | rois_yxyx = rois[:, [1, 0, 3, 2]] 86 | net = tf.image.crop_and_resize(net, boxes=rois_yxyx, crop_size=[3,3], box_ind=tf.zeros(shape=[num_classes], dtype=tf.int32)) 87 | # this dropout is not good enough for limited data 88 | #TODO: using 1024 is for pairwise-frcnn-dp(dropout + large) 89 | #TODO: there are different versions: dp+1024/128/1024+dp+128+dp 90 | #TODO: update2: remove the complex structure, just keep the 128D 91 | # is using 128 directly, it means using pairwise-frcnn 92 | # net = slim.dropout(net, dropout_keep_prob, is_training=is_training, scope='dropout_cls') 93 | net = slim.conv2d(net, 1024, [3, 3], padding='SAME', scope='conv3x3') 94 | net = slim.dropout(net, dropout_keep_prob, is_training=is_training, scope='dropout_cls') 95 | net = slim.conv2d(net, 128, [3, 3], padding='VALID', scope='conv1x1_2') 96 | net = slim.dropout(net, dropout_keep_prob, is_training=is_training, scope='dropout_cls') 97 | net = slim.conv2d(net, 1, [1, 1], padding='SAME', scope='conv1x1_1') 98 | end_points[end_point] = net 99 | cls = tf.squeeze(net, [1, 2], name='squeezed_cls') 100 | cls = tf.reshape(cls, [1, -1]) 101 | else: 102 | cls = None 103 | 104 | if bbox_regression: 105 | #todo: assume the batch size is 1 106 | end_point = 'bbox_regression' 107 | with tf.variable_scope(end_point): 108 | net = end_points['block8'] 109 | net = tf.image.resize_images(net, [32, 32]) 110 | rois_yxyx = rois[:, [1, 0, 3, 2]] 111 | net = tf.image.crop_and_resize(net, boxes=rois_yxyx, crop_size=[3,3], box_ind=tf.zeros(shape=[num_classes], dtype=tf.int32)) 112 | # net = slim.conv2d(net, 1024, [3, 3], padding='SAME', scope='conv3x3') 113 | # net = slim.dropout(net, dropout_keep_prob, is_training=is_training, scope='dropout_breg') 114 | net = slim.conv2d(net, 128, [3, 3], padding='VALID', scope='conv1x1_2') 115 | # net = slim.dropout(net, dropout_keep_prob, is_training=is_training, scope='dropout_breg') 116 | net = slim.conv2d(net, 4, [1, 1], padding='SAME', scope='conv1x1_1') 117 | end_points[end_point] = net 118 | regress = tf.squeeze(net, [1, 2], name='squeezed_regress') 119 | else: 120 | regress = None 121 | 122 | return prediction, cls, regress, end_points 123 | 124 | 125 | def swap_correct(logits, labels, batch_size, n_anchors=895, scope=None): 126 | with tf.variable_scope(scope, 'swap_correct'): 127 | logits_offset0 = logits[:, 0:n_anchors-1] 128 | logits_offset1 = logits[:, 1:n_anchors] 129 | 130 | labels_offset0 = labels[:, 0:n_anchors-1] 131 | labels_offset1 = labels[:, 1:n_anchors] 132 | 133 | logits_diff = logits_offset0 - logits_offset1 134 | labels_diff = labels_offset0 - labels_offset1 135 | 136 | correct_mask = tf.greater(tf.multiply(logits_diff, labels_diff), 0) 137 | n_corrects = tf.reduce_sum(tf.cast(correct_mask, tf.float32)) 138 | avg_correct = n_corrects / n_anchors / batch_size 139 | 140 | return avg_correct 141 | 142 | 143 | def mean_pairwise_squared_error(logits, gclasses, alpha=1., scope=None): 144 | """continious pairwise loss: 145 | """ 146 | with tf.variable_scope(scope, 'mean_pairwise_square_error'): 147 | total_loss = tf.losses.mean_pairwise_squared_error(gclasses, logits, weights=alpha) 148 | return total_loss 149 | 150 | 151 | def bbox_reg_loss(pred_xywh, labels, anchor_xywh, nearest_xywh): 152 | pred_xy = pred_xywh[:, 0:2] 153 | pred_wh = pred_xywh[:, 2:4] 154 | sig_pred_xy = tf.sigmoid(pred_xy) 155 | exp_pred_wh = tf.exp(pred_wh) 156 | anchor_xy = anchor_xywh[:, 0:2] 157 | anchor_wh = anchor_xywh[:, 2:4] 158 | nearest_xy = nearest_xywh[:, 0:2] 159 | nearest_wh = nearest_xywh[:, 2:4] 160 | diff_xy = sig_pred_xy - 0.5 + anchor_xy - nearest_xy 161 | diff_wh = exp_pred_wh - nearest_wh / anchor_wh 162 | loss = tf.multiply(tf.reduce_sum(abs_smooth(diff_xy), 1, keep_dims=True) + tf.reduce_sum(abs_smooth(diff_wh), 1, keep_dims=True), labels) 163 | 164 | return tf.reduce_sum(loss) 165 | 166 | 167 | def abs_smooth(x): 168 | """Smoothed absolute function. Useful to compute an L1 smooth error. 169 | Define as: 170 | x^2 / 2 if abs(x) < 1 171 | abs(x) - 0.5 if abs(x) > 1 172 | We use here a differentiable definition using min(x) and abs(x). Clearly 173 | not optimal, but good enough for our purpose! 174 | """ 175 | absx = tf.abs(x) 176 | minx = tf.minimum(absx, 1) 177 | r = 0.5 * ((absx - 1) * minx + absx) 178 | return r 179 | 180 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # View Proposal Net 2 | 3 | ## Requirements: 4 | This implementation is tested on ```Tensorflow 1.3```. 5 | 6 | For viewing results using ```view_results.py```, you will need ```matplotlib``` 7 | 8 | 9 | ## Qucik Start 10 | 11 | VPN is demonstrated in ```demo_new.py```. Before running, update the following: 12 | 13 | 1. Update the image directory to load images. 14 | 2. Download the pre-trained models from [Google Drive][downloadId]. Set the variable ```model_weight_path``` to point to it. 15 | 16 | 17 | [downloadId]:https://drive.google.com/open?id=1IXBtvwn8fMCmDRczQExIR3ZSDhinoqbi 18 | 19 | ## Train your own model 20 | We will release the training code soon. 21 | 22 | 23 | 27 | -------------------------------------------------------------------------------- /datasets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zijunwei/ViewProposalNet/68111337fa47f1ba38cb71d5147fabbf39f1db24/datasets/__init__.py -------------------------------------------------------------------------------- /datasets/custom_transforms.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import torch 3 | import math 4 | import random 5 | from PIL import Image, ImageOps 6 | import numpy as np 7 | import numbers 8 | import types 9 | from torchvision import transforms 10 | import matplotlib.pyplot as plt 11 | 12 | 13 | def show(img): 14 | npimg = img.numpy() 15 | plt.imshow(np.transpose(npimg, (1,2,0)), interpolation='nearest') 16 | 17 | 18 | class PIL2Numpy(object): 19 | """Convert PIL image to Numpy 20 | """ 21 | def __init__(self): 22 | pass 23 | 24 | def __call__(self, pil_image): 25 | return np.array(pil_image) 26 | 27 | class Resize(object): 28 | def __init__(self, w=224, h=224, interpolation=Image.BILINEAR): 29 | self.w = w 30 | self.h = h 31 | self.interpolation = interpolation 32 | def __call__(self, image): 33 | return image.resize((self.w, self.h), self.interpolation) 34 | 35 | 36 | class RandomOrder(object): 37 | def __init__(self): 38 | pass 39 | 40 | def __call__(self, pil_image): 41 | np_image = np.array(pil_image) 42 | 43 | random_num = random.randint(0, 5) 44 | if random_num == 0: 45 | np_image = np_image[:,:,(0, 1, 2)] 46 | if random_num == 1: 47 | np_image = np_image[:,:,(0, 2, 1)] 48 | if random_num == 2: 49 | np_image = np_image[:,:,(1, 0, 2)] 50 | if random_num == 3: 51 | np_image = np_image[:,:,(1, 2, 0)] 52 | if random_num == 4: 53 | np_image = np_image[:,:,(2, 1, 0)] 54 | if random_num == 5: 55 | np_image = np_image[:,:,(2, 1, 1)] 56 | 57 | return Image.fromarray(np_image) 58 | 59 | 60 | class RandomGray(object): 61 | def __init__(self, gray_rate=0.2): 62 | self.gray_rate = gray_rate 63 | 64 | def __call__(self, pil_image): 65 | random_num = random.uniform(0, 1) 66 | if random_num < self.gray_rate: 67 | pil_image = pil_image.convert('LA').convert('RGB') 68 | return pil_image 69 | 70 | class AddGaussianNoise(object): 71 | """Add gaussian noise to a FloatTensor 72 | """ 73 | 74 | def __init__(self, mean=0, sigma=0.05, random_state=np.random): 75 | self.sigma = sigma 76 | self.mean = mean 77 | self.random_state = random_state 78 | 79 | def __call__(self, image): 80 | c, h, w = image.size() 81 | gaussian = np.random.normal(self.mean, self.sigma, [c, w, h]) 82 | t_gaussian = torch.from_numpy(gaussian) 83 | t_gaussian = t_gaussian.type(torch.FloatTensor) 84 | return image.add_(t_gaussian) 85 | 86 | 87 | def distort_image(im, hue, sat, val): 88 | im = im.convert('HSV') 89 | cs = list(im.split()) 90 | cs[1] = cs[1].point(lambda i: i * sat) 91 | cs[2] = cs[2].point(lambda i: i * val) 92 | 93 | def change_hue(x): 94 | x += hue * 255 95 | if x > 255: 96 | x -= 255 97 | if x < 0: 98 | x += 255 99 | return x 100 | 101 | cs[0] = cs[0].point(change_hue) 102 | im = Image.merge(im.mode, tuple(cs)) 103 | 104 | im = im.convert('RGB') 105 | # constrain_image(im) 106 | return im 107 | 108 | 109 | def random_in_scale(s): 110 | return random.uniform(1-s, 1+s) 111 | 112 | 113 | class RandomDistortColor(object): 114 | def __init__(self, hue=0.1, sat=0.1, val=0.1): 115 | self.hue = hue 116 | self.sat = sat 117 | self.val = val 118 | 119 | def __call__(self, image): 120 | r_hue = random.uniform(-self.hue, self.hue) 121 | r_sat = random_in_scale(self.sat) 122 | r_val = random_in_scale(self.val) 123 | return distort_image(image, r_hue, r_sat, r_val) 124 | 125 | 126 | class RandomCrop(object): 127 | """Crops the given PIL.Image at a random location to have a region of 128 | the given size. size can be a tuple (target_width, target_height) 129 | or an integer, in which case the target will be of a square shape (size, size) 130 | """ 131 | 132 | def __init__(self, min_th, max_th): 133 | self.min_th = min_th 134 | self.max_th = max_th 135 | 136 | def __call__(self, img): 137 | scale_x = random.uniform(self.min_th, self.max_th) 138 | scale_y = random.uniform(self.min_th, self.max_th) 139 | shift_x = random.random() * (1 - scale_x) 140 | shift_y = random.random() * (1 - scale_y) 141 | w, h = img.size 142 | x1 = int(shift_x * w) 143 | y1 = int(shift_y * h) 144 | x2 = int((shift_x + scale_x) * w) 145 | y2 = int((shift_y + scale_y) * h) 146 | return img.crop((x1, y1, x2, y2)) 147 | 148 | 149 | # class RandomScale(object): 150 | # 151 | # def __init__(self, preset_size=None, interpolation=Image.BILINEAR): 152 | # self.interpolation = interpolation 153 | # self.preset = False 154 | # if preset_size is not None: 155 | # self.raw_w = preset_size 156 | # self.raw_h = preset_size 157 | # self.preset = True 158 | # 159 | # def __call__(self, img): 160 | # if self.preset: 161 | # raw_w = self.raw_w 162 | # raw_h = self.raw_h 163 | # else: 164 | # raw_w, raw_h = img.size 165 | # 166 | # scale_x = random.uniform(0.5, 1.5) 167 | # scale_y = random.uniform(0.5, 1.5) 168 | # new_w = int(raw_w * scale_x) 169 | # new_h = int(raw_h * scale_y) 170 | # 171 | # img = img.resize((new_w, new_h), self.interpolation) 172 | # img = img.resize((raw_w, raw_h), self.interpolation) 173 | # 174 | # return img 175 | 176 | 177 | class RandomScale(object): 178 | """Compared to v1 no longer scale back""" 179 | def __init__(self, preset_size=None, random_range=0.5, interpolation=Image.BILINEAR): 180 | self.interpolation = interpolation 181 | self.preset = False 182 | if preset_size is not None: 183 | self.new_w = preset_size 184 | self.new_h = preset_size 185 | self.preset = True 186 | self.random_range = random_range 187 | 188 | def __call__(self, img): 189 | if self.preset: 190 | new_w = self.new_w 191 | new_h = self.new_h 192 | else: 193 | new_w, new_h = img.size 194 | 195 | scale_x = random.uniform(1 - self.random_range, 1 + self.random_range) 196 | scale_y = random.uniform(1 - self.random_range, 1 + self.random_range) 197 | new_w = int(new_w * scale_x) 198 | new_h = int(new_h * scale_y) 199 | 200 | img = img.resize((new_w, new_h), self.interpolation) 201 | 202 | return img 203 | 204 | 205 | class Lighting(object): 206 | """Lighting noise(AlexNet - style PCA - based noise)""" 207 | 208 | def __init__(self, alphastd, eigval, eigvec): 209 | self.alphastd = alphastd 210 | self.eigval = eigval 211 | self.eigvec = eigvec 212 | 213 | def __call__(self, img): 214 | if self.alphastd == 0: 215 | return img 216 | 217 | alpha = img.new().resize_(3).normal_(0, self.alphastd) 218 | rgb = self.eigvec.type_as(img).clone()\ 219 | .mul(alpha.view(1, 3).expand(3, 3))\ 220 | .mul(self.eigval.view(1, 3).expand(3, 3))\ 221 | .sum(1).squeeze() 222 | 223 | return img.add(rgb.view(3, 1, 1).expand_as(img)) 224 | 225 | class Grayscale(object): 226 | 227 | def __call__(self, img): 228 | gs = img.clone() 229 | gs[0].mul_(0.299).add_(0.587, gs[1]).add_(0.114, gs[2]) 230 | gs[1].copy_(gs[0]) 231 | gs[2].copy_(gs[0]) 232 | return gs 233 | 234 | 235 | class Saturation(object): 236 | 237 | def __init__(self, var): 238 | self.var = var 239 | 240 | def __call__(self, img): 241 | gs = Grayscale()(img) 242 | alpha = random.uniform(0, self.var) 243 | return img.lerp(gs, alpha) 244 | 245 | 246 | class Brightness(object): 247 | 248 | def __init__(self, var): 249 | self.var = var 250 | 251 | def __call__(self, img): 252 | gs = img.new().resize_as_(img).zero_() 253 | alpha = random.uniform(0, self.var) 254 | return img.lerp(gs, alpha) 255 | 256 | 257 | class Contrast(object): 258 | 259 | def __init__(self, var): 260 | self.var = var 261 | 262 | def __call__(self, img): 263 | gs = Grayscale()(img) 264 | gs.fill_(gs.mean()) 265 | alpha = random.uniform(0, self.var) 266 | return img.lerp(gs, alpha) 267 | 268 | 269 | class RandomOrderTransform(object): 270 | """ Composes several transforms together in random order. 271 | """ 272 | 273 | def __init__(self, transforms): 274 | self.transforms = transforms 275 | 276 | def __call__(self, img): 277 | if self.transforms is None: 278 | return img 279 | order = torch.randperm(len(self.transforms)) 280 | for i in order: 281 | img = self.transforms[i](img) 282 | return img 283 | 284 | 285 | class ColorJitter(RandomOrderTransform): 286 | 287 | def __init__(self, brightness=0.4, contrast=0.4, saturation=0.4): 288 | self.transforms = [] 289 | if brightness != 0: 290 | self.transforms.append(Brightness(brightness)) 291 | if contrast != 0: 292 | self.transforms.append(Contrast(contrast)) 293 | if saturation != 0: 294 | self.transforms.append(Saturation(saturation)) 295 | 296 | 297 | class MinScale(object): 298 | """Rescale the input PIL.Image to the given size. 299 | 300 | Args: 301 | size (sequence or int): Desired output size. If size is a sequence like 302 | (w, h), output size will be matched to this. If size is an int, 303 | smaller edge of the image will be matched to this number. 304 | i.e, if height > width, then image will be rescaled to 305 | (size * height / width, size) 306 | interpolation (int, optional): Desired interpolation. Default is 307 | ``PIL.Image.BILINEAR`` 308 | """ 309 | 310 | def __init__(self, size, interpolation=Image.BILINEAR): 311 | assert isinstance(size, int) or (isinstance(size, collections.Iterable) and len(size) == 2) 312 | self.size = size 313 | self.interpolation = interpolation 314 | 315 | def __call__(self, img): 316 | """ 317 | Args: 318 | img (PIL.Image): Image to be scaled. 319 | 320 | Returns: 321 | PIL.Image: Rescaled image. 322 | """ 323 | if isinstance(self.size, int): 324 | w, h = img.size 325 | if (w <= h and w >= self.size) or (h <= w and h >= self.size): 326 | return img 327 | if w < h: 328 | ow = self.size 329 | oh = int(self.size * h / w) 330 | return img.resize((ow, oh), self.interpolation) 331 | else: 332 | oh = self.size 333 | ow = int(self.size * w / h) 334 | return img.resize((ow, oh), self.interpolation) 335 | else: 336 | return img.resize(self.size, self.interpolation) 337 | 338 | 339 | if __name__ == '__main__': 340 | image = Image.open('/Users/zwei/Dev/adobe_pytorch/image/img1.jpg').convert('RGB') 341 | # random_gray = RandomGray(0.5) 342 | # output_image = random_gray(image) 343 | # image_tensor = transforms.ToTensor()(image) 344 | # addGaussian = AddGaussianNoise() 345 | # output_image = addGaussian(image_tensor) 346 | print "DB" 347 | -------------------------------------------------------------------------------- /datasets/proposal_data_transforms.py: -------------------------------------------------------------------------------- 1 | from datasets import custom_transforms 2 | from torchvision import transforms 3 | 4 | 5 | def get_val_transform(image_size=320): 6 | transform = transforms.Compose([ 7 | custom_transforms.Resize(w=image_size, h=image_size), 8 | transforms.ToTensor(), 9 | transforms.Normalize(mean=[0.485, 0.456, 0.406], 10 | std=[1.0, 1.0, 1.0]) 11 | ]) 12 | return transform 13 | 14 | 15 | -------------------------------------------------------------------------------- /demo_new.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.append((os.path.dirname(__file__))) 4 | import tensorflow as tf 5 | import numpy as np 6 | import tensorflow.contrib.slim as slim 7 | import Network 8 | flags = tf.app.flags 9 | from py_utils import bboxes as boxes 10 | import project_utils 11 | import datasets.proposal_data_transforms as transforms 12 | from py_utils import file_utils, load_utils 13 | from tf_utils import utils as tf_utils 14 | # import progressbar 15 | import glob 16 | 17 | 18 | def main(argv=None): 19 | gpu_id = 0 20 | test_image_directory = './example_images' 21 | image_format = 'jpg' 22 | image_list = glob.glob(os.path.join(test_image_directory, '*.{:s}'.format(image_format))) 23 | image_list.sort() 24 | result_save_directory = 'ProposalResults' 25 | save_file = os.path.join(result_save_directory, 'ViewProposalResults-tmp.txt') 26 | anchors = project_utils.get_pdefined_anchors(anchor_file='datasets/pdefined_anchor.pkl') 27 | model_weight_path = './pretrained/ProposalNet/VPN' 28 | 29 | # Machine Learning Cores: 30 | data_transform = transforms.get_val_transform(image_size=320) 31 | 32 | 33 | with tf.Graph().as_default(): 34 | # not using batch yet 35 | with tf.variable_scope('inputs'): 36 | tf_image = tf.placeholder(dtype=tf.float32, shape=[1, None, None, 3], name='image_input') 37 | 38 | p_logits, _, _, _ = Network.base_net(tf_image, num_classes=len(anchors), rois=None, is_training=False, bbox_regression=False) 39 | 40 | init_fn = slim.assign_from_checkpoint_fn( 41 | model_weight_path, 42 | slim.get_model_variables(), ignore_missing_vars=True) # set to true to avoid the incompatibal ones 43 | 44 | 45 | config = tf_utils.gpu_config(gpu_id=gpu_id) 46 | image_annotation = {} 47 | 48 | with tf.Session(config=config) as sess: 49 | sess.run(tf.global_variables_initializer()) 50 | init_fn(sess) 51 | # pbar = progressbar.ProgressBar(max_value=len(image_list)) 52 | for id, s_image_path in enumerate(image_list): 53 | s_image_name = os.path.basename(s_image_path) 54 | # pbar.update(id) 55 | s_image = file_utils.default_image_loader(s_image_path) 56 | s_image_width, s_image_height = s_image.size 57 | 58 | s_image_tensor = data_transform(s_image) 59 | s_image_tensor = s_image_tensor.unsqueeze(0) 60 | s_image_np = np.transpose(s_image_tensor.numpy() * 256, [0, 2, 3, 1]) 61 | 62 | rpn_ = sess.run(p_logits, 63 | feed_dict={tf_image: s_image_np}) 64 | logits = rpn_[0] 65 | s_bboxes = [] 66 | 67 | for anchor_idx, s_anchor in enumerate(anchors): 68 | s_bbox = s_anchor[0:4] 69 | 70 | s_bboxes.append([int(s_bbox[0]*s_image_width), int(s_bbox[1]*s_image_height), 71 | int(s_bbox[2]*s_image_width), int(s_bbox[3]*s_image_height)]) 72 | 73 | scores_selected, bboxes_selected = boxes.sortNMSBBoxes(logits, s_bboxes, NMS_thres=0.6)#TODO: This is a tunable parameter 74 | 75 | # TODO: only keep Top5 76 | topN = 5 77 | pick_n = min(topN, len(scores_selected)) 78 | image_annotation[s_image_name] = {} 79 | image_annotation[s_image_name]['scores'] = scores_selected[0:pick_n] 80 | image_annotation[s_image_name]['bboxes'] = bboxes_selected[0:pick_n] 81 | print "Done Computing, saving to {:s}".format(save_file) 82 | load_utils.save_json(image_annotation, save_file) 83 | if __name__ == '__main__': 84 | tf.app.run() -------------------------------------------------------------------------------- /example_images/farm1_100_276822098_cbe498842d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zijunwei/ViewProposalNet/68111337fa47f1ba38cb71d5147fabbf39f1db24/example_images/farm1_100_276822098_cbe498842d.jpg -------------------------------------------------------------------------------- /example_images/farm1_104_273169537_7227f34eed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zijunwei/ViewProposalNet/68111337fa47f1ba38cb71d5147fabbf39f1db24/example_images/farm1_104_273169537_7227f34eed.jpg -------------------------------------------------------------------------------- /example_images/farm1_12_16181736_f6db921ae0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zijunwei/ViewProposalNet/68111337fa47f1ba38cb71d5147fabbf39f1db24/example_images/farm1_12_16181736_f6db921ae0.jpg -------------------------------------------------------------------------------- /example_images/farm1_158_332074945_ef8b72bb83.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zijunwei/ViewProposalNet/68111337fa47f1ba38cb71d5147fabbf39f1db24/example_images/farm1_158_332074945_ef8b72bb83.jpg -------------------------------------------------------------------------------- /example_images/farm1_159_341058164_555a9dd582.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zijunwei/ViewProposalNet/68111337fa47f1ba38cb71d5147fabbf39f1db24/example_images/farm1_159_341058164_555a9dd582.jpg -------------------------------------------------------------------------------- /example_images/farm1_161_360215948_4ed3ff39f6_b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zijunwei/ViewProposalNet/68111337fa47f1ba38cb71d5147fabbf39f1db24/example_images/farm1_161_360215948_4ed3ff39f6_b.jpg -------------------------------------------------------------------------------- /project_utils.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import pickle 3 | import numpy as np 4 | 5 | 6 | def get_pdefined_anchors(anchor_file): 7 | anchors = pickle.load(open(anchor_file, 'rb')) 8 | anchors = np.array(anchors) 9 | return anchors 10 | 11 | 12 | # def get_pdefined_anchors(): 13 | # cur_path = os.path.dirname(os.path.realpath(__file__)) 14 | # anchors = pickle.load(open(os.path.join(cur_path, 'params/pdefined_anchor.pkl'), 'rb')) 15 | # anchors = np.array(anchors) 16 | # return anchors 17 | # 18 | # def get_pdefined_anchors_xywh(): 19 | # anchors = get_pdefined_anchors() 20 | # anchors_xywh = [] 21 | # for s_anchor in anchors: 22 | # s_anchor_xywh = [s_anchor[0], s_anchor[1], s_anchor[2]-s_anchor[0], s_anchor[3]-s_anchor[1], s_anchor[4]] 23 | # anchors_xywh.append(s_anchor_xywh) 24 | # 25 | # anchors_xywh = np.array(anchors_xywh) 26 | # return anchors_xywh 27 | 28 | 29 | if __name__ == '__main__': 30 | anchors = get_pdefined_anchors_xywh() 31 | print "DEBUG" -------------------------------------------------------------------------------- /py_utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zijunwei/ViewProposalNet/68111337fa47f1ba38cb71d5147fabbf39f1db24/py_utils/__init__.py -------------------------------------------------------------------------------- /py_utils/bboxes.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def bboxes_jaccard(bboxes1, bboxes2): 4 | """Computing jaccard index (IOU) between bboxes1 and bboxes2. 5 | Note: bboxes1 and bboxes2 can be multi-dimensional, but should broacastable. 6 | """ 7 | if isinstance(bboxes1, (tuple, list)): 8 | bboxes1 = np.array(bboxes1) 9 | if isinstance(bboxes2, (tuple, list)): 10 | bboxes2 = np.array(bboxes2) 11 | 12 | bboxes1 = np.transpose(bboxes1) 13 | bboxes2 = np.transpose(bboxes2) 14 | # Intersection bbox and volume. 15 | int_ymin = np.maximum(bboxes1[0], bboxes2[0]) 16 | int_xmin = np.maximum(bboxes1[1], bboxes2[1]) 17 | int_ymax = np.minimum(bboxes1[2], bboxes2[2]) 18 | int_xmax = np.minimum(bboxes1[3], bboxes2[3]) 19 | 20 | int_h = np.maximum(int_ymax - int_ymin, 0.) 21 | int_w = np.maximum(int_xmax - int_xmin, 0.) 22 | int_vol = int_h * int_w 23 | # Union volume. 24 | vol1 = (bboxes1[2] - bboxes1[0]) * (bboxes1[3] - bboxes1[1]) 25 | vol2 = (bboxes2[2] - bboxes2[0]) * (bboxes2[3] - bboxes2[1]) 26 | jaccard = int_vol / (vol1 + vol2 - int_vol) 27 | return jaccard 28 | 29 | 30 | def bboxes_intersection(bboxes_ref, bboxes2): 31 | """Computing interset(bboxes2, bboxes_ref) / area(bboxex_ref). 32 | Note: bboxes1 and bboxes2 can be multi-dimensional, but should broacastable. 33 | 34 | """ 35 | # if isinstance(bboxes_ref, (list, tuple)): 36 | # bboxes_ref = np.array(bboxes_ref) 37 | # if isinstance(bboxes2, (list, tuple)): 38 | # bboxes2 = np.array(bboxes2) 39 | bboxes_ref = np.transpose(bboxes_ref) 40 | bboxes2 = np.transpose(bboxes2) 41 | # Intersection bbox and volume. 42 | int_ymin = np.maximum(bboxes_ref[0], bboxes2[0]) 43 | int_xmin = np.maximum(bboxes_ref[1], bboxes2[1]) 44 | int_ymax = np.minimum(bboxes_ref[2], bboxes2[2]) 45 | int_xmax = np.minimum(bboxes_ref[3], bboxes2[3]) 46 | 47 | int_h = np.maximum(int_ymax - int_ymin, 0.) 48 | int_w = np.maximum(int_xmax - int_xmin, 0.) 49 | int_vol = int_h * int_w 50 | # Union volume. 51 | vol = (bboxes_ref[2] - bboxes_ref[0]) * (bboxes_ref[3] - bboxes_ref[1]) 52 | score = int_vol / vol 53 | return score 54 | 55 | 56 | def bboxes_nms_multiclass(classes, scores, bboxes, nms_threshold=0.45): 57 | """Apply non-maximum selection to bounding boxes. 58 | """ 59 | keep_bboxes = np.ones(scores.shape, dtype=np.bool) 60 | for i in range(scores.size-1): 61 | if keep_bboxes[i]: 62 | # Computer overlap with bboxes which are following. 63 | overlap = bboxes_jaccard(bboxes[i], bboxes[(i+1):]) 64 | # Overlap threshold for keeping + checking part of the same class 65 | keep_overlap = np.logical_or(overlap < nms_threshold, classes[(i+1):] != classes[i]) 66 | keep_bboxes[(i+1):] = np.logical_and(keep_bboxes[(i+1):], keep_overlap) 67 | 68 | idxes = np.where(keep_bboxes) 69 | return classes[idxes], scores[idxes], bboxes[idxes] 70 | 71 | 72 | def bboxes_nms(scores, bboxes, nms_threshold=0.45): 73 | """Apply non-maximum selection to bounding boxes. 74 | """ 75 | if isinstance(scores, list): 76 | scores = np.array(scores) 77 | 78 | if isinstance(bboxes, list): 79 | bboxes = np.array(bboxes) 80 | 81 | keep_bboxes = np.ones(len(scores), dtype=np.bool) 82 | for i in range(len(scores)-1): 83 | if keep_bboxes[i]: 84 | # Computer overlap with bboxes which are following. 85 | overlap = bboxes_jaccard(bboxes[i], bboxes[(i+1):]) 86 | # Overlap threshold for keeping + checking part of the same class 87 | keep_overlap = (overlap < nms_threshold) 88 | keep_bboxes[(i+1):] = np.logical_and(keep_bboxes[(i+1):], keep_overlap) 89 | 90 | idxes = np.where(keep_bboxes) 91 | return scores[idxes].tolist(), bboxes[idxes].tolist(), idxes 92 | 93 | 94 | def sortNMSBBoxes(score_list, bboxes_list, NMS_thres=0.65, keepN=20): 95 | if isinstance(score_list, (list, tuple)): 96 | score_list = np.array(score_list) 97 | sorted_idx = np.argsort(-score_list) 98 | sorted_bboxes = [bboxes_list[i] for i in sorted_idx] 99 | sorted_scores = [score_list[i] for i in sorted_idx] 100 | s_scores_nms, s_bboxes_nms, _ = bboxes_nms(sorted_scores, sorted_bboxes, nms_threshold=NMS_thres) 101 | if keepN is not None: 102 | pick_n = min(keepN, len(s_scores_nms)) 103 | else: 104 | pick_n = len(s_scores_nms) 105 | return s_scores_nms[0:pick_n], s_bboxes_nms[0:pick_n] -------------------------------------------------------------------------------- /py_utils/dir_utils.py: -------------------------------------------------------------------------------- 1 | # Shrinked and adapted from z_utils.py 2 | import os 3 | import shutil 4 | import sys 5 | from datetime import datetime 6 | 7 | 8 | def get_date_str(): 9 | """ 10 | @return: A string representing the current date/time that can be used as a directory name. 11 | """ 12 | return str(datetime.now()).replace(' ', '-').replace(':', '-').replace('.', '-')[:-7] 13 | 14 | 15 | def get_dir(directory): 16 | """ 17 | Creates the given directory if it does not exist. 18 | 19 | @param directory: The path to the directory. 20 | @return: The path to the directory. 21 | """ 22 | if not os.path.exists(directory): 23 | os.makedirs(directory) 24 | return directory 25 | 26 | 27 | def clear_dir(directory): 28 | """ 29 | Removes all files in the given directory. 30 | 31 | @param directory: The path to the directory. 32 | """ 33 | for f in os.listdir(directory): 34 | path = os.path.join(directory, f) 35 | try: 36 | if os.path.isfile(path): 37 | os.unlink(path) 38 | elif os.path.isdir(path): 39 | shutil.rmtree(path) 40 | except Exception as e: 41 | print(e) 42 | 43 | 44 | class save_places: 45 | def __init__(self, dir_name): 46 | self.save_dir = get_dir(dir_name) 47 | 48 | self.model_save_dir = get_dir(os.path.join(self.save_dir, 'models')) 49 | self.summary_save_dir = get_dir(os.path.join(self.save_dir, 'summaries')) 50 | self.image_save_dir = get_dir(os.path.join(self.save_dir, 'images')) 51 | self.log_save_dir = get_dir(os.path.join(self.save_dir, 'logs')) 52 | 53 | def clear_save_name(self): 54 | """ 55 | Clears all saved content for SAVE_NAME. 56 | """ 57 | clear_dir(self.model_save_dir) 58 | clear_dir(self.summary_save_dir) 59 | clear_dir(self.log_save_dir) 60 | clear_dir(self.image_save_dir) 61 | print ('Clear stuff in {}'.format(os.path.join(self.save_dir))) 62 | 63 | -------------------------------------------------------------------------------- /py_utils/file_utils.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import glob 3 | from PIL import Image 4 | import progressbar 5 | 6 | def get_file_list(image_dir, file_format='jpg'): 7 | file_list = glob.glob(os.path.join(image_dir, '*.{:s}'.format(file_format))) 8 | return file_list 9 | 10 | 11 | def default_image_loader(path): 12 | return Image.open(path).convert('RGB') 13 | 14 | def verify_image_list(image_list, attemptOpen=False, image_loader=default_image_loader, verbose=False): 15 | verified_image_list = [] 16 | if verbose: 17 | pbar = progressbar.ProgressBar(max_value=len(image_list)) 18 | 19 | for i, s_image_path in enumerate(image_list): 20 | if verbose: 21 | pbar.update(i) 22 | if os.path.isfile(s_image_path): 23 | if attemptOpen: 24 | try: 25 | image_loader(s_image_path) 26 | verified_image_list.append(s_image_path) 27 | except: 28 | print "Cannot Load {:s}".format(s_image_path) 29 | else: 30 | verified_image_list.append(s_image_path) 31 | else: 32 | print "Image Not Exist: {:s}".format(s_image_path) 33 | return verified_image_list -------------------------------------------------------------------------------- /py_utils/generate_SlideWindow.py: -------------------------------------------------------------------------------- 1 | import math 2 | from py_utils import load_utils 3 | # generate candidate crops following: 4 | # https://arxiv.org/pdf/1701.01480.pdf 5 | # with the following difference: 6 | # this is no longer 5 * 5 grid, instead we first of all find the smaller size offset, and make sure the step is larger than 10 pixel 7 | # and slide over 8 | def generateCandidateCrops_M(image_size, include_orig=True): 9 | h, w = image_size 10 | min_gridsize = 5 11 | if include_orig: 12 | scales = [x / 10. for x in range(5, 11)] 13 | else: 14 | scales = [x / 10. for x in range(5, 10)] 15 | 16 | image_aspect_ratio = w * 1./ h 17 | aspect_ratios = [1., 3./2, 3./4, 4./3, 2./3, 16./9, 9./16, image_aspect_ratio] 18 | 19 | #round off aspect ratios to 2 digits 20 | aspect_ratios = [ round(i * 100) * 1. / 100 for i in aspect_ratios] 21 | # aspect_ratios = list(set(aspect_ratios)) 22 | 23 | xyxys = [] 24 | for s_scale in scales: 25 | for s_aspect_ratio in aspect_ratios: 26 | scaled_size = math.sqrt(w * h) * s_scale 27 | new_w = int(scaled_size * math.sqrt(s_aspect_ratio)) 28 | new_h = int(scaled_size / math.sqrt(s_aspect_ratio)) 29 | if new_h > h or new_w > w: 30 | continue 31 | 32 | offset_x = ( (w - new_w) / (min_gridsize - 1)) 33 | offset_y = ( (h - new_h) / (min_gridsize - 1)) 34 | 35 | #incase there is no offsest at all. if this is 1, then there might be situations that too many 36 | min_offset = max(20, min(offset_x, offset_y)) 37 | 38 | gridsize_x = int(math.floor((w - new_w) / min_offset) + 2) 39 | gridsize_y = int(math.floor((h - new_h) / min_offset) + 2) 40 | 41 | for idx_x in range(gridsize_x): 42 | for idx_y in range(gridsize_y): 43 | # new_xyxy = [min_offset*idx_x, min_offset*idx_y, min(w, min_offset*idx_x + new_w), min(h, min_offset*idx_y + new_h)] 44 | # not need for the check 45 | # new_xyxy = [min_offset*idx_x, min_offset*idx_y, min_offset*idx_x + new_w, min_offset*idx_y + new_h] 46 | new_xyxy = [min_offset*idx_x, min_offset*idx_y, min(w, min_offset*idx_x + new_w), min(h, min_offset*idx_y + new_h)] 47 | 48 | xyxys.append(new_xyxy) 49 | 50 | return xyxys 51 | 52 | def generateCandidateCropsForEval(image_size, scales=None, include_orig=True): 53 | h, w = image_size 54 | min_gridsize = 5 55 | if scales is None: 56 | if include_orig: 57 | scales = [x / 10. for x in range(5, 11)] 58 | else: 59 | scales = [x / 10. for x in range(5, 10)] 60 | 61 | image_aspect_ratio = w * 1./ h 62 | aspect_ratios = [1., 3./2, 3./4, 4./3, 2./3, 16./9, 9./16, image_aspect_ratio] 63 | 64 | #round off aspect ratios to 2 digits 65 | aspect_ratios = [round(i * 100) * 1. / 100 for i in aspect_ratios] 66 | aspect_ratios = list(set(aspect_ratios)) 67 | 68 | xyxys = [] 69 | for s_scale in scales: 70 | for s_aspect_ratio in aspect_ratios: 71 | scaled_size = math.sqrt(w * h) * s_scale 72 | new_w = int(scaled_size * math.sqrt(s_aspect_ratio)) 73 | new_h = int(scaled_size / math.sqrt(s_aspect_ratio)) 74 | if new_h > h or new_w > w: 75 | continue 76 | 77 | offset_x = ( (w - new_w) / (min_gridsize - 1)) 78 | offset_y = ( (h - new_h) / (min_gridsize - 1)) 79 | 80 | #incase there is no offsest at all. if this is 1, then there might be situations that too many 81 | min_offset = max(20, min(offset_x, offset_y)) 82 | 83 | gridsize_x = int(math.floor((w - new_w) / min_offset) + 2) 84 | gridsize_y = int(math.floor((h - new_h) / min_offset) + 2) 85 | 86 | for idx_x in range(gridsize_x): 87 | for idx_y in range(gridsize_y): 88 | new_xyxy = [min_offset*idx_x, min_offset*idx_y, min(w, min_offset*idx_x + new_w), min(h, min_offset*idx_y + new_h)] 89 | xyxys.append(new_xyxy) 90 | 91 | return xyxys 92 | 93 | 94 | if __name__ == '__main__': 95 | BBOXes = generateCandidateCropsForEval([450, 800], scales=[0.7, 0.8,0.9, 1.0]) 96 | # load_utils.save_num_list(BBOXes, 'debug.txt') 97 | # LoadedBBoxes = load_utils.load_XYXYS_list('debug.txt') 98 | print "Done" -------------------------------------------------------------------------------- /py_utils/load_utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys, os 3 | 4 | # when you're saving to json, make sure you convert dumps first then dump 5 | def load_json(data_file): 6 | with open(data_file, 'r') as df: 7 | json_string = json.load(df) 8 | data = json.loads(json_string) 9 | return data 10 | 11 | 12 | def save_json(json_object, data_file): 13 | with open(data_file, 'w') as df: 14 | json_object_string = json.dumps(json_object) 15 | json.dump(json_object_string, df) 16 | 17 | 18 | def load_string_list(data_file): 19 | with open(data_file, 'r') as df: 20 | loaded_list = [line.strip() for line in df] 21 | 22 | return loaded_list 23 | 24 | 25 | def save_string_list(obj_list, data_file): 26 | with open(data_file, 'w') as df: 27 | for s_object in obj_list: 28 | df.write('{:s}\n'.format(s_object)) 29 | 30 | 31 | def load_XYXY_list(data_file, n_item = 4): 32 | with open(data_file, 'r') as f: 33 | lines = f.readlines() 34 | crops = [] 35 | for s_line in lines: 36 | items = s_line.strip().split(',') 37 | assert len(items) == n_item, 'check file {:s} content'.format(data_file) 38 | s_crop = [int(items[0]), int(items[1]), int(items[2]), int(items[3])] 39 | crops.append(s_crop) 40 | return crops 41 | 42 | 43 | def load_XYXYS_list(data_file, n_item = 5): 44 | with open(data_file, 'r') as f: 45 | lines = f.readlines() 46 | crops = [] 47 | for s_line in lines: 48 | items = s_line.strip().split(',') 49 | assert len(items) == n_item, 'check file {:s} content'.format(data_file) 50 | s_crop = [int(items[0]), int(items[1]), int(items[2]), int(items[3]), float(items[4])] 51 | crops.append(s_crop) 52 | return crops 53 | 54 | 55 | def save_XYXY_list(obj_list, data_file): 56 | with open(data_file, 'w') as df: 57 | for s_object in obj_list: 58 | assert len(s_object)==4, 'Only accepts [x, y, x, y] format' 59 | df.write('{:d},{:d},{:d},{:d}\n'.format(*s_object)) 60 | 61 | 62 | def save_XYXYS_list(obj_list, data_file): 63 | with open(data_file, 'w') as df: 64 | for s_object in obj_list: 65 | assert len(s_object)==5, 'Only accepts [x, y, x, y, s] format' 66 | df.write('{:d},{:d},{:d},{:d},{:.4f}\n'.format(*s_object)) 67 | 68 | 69 | def save_XYXY_S_list(bbox_list, score_list, data_file): 70 | with open(data_file, 'w') as df: 71 | for s_bbox, s_score in zip(bbox_list, score_list): 72 | df.write('{:d},{:d},{:d},{:d},{:.4f}\n'.format(s_bbox[0], s_bbox[1], 73 | s_bbox[2], s_bbox[3], s_score)) 74 | 75 | 76 | def split_XYXYS_list(bboxes_s_list): 77 | bboxes = [] 78 | scores = [] 79 | for s_bbox_s in bboxes_s_list: 80 | assert len(s_bbox_s) == 5, 'Only accepts [x, y, x, y, s] format' 81 | bboxes.append(s_bbox_s[0:4]) 82 | scores.append(s_bbox_s[-1]) 83 | return bboxes, scores 84 | 85 | 86 | def merge_XYXY_S_list(bboxes, scores): 87 | bboxes_s = [] 88 | for (s_bbox, s_score) in zip(bboxes, scores): 89 | s_bbox_s = s_bbox + s_score 90 | bboxes_s.append(s_bbox_s) 91 | 92 | return bboxes_s 93 | 94 | 95 | def save_singlescore_list(score_list, save_file): 96 | """Saving list of scores, each element is saved to a row""" 97 | with open(save_file, 'wb') as f: 98 | for s in score_list: 99 | f.write('{:f}\r\n'.format(s)) 100 | 101 | 102 | def load_singlescore_list(annotation_file): 103 | """Loading a list of scores, each element is saved in a row""" 104 | with open(annotation_file, 'rb') as f: 105 | lines = f.read() 106 | elements = lines.strip().split('\n') 107 | elements = [float(x.strip()) for x in elements] 108 | return elements -------------------------------------------------------------------------------- /tf_utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zijunwei/ViewProposalNet/68111337fa47f1ba38cb71d5147fabbf39f1db24/tf_utils/__init__.py -------------------------------------------------------------------------------- /tf_utils/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | A set of helper functions for tensorflow 3 | """ 4 | import os 5 | import sys 6 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 7 | import tensorflow as tf 8 | 9 | 10 | #gpu_config: 11 | def gpu_config(gpu_id=None): 12 | if gpu_id is not None and gpu_id != -1: 13 | os.environ['CUDA_VISIBLE_DEVICES'] = str(gpu_id) 14 | 15 | config = tf.ConfigProto() 16 | config.gpu_options.allow_growth = True 17 | config.gpu_options.per_process_gpu_memory_fraction = 0.9 18 | config.allow_soft_placement = True 19 | else: 20 | config = tf.ConfigProto() 21 | return config 22 | 23 | 24 | -------------------------------------------------------------------------------- /view_results.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from PIL import Image 4 | 5 | import matplotlib.pyplot as plt 6 | import matplotlib.patches as patches 7 | import numpy as np 8 | import project_utils 9 | # from datasets.get_test_image_list import get_test_list, get_pdefined_anchors, getImagePath 10 | from py_utils import dir_utils, load_utils 11 | 12 | 13 | def viewBBoxes(image_file, bboxes, titles, showImageName=True): 14 | 15 | n_items_per_row = 4 16 | image = Image.open(image_file) 17 | image = np.array(image, dtype=np.uint8) 18 | n_crops = len(bboxes) 19 | n_rows = n_crops // n_items_per_row + 1 20 | 21 | fig = plt.figure(figsize=[20, 20]) 22 | if showImageName: 23 | fig.suptitle(os.path.basename(image_file)) 24 | 25 | for idx, s_bbox in enumerate(bboxes): 26 | ax =fig.add_subplot(n_rows, n_items_per_row, idx+1) 27 | ax.imshow(image) 28 | ax.set_axis_off() 29 | 30 | ax.set_title(titles[idx]) 31 | 32 | rect_i = patches.Rectangle((s_bbox[0], s_bbox[1]), s_bbox[2]-s_bbox[0], s_bbox[3]-s_bbox[1], linewidth=2, edgecolor='yellow', facecolor='none') 33 | # Add the patch to the Axes 34 | ax.add_patch(rect_i) 35 | plt.show(block=False) 36 | raw_input("Press Enter to continue...") 37 | plt.close() 38 | 39 | 40 | 41 | annotation_path = 'ProposalResults/ViewProposalResults-tmp.txt' 42 | image_path_root = '/home/zwei/Dev/CVPR18_release/tmp' 43 | 44 | image_data = load_utils.load_json(annotation_path) 45 | image_name_list = image_data.keys() 46 | image_name_list.sort() 47 | for idx, image_name in enumerate(image_name_list): 48 | if idx<20: 49 | continue 50 | s_image_path = os.path.join(image_path_root, image_name) 51 | bboxes = image_data[image_name]['bboxes'] 52 | scores = image_data[image_name]['scores'] 53 | viewBBoxes(s_image_path, bboxes, scores) 54 | 55 | print "DEBUG" 56 | 57 | --------------------------------------------------------------------------------