Skip to content

Commit 17ebd81

Browse files
authored
Merge pull request #321 from EasternEdgeRobotics/sub-pix
Allow images to be down-sampled before calibration
2 parents 83a7881 + 6a9e93d commit 17ebd81

4 files changed

Lines changed: 55 additions & 5 deletions

File tree

playbooks/files/defaultConfig.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ cameraCalibration:
106106
cameraBPreUndistortedDirectory: /home/eedge/pre-undistorted-b/
107107
chessboardWidth: 6
108108
chessboardHeight: 9
109+
downSample: 1.5
109110
distanceCalculator:
110111
imageDirectory: /home/eedge/undistorted-images/
111112
dataDirectory: /home/eedge/undistorted-images-data/

src/main/java/com/easternedgerobotics/rov/config/CameraCalibrationConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ public interface CameraCalibrationConfig {
1616
int chessboardWidth();
1717

1818
int chessboardHeight();
19+
20+
double downSample();
1921
}

src/main/java/com/easternedgerobotics/rov/video/CameraCalibration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ public CameraCalibration(
6363
public void calibrate() {
6464
final Scheduler.Worker worker = scheduler.createWorker();
6565
worker.schedule(() -> ChessboardCalibration.findCameraCalibrationResult(
66-
config.cameraAImagesDirectory(), config.chessboardWidth(), config.chessboardHeight()
66+
config.cameraAImagesDirectory(), config.chessboardWidth(), config.chessboardHeight(), config.downSample()
6767
).ifPresent(value -> store.set(config.cameraAName(), value)));
6868
worker.schedule(() -> ChessboardCalibration.findCameraCalibrationResult(
69-
config.cameraBImagesDirectory(), config.chessboardWidth(), config.chessboardHeight()
69+
config.cameraBImagesDirectory(), config.chessboardWidth(), config.chessboardHeight(), config.downSample()
7070
).ifPresent(value -> store.set(config.cameraBName(), value)));
7171
}
7272

src/main/java/com/easternedgerobotics/rov/video/ChessboardCalibration.java

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.bytedeco.javacpp.opencv_core.Size;
1212
import org.bytedeco.javacpp.opencv_core.TermCriteria;
1313
import org.bytedeco.javacpp.opencv_imgcodecs;
14+
import org.bytedeco.javacpp.opencv_imgproc;
1415
import org.pmw.tinylog.Logger;
1516

1617
import java.io.File;
@@ -40,7 +41,8 @@ private ChessboardCalibration() {
4041
public static Optional<CameraCalibrationValue> findCameraCalibrationResult(
4142
final String folder,
4243
final int boardWidth,
43-
final int boardHeight
44+
final int boardHeight,
45+
final double downSample
4446
) {
4547
final List<String> fileNames = getFolderFileNames(folder);
4648
final List<String> validNames = new ArrayList<>();
@@ -51,7 +53,7 @@ public static Optional<CameraCalibrationValue> findCameraCalibrationResult(
5153
final Mat distortionCoeffs = new Mat();
5254

5355
final Size imageSize = evaluateChessboardImages(
54-
fileNames, validNames, boardSize, objectCornerMatsVect, imageCornerMatsVect);
56+
fileNames, validNames, boardSize, downSample, objectCornerMatsVect, imageCornerMatsVect);
5557

5658
if (imageSize == null) {
5759
return Optional.empty();
@@ -82,6 +84,7 @@ public static Optional<CameraCalibrationValue> findCameraCalibrationResult(
8284
new TermCriteria(TermCriteria.MAX_ITER + TermCriteria.EPS, 30, 0.00001)
8385
);
8486

87+
Logger.info("calibrateCameraRmsError: " + calibrateCameraRmsError);
8588
final DoubleIndexer cameraMatrixIndexer = cameraMatrix.createIndexer();
8689
final StringBuilder cameraStringBuilder = new StringBuilder();
8790
cameraStringBuilder.append("cameraMatrix = {\n");
@@ -158,6 +161,7 @@ private static Size evaluateChessboardImages(
158161
final List<String> fileNames,
159162
final List<String> validNames,
160163
final Size boardSize,
164+
final double downSample,
161165
final MatVector objectCornerMatsVect,
162166
final MatVector imageCornerMatsVect
163167
) {
@@ -168,11 +172,52 @@ private static Size evaluateChessboardImages(
168172
final List<Mat> imageCornerMats = new ArrayList<>();
169173
Size imageSize = null;
170174

175+
final int winSizeLength = 5;
176+
final Size winSize = new Size(winSizeLength, winSizeLength);
177+
final Size zeroZone = new Size(-1, -1);
178+
final int maxIter = 30;
179+
final double epsilon = 0.00001;
180+
final double resizeDelta = 1.05;
181+
final TermCriteria termCriteria = new TermCriteria(
182+
opencv_core.CV_TERMCRIT_ITER | opencv_core.CV_TERMCRIT_EPS, maxIter, epsilon);
183+
171184
for (final String fileName : fileNames) {
172185
final Mat image = opencv_imgcodecs.imread(fileName, opencv_imgcodecs.IMREAD_GRAYSCALE);
173186
final Mat imageCorners = new Mat();
174187

175-
if (opencv_calib3d.findChessboardCorners(image, boardSize, imageCorners)) {
188+
final Size origSize = image.size();
189+
190+
final Mat resizeimage = new Mat();
191+
final Size downSize = new Size(
192+
(int) (origSize.width() / downSample),
193+
(int) (origSize.height() / downSample));
194+
opencv_imgproc.resize(image, resizeimage, downSize);
195+
196+
if (opencv_calib3d.findChessboardCorners(resizeimage, boardSize, imageCorners)) {
197+
Logger.info("Valid Calibration Image: " + fileName);
198+
199+
final FloatIndexer imageCornersIndex = imageCorners.createIndexer();
200+
for (double sample = downSample / resizeDelta; sample > 1; sample /= resizeDelta) {
201+
final Mat sampleImage = new Mat();
202+
final Size sampleSize = new Size(
203+
(int) (origSize.width() / sample),
204+
(int) (origSize.height() / sample));
205+
opencv_imgproc.resize(image, sampleImage, sampleSize);
206+
for (int i = 0; i < imageCorners.size(0); i++) {
207+
imageCornersIndex.put(i, 0, 0, imageCornersIndex.get(i, 0, 0) * (float) (downSample / sample));
208+
imageCornersIndex.put(i, 0, 1, imageCornersIndex.get(i, 0, 1) * (float) (downSample / sample));
209+
}
210+
opencv_imgproc.cornerSubPix(sampleImage, imageCorners, winSize, zeroZone, termCriteria);
211+
for (int i = 0; i < imageCorners.size(0); i++) {
212+
imageCornersIndex.put(i, 0, 0, imageCornersIndex.get(i, 0, 0) / (float) (downSample / sample));
213+
imageCornersIndex.put(i, 0, 1, imageCornersIndex.get(i, 0, 1) / (float) (downSample / sample));
214+
}
215+
}
216+
for (int i = 0; i < imageCorners.size(0); i++) {
217+
imageCornersIndex.put(i, 0, 0, imageCornersIndex.get(i, 0, 0) * (float) downSample);
218+
imageCornersIndex.put(i, 0, 1, imageCornersIndex.get(i, 0, 1) * (float) downSample);
219+
}
220+
opencv_imgproc.cornerSubPix(image, imageCorners, winSize, zeroZone, termCriteria);
176221
imageCornerMats.add(imageCorners);
177222
validNames.add(fileName);
178223
// Create imageSize on first valid image
@@ -182,6 +227,8 @@ private static Size evaluateChessboardImages(
182227
Logger.info("All images must have the same size!");
183228
return null;
184229
}
230+
} else {
231+
Logger.info("Invalid Calibration Image: " + fileName);
185232
}
186233
}
187234

0 commit comments

Comments
 (0)