def predict_image(model, image_path, score_threshold=0.1, max_detections=200, return_plot=True): """ Predict an image return_plot: Logical. If true, return a image object, else return bounding boxes """ #predict raw_image = cv2.imread(image_path) image = image_utils.preprocess_image(raw_image) image, scale = keras_retinanet_image.resize_image(image) if keras.backend.image_data_format() == 'channels_first': image = image.transpose((2, 0, 1)) # run network boxes, scores, labels = model.predict_on_batch( np.expand_dims(image, axis=0))[:3] # correct boxes for image scale boxes /= scale # select indices which have a score above the threshold indices = np.where(scores[0, :] > score_threshold)[0] # select those scores scores = scores[0][indices] # find the order with which to sort the scores scores_sort = np.argsort(-scores)[:max_detections] # select detections image_boxes = boxes[0, indices[scores_sort], :] image_scores = scores[scores_sort] image_labels = labels[0, indices[scores_sort]] image_detections = np.concatenate([ image_boxes, np.expand_dims(image_scores, axis=1), np.expand_dims(image_labels, axis=1) ], axis=1) if return_plot: draw_detections(raw_image, image_boxes, image_scores, image_labels, label_to_name=label_to_name, score_threshold=score_threshold) return raw_image else: return image_boxes
return new_detections, new_detections_metric def save_images(path_list, detections, generator, score_threshold, save_path, iou_frames): <<<<<<< HEAD for i in progressbar.progressbar(range(generator.size()), prefix='Saving images: '): ======= for i in progressbar.progressbar(range(generator.size()-9400), prefix='Saving images: '): >>>>>>> 19c53023491d92692b7d44f1343b74e2d6623f42 #draw_annotations(generator.load, generator.load_annotations(i), label_to_name=generator.label_to_name) image = generator.load_image(path_list[i][0]) draw_detections( image, detections[i][0], detections[i][1], detections[i][2], label_to_name=generator.label_to_name, score_threshold=score_threshold ) output_path = make_output_path(save_path, generator.image_path(path_list[i][0]), flatten=False) os.makedirs(os.path.dirname(output_path), exist_ok=True) cv2.imwrite(output_path, image) def evaluate(generator, detections, iou_threshold): all_detections = detections all_annotations = _get_annotations(generator) average_precisions = {} for label in range(generator.num_classes()): if not generator.has_label(label): continue
def _get_detections(generator, model, score_threshold=0.05, max_detections=300, save_path=None, experiment=None, postprocess=False): """ Get the detections from the model using the generator. The result is a list of lists such that the size is: all_detections[num_images][num_classes] = detections[num_detections, 4 + num_classes] # Arguments generator : The generator used to run images through the model. model : The model to run on the images. score_threshold : The score confidence threshold to use. max_detections : The maximum number of detections to use per image. save_path : The path to save the images with visualized detections to. experiment : Comet ML experiment # Returns A list of lists containing the detections for each image in the generator. """ all_detections = [[None for i in range(generator.num_classes())] for j in range(generator.size())] for i in range(generator.size()): raw_image = generator.load_image(i) plot_image = copy.deepcopy(raw_image) #Format name and save image_name = generator.image_names[i] row = generator.image_data[image_name] lfname = os.path.splitext(row["tile"])[0] + "_" + str( row["window"]) + "raw_image" #Skip if missing a component data source if raw_image is False: print("Empty image, skipping") continue #Store plotting images plot_rgb = plot_image[:, :, :3].copy() #predict image = generator.preprocess_image(raw_image) image, scale = generator.resize_image(image) if keras.backend.image_data_format() == 'channels_first': image = image.transpose((2, 0, 1)) # run network boxes, scores, labels = model.predict_on_batch( np.expand_dims(image, axis=0))[:3] # correct boxes for image scale boxes /= scale # select indices which have a score above the threshold indices = np.where(scores[0, :] > score_threshold)[0] # select those scores scores = scores[0][indices] # find the order with which to sort the scores scores_sort = np.argsort(-scores)[:max_detections] # select detections image_boxes = boxes[0, indices[scores_sort], :] image_scores = scores[scores_sort] image_labels = labels[0, indices[scores_sort]] image_detections = np.concatenate([ image_boxes, np.expand_dims(image_scores, axis=1), np.expand_dims(image_labels, axis=1) ], axis=1) #name image image_name = generator.image_names[i] row = generator.image_data[image_name] fname = os.path.splitext(row["tile"])[0] + "_" + str(row["window"]) #drape boxes if they exist if len(image_boxes) > 0: #get lidar cloud if a new tile, or if not the same tile as previous image. if generator.with_lidar: if i == 0: generator.load_lidar_tile() elif not generator.image_data[i][ "tile"] == generator.image_data[i - 1]["tile"]: generator.load_lidar_tile() #The tile could be the full tile, so let's check just the 400 pixel crop we are interested #Not the best structure, but the on-the-fly generator always has 0 bounds if hasattr(generator, 'hf'): bounds = generator.hf["utm_coords"][generator.row["window"]] else: bounds = [] if save_path is not None: draw_annotations(plot_rgb, generator.load_annotations(i), label_to_name=generator.label_to_name) draw_detections(plot_rgb, image_boxes, image_scores, image_labels, label_to_name=generator.label_to_name, score_threshold=score_threshold) #name image image_name = generator.image_names[i] row = generator.image_data[image_name] fname = os.path.splitext(row["tile"])[0] + "_" + str(row["window"]) #Write RGB cv2.imwrite(os.path.join(save_path, '{}.png'.format(fname)), plot_rgb) if experiment: experiment.log_image(os.path.join(save_path, '{}.png'.format(fname)), name=fname) # copy detections to all_detections for label in range(generator.num_classes()): all_detections[i][label] = image_detections[ image_detections[:, -1] == label, :-1] return all_detections
def _get_detections(generator, model, score_threshold=0.05, max_detections=100, save_path=None): """ Get the detections from the model using the generator. The result is a list of lists such that the size is: all_detections[num_images][num_classes] = detections[num_detections, 4 + num_classes] # Arguments generator : The generator used to run images through the model. model : The model to run on the images. score_threshold : The score confidence threshold to use. max_detections : The maximum number of detections to use per image. save_path : The path to save the images with visualized detections to. # Returns A list of lists containing the detections for each image in the generator. """ all_detections = [[None for i in range(generator.num_classes())] for j in range(generator.size())] all_masks = [[None for i in range(generator.num_classes())] for j in range(generator.size())] for i in range(generator.size()): raw_image = generator.load_image(i) image = generator.preprocess_image(raw_image.copy()) image, scale = generator.resize_image(image) # run network outputs = model.predict_on_batch(np.expand_dims(image, axis=0)) boxes = outputs[-4] scores = outputs[-3] labels = outputs[-2] masks = outputs[-1] # correct boxes for image scale boxes /= scale # select indices which have a score above the threshold indices = np.where(scores[0, :] > score_threshold)[0] # select those scores scores = scores[0][indices] # find the order with which to sort the scores scores_sort = np.argsort(-scores)[:max_detections] # select detections image_boxes = boxes[0, indices[scores_sort], :] image_scores = scores[scores_sort] image_labels = labels[0, indices[scores_sort]] image_masks = masks[0, indices[scores_sort], :, :, image_labels] image_detections = np.concatenate([ image_boxes, np.expand_dims(image_scores, axis=1), np.expand_dims(image_labels, axis=1) ], axis=1) if save_path is not None: # draw_annotations(raw_image, generator.load_annotations(i)[0], label_to_name=generator.label_to_name) draw_detections(raw_image, image_boxes, image_scores, image_labels, score_threshold=score_threshold, label_to_name=generator.label_to_name) draw_masks(raw_image, image_boxes.astype(int), image_masks, labels=image_labels) cv2.imwrite(os.path.join(save_path, '{}.png'.format(i)), raw_image) # copy detections to all_detections for label in range(generator.num_classes()): all_detections[i][label] = image_detections[ image_detections[:, -1] == label, :-1] all_masks[i][label] = image_masks[image_detections[:, -1] == label, ...] print('{}/{}'.format(i + 1, generator.size()), end='\r') return all_detections, all_masks
def neonRecall( sites, generator, model, score_threshold=0.05, max_detections=100, suppression_threshold=0.15, save_path=None, experiment=None): point_contains = [ ] site_data_dict = {} for site in sites: #Container for recall pts. #load field data field_data = pd.read_csv("data/field_data.csv") field_data = field_data[field_data['UTM_E'].notnull()] #select site site_data = field_data[field_data["siteID"]==site] #select tree species specieslist = pd.read_csv("data/AcceptedSpecies.csv",encoding="utf-8") specieslist = specieslist[specieslist["siteID"] == site] site_data = site_data[site_data["scientificName"].isin(specieslist["scientificName"].values)] #Single bole individuals as representitve, no individualID ending in non-digits site_data = site_data[site_data["individualID"].str.contains("\d$")] site_data_dict[site] = site_data #Only data within the last two years, sites can be hand managed #site_data=site_data[site_data["eventID"].str.contains("2015|2016|2017|2018")] for i in range(generator.size()): #Load image raw_image = generator.load_image(i) plot_image = copy.deepcopy(raw_image) #Skip if missing a component data source if raw_image is False: print("Empty image, skipping") continue #Store plotting images. plot_rgb = plot_image[:,:,:3].copy() plot_chm = plot_image[:,:,3] image = generator.preprocess_image(raw_image) image, scale = generator.resize_image(image) # run network boxes, scores, labels = model.predict_on_batch(np.expand_dims(image, axis=0))[:3] # correct boxes for image scale boxes /= scale # select indices which have a score above the threshold indices = np.where(scores[0, :] > score_threshold)[0] # select those scores scores = scores[0][indices] # find the order with which to sort the scores scores_sort = np.argsort(-scores)[:max_detections] # select detections image_boxes = boxes[0, indices[scores_sort], :] image_scores = scores[scores_sort] image_labels = labels[0, indices[scores_sort]] image_detections = np.concatenate([image_boxes, np.expand_dims(image_scores, axis=1), np.expand_dims(image_labels, axis=1)], axis=1) #Find geographic bounds base_dir = generator.DeepForest_config[generator.row["site"]][generator.name]["RGB"] tile_path = os.path.join(base_dir, generator.image_data[i]["tile"]) with rasterio.open(tile_path) as dataset: tile_bounds = dataset.bounds #drape boxes #get lidar cloud if a new tile, or if not the same tile as previous image. if i == 0: generator.load_lidar_tile() elif not generator.image_data[i]["tile"] == generator.image_data[i-1]["tile"]: generator.load_lidar_tile() #The tile could be the full tile, so let's check just the 400 pixel crop we are interested #Not the best structure, but the on-the-fly generator always has 0 bounds if hasattr(generator, 'hf'): bounds = generator.hf["utm_coords"][generator.row["window"]] else: bounds=[] density = Lidar.check_density(generator.lidar_tile, bounds=bounds) #print("Point density is {:.2f}".format(density)) if density > 100: #find window utm coordinates #print("Bounds for image {}, window {}, are {}".format(generator.row["tile"], generator.row["window"], bounds)) pc = postprocessing.drape_boxes(boxes=image_boxes, pc = generator.lidar_tile, bounds=bounds) #Get new bounding boxes new_boxes = postprocessing.cloud_to_box(pc, bounds) new_scores = image_scores[:new_boxes.shape[0]] new_labels = image_labels[:new_boxes.shape[0]] image_detections = np.concatenate([new_boxes, np.expand_dims(new_scores, axis=1), np.expand_dims(new_labels, axis=1)], axis=1) else: #print("Point density of {:.2f} is too low, skipping image {}".format(density, generator.row["tile"])) pass #add spatial NEON points site_data =site_data_dict[generator.row["site"]] plotID = os.path.splitext(generator.image_data[i]["tile"])[0] plot_data = site_data[site_data.plotID == plotID] #Save image and send it to logger if save_path is not None: x = (plot_data.UTM_E - tile_bounds.left).values / 0.1 y = (tile_bounds.top - plot_data.UTM_N).values / 0.1 for j in np.arange(len(x)): cv2.circle(plot_image,(int(x[j]),int(y[j])), 2, (0,0,255), -1) #Write RGB draw_detections(plot_rgb, image_boxes, image_scores, image_labels, label_to_name=generator.label_to_name,score_threshold=score_threshold) #name image image_name=generator.image_names[i] row=generator.image_data[image_name] fname=os.path.splitext(row["tile"])[0] + "_" + str(row["window"]) #Write RGB cv2.imwrite(os.path.join(save_path, '{}_NeonPlot.png'.format(fname)), plot_rgb) plot_chm = plot_chm/plot_chm.max() * 255 chm = np.uint8(plot_chm) draw_detections(chm, image_boxes, image_scores, image_labels, label_to_name=generator.label_to_name, score_threshold=score_threshold, color = (80,127,255)) cv2.imwrite(os.path.join(save_path, '{}_Lidar_NeonPlot.png'.format(plotID)), chm) #Format name and save if experiment: experiment.log_image(os.path.join(save_path, '{}_NeonPlot.png'.format(plotID)),file_name=str(plotID)) experiment.log_image(os.path.join(save_path, '{}_Lidar_NeonPlot.png'.format(plotID)),file_name=str("Lidar_" + plotID)) #calculate recall s = gp.GeoSeries(map(Point, zip(plot_data.UTM_E, plot_data.UTM_N))) #Calculate recall projected_boxes = [] for row in image_boxes: #Add utm bounds and create a shapely polygon pbox=create_polygon(row, tile_bounds, cell_size=0.1) projected_boxes.append(pbox) #for each point, is it within a prediction? for index, tree in plot_data.iterrows(): p=Point(tree.UTM_E, tree.UTM_N) within_polygon=[] for prediction in projected_boxes: within_polygon.append(p.within(prediction)) #Check for overlapping polygon, add it to list is_within = sum(within_polygon) > 0 point_contains.append(is_within) #sum recall across plots if len(point_contains)==0: recall = None else: ## Recall rate for plot recall = sum(point_contains)/len(point_contains) return(recall)
def predictTest(model, data_dir, target_path, score_threshold=0.2, seriesuids=None, imshow=True, input_min_max_side=(768, 768)): data_npy_name_list = [ file_name for file_name in os.listdir(data_dir) if '.npy' in file_name ] anno_list = [] target_dir = os.path.dirname(target_path) if not os.path.exists(target_dir): os.mkdir(target_dir) for data_npy_name in data_npy_name_list: seriesuid = data_npy_name.split('.npy')[0] if seriesuids is not None and seriesuid not in seriesuids: continue print('detect', seriesuid) data_path = os.path.join(data_dir, data_npy_name) info_pkl_path = os.path.join(data_dir, seriesuid + '.pkl') with open(info_pkl_path, 'rb') as fp: patient_info = pickle.load(fp) data_npy = np.load(data_path) # zyx data_npy = np.transpose(data_npy, (1, 2, 0)) # zyx -> yxz slice_start = INPUT_SLICE // 2 for slice_idx in range(slice_start, data_npy.shape[2] - INPUT_SLICE // 2, max(INPUT_SLICE // 2, 1)): s_start = slice_idx - INPUT_SLICE // 2 input_data = (data_npy[:, :, s_start:s_start + INPUT_SLICE]).copy() input_img, scale = resize_image( preprocess_image(input_data, 'caffe'), input_min_max_side[0], input_min_max_side[1]) boxes, scores, labels = model.predict_on_batch( np.expand_dims(input_img, axis=0)) boxes = boxes[0] scores = scores[0] labels = labels[0] if imshow: img_show = np.tile( ((input_img + 128)[:, :, 1:2]).astype(np.uint8), (1, 1, 3)) draw_detections(img_show, boxes, scores, labels, color=(0, 255, 0), score_threshold=score_threshold) cv2.imshow('detect_image', img_show) k = cv2.waitKey() if k == ord('q'): exit() elif k == ord('c'): imshow = False boxes /= scale for label, score, box in zip(labels, scores, boxes): if score < score_threshold: continue x1, y1, x2, y2 = box voxelX = (x1 + x2) / 2 voxelY = (y1 + y2) / 2 voxelZ = slice_idx coordX, coordY, coordZ = coord_pix_to_world( [voxelX, voxelY, voxelZ], patient_info['spacing'], patient_info['origin'], patient_info['direction']) the_label = CLASS_IDX_TO_MODEL_CLASS_ID[str(label)] anno_list.append( [seriesuid, coordX, coordY, coordZ, the_label, score]) anno_csv = pd.DataFrame(data=anno_list, columns=RESULT_CSV_COLUMNS) anno_csv.to_csv(target_path, index=False, encoding='UTF-8')
def predict_image(model, image_path, score_threshold=0.1, max_detections=200, return_plot=True): """ Predict invidiual tree crown bounding boxes for a single image model (object): A keras-retinanet model to predict bounding boxes, either load a model from weights, use the latest release, or train a new model from scratch. image_path (str): Path to image file on disk score_threshold (float): Minimum probability score to be included in final boxes, ranging from 0 to 1. max_detections (int): Maximum number of bounding box predictions per tile return_plot (bool): If true, return a image object, else return bounding boxes as a numpy array Returns: raw_image (array): If return_plot is TRUE, the image with the overlaid boxes is returned image_boxes: If return_plot is FALSE, the bounding boxes as a 4 column array -> xmin, ymin, xmax, ymax """ #predict raw_image = cv2.imread(image_path) image = preprocess(raw_image) image, scale = keras_retinanet_image.resize_image(image) if keras.backend.image_data_format() == 'channels_first': image = image.transpose((2, 0, 1)) # run network boxes, scores, labels = model.predict_on_batch( np.expand_dims(image, axis=0))[:3] # correct boxes for image scale boxes /= scale # select indices which have a score above the threshold indices = np.where(scores[0, :] > score_threshold)[0] # select those scores scores = scores[0][indices] # find the order with which to sort the scores scores_sort = np.argsort(-scores)[:max_detections] # select detections image_boxes = boxes[0, indices[scores_sort], :] image_scores = scores[scores_sort] image_labels = labels[0, indices[scores_sort]] image_detections = np.concatenate([ image_boxes, np.expand_dims(image_scores, axis=1), np.expand_dims(image_labels, axis=1) ], axis=1) if return_plot: draw_detections(raw_image, image_boxes, image_scores, image_labels, label_to_name=label_to_name, score_threshold=score_threshold) return raw_image else: return image_boxes
# print("image_scores",image_scores.shape,image_scores) # print("image_labels",image_labels.shape,image_labels) image_boxes = image_boxes[indices_postnms] image_scores = image_scores[indices_postnms] image_labels = image_labels[indices_postnms] # # print("image_boxes",image_boxes.shape,image_boxes) # print("image_scores",image_scores.shape,image_scores) # print("image_labels",image_labels.shape,image_labels) # print("indices_postnms", indices_postnms) image_detections = np.concatenate([image_boxes, np.expand_dims(image_scores, axis=1), np.expand_dims(image_labels, axis=1)], axis=1) data_sequence.results[id]=image_detections if save_path is not None and len(indices)>0: draw_detections(image, image_boxes, image_scores, image_labels, label_to_name=label_to_name,score_threshold=0) cv2.imwrite(os.path.join(save_path, '{}.jpg'.format(id)), image) # if len(indices)>0: psaver.add_instances(data_sequence.filename, xywh, image_boxes, image_scores) psaver.save() psaver.save_nms() psaver.save_tagbrowser() psaver.save_nms_tagbrowser() # with open(saving_result_path, 'wb') as handle: # pickle.dump(img_infos, handle, protocol = pickle.HIGHEST_PROTOCOL) ordered_data_sequence.stop()
def predict_image(model, image_path=None, raw_image=None, score_threshold=0.05, max_detections=200, return_plot=True, classes={"0": "Tree"}, color=None): """ Predict invidiual tree crown bounding boxes for a single image Args: model (object): A keras-retinanet model to predict bounding boxes, either load a model from weights, use the latest release, or train a new model from scratch. image_path (str): Path to image file on disk raw_image (str): Numpy image array in BGR channel order following openCV convention score_threshold (float): Minimum probability score to be included in final boxes, ranging from 0 to 1. max_detections (int): Maximum number of bounding box predictions per tile return_plot (bool): If true, return a image object, else return bounding boxes as a numpy array Returns: raw_image (array): If return_plot is TRUE, the image with the overlaid boxes is returned image_detections: If return_plot is FALSE, a np.array of image_boxes, image_scores, image_labels """ #Check for raw_image if raw_image is not None: numpy_image = raw_image.copy() else: #Read from path numpy_image = cv2.imread(image_path) #Make sure image exists try: numpy_image.shape except: raise IOError( "Image file {} cannot be read, check that it exists".format( image_path)) #Check that its 3 band bands = numpy_image.shape[2] if not bands == 3: raise IOError( "Input file {} has {} bands. DeepForest only accepts 3 band RGB rasters. If the image was cropped and saved as a .jpg, please ensure that no alpha channel was used." .format(path_to_raster, bands)) image = keras_retinanet_image.preprocess_image(numpy_image) image, scale = keras_retinanet_image.resize_image(image) if keras.backend.image_data_format() == 'channels_first': image = image.transpose((2, 0, 1)) # run network boxes, scores, labels = model.predict_on_batch( np.expand_dims(image, axis=0))[:3] # correct boxes for image scale boxes /= scale # select indices which have a score above the threshold indices = np.where(scores[0, :] > score_threshold)[0] # select those scores scores = scores[0][indices] # find the order with which to sort the scores scores_sort = np.argsort(-scores)[:max_detections] # select detections image_boxes = boxes[0, indices[scores_sort], :] image_scores = scores[scores_sort] image_labels = labels[0, indices[scores_sort]] image_detections = np.concatenate([ image_boxes, np.expand_dims(image_scores, axis=1), np.expand_dims(image_labels, axis=1) ], axis=1) df = pd.DataFrame( image_detections, columns=["xmin", "ymin", "xmax", "ymax", "score", "label"]) #Change numberic class into string label df.label = df.label.astype(int) df.label = df.label.apply(lambda x: classes[x]) if return_plot: draw_detections(numpy_image, image_boxes, image_scores, image_labels, label_to_name=None, score_threshold=score_threshold, color=color) return numpy_image else: return df
def Jaccard( generator, model, iou_threshold=0.5, score_threshold=0.05, max_detections=100, suppression_threshold=0.2, save_path=None, experiment=None, DeepForest_config = None ): """ Evaluate a given dataset using a given model. # Arguments generator : The generator that represents the dataset to evaluate. model : The model to evaluate. iou_threshold : The threshold used to consider when a detection is positive or negative. score_threshold : The score confidence threshold to use for detections. max_detections : The maximum number of detections to use per image. save_path : The path to save images with visualized detections to. experiment : Comet ml experiment to evaluate # Returns A dict mapping class names to mAP scores. """ #Load ground truth polygons ground_truth, ground_truth_tiles, ground_truth_utmbox=_load_groundtruth(DeepForest_config) plot_IoU ={} for plot in ground_truth: print(plot) #Load polygons polys=ground_truth[plot]["data"] #read rgb tile tile=ground_truth_tiles[plot] numpy_image=load_image(tile) #Gather detections final_boxes=predict_tile(numpy_image, generator, model, score_threshold, max_detections, suppression_threshold) #Save image and send it to logger if save_path is not None: draw_detections(numpy_image, final_boxes[:,:4], final_boxes[:,4], final_boxes[:,5], label_to_name=generator.label_to_name,score_threshold=score_threshold) cv2.imwrite(os.path.join(save_path, '{}.png'.format(plot)), numpy_image) if experiment: experiment.log_image(os.path.join(save_path, '{}.png'.format(plot)),file_name=str(plot)+"groundtruth") #Find overlap projected_boxes=[] for row in final_boxes: #Add utm bounds and create a shapely polygon pbox=create_polygon(row, ground_truth_utmbox[plot],cell_size=0.1) projected_boxes.append(pbox) if save_path is not None: draw_ground_overlap(plot,ground_truth,ground_truth_tiles,projected_boxes,save_path=save_path,experiment=experiment) #Match overlap and generate cost matrix and fill with non-zero elements IoU=calculateIoU(ground_truth[plot], projected_boxes) plot_IoU[plot]=IoU #Mean IoU across all plots #Mean IoU across all plots all_values=list(plot_IoU.values()) meanIoU=np.mean(list(chain(*all_values))) return meanIoU
def neonRecall( site, generator, model, score_threshold=0.05, max_detections=100, suppression_threshold=0.2, save_path=None, experiment=None, DeepForest_config = None): #load field data field_data=pd.read_csv("data/field_data.csv") field_data=field_data[field_data['UTM_E'].notnull()] #select site site_data=field_data[field_data["siteID"]==site] #select tree species specieslist=pd.read_csv("data/AcceptedSpecies.csv") specieslist = specieslist[specieslist["siteID"]==site] site_data=site_data[site_data["scientificName"].isin(specieslist["scientificName"].values)] #Single bole individuals as representitve, no individualID ending in non-digits site_data=site_data[site_data["individualID"].str.contains("\d$")] #Only data within the last two years, sites can be hand managed #site_data=site_data[site_data["eventID"].str.contains("2015|2016|2017|2018")] #Get remaining plots plots=site_data.plotID.unique() point_contains=[] for plot in plots: #select plot plot_data=site_data[site_data["plotID"]==plot] #load plot image tile="data/" + site + "/" + plot + ".tif" #Check if file exists, if not, skip if os.path.exists(tile): numpy_image=load_image(tile) else: continue #Gather detections final_boxes=predict_tile(numpy_image,generator,model,score_threshold,max_detections,suppression_threshold) #If empty, skip. if final_boxes is None: continue #Find geographic bounds with rasterio.open(tile) as dataset: bounds=dataset.bounds #Save image and send it to logger if save_path is not None: draw_detections(numpy_image, final_boxes[:,:4], final_boxes[:,4], final_boxes[:,5], label_to_name=generator.label_to_name,score_threshold=0.05) #add points x=(plot_data.UTM_E- bounds.left).values/0.1 y=(bounds.top - plot_data.UTM_N).values/0.1 for i in np.arange(len(x)): cv2.circle(numpy_image,(int(x[i]),int(y[i])), 5, (0,0,255), 1) cv2.imwrite(os.path.join(save_path, '{}_NeonPlot.png'.format(plot)), numpy_image) if experiment: experiment.log_image(os.path.join(save_path, '{}_NeonPlot.png'.format(plot)),file_name=str(plot)) projected_boxes = [] for row in final_boxes: #Add utm bounds and create a shapely polygon pbox=create_polygon(row, bounds,cell_size=0.1) projected_boxes.append(pbox) #for each point for index,tree in plot_data.iterrows(): p=Point(tree.UTM_E,tree.UTM_N) within_polygon=[] for prediction in projected_boxes: within_polygon.append(p.within(prediction)) #Check for overlapping polygon, add it to list point_contains.append(sum(within_polygon) > 0) if len(point_contains)==0: recall=0 else: ## Recall rate for plot recall=sum(point_contains)/len(point_contains) #Log return(recall)