def gray2rgb(input_image, with_color=True, cmap='jet', warning=True, debug=True): ''' convert a grayscale image (1-channel) to a rgb image parameters: input_image: an pil or numpy image with_color: add false colormap output: rgb_image: an uint8 rgb 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 isgrayimage_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' if with_color: if cmap == 'jet': rgb_image = cv2.applyColorMap(np_image, cv2.COLORMAP_JET) else: assert False, 'cmap %s is not supported' % cmap else: rgb_image = cv2.cvtColor(np_image, cv2.COLOR_GRAY2RGB) return rgb_image
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 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 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 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 image_find_peaks(input_image, percent_threshold=0.5, warning=True, debug=True): ''' this function find all strict local peaks and a strict global peak from a grayscale image the strict local maximum means that the pixel value must be larger than all nearby pixel values parameters: input_image: a pil or numpy grayscale image percent_threshold: determine to what pixel value to be smoothed out. e.g., when 0.4, all pixel values less than 0.4 * np.max(input_image) are smoothed out to be 0 outputs: peak_array: a numpy float32 array, 3 x num_peaks, (x, y, score) peak_global: a numpy float32 array, 3 x 1: (x, y, score) ''' np_image, _ = safe_image_like(input_image, warning=warning, debug=debug) if isuintimage(np_image): np_image = np_image.astype('float32') / 255. if debug: assert isgrayimage_dimension(np_image) and isfloatimage( np_image), 'the input image is not a grayscale and float image' assert isscalar( percent_threshold ) and percent_threshold >= 0 and percent_threshold <= 1, 'the percent_threshold is not correct' max_value = np.max(np_image) np_image[np_image < percent_threshold * max_value] = 0.0 height, width = np_image.shape[0], np_image.shape[1] npimage_center, npimage_top, npimage_bottom, npimage_left, npimage_right = np.zeros( [height + 2, width + 2]), np.zeros([height + 2, width + 2]), np.zeros([ height + 2, width + 2 ]), np.zeros([height + 2, width + 2]), np.zeros([height + 2, width + 2]) # shift in different directions to find local peak, only works for convex blob npimage_center[1:-1, 1:-1] = np_image npimage_left[1:-1, 0:-2] = np_image npimage_right[1:-1, 2:] = np_image npimage_top[0:-2, 1:-1] = np_image npimage_bottom[2:, 1:-1] = np_image # compute pixels larger than its shifted version of heatmap right_bool = npimage_center > npimage_right left_bool = npimage_center > npimage_left bottom_bool = npimage_center > npimage_bottom top_bool = npimage_center > npimage_top # the strict local maximum must be bigger than all nearby pixel values peakMap = np.logical_and( np.logical_and(np.logical_and(right_bool, left_bool), top_bool), bottom_bool) peakMap = peakMap[1:-1, 1:-1] peak_location_tuple = np.nonzero(peakMap) # find true num_peaks = len(peak_location_tuple[0]) if num_peaks == 0: if warning: print('No single local peak found') return np.zeros((3, 0), dtype='float32'), np.zeros((3, 0), dtype='float32') # convert to a numpy array format peak_array = np.zeros((3, num_peaks), dtype='float32') peak_array[0, :], peak_array[ 1, :] = peak_location_tuple[1], peak_location_tuple[0] for peak_index in range(num_peaks): peak_array[2, peak_index] = np_image[int(peak_array[1, peak_index]), int(peak_array[0, peak_index])] # find the global peak from all local peaks global_peak_index = np.argmax(peak_array[2, :]) peak_global = peak_array[:, global_peak_index].reshape((3, 1)) return peak_array, peak_global