/*
* Copyright (c) 2011-2016, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.
*/
package boofcv.app.calib;
import boofcv.abst.fiducial.calib.CalibrationDetectorChessboard;
import boofcv.abst.fiducial.calib.CalibrationDetectorCircleAsymmGrid;
import boofcv.abst.fiducial.calib.CalibrationDetectorSquareGrid;
import boofcv.abst.geo.calibration.DetectorFiducialCalibration;
import boofcv.alg.geo.calibration.CalibrationObservation;
import boofcv.struct.geo.PointIndex2D_F64;
import georegression.geometry.UtilPolygons2D_F64;
import georegression.metric.UtilAngle;
import georegression.struct.point.Point2D_F64;
import georegression.struct.shapes.Polygon2D_F64;
import java.util.List;
/**
* Interface used to provide calibration target specific information
*
* @author Peter Abeles
*/
public interface CalibrationView {
/**
* Intialize by providing it a reference to the detector. This is then used to determine the appearance
* of the target
*/
void initialize( DetectorFiducialCalibration detector );
/**
* Get the sidesCollision for collision detection with points
*/
void getSidesCollision(CalibrationObservation detections , List<Point2D_F64> sides );
/**
* Returns a quadrilateral that's used when checking focus and if the target is being held straight
*/
void getQuadFocus( CalibrationObservation detections , List<Point2D_F64> sides );
/**
* Returns how wide the image border should be given the visual width of the canonical fiducial
*/
int getBufferWidth( double gridPixelsWide );
class Chessboard implements CalibrationView {
int numRows,numCols;
int pointRows,pointCols;
public void initialize( DetectorFiducialCalibration detector ) {
CalibrationDetectorChessboard chessboard = (CalibrationDetectorChessboard)detector;
this.numRows = chessboard.getGridRows();
this.numCols = chessboard.getGridColumns();
pointRows = numRows-1;
pointCols = numCols-1;
}
@Override
public void getSidesCollision(CalibrationObservation detections, List<Point2D_F64> sides) {
sides.clear();
sides.add( get(0, 0, detections.points));
sides.add( get(0, pointCols-1, detections.points));
sides.add( get(pointRows-1, pointCols-1, detections.points));
sides.add( get(pointRows-1, 0, detections.points));
}
@Override
public void getQuadFocus(CalibrationObservation detections, List<Point2D_F64> sides) {
getSidesCollision(detections, sides);
}
private Point2D_F64 get(int row , int col , List<PointIndex2D_F64> detections ) {
return detections.get(row*pointCols+col);
}
@Override
public int getBufferWidth( double gridPixelsWide ) {
return (int)(0.2*gridPixelsWide/(pointCols-1)+0.5);
}
}
class SquareGrid implements CalibrationView {
int gridCols;
int pointRows,pointCols;
public void initialize( DetectorFiducialCalibration detector ) {
CalibrationDetectorSquareGrid target = (CalibrationDetectorSquareGrid)detector;
pointRows = target.getPointRows();
pointCols = target.getPointColumns();
gridCols = target.getGridColumns();
gridCols += gridCols/2;
}
@Override
public void getSidesCollision(CalibrationObservation detections, List<Point2D_F64> sides) {
sides.clear();
sides.add( get(0, 0, detections.points));
sides.add( get(0, pointCols-1, detections.points));
sides.add( get(pointRows-1, pointCols-1, detections.points));
sides.add( get(pointRows-1, 0, detections.points));
}
@Override
public void getQuadFocus(CalibrationObservation detections, List<Point2D_F64> sides) {
getSidesCollision(detections, sides);
}
private Point2D_F64 get( int row , int col , List<PointIndex2D_F64> detections ) {
return detections.get(row*pointCols+col);
}
@Override
public int getBufferWidth( double gridPixelsWide ) {
return (int)(0.15*(gridPixelsWide/gridCols)+0.5);
}
}
class CircleAsymmGrid implements CalibrationView {
int gridRows, gridCols;
double spaceToRadius;
// indexes of corners in convex hull
int indexes[];
public void initialize( DetectorFiducialCalibration detector ) {
CalibrationDetectorCircleAsymmGrid target = (CalibrationDetectorCircleAsymmGrid)detector;
gridRows = target.getRows();
gridCols = target.getColumns();
spaceToRadius = target.getSpaceToRadius();
// find the convex hull and use that as the collision region
List<Point2D_F64> layout = detector.getLayout();
Polygon2D_F64 poly = new Polygon2D_F64(layout.size());
UtilPolygons2D_F64.convexHull(layout,poly);
if( !poly.isCCW() )
poly.flip();
UtilPolygons2D_F64.removeAlmostParallel(poly, UtilAngle.radian(5));
// save the indexes of these points
indexes = new int[layout.size()];
for (int i = 0; i < poly.size(); i++) {
int match = -1;
for (int j = 0; j < layout.size(); j++) {
if( layout.get(j).distance(poly.get(i)) <= 1e-8 ) {
match = j;
break;
}
}
indexes[i] = match;
}
}
@Override
public void getSidesCollision(CalibrationObservation detections, List<Point2D_F64> sides) {
sides.clear();
for( int i = 0; i < indexes.length; i++ ) {
sides.add( detections.get(indexes[i]));
}
}
@Override
public void getQuadFocus(CalibrationObservation detections, List<Point2D_F64> sides) {
sides.clear();
int outerCols=gridCols - (1-gridCols%2);
int outerRows=gridRows - (1-gridRows%2);
sides.add( detections.get(0) );
sides.add( detections.get(getIndex(0,outerCols-1)) );
sides.add( detections.get(getIndex(outerRows-1,outerCols-1)) );
sides.add( detections.get(getIndex(outerRows-1,0)) );
}
private int getIndex( int row , int col ) {
int evenCols = gridCols/2 + gridCols%2;
int oddCols = gridCols/2;
int index = (row/2+row%2)*evenCols + (row/2)*oddCols;
if( row%2 == 0 )
index += col/2;
else
index += col/2+col%2;
return index;
}
@Override
public int getBufferWidth( double gridPixelsWide ) {
int outerCols=gridCols/2+gridCols%2;
double spaceWidth = gridPixelsWide/(outerCols-1);
System.out.println("grid width "+gridPixelsWide+" spaceWidth "+spaceWidth+" GRID COLS "+gridCols+" outerCols "+outerCols);
return (int)(1.25*spaceWidth/spaceToRadius+0.5);
}
}
}