def find_crosses(image_data, cross_size = 7, nms_threshold_high = 30, nms_threshold_low = 10, nms_threshold_axis_deletion = 2): """ :param image_data: :return: (x axis cross, y axis cross), [list of detected plot points] """ height = image_data.shape[0] width = image_data.shape[1] nms_mask_visited = numpy.zeros((height, width), dtype=bool) if utils_general.is_debug: find_crosses.counter += 1 image_dump = Image.new("L", (width, height)) x_axis_cross, y_axis_cross = find_axes(image_data, width, height) if x_axis_cross == -1 or y_axis_cross == -1: raise ValueError("Axis not found") if utils_general.is_debug: print("Detected axes cross: ", x_axis_cross, y_axis_cross) map_to_image_and_save(image_dump, image_data, "debug/", str(find_crosses.counter), "_before_cross_filter.png", mode = "user-wise") #Convolving image data with kernel detecting crosses cross_center = cross_size//2 negative_normalizer = 2*cross_size-1 positive_normalizer = cross_size*cross_size - (4*cross_size - 8) - negative_normalizer cross_kernel = numpy.array([[-1.0/negative_normalizer if xxx == cross_center or yyy == cross_center else (0 if abs(xxx - cross_center) == 1 or abs(yyy - cross_center) == 1 else 1.0/positive_normalizer) for xxx in range(cross_size)] for yyy in range(cross_size)]) data_cross = convolve2d(image_data, cross_kernel, mode='same') #Fixup in case if there're holes in axes' lines for i in range(-6, 7): if 0 <= y_axis_cross + i < height: if 0 <= x_axis_cross - 1: data_cross[y_axis_cross + i, x_axis_cross - 1] = 255 data_cross[y_axis_cross + i, x_axis_cross] = 255 if x_axis_cross + 1 < width: data_cross[y_axis_cross + i, x_axis_cross + 1] = 255 if 0 <= x_axis_cross + i < width: if 0 <= y_axis_cross - 1: data_cross[y_axis_cross - 1, x_axis_cross + i] = 255 data_cross[y_axis_cross, x_axis_cross + i] = 255 if y_axis_cross + 1 < height: data_cross[y_axis_cross + 1, x_axis_cross + i] = 255 data_cross = convolve2d(data_cross, get_gaussian_kernel(3, 2, True)) if utils_general.is_debug: map_to_image_and_save(image_dump, data_cross, "debug/", str(find_crosses.counter), "_before_nms.png", mode = "user-wise") x_low, x_high, y_low, y_high = find_plot_box([(x_axis_cross, y_axis_cross)], data_cross, nms_mask_visited, nms_threshold_axis_deletion, width, height) box = ((y_low, y_high), (x_low, x_high)) if utils_general.is_debug: print("Graph box: ", box) data_cross = apply_recursive_nms(box, data_cross, nms_mask_visited, nms_threshold_low, nms_threshold_high) if utils_general.is_debug: map_to_image_and_save(image_dump, data_cross, "debug/", str(find_crosses.counter), "_after_nms.png", mode = "user-wise") #Lising points passed through non-maximal suppression crosses_result_pt_list = [] crosses_result_val_list = [] for y in range(box[0][0], box[0][1]): for x in range(box[1][0], box[1][1]): if data_cross[y, x] > 0: crosses_result_pt_list.append((x - cross_center/2, y - cross_center/2, data_cross[y, x])) crosses_result_val_list.append(data_cross[y, x]) if not crosses_result_val_list: raise ValueError("Axis is found, but not plot points detected") #Filtering weak fitting points threshold_cross_value = median(crosses_result_val_list)/2 crosses_result_pt_list = [(item[0], item[1]) for item in crosses_result_pt_list if item[2] > threshold_cross_value] return x_axis_cross, y_axis_cross, crosses_result_pt_list
height = image.size[1] pix = image.load() if utils_general.is_debug: image.save(join(debug_dir, filename + "_image+median.png"), "PNG") # Creates image for gradient then processing it image_gradient, gradient_abs = compute_gradient(pix, width, height, gradient_threshold) if utils_general.is_debug: image_gradient.save(join(debug_dir, filename + "_gradient.png"), "PNG") external_borders_map = np.zeros((width, height)) #[[0]*height for x in range(width)] external_borders_map = mark_external_borders(external_borders_map, gradient_abs, 0, height, 0, width, 25, 1, False) if utils_general.is_debug: map_to_image_and_save(image_gradient, external_borders_map, debug_dir, filename, "_processed_gradient.png", mode="data-wise") # Performs quick window search. Thus we obtain approximate location of document. processed_gradient_ii = compute_integral_image_buffer(external_borders_map, height, width, mode="buffer") x_pt, y_pt, x_window_size, y_window_size = integral_image_window_detect(processed_gradient_ii, width, height) if utils_general.is_debug: if x_window_size != y_window_size: print("WARNING: quick window search unsuccessful, performing search on whole image") draw.rectangle((x_pt, y_pt, x_pt + x_window_size, y_pt + y_window_size), fill=None) image.save(join(debug_dir, filename + "_window_detected.png"), "PNG") external_borders_map = mark_external_borders(external_borders_map, gradient_abs, y_pt, y_pt + y_window_size, x_pt, x_pt + x_window_size, 1000, 0, True) if utils_general.is_debug: