/*
* 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.demonstrations.calibration;
import boofcv.alg.fiducial.calib.squares.SquareEdge;
import boofcv.alg.fiducial.calib.squares.SquareGrid;
import boofcv.alg.fiducial.calib.squares.SquareNode;
import boofcv.alg.filter.binary.Contour;
import boofcv.gui.DemonstrationBase;
import boofcv.gui.binary.VisualizeBinaryData;
import boofcv.gui.feature.VisualizeFeatures;
import boofcv.gui.feature.VisualizeShapes;
import boofcv.gui.image.ImageZoomPanel;
import boofcv.struct.distort.PointTransform_F32;
import boofcv.struct.image.GrayF32;
import boofcv.struct.image.GrayU8;
import boofcv.struct.image.ImageType;
import georegression.geometry.UtilPolygons2D_F64;
import georegression.struct.point.Point2D_F32;
import georegression.struct.point.Point2D_F64;
import georegression.struct.shapes.Polygon2D_F64;
import org.ddogleg.struct.FastQueue;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import static boofcv.gui.fiducial.VisualizeFiducial.drawLine;
/**
* base class for chessboard and square grid calibration target detection
*
* @author Peter Abeles
*/
public abstract class CommonDetectCalibrationApp extends DemonstrationBase
implements ChessboardPanel.Listener
{
boolean success;
ChessboardPanel controlPanel;
VisualizePanel imagePanel = new VisualizePanel();
BufferedImage input;
BufferedImage binary;
GrayF32 grayPrev = new GrayF32(1,1);
public CommonDetectCalibrationApp( int numRows , int numColumns , List exampleInputs ) {
super(exampleInputs, ImageType.single(GrayF32.class));
controlPanel = new ChessboardPanel(numRows,numColumns,true);
add(imagePanel,BorderLayout.CENTER);
add(controlPanel,BorderLayout.WEST);
controlPanel.setListener(this);
imagePanel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
double scale = imagePanel.getScale();
System.out.println("clicked at " + (e.getX()/scale) + " " + (e.getY()/scale));
}
});
imagePanel.addMouseWheelListener(controlPanel);
}
protected abstract void declareDetector();
protected abstract boolean process( GrayF32 image );
protected abstract GrayU8 getBinaryImage();
protected abstract java.util.List> getClusters();
protected abstract java.util.List getCalibrationPoints();
protected abstract java.util.List getContours();
protected abstract FastQueue getFoundPolygons();
protected abstract java.util.List getGrids();
@Override
public void processImage( final BufferedImage buffered , GrayF32 gray ) {
this.input = buffered;
synchronized ( this ) {
binary = conditionalDeclare(buffered, binary, BufferedImage.TYPE_INT_RGB);
grayPrev.setTo(gray);
}
processFrame();
}
private void renderGraph( Graphics2D g2 , double scale ) {
java.util.List> graphs = getClusters();
BasicStroke strokeWide = new BasicStroke(3);
BasicStroke strokeNarrow = new BasicStroke(2);
Line2D.Double l = new Line2D.Double();
g2.setStroke(new BasicStroke(3));
for( int i = 0; i < graphs.size(); i++ ) {
java.util.List graph = graphs.get(i);
int key = graphs.size() == 1 ? 0 : 255 * i / (graphs.size() - 1);
int rgb = key << 8 | (255 - key);
g2.setColor(new Color(rgb));
java.util.List edges = new ArrayList();
for( SquareNode n : graph ) {
for (int j = 0; j < n.edges.length; j++) {
if( n.edges[j] != null && !edges.contains(n.edges[j])) {
edges.add( n.edges[j]);
}
}
}
for( SquareEdge e : edges ) {
Point2D_F64 a = e.a.center;
Point2D_F64 b = e.b.center;
l.setLine(a.x*scale,a.y*scale,b.x*scale,b.y*scale);
g2.setColor(Color.CYAN);
g2.setStroke(strokeWide);
g2.draw(l);
g2.setColor(new Color(rgb));
g2.setStroke(strokeNarrow);
g2.draw(l);
}
}
}
@Override
public void calibEventGUI() {
if( controlPanel.getSelectedView() == 0 ) {
imagePanel.setBufferedImage(input);
} else if( controlPanel.getSelectedView() == 1 ){
imagePanel.setBufferedImage(binary);
} else {
throw new RuntimeException("Unknown");
}
imagePanel.setScale(controlPanel.getScale());
imagePanel.repaint();
}
@Override
public void calibEventDetectorModified() {
synchronized ( this ) {
declareDetector();
}
processFrame();
}
public void processFrame() {
synchronized ( this ) {
success = process(grayPrev);
VisualizeBinaryData.renderBinary(getBinaryImage(), false, binary);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (success)
controlPanel.setSuccessMessage("FOUND", true);
else
controlPanel.setSuccessMessage("FAILED", false);
imagePanel.setPreferredSize(new Dimension(input.getWidth()+5, input.getHeight()+5));
calibEventGUI();
imagePanel.repaint();
}
});
}
class VisualizePanel extends ImageZoomPanel {
@Override
protected void paintInPanel(AffineTransform tran,Graphics2D g2 ) {
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
synchronized ( CommonDetectCalibrationApp.this ) {
if( success ) {
if ( controlPanel.isShowPoints() ) {
java.util.List candidates = getCalibrationPoints();
for (Point2D_F64 c : candidates) {
VisualizeFeatures.drawPoint(g2, (int) (scale * c.x + 0.5), (int) (scale * c.y + 0.5), 1, Color.RED);
}
}
if( controlPanel.isShowNumbers() ) {
drawNumbers(g2, getCalibrationPoints(),null,scale);
}
}
if( controlPanel.doShowContour ) {
java.util.List contour = getContours();
g2.setStroke(new BasicStroke(1));
g2.setColor(Color.RED);
VisualizeBinaryData.renderExternal(contour,false,true,scale,g2);
}
if( controlPanel.isShowGraph() ) {
renderGraph(g2, scale);
}
if( controlPanel.isShowOrder() ) {
renderOrder(g2,scale);
}
if( controlPanel.isShowSquares() ) {
FastQueue squares = getFoundPolygons();
for (int i = 0; i < squares.size(); i++) {
Polygon2D_F64 p = squares.get(i);
if (isInGrids(p))
continue;
g2.setColor(Color.cyan);
g2.setStroke(new BasicStroke(4));
drawPolygon(p, g2, scale);
g2.setColor(Color.blue);
g2.setStroke(new BasicStroke(2));
drawPolygon(p, g2, scale);
drawCornersInside(g2,scale,p);
}
}
if( controlPanel.isShowGrids() ) {
java.util.List grids = getGrids();
for (int i = 0; i < grids.size(); i++) {
SquareGrid g = grids.get(i);
int a = grids.size() == 1 ? 0 : 255 * i / (grids.size() - 1);
int rgb = a << 16 | (255 - a) << 8;
g2.setStroke(new BasicStroke(3));
Color color = new Color(rgb);
for (int j = 0; j < g.nodes.size(); j++) {
SquareNode n = g.nodes.get(j);
if( n == null )
continue;
g2.setColor(color);
VisualizeShapes.drawPolygon(n.corners, true, scale, g2);
drawCornersInside(g2,scale,n.corners);
}
}
}
}
}
}
private void renderOrder(Graphics2D g2, double scale ) {
java.util.List grids = getGrids();
g2.setStroke(new BasicStroke(3));
Line2D.Double l = new Line2D.Double();
for (int i = 0; i < grids.size(); i++) {
SquareGrid g = grids.get(i);
SquareNode p0 = null;
for (int j = 0; j < g.nodes.size(); j++) {
SquareNode p1 = g.nodes.get(j);
if( p1 == null)
continue;
if( p0 != null) {
double fraction = j / ((double) g.nodes.size() - 1);
fraction = fraction * 0.8 + 0.1;
int red = (int)(0xFF*fraction) + (int)(0x10*(1-fraction));
int green = (int)(0x00*fraction) + (int)(0x00*(1-fraction));
int blue = (int)(0x10*fraction) + (int)(0xff*(1-fraction));
int lineRGB = red << 16 | green << 8 | blue;
l.setLine(scale * p0.center.x , scale * p0.center.y, scale * p1.center.x, scale * p1.center.y );
g2.setColor(new Color(lineRGB));
g2.draw(l);
}
p0 = p1;
}
}
}
public static void drawPolygon( Polygon2D_F64 polygon, Graphics2D g2 , double scale ) {
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Line2D.Double l = new Line2D.Double();
for( int i = 0; i < polygon.size()-1; i++ ) {
Point2D_F64 p0 = polygon.get(i);
Point2D_F64 p1 = polygon.get(i+1);
drawLine(g2, l, p0.x*scale, p0.y*scale, p1.x*scale, p1.y*scale);
}
if( polygon.size() > 0) {
Point2D_F64 p0 = polygon.get(0);
Point2D_F64 p1 = polygon.get(polygon.size()-1);
drawLine(g2, l, p0.x*scale, p0.y*scale, p1.x*scale, p1.y*scale);
}
}
private boolean isInGrids( Polygon2D_F64 p ) {
java.util.List grids = getGrids();
for (int i = 0; i < grids.size(); i++) {
SquareGrid g = grids.get(i);
for (int j = 0; j < g.nodes.size(); j++) {
if( g.nodes.get(j) != null && g.nodes.get(j).corners == p )
return true;
}
}
return false;
}
private void drawCornersInside( Graphics2D g2 , double scale, Polygon2D_F64 poly ) {
Color colors[] = new Color[]{Color.RED,new Color(190, 0, 0),Color.GREEN,new Color(0, 190, 0)};
Point2D_F64 center = new Point2D_F64();
UtilPolygons2D_F64.vertexAverage(poly,center);
for (int i = 0; i < poly.size(); i++) {
Point2D_F64 p = poly.get(i);
Color c = i < 4 ? colors[i] : Color.BLUE;
double dx = p.x - center.x;
double dy = p.y - center.y;
double x = (center.x + dx*0.75)*scale;
double y = (center.y + dy*0.75)*scale;
VisualizeFeatures.drawPoint(g2, x, y, 3, c, false);
}
}
public static void drawNumbers( Graphics2D g2 , java.util.List foundTarget ,
PointTransform_F32 transform ,
double scale ) {
Font regular = new Font("Serif", Font.PLAIN, 16);
g2.setFont(regular);
Point2D_F32 adj = new Point2D_F32();
AffineTransform origTran = g2.getTransform();
for (int i = 0; i < foundTarget.size(); i++) {
Point2D_F64 p = foundTarget.get(i);
if (transform != null) {
transform.compute((float) p.x, (float) p.y, adj);
} else {
adj.set((float) p.x, (float) p.y);
}
String text = String.format("%2d", i);
int x = (int) (adj.x * scale);
int y = (int) (adj.y * scale);
g2.setColor(Color.BLACK);
g2.drawString(text, x - 1, y);
g2.drawString(text, x + 1, y);
g2.drawString(text, x, y - 1);
g2.drawString(text, x, y + 1);
g2.setTransform(origTran);
g2.setColor(Color.GREEN);
g2.drawString(text, x, y);
}
}
}
Ads help maintain this website.