Skip to content

Commit 6e1046f

Browse files
committed
Add demo for fisheye correction using chessboard and dot-pattern
1 parent b8243eb commit 6e1046f

File tree

7 files changed

+148
-4
lines changed

7 files changed

+148
-4
lines changed
4.24 MB
Loading
3.46 MB
Loading
497 KB
Loading
335 KB
Loading

docs/source/technical_notes/fisheye_correction.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,29 @@ To summarize, only a small amount of code is required to calibrate the camera, a
468468
# img_corr = util.unwarp_image_backward_cv2(img0, xcenter, ycenter, list_bfact, pad=400)
469469
losa.save_image(output_base + "/corrected_img.jpg", img_corr)
470470
471+
472+
Using other types of calibration images
473+
---------------------------------------
474+
475+
Other types of calibration images can also be used and are straightforward to process using the Discorpy API.
476+
The following shows the results of using a chessboard image. Both the `image <https://github.com/DiamondLightSource/discorpy/tree/master/data/fisheye>`__
477+
and the `code <https://github.com/DiamondLightSource/discorpy/tree/master/examples>`__
478+
are available on the Discorpy GitHub page. As can be seen, the calibration image clearly has perspective
479+
distortion, but this is no longer a problem with the latest developments.
480+
481+
.. figure:: figs/fisheye_correction/fig13.jpg
482+
:name: fisheye_fig_13
483+
:figwidth: 100 %
484+
:align: center
485+
:figclass: align-center
486+
487+
Radial distortion calibration using a chessboard image: (a) Before correction. (b) After correction.
488+
489+
490+
.. figure:: figs/fisheye_correction/fig14.jpg
491+
:name: fisheye_fig_14
492+
:figwidth: 100 %
493+
:align: center
494+
:figclass: align-center
495+
496+
Radial distortion calibration using a dot-pattern image: (a) Before correction. (b) After correction.

examples/fisheye_calibration.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#============================================================================
2-
# Demonstration on how to calibrate a fisheye camera.
3-
# ============================================================================
1+
#==============================================================================
2+
# Demonstration on how to calibrate a fisheye camera using a line-pattern image
3+
# =============================================================================
44

55
import discorpy.losa.loadersaver as losa
66
import discorpy.prep.preprocessing as prep
@@ -9,7 +9,7 @@
99
import discorpy.post.postprocessing as post
1010
import discorpy.util.utility as util
1111

