def scan_center(xcenter, ycenter, start, stop, step, list_coef, list_power, output_base, mat0, mat_pad, pad, axis="x", ntime=1): (height, width) = mat0.shape list_ffact = list_power * list_coef if axis == "x": for num in np.arange(start, stop + step, step): line_img_warped = post.unwarp_image_backward( mat_pad, xcenter + num + pad, ycenter + pad, list_ffact) line_img_warped = line_img_warped[pad:pad + height, pad:pad + width] name = ("0000" + str(xcenter + num))[-7:] io.save_image( output_base + "/xcenter_ntime_" + str(ntime) + "/img_" + name + ".jpg", mat0 + 0.5 * line_img_warped) else: for num in range(start, stop + step, step): line_img_warped = post.unwarp_image_backward( mat_pad, xcenter + pad, ycenter + num + pad, list_ffact) line_img_warped = line_img_warped[pad:pad + height, pad:pad + width] name = ("0000" + str(ycenter + num))[-7:] io.save_image( output_base + "/ycenter_ntime_" + str(ntime) + "/img_" + name + ".jpg", mat0 + 0.5 * line_img_warped)
def test_unwarp_image_backward(self): x0, y0 = (self.wid // 2, self.hei // 2) list_fact = [1.0, 3.0 * 10**(-3)] mat = np.zeros((self.hei, self.wid), dtype=np.float32) mat[4:-3, 4:-3] = 1.0 mat_warp = post.unwarp_image_backward(mat, x0, y0, list_fact) vals = np.mean(mat_warp, axis=0)[11:-10] pos = len(vals) // 2 self.assertTrue(vals[0] < vals[pos] and vals[-1] < vals[pos])
def scan_coef(idx, start, stop, step, list_coef, list_power, output_base, mat0, mat_pad, pad, ntime=1): (height, width) = mat0.shape for num in np.arange(start, stop + step, step): list_coef_est = np.copy(list_coef) list_coef_est[idx] = list_coef_est[idx] + num list_ffact = list_power * list_coef_est line_img_warped = post.unwarp_image_backward(mat_pad, xcenter + pad, ycenter + pad, list_ffact) line_img_warped = line_img_warped[pad:pad + height, pad:pad + width] name = ("0000" + str(list_coef_est[idx]))[-5:] io.save_image( output_base + "/coef_" + str(idx) + "_ntime_" + str(ntime) + "/img_" + name + ".jpg", mat0 + 0.5 * line_img_warped)
list_fact) # Calculate the residual of the unwarpped points. list_hor_data = post.calc_residual_hor(list_uhor_lines, xcenter, ycenter) list_ver_data = post.calc_residual_ver(list_uver_lines, xcenter, ycenter) # Save the results for checking io.save_plot_image(output_base + "/unwarpped_horizontal_lines.png", list_uhor_lines, height, width) io.save_plot_image(output_base + "/unwarpped_vertical_lines.png", list_uver_lines, height, width) io.save_residual_plot(output_base + "/hor_residual_after_correction.png", list_hor_data, height, width) io.save_residual_plot(output_base + "/ver_residual_after_correction.png", list_ver_data, height, width) # Correct the image corrected_mat = post.unwarp_image_backward(mat0, xcenter, ycenter, list_fact) # Save results. io.save_image(output_base + "/corrected_image.jpg", corrected_mat) io.save_image(output_base + "/difference.jpg", corrected_mat - mat0) # ---------------------------------------- # Load original color image for correction # ------------------------------------------ # Load coefficients from previous calculation if need to # (xcenter, ycenter, list_fact) = io.load_metadata_txt( # output_base + "/coefficients_radial_distortion.txt") img = io.load_image(file_path, average=False) img_corrected = np.copy(img) # Unwarped each color channel of the image
# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #============================================================================ # Author: Nghia T. Vo # E-mail: [email protected] #============================================================================ """ Example to show how to apply distortion correction to images of the Hazard Cameras (Hazcams) on the underside of NASA’s Perseverance Mars rover. """ import numpy as np import discorpy.losa.loadersaver as io import discorpy.post.postprocessing as post from PIL import Image # Load color image file_path = "Sol0_1st_color.png" output_base = "figs/" mat = np.asarray(Image.open(file_path), dtype=np.float32) # Import distortion coefficients (xcenter, ycenter, list_fact) = io.load_metadata_txt("figs/coefficients.txt") for i in range(mat.shape[-1]): mat[:, :, i] = post.unwarp_image_backward(mat[:, :, i], xcenter, ycenter, list_fact) io.save_image(output_base + "/Sol0_1st_color_correction.png", mat)
# Save the results for later use. io.save_metadata_txt(output_base + "/coefficients_radial_distortion.txt", xcenter, ycenter, list_fact) print("X-center: {0}. Y-center: {1}".format(xcenter, ycenter)) print("Coefficients: {0}".format(list_fact)) # Apply correction to the lines of points 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) # Save the results for checking io.save_plot_image(output_base + "/unwarpped_horizontal_lines.png", list_uhor_lines, height, width) io.save_plot_image(output_base + "/unwarpped_vertical_lines.png", list_uver_lines, height, width) # Calculate the residual of the unwarpped points. list_hor_data = post.calc_residual_hor(list_uhor_lines, xcenter, ycenter) list_ver_data = post.calc_residual_ver(list_uver_lines, xcenter, ycenter) # Save the results for checking io.save_residual_plot(output_base + "/hor_residual_after_correction.png", list_hor_data, height, width) io.save_residual_plot(output_base + "/ver_residual_after_correction.png", list_ver_data, height, width) # Correct the image corrected_mat = post.unwarp_image_backward(mat0, xcenter, ycenter, list_fact) # Save results. Note that the output is 32-bit numpy array. Convert to lower-bit if need to. io.save_image(output_base + "/corrected_image.tif", corrected_mat) io.save_image(output_base + "/difference.tif", corrected_mat - mat0)
# Get a good estimation of the forward model list_ffact = list_coef * list_power # Transform to the backward model for correction ref_points = [[i - ycenter, j - xcenter] for i in range(0, height, 50) for j in range(0, width, 50)] list_bfact = proc.transform_coef_backward_and_forward(list_ffact, ref_points=ref_points) # Load the color image img = io.load_image(file_path, average=False) img_corrected = np.copy(img) # Unwarped each color channel of the image for i in range(img.shape[-1]): img_corrected[:, :, i] = post.unwarp_image_backward(img[:, :, i], xcenter, ycenter, list_bfact) # Save the unwarped image. io.save_image(output_base + "/F_R_hazcam_unwarped.png", img_corrected) # Correct other images from the same camera img = io.load_image("C:/data/percy_cam/rock_core1.png", average=False) img_corrected = np.copy(img) for i in range(img.shape[-1]): img_corrected[:, :, i] = post.unwarp_image_backward(img[:, :, i], xcenter, ycenter, list_bfact) io.save_image(output_base + "/rock_core1_unwarped.png", img_corrected) img = io.load_image("C:/data/percy_cam/rock_core2.png", average=False) img_corrected = np.copy(img)
import numpy as np import discorpy.losa.loadersaver as io import discorpy.post.postprocessing as post # Load image mat0 = io.load_image("Sol0_1st_color.png") output_base = "figs/" (height, width) = mat0.shape mat0 = mat0 / np.max(mat0) # Create line pattern line_pattern = np.zeros((height, width), dtype=np.float32) for i in range(50, height - 50, 40): line_pattern[i - 1:i + 2] = 1.0 # Estimate parameters by visual inspection. # Coarse estimation xcenter = width / 2.0 + 110.0 ycenter = height / 2.0 - 20.0 list_pow = np.asarray([1.0, 10**(-4), 10**(-7), 10**(-10), 10**(-13)]) # Fine estimation list_coef = np.asarray([1.0, 4.0, 5.0, 17.0, 3.0]) list_ffact = list_pow * list_coef pad = width mat_pad = np.pad(line_pattern, pad, mode='edge') mat_cor = post.unwarp_image_backward(mat_pad, xcenter + pad, ycenter + pad, list_ffact) mat_cor = mat_cor[pad:pad + height, pad:pad + width] io.save_image(output_base + "/overlay.jpg", (mat0 + 0.5 * mat_cor))
# xcenter, ycenter, num_coef) # list_uhor_lines = post.unwarp_line_forward(list_hor_lines2, xcenter, ycenter, # list_ffact) # list_uver_lines = post.unwarp_line_forward(list_ver_lines2, xcenter, ycenter, # list_ffact) # Check the residual of unwarped lines: 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 + "/hor_residual_after_correction.png", list_hor_data, height, width) io.save_residual_plot(output_base + "/ver_residual_after_correction.png", list_ver_data, height, width) # Unwarp the image mat_rad_corr = post.unwarp_image_backward(mat0, xcenter, ycenter, list_fact) # Save results io.save_image(output_base + "/image_radial_corrected.jpg", mat_rad_corr) io.save_image(output_base + "/radial_difference.jpg", mat_rad_corr - mat0) # ------------------------------------- # For perspective distortion correction # ------------------------------------- # Generate source points and target points to calculate coefficients of a perspective model source_points, target_points = proc.generate_source_target_perspective_points( list_uhor_lines, list_uver_lines, equal_dist=True, scale="mean", optimizing=False)