def get_boxes4deforming_area(vel_file, mask_file, step=2, num_pixel=30**2, min_percentage=0.2, ramp_type='quadratic', display=False): """Get list of boxes to cover the deforming areas. A pixel is identified as deforming if its velocity exceeds the MAD of the whole image. Parameters: vel_file : str, path of velocity file mask_file : str, path of mask file win_size : int, length and width of the output box min_percentage : float between 0 and 1, minimum percentage of deforming points in the box ramp_type : str, type of phase ramps to be removed while evaluating the deformation display : bool, plot the identification result or not Returns: box_list : list of t-tuple of int, each indicating (col0, row0, col1, row1) """ win_size = int(np.sqrt(num_pixel) * step) print('-'*30) print('get boxes on deforming areas with step: {} pixels'.format(step)) mask = readfile.read(mask_file)[0] vel, atr = readfile.read(vel_file) print('removing a {} phase ramp from input velocity before the evaluation'.format(ramp_type)) vel = deramp(vel, mask, ramp_type=ramp_type, metadata=atr)[0] #remove ramp before the evaluation # get deforming pixels mad = ut.median_abs_deviation_threshold(vel[mask], center=0., cutoff=3) #deformation threshold print('velocity threshold / median abs dev: {:.3f} cm/yr'.format(mad)) vel[mask == 0] = 0 mask_aoi = (vel >= mad) + (vel <= -1. * mad) print('number of points: {}'.format(np.sum(mask_aoi))) # get deforming boxes box_list = [] min_num = min_percentage * (win_size ** 2) length, width = vel.shape num_row = np.ceil(length / win_size).astype(int) num_col = np.ceil(width / win_size).astype(int) for i in range(num_row): r0 = i * win_size r1 = min([length, r0 + win_size]) for j in range(num_col): c0 = j * win_size c1 = min([width, c0 + win_size]) box = (c0, r0, c1, r1) if np.sum(mask_aoi[r0:r1, c0:c1]) >= min_num: box_list.append(box) print('number of boxes : {}'.format(len(box_list))) if display: fig, axs = plt.subplots(nrows=1, ncols=2, figsize=[12, 8], sharey=True) vel[mask == 0] = np.nan axs[0].imshow(vel, cmap='jet') axs[1].imshow(mask_aoi, cmap='gray') for box in box_list: for ax in axs: rect = Rectangle((box[0],box[1]), width=(box[2]-box[0]), height=(box[3]-box[1]), linewidth=2, edgecolor='r', fill=False) ax.add_patch(rect) plt.show() return box_list
def analyze_rms(date_list, rms_list, inps): # reference date ref_idx = np.argmin(rms_list) print('-' * 50 + '\ndate with min RMS: {} - {:.4f}'.format( date_list[ref_idx], rms_list[ref_idx])) ref_date_file = 'reference_date.txt' if ut.run_or_skip( out_file=ref_date_file, in_file=[inps.timeseries_file, inps.mask_file, inps.template_file], check_readable=False) == 'run': with open(ref_date_file, 'w') as f: f.write(date_list[ref_idx] + '\n') print('save date to file: ' + ref_date_file) # exclude date(s) - outliers try: rms_threshold = ut.median_abs_deviation_threshold(rms_list, center=0., cutoff=inps.cutoff) except: # equivalent calculation using numpy assuming Gaussian distribution rms_threshold = np.median(rms_list) / .6745 * inps.cutoff ex_idx = [rms_list.index(i) for i in rms_list if i > rms_threshold] print(('-' * 50 + '\ndate(s) with RMS > {} * median RMS' ' ({:.4f})'.format(inps.cutoff, rms_threshold))) ex_date_file = 'exclude_date.txt' if ex_idx: # print for i in ex_idx: print('{} - {:.4f}'.format(date_list[i], rms_list[i])) # save to text file with open(ex_date_file, 'w') as f: for i in ex_idx: f.write(date_list[i] + '\n') print('save date(s) to file: ' + ex_date_file) else: print('None.') if os.path.isfile(ex_date_file): rmCmd = 'rm {}'.format(ex_date_file) print(rmCmd) os.system(rmCmd) # plot bar figure and save fig_file = os.path.splitext(inps.rms_file)[0] + '.pdf' fig, ax = plt.subplots(figsize=inps.fig_size) print('create figure in size:', inps.fig_size) ax = plot_rms_bar(ax, date_list, np.array(rms_list) * 1000., cutoff=inps.cutoff) fig.savefig(fig_file, bbox_inches='tight', transparent=True) print('save figure to file: ' + fig_file) return inps
def get_boxes4deforming_area(vel_file, mask_file, win_size=30, min_percentage=0.2, ramp_type='quadratic', display=False): """Get list of boxes to cover the deforming areas. A pixel is identified as deforming if its velocity exceeds the MAD of the whole image. Parameters: vel_file : str, path of velocity file mask_file : str, path of mask file win_size : int, length and width of the output box min_percentage : float between 0 and 1, minimum percentage of deforming points in the box ramp_type : str, type of phase ramps to be removed while evaluating the deformation display : bool, plot the identification result or not Returns: box_list : list of t-tuple of int, each indicating (col0, row0, col1, row1) """ print('-'*30) print('get boxes on deforming areas') mask = readfile.read(mask_file)[0] vel, atr = readfile.read(vel_file) print('removing a {} phase ramp from input velocity before the evaluation'.format(ramp_type)) vel = deramp(vel, mask, ramp_type=ramp_type, metadata=atr)[0] #remove ramp before the evaluation # get deforming pixels mad = ut.median_abs_deviation_threshold(vel[mask], center=0., cutoff=3) #deformation threshold print('velocity threshold / median abs dev: {:.3f} cm/yr'.format(mad)) vel[mask == 0] = 0 mask_aoi = (vel >= mad) + (vel <= -1. * mad) print('number of points: {}'.format(np.sum(mask_aoi))) # get deforming boxes box_list = [] min_num = min_percentage * (win_size ** 2) length, width = vel.shape num_row = np.ceil(length / win_size).astype(int) num_col = np.ceil(width / win_size).astype(int) for i in range(num_row): r0 = i * win_size r1 = min([length, r0 + win_size]) for j in range(num_col): c0 = j * win_size c1 = min([width, c0 + win_size]) box = (c0, r0, c1, r1) if np.sum(mask_aoi[r0:r1, c0:c1]) >= min_num: box_list.append(box) print('number of boxes : {}'.format(len(box_list))) if display: fig, axs = plt.subplots(nrows=1, ncols=2, figsize=[12, 8], sharey=True) vel[mask == 0] = np.nan axs[0].imshow(vel, cmap='jet') axs[1].imshow(mask_aoi, cmap='gray') for box in box_list: for ax in axs: rect = Rectangle((box[0],box[1]), (box[2]-box[0]), (box[3]-box[1]), linewidth=2, edgecolor='r', fill=False) ax.add_patch(rect) plt.show() return box_list
def analyze_rms(date_list, rms_list, inps): # reference date ref_idx = np.argmin(rms_list) print('-'*50+'\ndate with min RMS: {} - {:.4f}'.format(date_list[ref_idx], rms_list[ref_idx])) ref_date_file = 'reference_date.txt' if ut.run_or_skip(out_file=ref_date_file, in_file=[inps.timeseries_file, inps.mask_file, inps.template_file], check_readable=False) == 'run': with open(ref_date_file, 'w') as f: f.write(date_list[ref_idx]+'\n') print('save date to file: '+ref_date_file) # exclude date(s) - outliers try: rms_threshold = ut.median_abs_deviation_threshold(rms_list, center=0., cutoff=inps.cutoff) except: # equivalent calculation using numpy assuming Gaussian distribution rms_threshold = np.median(rms_list) / .6745 * inps.cutoff ex_idx = [rms_list.index(i) for i in rms_list if i > rms_threshold] print(('-'*50+'\ndate(s) with RMS > {} * median RMS' ' ({:.4f})'.format(inps.cutoff, rms_threshold))) ex_date_file = 'exclude_date.txt' if ex_idx: # print for i in ex_idx: print('{} - {:.4f}'.format(date_list[i], rms_list[i])) # save to text file with open(ex_date_file, 'w') as f: for i in ex_idx: f.write(date_list[i]+'\n') print('save date(s) to file: '+ex_date_file) else: print('None.') if os.path.isfile(ex_date_file): rmCmd = 'rm {}'.format(ex_date_file) print(rmCmd) os.system(rmCmd) # plot bar figure and save fig_file = os.path.splitext(inps.rms_file)[0]+'.pdf' fig, ax = plt.subplots(figsize=inps.fig_size) print('create figure in size:', inps.fig_size) ax = plot_rms_bar(ax, date_list, np.array(rms_list)*1000., cutoff=inps.cutoff) fig.savefig(fig_file, bbox_inches='tight', transparent=True) print('save figure to file: '+fig_file) return inps
def plot_rms_bar(ax, date_list, rms, cutoff=3., font_size=12, tick_year_num=1, legend_loc='best', disp_legend=True, disp_side_plot=True, disp_thres_text=False, ylabel=r'Residual Phase $\hat \phi_{resid}$ RMS [mm]'): """ Bar plot Phase Residual RMS Parameters: ax : Axes object date_list : list of string in YYYYMMDD format rms : 1D np.array of float for RMS value in mm cutoff : cutoff value of MAD outlier detection tick_year_num : int, number of years per major tick legend_loc : 'upper right' or (0.5, 0.5) Returns: ax : Axes object """ dates, datevector = ptime.date_list2vector(date_list) dates = np.array(dates) try: bar_width = min(ut.most_common(np.diff(dates).tolist(), k=2)) * 3 / 4 except: bar_width = np.min(np.diff(dates).tolist()) * 3 / 4 rms = np.array(rms) # Plot all dates ax.bar(dates, rms, bar_width.days, color=pp.mplColors[0]) # Plot reference date ref_idx = np.argmin(rms) ax.bar(dates[ref_idx], rms[ref_idx], bar_width.days, color=pp.mplColors[1], label='Reference date') # Plot exclude dates rms_threshold = ut.median_abs_deviation_threshold(rms, center=0., cutoff=cutoff) ex_idx = rms > rms_threshold if not np.all(ex_idx == False): ax.bar(dates[ex_idx], rms[ex_idx], bar_width.days, color='darkgray', label='Exclude date') # Plot rms_threshold line (ax, xmin, xmax) = pp.auto_adjust_xaxis_date(ax, datevector, font_size, every_year=tick_year_num) ax.plot(np.array([xmin, xmax]), np.array([rms_threshold, rms_threshold]), '--k', label='Median Abs Dev * {}'.format(cutoff)) # axis format ax = pp.auto_adjust_yaxis(ax, np.append(rms, rms_threshold), font_size, ymin=0.0) ax.set_xlabel('Time [years]', fontsize=font_size) ax.set_ylabel(ylabel, fontsize=font_size) ax.tick_params(which='both', direction='in', labelsize=font_size, bottom=True, top=True, left=True, right=True) # 2nd axes for circles if disp_side_plot: divider = make_axes_locatable(ax) ax2 = divider.append_axes("right", "10%", pad="2%") ax2.plot(np.ones(rms.shape, np.float32) * 0.5, rms, 'o', mfc='none', color=pp.mplColors[0]) ax2.plot(np.ones(rms.shape, np.float32)[ref_idx] * 0.5, rms[ref_idx], 'o', mfc='none', color=pp.mplColors[1]) if not np.all(ex_idx == False): ax2.plot(np.ones(rms.shape, np.float32)[ex_idx] * 0.5, rms[ex_idx], 'o', mfc='none', color='darkgray') ax2.plot(np.array([0, 1]), np.array([rms_threshold, rms_threshold]), '--k') ax2.set_ylim(ax.get_ylim()) ax2.set_xlim([0, 1]) ax2.tick_params(which='both', direction='in', labelsize=font_size, bottom=True, top=True, left=True, right=True) ax2.get_xaxis().set_ticks([]) ax2.get_yaxis().set_ticklabels([]) if disp_legend: ax.legend(loc=legend_loc, frameon=False, fontsize=font_size) # rms_threshold text if disp_thres_text: ymin, ymax = ax.get_ylim() yoff = (ymax - ymin) * 0.1 if (rms_threshold - ymin) > 0.5 * (ymax - ymin): yoff *= -1. ax.annotate('Median Abs Dev * {}'.format(cutoff), xy=(xmin + (xmax - xmin) * 0.05, rms_threshold + yoff), color='k', xycoords='data', fontsize=font_size) return ax
def detect_unwrap_error(ifgram_file, mask_file, mask_cc_file='maskConnComp.h5', unwDatasetName='unwrapPhase', cutoff=1., min_num_pixel=1e4): """Detect unwrapping error based on phase closure and extract coherent conn comps based on its histogram distribution Check: https://en.wikipedia.org/wiki/Otsu%27s_method from skimage.filters import threshold_otsu Parameters: ifgram_file : string, path of ifgram stack file mask_file : string, path of mask file, e.g. waterMask.h5, maskConnComp.h5 mask_cc_file: string, path of mask file for coherent conn comps cutoff : float, cutoff value for the mean number of nonzero phase closure to be selected as coherent conn comps candidate min_num_pixel : float, min number of pixels left after morphology operation to be determined as coherent conn comps Returns: mask_cc_file : string, path of mask file for coherent conn comps """ print('-'*50) print('detect unwraping error based on phase closure') obj = ifgramStack(ifgram_file) obj.open(print_msg=False) C = obj.get_design_matrix4triplet(obj.get_date12_list(dropIfgram=False)) num_nonzero_closure = get_nonzero_phase_closure(ifgram_file, unwDatasetName=unwDatasetName) # get histogram of num_nonzero_phase_closure mask = readfile.read(mask_file)[0] mask *= num_nonzero_closure != 0. fig, ax = plt.subplots(nrows=1, ncols=2, figsize=[12, 4]) num4disp = np.array(num_nonzero_closure, dtype=np.float32) num4disp[mask == 0] = np.nan im = ax[0].imshow(num4disp) ax[0].set_xlabel('Range [pix.]') ax[0].set_ylabel('Azimuth [pix.]') ax[0] = pp.auto_flip_direction(obj.metadata, ax=ax[0], print_msg=False) cbar = fig.colorbar(im, ax=ax[0]) cbar.set_label('number of non-zero phase closure') print('2. extract coherent conn comps with unwrap error based on histogram distribution') max_nonzero_closure = int(np.max(num_nonzero_closure[mask])) bin_value, bin_edge = ax[1].hist(num_nonzero_closure[mask].flatten(), range=(0, max_nonzero_closure), log=True, bins=max_nonzero_closure)[0:2] ax[1].set_xlabel('number of non-zero phase closure') ax[1].set_ylabel('number of pixels') if 'Closure' not in unwDatasetName: print('eliminate pixels with number of nonzero phase closure < 5% of total phase closure number') print('\twhich can be corrected using phase closure alone.') bin_value[:int(C.shape[0]*0.05)] = 0. bin_value_thres = ut.median_abs_deviation_threshold(bin_value, cutoff=cutoff) print('median abs deviation cutoff value: {}'.format(cutoff)) plt.plot([0, max_nonzero_closure], [bin_value_thres, bin_value_thres]) out_img = 'numUnwErr_stat.png' fig.savefig(out_img, bbox_inches='tight', transparent=True, dpi=300) print('save unwrap error detection result to {}'.format(out_img)) # histogram --> candidates of coherence conn comps --> mask_cc # find pixel clusters sharing similar number of non-zero phase closure print('searching connected components with more than {} pixels'.format(min_num_pixel)) bin_label, n_bins = ndimage.label(bin_value > bin_value_thres) mask_cc = np.zeros(num_nonzero_closure.shape, dtype=np.int16) # first conn comp - reference conn comp with zero non-zero phase closure num_cc = 1 mask_cc1 = num_nonzero_closure == 0. mask_cc1s = ut.get_all_conn_components(mask_cc1, min_num_pixel=min_num_pixel) for mask_cc1 in mask_cc1s: mask_cc += mask_cc1 # other conn comps - target conn comps to be corrected for unwrap error for i in range(n_bins): idx = np.where(bin_label == i+1)[0] mask_cci0 = np.multiply(num_nonzero_closure >= bin_edge[idx[0]], num_nonzero_closure < bin_edge[idx[-1]+1]) mask_ccis = ut.get_all_conn_components(mask_cci0, min_num_pixel=min_num_pixel) if mask_ccis: for mask_cci in mask_ccis: num_cc += 1 mask_cc += mask_cci * num_cc fig, ax = plt.subplots(nrows=1, ncols=2, figsize=[8, 4]) im = ax[0].imshow(mask_cci0) im = ax[1].imshow(mask_cci) fig.savefig('mask_cc{}.png'.format(num_cc), bbox_inches='tight', transparent=True, dpi=300) # save to hdf5 file num_bridge = num_cc - 1 atr = dict(obj.metadata) atr['FILE_TYPE'] = 'mask' atr['UNIT'] = 1 writefile.write(mask_cc, out_file=mask_cc_file, metadata=atr) # plot and save figure to img file out_img = '{}.png'.format(os.path.splitext(mask_cc_file)[0]) fig, ax = plt.subplots(figsize=[6, 8]) im = ax.imshow(mask_cc) ax = pp.auto_flip_direction(atr, ax=ax, print_msg=False) divider = make_axes_locatable(ax) cax = divider.append_axes("right", "3%", pad="3%") cbar = plt.colorbar(im, cax=cax, ticks=np.arange(num_bridge+2)) fig.savefig(out_img, bbox_inches='tight', transparent=True, dpi=300) print('save to {}'.format(out_img)) return mask_cc_file
def plot_rms_bar(ax, date_list, rms, cutoff=3., font_size=12, tick_year_num=1, legend_loc='best', disp_legend=True, disp_side_plot=True, disp_thres_text=True, ylabel=r'Residual Phase $\hat \phi_{resid}$ RMS [mm]'): """ Bar plot Phase Residual RMS Parameters: ax : Axes object date_list : list of string in YYYYMMDD format rms : 1D np.array of float for RMS value in mm cutoff : cutoff value of MAD outlier detection tick_year_num : int, number of years per major tick legend_loc : 'upper right' or (0.5, 0.5) Returns: ax : Axes object """ dates, datevector = ptime.date_list2vector(date_list) dates = np.array(dates) try: bar_width = min(ut.most_common(np.diff(dates).tolist(), k=2))*3/4 except: bar_width = np.min(np.diff(dates).tolist())*3/4 rms = np.array(rms) # Plot all dates ax.bar(dates, rms, bar_width.days, color=pp.mplColors[0]) # Plot reference date ref_idx = np.argmin(rms) ax.bar(dates[ref_idx], rms[ref_idx], bar_width.days, color=pp.mplColors[1], label='Reference date') # Plot exclude dates rms_threshold = ut.median_abs_deviation_threshold(rms, center=0., cutoff=cutoff) ex_idx = rms > rms_threshold if not np.all(ex_idx==False): ax.bar(dates[ex_idx], rms[ex_idx], bar_width.days, color='darkgray', label='Exclude date') # Plot rms_threshold line (ax, xmin, xmax) = pp.auto_adjust_xaxis_date(ax, datevector, font_size, every_year=tick_year_num) ax.plot(np.array([xmin, xmax]), np.array([rms_threshold, rms_threshold]), '--k', label='RMS threshold') # axis format ax = pp.auto_adjust_yaxis(ax, np.append(rms, rms_threshold), font_size, ymin=0.0) ax.set_xlabel('Time [years]', fontsize=font_size) ax.set_ylabel(ylabel, fontsize=font_size) ax.tick_params(which='both', direction='in', labelsize=font_size, bottom=True, top=True, left=True, right=True) # 2nd axes for circles if disp_side_plot: divider = make_axes_locatable(ax) ax2 = divider.append_axes("right", "10%", pad="2%") ax2.plot(np.ones(rms.shape, np.float32) * 0.5, rms, 'o', mfc='none', color=pp.mplColors[0]) ax2.plot(np.ones(rms.shape, np.float32)[ref_idx] * 0.5, rms[ref_idx], 'o', mfc='none', color=pp.mplColors[1]) if not np.all(ex_idx==False): ax2.plot(np.ones(rms.shape, np.float32)[ex_idx] * 0.5, rms[ex_idx], 'o', mfc='none', color='darkgray') ax2.plot(np.array([0, 1]), np.array([rms_threshold, rms_threshold]), '--k') ax2.set_ylim(ax.get_ylim()) ax2.set_xlim([0, 1]) ax2.tick_params(which='both', direction='in', labelsize=font_size, bottom=True, top=True, left=True, right=True) ax2.get_xaxis().set_ticks([]) ax2.get_yaxis().set_ticklabels([]) if disp_legend: ax.legend(loc=legend_loc, frameon=False, fontsize=font_size) # rms_threshold text if disp_thres_text: ymin, ymax = ax.get_ylim() yoff = (ymax - ymin) * 0.1 if (rms_threshold - ymin) > 0.5 * (ymax - ymin): yoff *= -1. ax.annotate('Median Abs Dev * {}'.format(cutoff), xy=(xmin + (xmax-xmin)*0.05, rms_threshold + yoff ), color='k', xycoords='data', fontsize=font_size) return ax
def detect_unwrap_error(ifgram_file, mask_file, mask_cc_file='maskConnComp.h5', unwDatasetName='unwrapPhase', cutoff=1., min_num_pixel=1e4): """Detect unwrapping error based on phase closure and extract coherent conn comps based on its histogram distribution Check: https://en.wikipedia.org/wiki/Otsu%27s_method from skimage.filters import threshold_otsu Parameters: ifgram_file : string, path of ifgram stack file mask_file : string, path of mask file, e.g. waterMask.h5, maskConnComp.h5 mask_cc_file: string, path of mask file for coherent conn comps cutoff : float, cutoff value for the mean number of nonzero phase closure to be selected as coherent conn comps candidate min_num_pixel : float, min number of pixels left after morphology operation to be determined as coherent conn comps Returns: mask_cc_file : string, path of mask file for coherent conn comps """ print('-' * 50) print('detect unwraping error based on phase closure') obj = ifgramStack(ifgram_file) obj.open(print_msg=False) C = obj.get_design_matrix4triplet(obj.get_date12_list(dropIfgram=False)) num_nonzero_closure = get_nonzero_phase_closure( ifgram_file, unwDatasetName=unwDatasetName) # get histogram of num_nonzero_phase_closure mask = readfile.read(mask_file)[0] mask *= num_nonzero_closure != 0. fig, ax = plt.subplots(nrows=1, ncols=2, figsize=[12, 4]) num4disp = np.array(num_nonzero_closure, dtype=np.float32) num4disp[mask == 0] = np.nan im = ax[0].imshow(num4disp) ax[0].set_xlabel('Range [pix.]') ax[0].set_ylabel('Azimuth [pix.]') ax[0] = pp.auto_flip_direction(obj.metadata, ax=ax[0], print_msg=False) cbar = fig.colorbar(im, ax=ax[0]) cbar.set_label('number of non-zero phase closure') print( '2. extract coherent conn comps with unwrap error based on histogram distribution' ) max_nonzero_closure = int(np.max(num_nonzero_closure[mask])) bin_value, bin_edge = ax[1].hist(num_nonzero_closure[mask].flatten(), range=(0, max_nonzero_closure), log=True, bins=max_nonzero_closure)[0:2] ax[1].set_xlabel('number of non-zero phase closure') ax[1].set_ylabel('number of pixels') if 'Closure' not in unwDatasetName: print( 'eliminate pixels with number of nonzero phase closure < 5% of total phase closure number' ) print('\twhich can be corrected using phase closure alone.') bin_value[:int(C.shape[0] * 0.05)] = 0. bin_value_thres = ut.median_abs_deviation_threshold(bin_value, cutoff=cutoff) print('median abs deviation cutoff value: {}'.format(cutoff)) plt.plot([0, max_nonzero_closure], [bin_value_thres, bin_value_thres]) out_img = 'numUnwErr_stat.png' fig.savefig(out_img, bbox_inches='tight', transparent=True, dpi=300) print('save unwrap error detection result to {}'.format(out_img)) # histogram --> candidates of coherence conn comps --> mask_cc # find pixel clusters sharing similar number of non-zero phase closure print('searching connected components with more than {} pixels'.format( min_num_pixel)) bin_label, n_bins = ndimage.label(bin_value > bin_value_thres) mask_cc = np.zeros(num_nonzero_closure.shape, dtype=np.int16) # first conn comp - reference conn comp with zero non-zero phase closure num_cc = 1 mask_cc1 = num_nonzero_closure == 0. mask_cc1s = ut.get_all_conn_components(mask_cc1, min_num_pixel=min_num_pixel) for mask_cc1 in mask_cc1s: mask_cc += mask_cc1 # other conn comps - target conn comps to be corrected for unwrap error for i in range(n_bins): idx = np.where(bin_label == i + 1)[0] mask_cci0 = np.multiply(num_nonzero_closure >= bin_edge[idx[0]], num_nonzero_closure < bin_edge[idx[-1] + 1]) mask_ccis = ut.get_all_conn_components(mask_cci0, min_num_pixel=min_num_pixel) if mask_ccis: for mask_cci in mask_ccis: num_cc += 1 mask_cc += mask_cci * num_cc fig, ax = plt.subplots(nrows=1, ncols=2, figsize=[8, 4]) im = ax[0].imshow(mask_cci0) im = ax[1].imshow(mask_cci) fig.savefig('mask_cc{}.png'.format(num_cc), bbox_inches='tight', transparent=True, dpi=300) # save to hdf5 file num_bridge = num_cc - 1 atr = dict(obj.metadata) atr['FILE_TYPE'] = 'mask' atr['UNIT'] = 1 writefile.write(mask_cc, out_file=mask_cc_file, metadata=atr) # plot and save figure to img file out_img = '{}.png'.format(os.path.splitext(mask_cc_file)[0]) fig, ax = plt.subplots(figsize=[6, 8]) im = ax.imshow(mask_cc) ax = pp.auto_flip_direction(atr, ax=ax, print_msg=False) divider = make_axes_locatable(ax) cax = divider.append_axes("right", "3%", pad="3%") cbar = plt.colorbar(im, cax=cax, ticks=np.arange(num_bridge + 2)) fig.savefig(out_img, bbox_inches='tight', transparent=True, dpi=300) print('save to {}'.format(out_img)) return mask_cc_file