def clip_bboxes_TLBR(bboxes_in, im_width, im_height, warning=True, debug=True): ''' this function clips bboxes inside the image boundary, the coordinates in the clipped bbox are half-included [x, y) parameters: bboxes_in: TLBR format, a list of 4 elements, a listoflist of 4 elements: e.g., [[1,2,3,4], [5,6,7,8]], a numpy array with shape or (N, 4) or (4, ) im_width/im_height: scalar outputs: clipped_bboxes: TLBR format, numpy array with shape of (N, 4) ''' np_bboxes = safe_bbox(bboxes_in, warning=warning, debug=debug) if debug: assert isinteger(im_width) and isinteger( im_height), 'the image width and height are not correct' assert bboxcheck_TLBR(np_bboxes, warning=warning, debug=debug), 'the input bboxes are not good' clipped_bboxes = np.zeros_like(np_bboxes) clipped_bboxes[:, 0] = np.maximum(np.minimum(np_bboxes[:, 0], im_width), 0) # x1 >= 0 & x1 <= width, included clipped_bboxes[:, 1] = np.maximum(np.minimum(np_bboxes[:, 1], im_height), 0) # y1 >= 0 & y1 <= height, included clipped_bboxes[:, 2] = np.maximum(np.minimum(np_bboxes[:, 2], im_width), 0) # x2 >= 0 & x2 <= width, not included clipped_bboxes[:, 3] = np.maximum(np.minimum(np_bboxes[:, 3], im_height), 0) # y2 >= 0 & y2 <= height, not included return clipped_bboxes
def clip_bboxes_TLWH(bboxes_in, im_width, im_height, warning=True, debug=True): ''' this function clips bboxes inside the image boundary parameters: bboxes_in: TLWH format, a list of 4 elements, a listoflist of 4 elements: e.g., [[1,2,3,4], [5,6,7,8]], a numpy array with shape or (N, 4) or (4, ) im_width/im_height: scalar outputs: clipped_bboxes_TLWH: TLWH format, numpy array with shape of (N, 4) ''' np_bboxes = safe_bbox(bboxes_in, warning=warning, debug=debug) if debug: assert isinteger(im_width) and isinteger( im_height), 'the image width and height are not correct' assert bboxcheck_TLWH(np_bboxes, warning=warning, debug=debug), 'the input bboxes are not good' bboxes_TLBR = bbox_TLWH2TLBR(np_bboxes, debug=debug) clipped_bboxes_TLBR = clip_bboxes_TLBR(bboxes_TLBR, im_width, im_height, warning=warning, debug=debug) clipped_bboxes_TLWH = bbox_TLBR2TLWH(clipped_bboxes_TLBR, warning=warning, debug=debug) return clipped_bboxes_TLWH
def image_pad_around(input_image, pad_rect, pad_value=0, warning=True, debug=True): ''' this function is to pad given value to an image in provided region, all images in this function are floating images parameters: input_image: an pil or numpy image pad_rect: a list of 4 non-negative integers, describing how many pixels to pad. The order is [left, top, right, bottom] pad_value: an intger between [0, 255] outputs: img_padded: an uint8 numpy image with padding ''' np_image, _ = safe_image(input_image, warning=warning, debug=debug) if isfloatimage(np_image): np_image = (np_image * 255.).astype('uint8') if len(np_image.shape) == 2: np_image = np.expand_dims(np_image, axis=2) # extend the third channel if the image is grayscale if debug: assert isuintimage(np_image), 'the input image is not an uint8 image' assert isinteger(pad_value) and pad_value >= 0 and pad_value <= 255, 'the pad value should be an integer within [0, 255]' assert islistofnonnegativeinteger(pad_rect) and len(pad_rect) == 4, 'the input pad rect is not a list of 4 non-negative integers' im_height, im_width, im_channel = np_image.shape[0], np_image.shape[1], np_image.shape[2] # calculate the padded size of image pad_left, pad_top, pad_right, pad_bottom = pad_rect[0], pad_rect[1], pad_rect[2], pad_rect[3] new_height = im_height + pad_top + pad_bottom new_width = im_width + pad_left + pad_right # padding img_padded = np.zeros([new_height, new_width, im_channel]).astype('uint8') img_padded.fill(pad_value) img_padded[pad_top : new_height - pad_bottom, pad_left : new_width - pad_right, :] = np_image if img_padded.shape[2] == 1: img_padded = img_padded[:, :, 0] return img_padded
def visualize_nearest_neighbor(featuremap_dict, num_neighbor=5, top_number=5, vis=True, save_csv=False, csv_save_path=None, save_vis=False, save_img=False, save_thumb_name='nearest_neighbor.png', img_src_folder=None, ext_filter='.jpg', nn_save_folder=None, debug=True): ''' visualize nearest neighbor for featuremap from images parameter: featuremap_dict: a dictionary contains image path as key, and featuremap as value, the featuremap needs to be numpy array with any shape. No flatten needed num_neighbor: number of neighbor to visualize, the first nearest is itself top_number: number of top to visualize, since there might be tons of featuremap (length of dictionary), we choose the top ten with lowest distance with their nearest neighbor csv_save_path: path to save .csv file which contains indices and distance array for all elements nn_save_folder: save the nearest neighbor images for top featuremap return: all_sorted_nearest_id: a 2d matrix, each row is a feature followed by its nearest neighbor in whole feature dataset, the column is sorted by the distance of all nearest neighbor each row selected_nearest_id: only top number of sorted nearest id ''' print('processing feature map to nearest neightbor.......') if debug: assert isdict(featuremap_dict), 'featuremap should be dictionary' assert all( isnparray(featuremap_tmp) for featuremap_tmp in featuremap_dict. values()), 'value of dictionary should be numpy array' assert isinteger( num_neighbor ) and num_neighbor > 1, 'number of neighborhodd is an integer larger than 1' if save_csv and csv_save_path is not None: assert is_path_exists_or_creatable( csv_save_path), 'path to save .csv file is not correct' if save_vis or save_img: if nn_save_folder is not None: # save image directly assert isstring(ext_filter), 'extension filter is not correct' assert is_path_exists( img_src_folder), 'source folder for image is not correct' assert all( isstring(path_tmp) for path_tmp in featuremap_dict.keys() ) # key should be the path for the image assert is_path_exists_or_creatable( nn_save_folder ), 'folder to save top visualized images is not correct' assert isstring( save_thumb_name), 'name of thumbnail is not correct' if ext_filter.find('.') == -1: ext_filter = '.%s' % ext_filter # flatten the feature map nn_feature_dict = dict() for key, featuremap_tmp in featuremap_dict.items(): nn_feature_dict[key] = featuremap_tmp.flatten() num_features = len(nn_feature_dict) # nearest neighbor featuremap = np.array(nn_feature_dict.values()) nearbrs = NearestNeighbors(n_neighbors=num_neighbor, algorithm='ball_tree').fit(featuremap) distances, indices = nearbrs.kneighbors(featuremap) if debug: assert featuremap.shape[ 0] == num_features, 'shape of feature map is not correct' assert indices.shape == ( num_features, num_neighbor), 'shape of indices is not correct' assert distances.shape == ( num_features, num_neighbor), 'shape of indices is not correct' # convert the nearest indices for all featuremap to the key accordingly id_list = nn_feature_dict.keys() max_length = len(max( id_list, key=len)) # find the maximum length of string in the key nearest_id = np.chararray(indices.shape, itemsize=max_length + 1) for x in range(nearest_id.shape[0]): for y in range(nearest_id.shape[1]): nearest_id[x, y] = id_list[indices[x, y]] if debug: assert list(nearest_id[:, 0]) == id_list, 'nearest neighbor has problem' # sort the feature based on distance print('sorting the feature based on distance') featuremap_distance = np.sum(distances, axis=1) if debug: assert featuremap_distance.shape == ( num_features, ), 'distance is not correct' sorted_indices = np.argsort(featuremap_distance) all_sorted_nearest_id = nearest_id[sorted_indices, :] # save to the csv file if save_csv and csv_save_path is not None: print('Saving nearest neighbor result as .csv to path: %s' % csv_save_path) with open(csv_save_path, 'w+') as file: np.savetxt(file, distances, delimiter=',', fmt='%f') np.savetxt(file, all_sorted_nearest_id, delimiter=',', fmt='%s') file.close() # choose the best to visualize selected_sorted_indices = sorted_indices[0:top_number] if debug: for i in range(num_features - 1): assert featuremap_distance[ sorted_indices[i]] < featuremap_distance[sorted_indices[ i + 1]], 'feature map is not well sorted based on distance' selected_nearest_id = nearest_id[selected_sorted_indices, :] if save_vis: fig, axarray = plt.subplots(top_number, num_neighbor) for index in range(top_number): for nearest_index in range(num_neighbor): img_path = os.path.join( img_src_folder, '%s%s' % (selected_nearest_id[index, nearest_index], ext_filter)) if debug: print('loading image from %s' % img_path) img = imread(img_path) if isgrayimage_dimension(img): axarray[index, nearest_index].imshow(img, cmap='gray') elif iscolorimage_dimension(img): axarray[index, nearest_index].imshow(img) else: assert False, 'unknown error' axarray[index, nearest_index].axis('off') save_thumb = os.path.join(nn_save_folder, save_thumb_name) fig.savefig(save_thumb) if vis: plt.show() plt.close(fig) # save top visualization to the folder if save_img and nn_save_folder is not None: for top_index in range(top_number): file_list = selected_nearest_id[top_index] save_subfolder = os.path.join(nn_save_folder, file_list[0]) mkdir_if_missing(save_subfolder) for file_tmp in file_list: file_src = os.path.join(img_src_folder, '%s%s' % (file_tmp, ext_filter)) save_path = os.path.join(save_subfolder, '%s%s' % (file_tmp, ext_filter)) if debug: print('saving %s to %s' % (file_src, save_path)) shutil.copyfile(file_src, save_path) return all_sorted_nearest_id, selected_nearest_id
def load_list_from_folder(folder_path, ext_filter=None, depth=1, recursive=False, sort=True, save_path=None, debug=True): ''' load a list of files or folders from a system path parameters: folder_path: root to search ext_filter: a string to represent the extension of files interested depth: maximum depth of folder to search, when it's None, all levels of folders will be searched recursive: False: only return current level True: return all levels till to the input depth outputs: fulllist: a list of elements num_elem: number of the elements ''' folder_path = safepath(folder_path) if debug: assert isfolder( folder_path), 'input folder path is not correct: %s' % folder_path if not is_path_exists(folder_path): return [], 0 if debug: assert islogical( recursive), 'recursive should be a logical variable: {}'.format( recursive) assert depth is None or ( isinteger(depth) and depth >= 1), 'input depth is not correct {}'.format(depth) assert ext_filter is None or (islist(ext_filter) and all( isstring(ext_tmp) for ext_tmp in ext_filter)) or isstring( ext_filter), 'extension filter is not correct' if isstring(ext_filter): # convert to a list ext_filter = [ext_filter] fulllist = list() if depth is None: # find all files recursively recursive = True wildcard_prefix = '**' if ext_filter is not None: for ext_tmp in ext_filter: wildcard = os.path.join(wildcard_prefix, '*' + string2ext_filter(ext_tmp)) curlist = glob2.glob(os.path.join(folder_path, wildcard)) if sort: curlist = sorted(curlist) fulllist += curlist else: wildcard = wildcard_prefix curlist = glob2.glob(os.path.join(folder_path, wildcard)) if sort: curlist = sorted(curlist) fulllist += curlist else: # find files based on depth and recursive flag wildcard_prefix = '*' for index in range(depth - 1): wildcard_prefix = os.path.join(wildcard_prefix, '*') if ext_filter is not None: for ext_tmp in ext_filter: wildcard = wildcard_prefix + string2ext_filter(ext_tmp) curlist = glob.glob(os.path.join(folder_path, wildcard)) if sort: curlist = sorted(curlist) fulllist += curlist else: wildcard = wildcard_prefix curlist = glob.glob(os.path.join(folder_path, wildcard)) if sort: curlist = sorted(curlist) fulllist += curlist if recursive and depth > 1: newlist, _ = load_list_from_folder(folder_path=folder_path, ext_filter=ext_filter, depth=depth - 1, recursive=True) fulllist += newlist fulllist = [os.path.normpath(path_tmp) for path_tmp in fulllist] num_elem = len(fulllist) # save list to a path if save_path is not None: save_path = safepath(save_path) if debug: assert is_path_exists_or_creatable( save_path), 'the file cannot be created' with open(save_path, 'w') as file: for item in fulllist: file.write('%s\n' % item) file.close() return fulllist, num_elem