3.3.4. Process a line-pattern image
The following workflow shows how to use Discorpy to process a line-pattern image, collected at Beamline I13 Diamond Light Source.
Load the image, calculate the slopes of lines at the middle of the image and distances between. These values will be used by the grouping step.
import discorpy.losa.loadersaver as io import discorpy.prep.preprocessing as prep import discorpy.prep.linepattern as lprep import discorpy.proc.processing as proc import discorpy.post.postprocessing as post # Initial parameters file_path = "../../data/line_pattern_01.jpg" output_base = "E:/output_demo_04/" num_coef = 5 # Number of polynomial coefficients print("1-> Load image: {}".format(file_path)) mat0 = io.load_image(file_path) (height, width) = mat0.shape print("2-> Calculate slope and distance between lines!!!") slope_hor, dist_hor = lprep.calc_slope_distance_hor_lines(mat0) slope_ver, dist_ver = lprep.calc_slope_distance_ver_lines(mat0) print(" Horizontal slope: ", slope_hor, " Distance: ", dist_hor) print(" Vertical slope: ", slope_ver, " Distance: ", dist_ver) # Horizontal slope: 9.921048172113442e-16 Distance: 62.22050730757496 # Vertical slope: 1.5501637768927253e-17 Distance: 62.258521480417485
Fig. 49 Line-pattern image.
Points belong to lines are detected by locating local minimum points of intensity-profiles across the image. The number of intensity-profiles generated is controlled by the ratio parameter. The sensitive parameter controls the sensitivity of the detection method.
print("3-> Extract reference-points !!!!") list_points_hor_lines = lprep.get_cross_points_hor_lines(mat0, slope_ver, dist_ver, ratio=0.5, sensitive=0.1) list_points_ver_lines = lprep.get_cross_points_ver_lines(mat0, slope_hor, dist_hor, ratio=0.5, sensitive=0.1) io.save_plot_points(output_base + "/extracted_hor_points.png", list_points_hor_lines, height, width) io.save_plot_points(output_base + "/extracted_ver_points.png", list_points_ver_lines, height, width)
Fig. 50 Detected points. (a) Horizontal lines. (b) Vertical lines.
Group detected-points into lines (Fig. 51). This step can remove unwanted points.
print("4-> Group points into lines !!!!") list_hor_lines = prep.group_dots_hor_lines(list_points_hor_lines, slope_hor, dist_hor) list_ver_lines = prep.group_dots_ver_lines(list_points_ver_lines, slope_ver, dist_ver) # Optional: remove residual dots list_hor_lines = prep.remove_residual_dots_hor(list_hor_lines, slope_hor, 2.0) list_ver_lines = prep.remove_residual_dots_ver(list_ver_lines, slope_ver, 2.0) io.save_plot_image(output_base + "/grouped_hor_lines.png", list_hor_lines, height, width) io.save_plot_image(output_base + "/grouped_ver_lines.png", list_ver_lines, height, width)
Fig. 51 Grouped points. (a) Horizontal lines. (b) Vertical lines.
The rest of the workflow is similar to other demos.
print("5-> Correct perspective effect !!!!") # Optional: correct perspective effect. list_hor_lines, list_ver_lines = proc.regenerate_grid_points_parabola( list_hor_lines, list_ver_lines, perspective=True) # Check if the distortion is significant. list_hor_data = post.calc_residual_hor(list_hor_lines, 0.0, 0.0) io.save_residual_plot(output_base + "/residual_horizontal_points_before.png", list_hor_data, height, width) list_ver_data = post.calc_residual_ver(list_ver_lines, 0.0, 0.0) io.save_residual_plot(output_base + "/residual_vertical_points_before.png", list_ver_data, height, width) print("6-> Calculate the centre of distortion !!!!") (xcenter, ycenter) = proc.find_cod_coarse(list_hor_lines, list_ver_lines) print(" X-center: {0}, Y-center: {1}".format(xcenter, ycenter)) print("7-> Calculate radial distortion coefficients !!!!") list_fact = proc.calc_coef_backward(list_hor_lines, list_ver_lines, xcenter, ycenter, num_coef) # Check the correction results list_uhor_lines = post.unwarp_line_backward(list_hor_lines, xcenter, ycenter, list_fact) list_uver_lines = post.unwarp_line_backward(list_ver_lines, xcenter, ycenter, list_fact) list_hor_data = post.calc_residual_hor(list_uhor_lines, xcenter, ycenter) list_ver_data = post.calc_residual_ver(list_uver_lines, xcenter, ycenter) io.save_residual_plot(output_base + "/residual_horizontal_points_after.png", list_hor_data, height, width) io.save_residual_plot(output_base + "/residual_vertical_points_after.png", list_ver_data, height, width) # Output print("8-> Apply correction to image !!!!") corrected_mat = post.unwarp_image_backward(mat0, xcenter, ycenter, list_fact) io.save_image(output_base + "/corrected_image.tif", corrected_mat) io.save_metadata_txt(output_base + "/coefficients.txt", xcenter, ycenter, list_fact) io.save_image(output_base + "/difference.tif", mat0 - corrected_mat) print("!!! Done !!!!")
Fig. 52 Residual of distorted points. (a) Horizontal lines. (b) Vertical lines.
Fig. 53 Residual of unwarped points. (a) Horizontal lines. (b) Vertical lines.
Fig. 54 Unwarped image.
Fig. 55 Difference between images before (Fig. 49) and after (Fig. 54) unwarping.
Click here
to download the Python codes.