def generate_positive_regions(image_dir, bbinfo_dir, modifiers_config=None, window_dims=None, min_size=(48,48)): print 'generate_positive_regions:' all_images = utils.list_images_in_directory(image_dir) # Create the modifier generator: # Note: Simply generate null modifiers if no modifier config is passed. modifier_generator = itertools.repeat(utils.RegionModifiers()) if modifiers_config: modifier_generator = utils.RegionModifiers.random_generator_from_config_dict(modifiers_config) # Filter out images without bounding boxes: bbinfo_map = utils.load_opencv_bounding_box_info_directory(bbinfo_dir, suffix='bbinfo') source_images = [img_path for img_path in all_images if not utils.info_entry_for_image(bbinfo_map, img_path) is None] # Extract image regions: source_regions = [] for img_path in source_images: rects = utils.info_entry_for_image(bbinfo_map, img_path) for rect in rects: # Reject small samples: if rect.w < float(min_size[0]) or rect.h < float(min_size[1]): continue region = utils.ImageRegion(rect, img_path) source_regions.append(region) print 'Found {} source regions.'.format(len(source_regions)) # Generate an infinite list of samples: while True: # Randomise the order of source images: # Note: Don't randomise if no modifiers are used. if modifiers_config: random.shuffle(source_regions) # For each source region: for reg in source_regions: mod = modifier_generator.next() # Enlarge to correct aspect ratio: new_rect = reg.rect if window_dims: aspect = window_dims[0] / float(window_dims[1]) new_rect = new_rect.enlarge_to_aspect(aspect) imsize = utils.get_image_dimensions(reg.fname) if not new_rect.lies_within_frame(imsize): # print 'bad', new_rect continue # else: # print new_rect # Assign a random modifier, and yield the region: new_reg = utils.ImageRegion(new_rect, reg.fname, mod) yield new_reg # If we're not using modifiers, only use each region once: if not modifiers_config: break
def generate_negative_regions_with_exclusions(bak_img_dir, exl_info_map, window_dims, modifiers_config=None): print 'generate_negative_regions_with_exclusions:' all_images = utils.list_images_in_directory(bak_img_dir) if len(all_images) == 0: raise ValueError('The given directory \'{}\' contains no images.'.format(bak_img_dir)) print ' Found {} images.'.format(len(all_images)) all_images = [img_path for img_path in all_images if not utils.info_entry_for_image(exl_info_map, img_path) is None] print ' Found {} images with exclusion info.'.format(len(all_images)) if len(all_images) == 0: raise ValueError('The given directory \'{}\' contains no images with exclusion info.'.format(bak_img_dir)) image_list = all_images random.shuffle(image_list) modifier_generator = itertools.repeat(utils.RegionModifiers()) if modifiers_config: modifier_generator = utils.RegionModifiers.random_generator_from_config_dict(modifiers_config) while True: for img_path in image_list: imsize = utils.get_image_dimensions(img_path) for reg in generate_negative_regions_in_image_with_exclusions(img_path, exl_info_map, window_dims): mod = modifier_generator.next() # Assign a random modifier, and yield the region: new_reg = utils.ImageRegion(reg.rect, reg.fname, mod) yield new_reg # Shuffle the image list: random.shuffle(image_list)
def checkBoundingBoxes(img_paths, bbinfo_dir): global_info = utils.load_opencv_bounding_box_info_directory( bbinfo_dir, suffix='bbinfo') # global_info = loadGlobalInfo(bbinfo_dir) error_occurred = False bad_images = [] warn_images = [] for img_path in img_paths: imsize = None try: im = Image.open(img_path) imsize = im.size im.close() except Exception as e: print "Error opening image {}: {}".format(img_path, e) error_occurred = True continue # Get bounding box: rects = utils.info_entry_for_image(global_info, img_path) for rect in rects: if not rect.touches_frame_edge(imsize): warn_images.append((img_path, rect, imsize)) if not rect.lies_within_frame(imsize): bad_images.append((img_path, rect, imsize)) if warn_images: print """ WARNING: Some bounding boxes touch the image edges. An older version of this script defined bounding boxes differently in which case the case where rect.x + rect.w == img_width would indicate a bounding box extending outside of the image dimensions. The newer KITTI scripts define bounding box size as the true pixel size, making this test indicate a box touching the image edge, which is fine. If the OpenCV scripts fail, this may be the reason. (Uncomment the following line to see the suspicious boxes) """ # pprint(warn_images) if error_occurred or bad_images: print 'EXITING DUE TO INVALID BOUNDING BOXES:' pprint(bad_images) sys.exit(1) assert (False)
def checkBoundingBoxes(img_paths, bbinfo_dir): global_info = utils.load_opencv_bounding_box_info_directory(bbinfo_dir, suffix='bbinfo') # global_info = loadGlobalInfo(bbinfo_dir) error_occurred = False bad_images = [] warn_images = [] for img_path in img_paths: imsize = None try: im = Image.open(img_path) imsize = im.size im.close() except Exception as e: print "Error opening image {}: {}".format(img_path, e) error_occurred = True continue # Get bounding box: rects = utils.info_entry_for_image(global_info, img_path) for rect in rects: if not rect.touches_frame_edge(imsize): warn_images.append((img_path, rect, imsize)) if not rect.lies_within_frame(imsize): bad_images.append((img_path, rect, imsize)) if warn_images: print """ WARNING: Some bounding boxes touch the image edges. An older version of this script defined bounding boxes differently in which case the case where rect.x + rect.w == img_width would indicate a bounding box extending outside of the image dimensions. The newer KITTI scripts define bounding box size as the true pixel size, making this test indicate a box touching the image edge, which is fine. If the OpenCV scripts fail, this may be the reason. (Uncomment the following line to see the suspicious boxes) """ # pprint(warn_images) if error_occurred or bad_images: print 'EXITING DUE TO INVALID BOUNDING BOXES:' pprint(bad_images) sys.exit(1) assert(False)
def write_img(img_path, dat_file, write_bbox=True): rel_img_path = None if os.path.isabs(img_path): rel_img_path = os.path.relpath(img_path, abs_output_dir) else: rel_img_path = os.path.relpath(img_path, output_dir) dat_line = rel_img_path if write_bbox: rects = utils.info_entry_for_image(global_info, img_path) details = ' '.join([' '.join(map(str, rect.opencv_bbox)) for rect in rects]) dat_line = "{} {} {}".format(rel_img_path, len(rects), details) # print 'dat_line:', dat_line dat_file.write(dat_line)
def write_img(img_path, dat_file, write_bbox=True): rel_img_path = None if os.path.isabs(img_path): rel_img_path = os.path.relpath(img_path, abs_output_dir) else: rel_img_path = os.path.relpath(img_path, output_dir) dat_line = rel_img_path if write_bbox: rects = utils.info_entry_for_image(global_info, img_path) details = ' '.join( [' '.join(map(str, rect.opencv_bbox)) for rect in rects]) dat_line = "{} {} {}".format(rel_img_path, len(rects), details) # print 'dat_line:', dat_line dat_file.write(dat_line)
def generate_negative_regions_in_image_with_exclusions(img_path, exl_info_map, window_dims): excl_info = utils.info_entry_for_image(exl_info_map, img_path) # Only consider images with exclusions: if excl_info is None: return imsize = utils.get_image_dimensions(img_path) img_w, img_h = imsize aspect = window_dims[0] / float(window_dims[1]) scale_step = 1.25 window_step = 0.5 max_scale = 0.5 min_w = 64 min_scale = min_w / float(img_w) scale = min_scale # Used to probabilistically reject a fraction of samples at each scale # level. This decreases the difference in the number of samples selected # from each scale level (otherwise, small scale levels would contain an # overwhelmingly large number of sample windows). def accept_sample(curr_scale): f = (curr_scale - min_scale) / (max_scale - min_scale) min_prob = 0.3**0.5 max_prob = 1.0 prob = min_prob*(1-f) + max_prob*(f) return np.random.uniform() < prob*prob # Probability of rejecting samples that are not close to exclusion regions. # (Most images have large portions of sky and ground, and this prevents # oversampling those areas) far_reject_prob = 0.97 num_found = 0 while True: w = int(round(img_w * scale)) h = int(round(img_w * scale / aspect)) sw = int(window_step*w) sh = int(window_step*h) # print 'scale, (w, h), (sw, sh):', scale, (w, h), (sw, sh) if scale > max_scale: return scale *= scale_step count = 0 for x in xrange(0, img_w, sw): for y in xrange(0, img_h, sh): if x + w > img_w or y + h > img_h: break # Randomly reject samples based on scale: if not accept_sample(scale): continue rect = gm.PixelRectangle.from_opencv_bbox([x, y, w, h]) # Nudge rectangles to avoid exclusion regions: intersecting = filter(rect.intersects_pixelrectangle, excl_info) if len(intersecting) == 1: excl = intersecting[0] rect, offset = rect.moved_to_clear(excl, return_offset=True) if abs(offset[0]) >= sw or abs(offset[1]) >= sh: continue rect = rect.translated((0,0), imsize) # Ensure the rectangle does not intersect an exclusion region: if not any((rect.intersects_pixelrectangle(pr) for pr in excl_info)): # Determing whether the rectangle is close to an exclusion # region: is_close_to_exclusion = any((rect.distance_pixelrectangle(pr) < w for pr in excl_info)) # Prefer rectangles that are close to exclusion regions: if not is_close_to_exclusion: if np.random.uniform() < far_reject_prob: continue reg = utils.ImageRegion(rect, img_path) num_found += 1 # import sys # sys.stdout.write(str(num_found) + ',') # sys.stdout.flush() yield reg count += 1