def test_gray2rgb(): image_path = '../lena.jpg' img = Image.open(image_path).convert('L') img = np.array(img) print('input grayscale image has dimension of: '), print(img.shape) assert isgrayimage_dimension(img), 'the input image is not a gray image' visualize_image(img, vis=True) img_rgb = gray2rgb(img, with_color=True) print('converted rgb image has dimension of: '), print(img_rgb.shape) assert iscolorimage_dimension( img_rgb), 'the converted image is not a color image' visualize_image(img_rgb, vis=True) # test when input image is float image test_floatimage = (img.astype('float32')) / 255. img_rgb = gray2rgb(test_floatimage, with_color=True) assert iscolorimage_dimension( img_rgb), 'the converted image is not a color image' visualize_image(img_rgb, vis=True) # test when input image is PIL image test_pil_format_image = Image.fromarray(img) img_rgb = gray2rgb(test_pil_format_image, with_color=True) assert iscolorimage_dimension( img_rgb), 'the converted image is not a color image' print('\n\nDONE! SUCCESSFUL!!\n')
def image_clahe(input_image, clip_limit=2.0, grid_size=8, warning=True, debug=True): ''' do contrast limited adative histogram equalization for an image: could be a color image or gray image the color space used for histogram equalization is LAB parameters: input_image: a pil or numpy image outputs: clahe_image: an uint8 numpy image (rgb or gray) ''' np_image, _ = safe_image(input_image, warning=warning, debug=debug) if isfloatimage(np_image): np_image = (np_image.astype('float32') * 255.).astype('uint8') if debug: assert isuintimage(np_image), 'the input image should be a uint8 image' clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=(grid_size, grid_size)) if iscolorimage_dimension(np_image): lab_image = rgb2lab(np_image, warning=warning, debug=debug) input_data = lab_image[:, :, 0] # extract the value channel clahe_lab_image = clahe.apply(input_data) lab_image[:, :, 0] = clahe_lab_image clahe_image = lab2rgb(lab_image, warning=warning, debug=debug) elif isgrayimage_dimension(np_image): clahe_image = clahe.apply(np_image) else: assert False, 'the input image is neither a color image or a grayscale image' return clahe_image
def image_hist_equalization_hsv(input_image, warning=True, debug=True): ''' do histogram equalization for an image: could be a color image or gray image the color space used for histogram equalization is HSV parameters: input_image: a pil or numpy image outputs: equalized_image: an uint8 numpy image (rgb or gray) ''' np_image, _ = safe_image(input_image, warning=warning, debug=debug) if isuintimage(np_image): np_image = np_image.astype('float32') / 255. if debug: assert isfloatimage( np_image), 'the input image should be a float image' if iscolorimage_dimension(np_image): hsv_image = rgb2hsv(np_image, warning=warning, debug=debug) input_data = hsv_image[:, :, 2] # extract the value channel equalized_hsv_image = ( hist_equalization(input_data, num_bins=256, debug=debug) * 255.).astype('uint8') hsv_image[:, :, 2] = equalized_hsv_image equalized_image = hsv2rgb(hsv_image, warning=warning, debug=debug) elif isgrayimage_dimension(np_image): equalized_image = ( hist_equalization(np_image, num_bins=256, debug=debug) * 255.).astype('uint8') else: assert False, 'the input image is neither a color image or a grayscale image' return equalized_image
def convolve(self, input_image): ''' convolve the kernel with the input image, whatever the input image format is. If the input image is a color image, the filter is expanded to a 3D shape parameters: input_image: an pil or numpy, gray or color image outputs: filtered_image: a float32 numpy image, shape is same as before ''' np_image, _ = safe_image(input_image, warning=self.warning, debug=self.debug) if isuintimage(np_image): np_image = np_image.astype('float32') / 255. if self.debug: assert isfloatimage( np_image), 'the input image should be a float image' self.weights is not None, 'the kernel is not defined yet' if iscolorimage_dimension(np_image): self.weights = self.expand_3d( ) # expand the filter to 3D for color image elif isgrayimage_dimension(np_image): np_image = np_image.reshape( np_image.shape[0], np_image.shape[1]) # squeeze the image dimension to 2 filtered_image = ndimage.filters.convolve(np_image, self.weights) return filtered_image
def visualize_image(input_image, bgr2rgb=False, save_path=None, vis=False, warning=True, debug=True, closefig=True): ''' visualize an image parameters: input_image: a pil or numpy image bgr2rgb: true if the image needs to be converted from bgr to rgb save_path: a path to save. Do not save if it is None closefig: False if you want to add more elements on the image outputs: fig, ax: figure handle for future use ''' np_image, _ = safe_image(input_image, warning=warning, debug=debug) width, height = np_image.shape[1], np_image.shape[0] fig, ax = get_fig_ax_helper(fig=None, ax=None, width=width, height=height, frameon=False) ax = fig.add_axes([0, 0, 1, 1]) ax.set_axis_off() fig.axes[0].get_xaxis().set_visible(False) fig.axes[0].get_yaxis().set_visible(False) fig.axes[1].get_xaxis().set_visible(False) fig.axes[1].get_yaxis().set_visible(False) # display image if iscolorimage_dimension(np_image): if bgr2rgb: np_image = image_bgr2rgb(np_image) ax.imshow(np_image, interpolation='nearest') elif isgrayimage_dimension(np_image): np_image = np_image.reshape(np_image.shape[0], np_image.shape[1]) ax.imshow(np_image, interpolation='nearest', cmap='gray') else: assert False, 'unknown image type' ax.set(xlim=[0, width], ylim=[height, 0], aspect=1) return save_vis_close_helper(fig=fig, ax=ax, vis=vis, save_path=save_path, debug=debug, warning=warning, closefig=closefig)
def tracking_lk_opencv(input_image1, input_image2, input_pts, backward=False, win_size=15, pyramid=5, warning=True, debug=True): ''' tracking a set of points in two images using Lucas-Kanade tracking implemented in opencv parameters: input_image1, input_image2: a pil or numpy image, color or gray input_pts: a list of 2 elements, a listoflist of 2 elements: e.g., [[1,2], [5,6]], a numpy array with shape or (2, N) or (2, ) backward: run backward tracking if true win_sie: window sized used for lucas kanade tracking pyramid: number of levels of pyramid used for lucas kanade tracking outputs: pts_forward: tracked points in forward pass, 2 x N float32 numpy pts_bacward: tracked points in backward pass, 2 x N float32 numpy, None is not runnign the backward pass backward_err_list: a list of error in forward-backward pass check, None if not running the backward pass found_index_list: a list of 0 or 1, 1 if the tracking converges, 0 if not converging ''' np_image1, _ = safe_image(input_image1, warning=warning, debug=debug) np_image2, _ = safe_image(input_image2, warning=warning, debug=debug) np_pts = safe_2dptsarray(input_pts, homogeneous=False, warning=warning, debug=debug).astype('float32') # 2 x N if debug: assert isscalar(win_size) and isscalar(pyramid), 'the hyperparameters of lucas-kanade tracking is not correct' num_pts = np_pts.shape[1] # formatting the input if iscolorimage_dimension(np_image1): np_image1 = rgb2gray(np_image1) if iscolorimage_dimension(np_image2): np_image2 = rgb2gray(np_image2) lk_params = dict(winSize=(win_size, win_size), maxLevel=pyramid, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10000, 0.03)) pts_root = np.expand_dims(np_pts.transpose(), axis=1) # N x 1 x 2 pts_forward, status_for, err_for = cv2.calcOpticalFlowPyrLK(np_image1, np_image2, pts_root, None, **lk_params) found_index_for = np.where(status_for[:, 0] == 1)[0].tolist() if backward: pts_bacward, status_bac, err_bac = cv2.calcOpticalFlowPyrLK(np_image2, np_image1, pts_forward, None, **lk_params) # print(status_bac) found_index_bac = np.where(status_bac[:, 0] == 1)[0].tolist() # aa pts_bacward = pts_bacward.reshape((-1, 2)).transpose() _, backward_err_list = pts_euclidean(np_pts, pts_bacward, warning=warning, debug=debug) found_index_list = find_unique_common_from_lists(found_index_for, found_index_bac, warning=warning, debug=debug) else: pts_bacward, backward_err_list = None, None found_index_list = found_index_for pts_forward = pts_forward.reshape((-1, 2)).transpose() # 2 x N return pts_forward, pts_bacward, backward_err_list, found_index_list
def image_rgb2bgr(input_image, warning=True, debug=True): ''' this function converts a rgb image to a bgr image parameters: input_image: a pil or numpy rgb image outputs: np_image: a numpy bgr image ''' np_image, _ = safe_image(input_image, warning=warning, debug=debug) if debug: assert iscolorimage_dimension( np_image), 'the input image is not a color image' np_image = np_image[:, :, ::-1] # convert RGB to BGR return np_image
def rgb2hsv(input_image, warning=True, debug=True): ''' convert a rgb image to a hsv image using opencv package parameters: input_image: an pil or numpy image output: hsv_image: an uint8 hsv numpy image ''' np_image, _ = safe_image(input_image, warning=warning, debug=debug) if isfloatimage(np_image): np_image = (np_image * 255.).astype('uint8') if debug: assert iscolorimage_dimension( np_image), 'the input image should be a rgb image' assert isuintimage( np_image ), 'the input numpy image should be uint8 image in order to use opencv' hsv_img = cv2.cvtColor(np_image, cv2.COLOR_RGB2HSV) return hsv_img
def rgb2gray(input_image, warning=True, debug=True): ''' convert a color image to a grayscale image (1-channel) parameters: input_image: an pil or numpy image output: gray_image: an uint8 HW gray numpy image ''' np_image, _ = safe_image(input_image, warning=warning, debug=debug) if isfloatimage(np_image): np_image = (np_image * 255.).astype('uint8') if debug: assert iscolorimage_dimension( np_image), 'the input numpy image is not correct: {}'.format( np_image.shape) assert isuintimage( np_image ), 'the input numpy image should be uint8 image in order to use opencv' gray_image = cv2.cvtColor(np_image, cv2.COLOR_RGB2GRAY) return gray_image
def rgb2hsv_v2(input_image, warning=True, debug=True): ''' convert a rgb image to a hsv image, using PIL package, not compatible with opencv package parameters: input_image: an pil or numpy image output: hsv_image: an uint8 hsv numpy image ''' np_image, _ = safe_image(input_image, warning=warning, debug=debug) if isfloatimage(np_image): np_image = (np_image * 255.).astype('uint8') if debug: assert iscolorimage_dimension( np_image), 'the input image should be a rgb image' assert isuintimage( np_image ), 'the input numpy image should be uint8 image in order to use PIL' pil_rgb_img = Image.fromarray(np_image) pil_hsv_img = pil_rgb_img.convert('HSV') hsv_img = np.array(pil_hsv_img) return hsv_img
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