12-
file_path = "../data/GoPro8_line_pattern.jpg"
12+
file_path = "../data/fisheye/GoPro8_line_pattern.jpg"
1313
output_base = "E:/fisheye_correction"
1414
num_factor = 5
1515

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#==============================================================================
2+
# Demonstration on how to calibrate a fisheye camera using a chessboard image
3+
# =============================================================================
4+
5+
import discorpy.losa.loadersaver as losa
6+
import discorpy.prep.preprocessing as prep
7+
import discorpy.prep.linepattern as lprep
8+
import discorpy.proc.processing as proc
9+
import discorpy.post.postprocessing as post
10+
import discorpy.util.utility as util
11+
import matplotlib.pyplot as plt
12+
13+
file_path = r"..\data\fisheye\GoPro8_chessboard_pattern.jpg"
14+
test_file_path = r"..\data\fisheye\GoPro8_testing_image.jpg"
15+
output_base = r"F:\tmp\fisheye_correction_chessboard"
16+
17+
print(" 1-> Load image ...")
18+
img0 = losa.load_image(file_path)
19+
(height, width) = img0.shape
20+
img_norm = prep.normalization_fft(img0, 10)
21+
22+
chessboad = True
23+
num_factor = 5
24+
25+
print(" 2-> Calculate slope and distance between lines...")
26+
slope_hor, dist_hor = lprep.calc_slope_distance_hor_lines(img_norm, chessboard=chessboad)
27+
slope_ver, dist_ver = lprep.calc_slope_distance_ver_lines(img_norm, chessboard=chessboad)
28+
print(f" Horizontal slope: {slope_hor} Distance: {dist_hor}")
29+
print(f" Vertical slope : {slope_ver} Distance: {dist_ver}")
30+
print(" 3-> Extract reference-points !!!!")
31+
32+
# Detect points on lines, lines are dark, background is bright.
33+
list_points_hor_lines = lprep.get_cross_points_hor_lines(img_norm, slope_ver, dist_ver,
34+
bgr='bright', chessboard=chessboad,
35+
radius=9, sensitive=0.3)
36+
list_points_ver_lines = lprep.get_cross_points_ver_lines(img_norm, slope_hor, dist_hor,
37+
bgr='bright', chessboard=chessboad,
38+
radius=9, sensitive=0.3)
39+
40+
hor_margin = (500, 450)
41+
ver_margin = (250, 250)
42+
list_points_hor_lines = prep.remove_points_using_parabola_mask(list_points_hor_lines,
43+
height, width,
44+
hor_curviness=0.4,
45+
ver_curviness=0.3,
46+
hor_margin=hor_margin,
47+
ver_margin=ver_margin)
48+
49+
list_points_ver_lines = prep.remove_points_using_parabola_mask(list_points_ver_lines,
50+
height, width,
51+
hor_curviness=0.4,
52+
ver_curviness=0.3,
53+
hor_margin=hor_margin,
54+
ver_margin=ver_margin)
55+
56+
mask = prep.make_parabola_mask(height, width,hor_curviness=0.4, ver_curviness=0.3,
57+
hor_margin=hor_margin, ver_margin=ver_margin)
58+
59+
# plt.imshow(img_norm * mask, origin="lower")
60+
# plt.show()
61+
# plt.imshow(img_norm, origin="lower")
62+
# plt.plot(list_points_hor_lines[:, 1], list_points_hor_lines[:, 0], ".", color="red")
63+
# plt.plot(list_points_ver_lines[:, 1], list_points_ver_lines[:, 0], ".", color="blue")
64+
# plt.show()
65+
66+
print(" 4-> Group points into lines !!!!")
67+
list_hor_lines = prep.group_dots_hor_lines_based_polyfit(list_points_hor_lines,
68+
slope_hor, dist_hor,
69+
ratio=0.1, num_dot_miss=3,
70+
accepted_ratio=0.65, order=2)
71+
list_ver_lines = prep.group_dots_ver_lines_based_polyfit(list_points_ver_lines,
72+
slope_ver, dist_ver,
73+
ratio=0.1, num_dot_miss=3,
74+
accepted_ratio=0.65, order=2)
75+
76+
plt.imshow(img_norm, origin="lower")
77+
for line in list_hor_lines:
78+
plt.plot(line[:, 1], line[:, 0], "-o", color="red")
79+
for line in list_ver_lines:
80+
plt.plot(line[:, 1], line[:, 0], "-o", color="blue")
81+
plt.show()
82+
83+
list_hor_lines = prep.remove_residual_dots_hor(list_hor_lines, slope_hor, 3.0)
84+
list_ver_lines = prep.remove_residual_dots_ver(list_ver_lines, slope_ver, 3.0)
85+
86+
# for line in list_hor_lines:
87+
# plt.plot(line[:, 1], line[:, 0], "-o", color="red")
88+
# for line in list_ver_lines:
89+
# plt.plot(line[:, 1], line[:, 0], "-o", color="blue")
90+
# plt.show()
91+
92+
# Find center of distortion
93+
xcenter, ycenter = proc.find_center_based_vanishing_points_iteration(
94+
list_hor_lines, list_ver_lines, iteration=2)
95+
print(f"Center of distortion: X-center {xcenter}. Y-center {ycenter}")
96+
# Correct perspective distortion
97+
corr_hor_lines, corr_ver_lines = proc.correct_perspective_effect(
98+
list_hor_lines, list_ver_lines, xcenter, ycenter)
99+
# Calculate polynomial coefficients of the radial distortion
100+
list_bfact = proc.calc_coef_backward(corr_hor_lines, corr_ver_lines, xcenter,
101+
ycenter, num_factor)
102+
print(f"Polynomial coefficients of radial distortion: {list_bfact}")
103+
losa.save_metadata_json(output_base + "/distortion_parameters.json", xcenter,
104+
ycenter, list_bfact)
105+
106+
# Load calibration image as color image
107+
img0 = losa.load_image(file_path, average=False)
108+
img_corr = util.unwarp_color_image_backward(img0, xcenter, ycenter, list_bfact,
109+
pad=400)
110+
### Using OpenCV-remap backend for fast computing.
111+
# img_corr = util.unwarp_image_backward_cv2(img0, xcenter, ycenter,
112+
# list_bfact, pad=400)
113+
losa.save_image(output_base + "/corrected_img.jpg", img_corr)
114+
115+
img0 = losa.load_image(test_file_path, average=False)
116+
img_corr = util.unwarp_color_image_backward(img0, xcenter, ycenter, list_bfact,
117+
pad=400)
118+
losa.save_image(output_base + "/corrected_test_img.jpg", img_corr)

0 commit comments

Comments
 (0)