def get_image_with_height_list(sample_txt, img_ext, info_type='training'): height_list = [] width_list = [] band_count = 0 image_path_list = [] dtype = 'unknown' with open(sample_txt, 'r') as f_obj: lines = f_obj.readlines() for line in lines: image_path = os.path.join('split_images', line.strip() + img_ext) height, width, band_count, dtype = raster_io.get_height_width_bandnum_dtype(image_path) image_path_list.append(image_path) height_list.append(height) width_list.append(width) # save info to file, if it exists, add information to the file img_count = len(image_path_list) with open('sub_images_patches_info.txt','a') as f_obj: f_obj.writelines('information of %s image patches: \n'%info_type) f_obj.writelines('number of %s image patches : %d \n' % (info_type,img_count)) f_obj.writelines('band count : %d \n'%band_count) f_obj.writelines('data type : %s \n'%dtype) f_obj.writelines('maximum width and height: %d, %d \n'% (max(width_list), max(height_list)) ) f_obj.writelines('minimum width and height: %d, %d \n'% (min(width_list), min(height_list)) ) f_obj.writelines('mean width and height: %.2f, %.2f \n\n'% (sum(width_list)/img_count, sum(height_list)/img_count)) return True
def get_yolo_boxes_one_img(idx, total, image_path, label_path, num_classes_noBG, rm_edge_obj=False): print('to yolo box: %d/%d' % (idx + 1, total)) # a object : [ class_id, minX, minY, maxX, maxY ] objects = get_boxes_from_label_image(label_path) save_object_txt = os.path.splitext(image_path)[0] + '.txt' height, width, count, dtype = raster_io.get_height_width_bandnum_dtype( label_path) with open(save_object_txt, 'w') as f_obj: for object in objects: class_id, minX, minY, maxX, maxY = object if class_id > num_classes_noBG: raise ValueError( 'Class ID: %d greater than number of classes in label: %s' % (class_id, label_path)) # remove objects touch the image edge, usually, target object is in the center of images, # but some targets close to this one may be cut when we extract sub-images or split imgaes if rm_edge_obj: if minX == 0 or minY == 0 or maxX == (width - 1) or maxY == ( height - 1): print( 'warning, object (minX, minY, maxX, maxY): (%d %d %d %d) touched the edge in %s, ignore it' % (minX, minY, maxX, maxY, label_path)) continue # in semantic, class_id 0 is background, yolo, class 0 is target, so minus 1 class_id -= 1 x, y, w, h = convert((width, height), (minX, maxX, minY, maxY)) f_obj.writelines('%d %f %f %f %f\n' % (class_id, x, y, w, h))
def test_darknet_batch_detection_rs_images(): print('\n') print('Run test_darknet_batch_detection_rs_images') config_file = 'yolov4_obj_oneband.cfg' yolo_data = os.path.join('data', 'obj.data') weights = os.path.join('exp1', 'yolov4_obj_oneband_best.weights') batch_size = 1 # these three have the same size # image_names = ['20200818_mosaic_8bit_rgb_p_1001.png'] #, '20200818_mosaic_8bit_rgb_p_1038.png', '20200818_mosaic_8bit_rgb_p_1131.png'] image_names = ['Alaska_north_slope_hillshade_20170426_poly_28_p_0.png'] #, '20200818_mosaic_8bit_rgb_p_1038.png', '20200818_mosaic_8bit_rgb_p_1131.png'] image_names = [os.path.join('debug_img', item) for item in image_names] image_path = image_names[0] save_dir = './' height, width, band_num, date_type = raster_io.get_height_width_bandnum_dtype(image_path) # print('input image: height, width, band_num, date_type',height, width, band_num, date_type) # divide the image the many small patches, then calcuate one by one, solving memory issues. patch_w = 480 patch_h = 480 overlay_x = 160 overlay_y = 160 image_patches = split_image.sliding_window(width,height,patch_w,patch_h,adj_overlay_x=overlay_x,adj_overlay_y=overlay_y) patch_count = len(image_patches) if os.path.isdir(save_dir) is False: io_function.mkdir(save_dir) # group patches based on size, each patch is (xoff,yoff ,xsize, ysize) patch_groups = {} for patch in image_patches: wh_str = 'w%d'%patch[2] + '_' + 'h%d'%patch[3] if wh_str in patch_groups.keys(): patch_groups[wh_str].append(patch) else: patch_groups[wh_str] = [patch] # load network network, class_names, class_colors = load_darknet_network(config_file, yolo_data, weights, batch_size=batch_size) darknet_batch_detection_rs_images(network, image_path, save_dir, patch_groups, patch_count, class_names, batch_size, thresh=0.25, hier_thresh=.5, nms=.45)
def get_sub_images_multi_regions(para_file): print( "extract sub-images and sub-labels for a given shape file (training polygons)" ) if os.path.isfile(para_file) is False: raise IOError('File %s not exists in current folder: %s' % (para_file, os.getcwd())) get_subImage_script = os.path.join(code_dir, 'datasets', 'get_subImages.py') SECONDS = time.time() # get name of training areas multi_training_regions = parameters.get_string_list_parameters_None_if_absence( para_file, 'training_regions') if multi_training_regions is None or len(multi_training_regions) < 1: raise ValueError('No training area is set in %s' % para_file) # multi_training_files = parameters.get_string_parameters_None_if_absence(para_file, 'multi_training_files') dstnodata = parameters.get_string_parameters(para_file, 'dst_nodata') buffersize = parameters.get_string_parameters(para_file, 'buffer_size') rectangle_ext = parameters.get_string_parameters(para_file, 'b_use_rectangle') process_num = parameters.get_digit_parameters(para_file, 'process_num', 'int') b_no_label_image = parameters.get_bool_parameters_None_if_absence( para_file, 'b_no_label_image') if os.path.isfile('sub_images_labels_list.txt'): io_function.delete_file_or_dir('sub_images_labels_list.txt') subImage_dir = parameters.get_string_parameters_None_if_absence( para_file, 'input_train_dir') subLabel_dir = parameters.get_string_parameters_None_if_absence( para_file, 'input_label_dir') # loop each training regions for idx, area_ini in enumerate(multi_training_regions): input_image_dir = parameters.get_directory_None_if_absence( area_ini, 'input_image_dir') # it is ok consider a file name as pattern and pass it the following functions to get file list input_image_or_pattern = parameters.get_string_parameters( area_ini, 'input_image_or_pattern') b_sub_images_json = parameters.get_bool_parameters( area_ini, 'b_sub_images_json') if b_sub_images_json is True: # copy sub-images, then covert json files to label images. object_names = parameters.get_string_list_parameters( para_file, 'object_names') get_subImages_json.get_subimages_label_josn( input_image_dir, input_image_or_pattern, subImage_dir, subLabel_dir, object_names, b_no_label_image=b_no_label_image, process_num=process_num) pass else: all_train_shp = parameters.get_file_path_parameters_None_if_absence( area_ini, 'training_polygons') train_shp = parameters.get_string_parameters( area_ini, 'training_polygons_sub') # get subImage and subLabel for one training polygons print( 'extract training data from image folder (%s) and polgyons (%s)' % (input_image_dir, train_shp)) if b_no_label_image is True: get_subImage_one_shp(get_subImage_script, all_train_shp, buffersize, dstnodata, rectangle_ext, train_shp, input_image_dir, file_pattern=input_image_or_pattern, process_num=process_num) else: get_subImage_subLabel_one_shp( get_subImage_script, all_train_shp, buffersize, dstnodata, rectangle_ext, train_shp, input_image_dir, file_pattern=input_image_or_pattern, process_num=process_num) # check black sub-images or most part of the sub-images is black (nodata) new_sub_image_label_list = [] delete_sub_image_label_list = [] subImage_dir_delete = subImage_dir + '_delete' subLabel_dir_delete = subLabel_dir + '_delete' io_function.mkdir(subImage_dir_delete) if b_no_label_image is None or b_no_label_image is False: io_function.mkdir(subLabel_dir_delete) get_valid_percent_entropy.plot_valid_entropy(subImage_dir) with open('sub_images_labels_list.txt', 'r') as f_obj: lines = f_obj.readlines() for line in lines: image_path, label_path = line.strip().split(':') # valid_per = raster_io.get_valid_pixel_percentage(image_path) valid_per, entropy = raster_io.get_valid_percent_shannon_entropy( image_path) # base=10 if valid_per > 60 and entropy >= 0.5: new_sub_image_label_list.append(line) else: delete_sub_image_label_list.append(line) io_function.movefiletodir(image_path, subImage_dir_delete) if os.path.isfile(label_path): io_function.movefiletodir(label_path, subLabel_dir_delete) if len(delete_sub_image_label_list) > 0: with open('sub_images_labels_list.txt', 'w') as f_obj: for line in new_sub_image_label_list: f_obj.writelines(line) # check weather they have the same subImage and subLabel if b_no_label_image is None or b_no_label_image is False: sub_image_list = io_function.get_file_list_by_pattern( subImage_dir, '*.tif') sub_label_list = io_function.get_file_list_by_pattern( subLabel_dir, '*.tif') if len(sub_image_list) != len(sub_label_list): raise ValueError( 'the count of subImage (%d) and subLabel (%d) is different' % (len(sub_image_list), len(sub_label_list))) # save brief information of sub-images height_list = [] width_list = [] band_count = 0 dtype = 'unknown' for line in new_sub_image_label_list: image_path, label_path = line.strip().split(':') height, width, band_count, dtype = raster_io.get_height_width_bandnum_dtype( image_path) height_list.append(height) width_list.append(width) # save info to file, if it exists, it will be overwritten img_count = len(new_sub_image_label_list) with open('sub_images_patches_info.txt', 'w') as f_obj: f_obj.writelines('information of sub-images: \n') f_obj.writelines('number of sub-images : %d \n' % img_count) f_obj.writelines('band count : %d \n' % band_count) f_obj.writelines('data type : %s \n' % dtype) f_obj.writelines('maximum width and height: %d, %d \n' % (max(width_list), max(height_list))) f_obj.writelines('minimum width and height: %d, %d \n' % (min(width_list), min(height_list))) f_obj.writelines( 'mean width and height: %.2f, %.2f \n\n' % (sum(width_list) / img_count, sum(height_list) / img_count)) duration = time.time() - SECONDS os.system( 'echo "$(date): time cost of getting sub images and labels: %.2f seconds">>time_cost.txt' % duration)
def predict_rs_image_yolo_poythonAPI(image_path, save_dir, model, config_file, yolo_data, patch_w, patch_h, overlay_x, overlay_y, batch_size=1): ''' predict an remote sensing using YOLO Python API :param image_path: :param save_dir: :param model: :param config_file: :param yolo_data: :param patch_w: :param patch_h: :param overlay_x: :param overlay_y: :param batch_size: :return: ''' height, width, band_num, date_type = raster_io.get_height_width_bandnum_dtype( image_path) # print('input image: height, width, band_num, date_type',height, width, band_num, date_type) # divide the image the many small patches, then calcuate one by one, solving memory issues. image_patches = split_image.sliding_window(width, height, patch_w, patch_h, adj_overlay_x=overlay_x, adj_overlay_y=overlay_y) patch_count = len(image_patches) if os.path.isdir(save_dir) is False: io_function.mkdir(save_dir) # group patches based on size, each patch is (xoff,yoff ,xsize, ysize) patch_groups = {} for patch in image_patches: wh_str = 'w%d' % patch[2] + '_' + 'h%d' % patch[3] if wh_str in patch_groups.keys(): patch_groups[wh_str].append(patch) else: patch_groups[wh_str] = [patch] network, class_names, _ = load_darknet_network(config_file, yolo_data, model, batch_size=batch_size) # batch detection if batch_size > 1: return darknet_batch_detection_rs_images(network, image_path, save_dir, patch_groups, patch_count, class_names, batch_size) # read the entire image entire_img_data, nodata = raster_io.read_raster_all_bands_np(image_path) entire_img_data = entire_img_data.transpose(1, 2, 0) # to opencv format # # RGB to BGR: Matplotlib image to OpenCV https://www.scivision.dev/numpy-image-bgr-to-rgb/ # entire_img_data = entire_img_data[..., ::-1].copy() # cancel RGB to BGR, since it make results worse, (maybe darknet already read images as RGB during training) entire_height, entire_width, band_num = entire_img_data.shape print("entire_height, entire_width, band_num", entire_height, entire_width, band_num) if band_num not in [1, 3]: raise ValueError('only accept one band or three band images') patch_idx = 0 for key in patch_groups.keys(): patches_sameSize = patch_groups[key] # get width, height, and band_num of a patch, then create a darknet image. # img_data, nodata = raster_io.read_raster_all_bands_np(image_path, boundary=patches_sameSize[0]) # img_data = img_data.transpose(1, 2, 0) # height, width, band_num = img_data.shape # if band_num not in [1, 3]: # raise ValueError('only accept one band or three band images') height, width = patches_sameSize[0][3], patches_sameSize[0][2] # Create one with image we reuse for each detect : images with the same size. darknet_image = darknet.make_image(width, height, band_num) for idx, patch in enumerate(patches_sameSize): t0 = time.time() # patch: (xoff,yoff ,xsize, ysize) # img_data, nodata = raster_io.read_raster_all_bands_np(image_path,boundary=patch) # img_data = img_data.transpose(1, 2, 0) img_data = copy_one_patch_image_data(patch, entire_img_data) # prediction darknet.copy_image_from_bytes(darknet_image, img_data.tobytes()) # thresh=0.25, relative low, set to 0 will output too many, post-process later detections = darknet.detect_image(network, class_names, darknet_image, thresh=0.25) # save results save_res_json = os.path.join(save_dir, '%d.json' % patch_idx) save_one_patch_detection_json(patch, detections, class_names, save_res_json) if patch_idx % 100 == 0: print('saving %d patch, total: %d, cost %f second' % (patch_idx, patch_count, time.time() - t0)) patch_idx += 1 darknet.free_image(darknet_image)
def merge_subImages_from_gan(multi_gan_source_regions, multi_gan_regions, gan_working_dir, gan_dir_pre_name, save_image_dir, save_label_dir): ''' merge translate subimages from GAN to orginal sub_images :param multi_gan_regions: :param gan_working_dir: :param gan_dir_pre_name: :return: ''' current_dir = os.getcwd() sub_img_label_txt_noGAN, sub_img_label_txt, area_ini_sub_images_labels_dict = original_sub_images_labels_list_before_gan( ) # # get original sub-images and labels # org_sub_images = [] # org_sub_labels = [] # with open(sub_img_label_txt_noGAN) as txt_obj: # line_list = [name.strip() for name in txt_obj.readlines()] # for line in line_list: # sub_image, sub_label = line.split(':') # org_sub_images.append(os.path.join(current_dir,sub_image)) # org_sub_labels.append(os.path.join(current_dir,sub_label)) # # # merge new sub images, and copy sub labels if necessary. new_sub_images = [] new_sub_labels = [] area_ini_sub_images_labels = io_function.read_dict_from_txt_json( area_ini_sub_images_labels_dict) # copy the original sub images and labels before GAN for key in area_ini_sub_images_labels.keys(): for line in area_ini_sub_images_labels[key]: sub_image, sub_label = line.split(':') new_sub_images.append(sub_image) new_sub_labels.append(sub_label) for area_idx, (area_ini, area_src_ini) in enumerate( zip(multi_gan_regions, multi_gan_source_regions)): area_name = parameters.get_string_parameters(area_ini, 'area_name') area_remark = parameters.get_string_parameters(area_ini, 'area_remark') area_time = parameters.get_string_parameters(area_ini, 'area_time') gan_project_save_dir = get_gan_project_save_dir( gan_working_dir, gan_dir_pre_name, area_name, area_remark, area_time, area_src_ini) org_sub_images = [] org_sub_labels = [] for line in area_ini_sub_images_labels[os.path.basename(area_src_ini)]: sub_image, sub_label = line.split(':') org_sub_images.append(os.path.join(current_dir, sub_image)) org_sub_labels.append(os.path.join(current_dir, sub_label)) # the new images, keep the same order of original images for idx, (org_img, org_label) in enumerate(zip(org_sub_images, org_sub_labels)): new_img = os.path.join(gan_project_save_dir, 'subImages_translate', 'I%d.tif' % idx) if os.path.isfile(new_img) is False: basic.outputlogMessage( 'warning, %d th image does not exist, ' 'may exceed gen_max_dataset_size, skip the following images ' % idx) break # check height, width, band count, datatype height, width, count, dtype = raster_io.get_height_width_bandnum_dtype( new_img) o_height, o_width, o_count, o_dtype = raster_io.get_height_width_bandnum_dtype( org_img) if height != o_height or width != o_width or count != o_count or dtype != o_dtype: raise ValueError( 'inconsistence between new GAN image and original images: %s vs %s' % (str([height, width, count, dtype ]), str([o_height, o_width, o_count, o_dtype]))) # copy subimage and sublabel new_file_name_no_ext = io_function.get_name_no_ext( org_img) + '_' + os.path.basename(gan_project_save_dir) save_img_path = os.path.join(save_image_dir, new_file_name_no_ext + '_gan.tif') save_label_path = os.path.join(save_label_dir, new_file_name_no_ext + '_label.tif') io_function.copy_file_to_dst(new_img, save_img_path, overwrite=False) io_function.copy_file_to_dst(org_label, save_label_path, overwrite=False) new_sub_images.append(save_img_path) new_sub_labels.append(save_label_path) # save new images_labels_list.txt, overwrite the original one with open(sub_img_label_txt, 'w') as f_obj: lines = [ img + ':' + label + '\n' for img, label in zip(new_sub_images, new_sub_labels) ] f_obj.writelines(lines) return True