001/******************************************************************************* 002 * Permission to use and distribute this software is granted under the BSD 2-Clause 003 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 004 * Copyright (c) 2016-2023 Wilhelm Burger. All rights reserved. 005 * Visit https://imagingbook.com for additional details. 006 ******************************************************************************/ 007package Calibration_Plugins_2; 008 009import ij.IJ; 010import ij.ImagePlus; 011import ij.ImageStack; 012import ij.gui.GenericDialog; 013import ij.plugin.PlugIn; 014import ij.process.ImageProcessor; 015import imagingbook.calibration.zhang.Camera; 016import imagingbook.calibration.zhang.InterCameraMapping; 017import imagingbook.calibration.zhang.data.CalibrationImage; 018import imagingbook.calibration.zhang.data.ZhangData; 019import imagingbook.common.geometry.mappings.Mapping2D; 020import imagingbook.common.image.ImageMapper; 021import imagingbook.common.image.interpolation.InterpolationMethod; 022import imagingbook.core.jdoc.JavaDocHelp; 023import imagingbook.core.resource.ImageResource; 024 025import static imagingbook.common.ij.DialogUtils.formatText; 026 027 028/** 029 * This plugin opens an image stack containing the 5 Zhang test images (assumed to be taken with camera A) and 030 * re-renders the images by mapping them to a new camera B. In this example, only the lens distortion coefficients are 031 * modified but in principle all intrinsic parameters of camera B could be changed. 032 * 033 * @author W. Burger 034 * @version 2021-08-22 035 */ 036public class Replace_Camera_Demo implements PlugIn, JavaDocHelp { 037 038 private static ImageResource resource = CalibrationImage.CalibImageStack; 039 040 // modified lens distortion coefficients: 041 private static double k1 = -0.1; 042 private static double k2 = 2.0; 043 044 public void run(String arg0) { 045 // open the test image (stack): 046 ImagePlus testIm = resource.getImagePlus(); 047 048 if (testIm == null) { 049 IJ.error("Could not open calibration images!"); 050 return; 051 } 052 testIm.show(); 053 054 // get the camera intrinsics (typically by calibration): 055 Camera cameraA = ZhangData.getCameraIntrinsics(); 056 057 double[] cameraParameters = cameraA.getParameterVector(); 058 k1 = cameraParameters[5]; 059 k2 = cameraParameters[6]; 060 061 if (!runDialog()) { 062 return; 063 } 064 065 cameraParameters[5] = k1; // change only radial distortion parameters 066 cameraParameters[6] = k2; 067 068 Camera cameraB = new Camera(cameraParameters); 069 070 // create a special geometric mapping 071 Mapping2D mapping = new InterCameraMapping(cameraA, cameraB); // inverse, maps target to source 072 073 // rectify the images and create a new stack: 074 ImageStack distStack = testIm.getStack(); 075 final int w = distStack.getWidth(); 076 final int h = distStack.getHeight(); 077 final int M = distStack.getSize(); 078 079 ImageStack rectStack = new ImageStack(w, h); 080 for (int i = 0; i < M; i++) { 081 IJ.showProgress(i, M); 082 ImageProcessor source = distStack.getProcessor(i + 1); 083 ImageProcessor target = source.createProcessor(w, h); 084 ImageMapper mapper = new ImageMapper(mapping, null, InterpolationMethod.Bicubic); 085 mapper.map(source, target); 086// mapping.applyTo(source, target, InterpolationMethod.Bicubic); 087 rectStack.addSlice("frame"+ (i + 1), target); 088 } 089 090 new ImagePlus(testIm.getShortTitle() + " (modfied)", rectStack).show(); 091 } 092 093 // ------------------------------------------------------------------------- 094 095 private boolean runDialog() { 096 GenericDialog gd = new GenericDialog(this.getClass().getSimpleName()); 097 gd.addHelp(getJavaDocUrl()); 098 gd.setInsets(0, 0, 0); 099 gd.addMessage(formatText(60, 100 "This plugin transforms the stack of test images by replacing", 101 "the original camera by a new camera with different parameters.", 102 "Only the radial distortion parameters (κ1, κ2) are changed.", 103 "For example, try κ1 = -0.1, κ2 = 2.0.")); 104 105 gd.addNumericField("Rad. distortion param. κ1", k1, 3); 106 gd.addNumericField("Rad. distortion param. κ2", k2, 3); 107 108 gd.showDialog(); 109 if (gd.wasCanceled()) 110 return false; 111 112 k1 = gd.getNextNumber(); 113 k2 = gd.getNextNumber(); 114 return true; 115 } 116 117}