![JAR search and dependency download from the Maven repository](/logo.png)
boofcv.gui.calibration.CalibratedImageGridPanel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of visualize Show documentation
Show all versions of visualize Show documentation
BoofCV is an open source Java library for real-time computer vision and robotics applications.
The newest version!
/*
* 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.gui.calibration;
import boofcv.abst.geo.calibration.ImageResults;
import boofcv.alg.distort.AdjustmentType;
import boofcv.alg.distort.ImageDistort;
import boofcv.alg.distort.LensDistortionOps;
import boofcv.alg.geo.RectifyImageOps;
import boofcv.alg.geo.calibration.CalibrationObservation;
import boofcv.core.image.border.BorderType;
import boofcv.gui.feature.VisualizeFeatures;
import boofcv.io.image.ConvertBufferedImage;
import boofcv.struct.calib.CameraPinholeRadial;
import boofcv.struct.distort.Point2Transform2_F32;
import boofcv.struct.geo.PointIndex2D_F64;
import boofcv.struct.image.GrayF32;
import boofcv.struct.image.ImageType;
import boofcv.struct.image.Planar;
import georegression.struct.point.Point2D_F32;
import georegression.struct.point.Point2D_F64;
import org.ejml.data.DenseMatrix64F;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
/**
* Displays information images of planar calibration targets.
*
* @author Peter Abeles
*/
public class CalibratedImageGridPanel extends JPanel {
// images of calibration target
List images;
// which image is being displayed
int selectedImage;
// for displaying undistorted image
BufferedImage undistorted;
// true if the image has been undistorted
boolean isUndistorted = false;
// observed feature locations
List features = new ArrayList<>();
// results of calibration
List results = new ArrayList<>();
// for displaying corrected image
Planar origMS;
Planar correctedMS;
// configures what is displayed or not
boolean showPoints = true;
boolean showErrors = true;
boolean showUndistorted = false;
boolean showAll = false;
boolean showNumbers = true;
boolean showOrder = true;
ImageDistort undoRadial;
Point2Transform2_F32 remove_p_to_p;
// how much errors are scaled up
double errorScale;
// int horizontal line
int lineY=-1;
public void setDisplay( boolean showPoints , boolean showErrors ,
boolean showUndistorted , boolean showAll , boolean showNumbers ,
boolean showOrder,
double errorScale )
{
this.showPoints = showPoints;
this.showErrors = showErrors;
this.showUndistorted = showUndistorted;
this.showAll = showAll;
this.showNumbers = showNumbers;
this.showOrder = showOrder;
this.errorScale = errorScale;
}
public void setSelected( int selected ) {
this.selectedImage = selected;
this.isUndistorted = false;
if( origMS == null ) {
BufferedImage image = images.get(selected);
// the number of bands can be difficult to ascertain without digging deep into the data structure
// so just declare a new one using convert
origMS = ConvertBufferedImage.convertFromMulti(image,null,true,GrayF32.class);
correctedMS = ConvertBufferedImage.convertFromMulti(image,null,true,GrayF32.class);
undistorted = new BufferedImage(image.getWidth(),image.getHeight(),image.getType());
}
}
public void setImages( List images ) {
this.images = images;
}
public void setResults( List features , List results ) {
this.features = features;
this.results = results;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
if( images == null || selectedImage >= images.size() )
return;
BufferedImage image = images.get(selectedImage);
double scaleX = getWidth()/(double)image.getWidth();
double scaleY = getHeight()/(double)image.getHeight();
double scale = Math.min(1,Math.min(scaleX,scaleY));
AffineTransform tranOrig = g2.getTransform();
AffineTransform tran = g2.getTransform();
tran.concatenate(AffineTransform.getScaleInstance(scale,scale));
g2.setTransform(tran);
if( showUndistorted) {
if( undoRadial != null && !isUndistorted ) {
undoRadialDistortion(image);
isUndistorted = true;
}
g2.drawImage(undistorted,0,0,null);
} else
g2.drawImage(image,0,0,null);
g2.setTransform(tranOrig);
if( features.size() > selectedImage ) {
drawFeatures(g2, scale);
}
if( lineY > -1 ) {
g2.setColor(Color.RED);
g2.setStroke(new BasicStroke(3));
g2.drawLine(0,lineY,getWidth(),lineY);
}
}
private void undoRadialDistortion(BufferedImage image) {
ConvertBufferedImage.convertFromMulti(image, origMS,true, GrayF32.class);
for( int i = 0; i < origMS.getNumBands(); i++ ) {
GrayF32 in = origMS.getBand(i);
GrayF32 out = correctedMS.getBand(i);
undoRadial.apply(in,out);
}
if( correctedMS.getNumBands() == 3 )
ConvertBufferedImage.convertTo(correctedMS,undistorted,true);
else if( correctedMS.getNumBands() == 1 )
ConvertBufferedImage.convertTo(correctedMS.getBand(0),undistorted);
else
throw new RuntimeException("What kind of image has "+correctedMS.getNumBands()+"???");
}
private void drawFeatures(Graphics2D g2 , double scale) {
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
CalibrationObservation set = features.get(selectedImage);
Point2D_F32 adj = new Point2D_F32();
if( showOrder ) {
List adjusted;
if( showUndistorted ) {
adjusted = new ArrayList<>();
for( PointIndex2D_F64 p : set.points ) {
remove_p_to_p.compute((float)p.x,(float)p.y,adj);
adjusted.add(new Point2D_F64(adj.x,adj.y));
}
} else {
adjusted = (List)set.points;
}
renderOrder(g2,scale, adjusted);
}
if( showPoints ) {
g2.setColor(Color.BLACK);
g2.setStroke(new BasicStroke(3));
for( PointIndex2D_F64 p : set.points ) {
if( showUndistorted ) {
remove_p_to_p.compute((float)p.x,(float)p.y,adj);
} else {
adj.set((float)p.x,(float)p.y);
}
VisualizeFeatures.drawCross(g2, adj.x*scale, adj.y*scale, 4);
}
g2.setStroke(new BasicStroke(1));
g2.setColor(Color.RED);
for( PointIndex2D_F64 p : set.points ) {
if( showUndistorted ) {
remove_p_to_p.compute((float)p.x,(float)p.y,adj);
} else {
adj.set((float)p.x,(float)p.y);
}
VisualizeFeatures.drawCross(g2, adj.x*scale, adj.y*scale, 4);
}
}
if( showAll ) {
for( CalibrationObservation l : features ) {
for( PointIndex2D_F64 p : l.points ) {
if( showUndistorted ) {
remove_p_to_p.compute((float)p.x,(float)p.y,adj);
} else {
adj.set((float)p.x,(float)p.y);
}
VisualizeFeatures.drawPoint(g2,adj.x*scale,adj.y*scale,2,Color.BLUE,false);
}
}
}
if( showNumbers ) {
if( showUndistorted )
drawNumbers(g2, set,remove_p_to_p,scale);
else
drawNumbers(g2, set,null,scale);
}
if( showErrors && results != null && results.size() > selectedImage ) {
ImageResults result = results.get(selectedImage);
g2.setStroke(new BasicStroke(4));
g2.setColor(Color.BLACK);
for( int i = 0; i < set.size(); i++ ) {
PointIndex2D_F64 p = set.get(i);
if( showUndistorted ) {
remove_p_to_p.compute((float)p.x,(float)p.y,adj);
} else {
adj.set((float)p.x,(float)p.y);
}
double r = errorScale*result.pointError[i];
if( r < 1 )
continue;
VisualizeFeatures.drawCircle(g2, adj.x * scale, adj.y * scale, r);
}
g2.setStroke(new BasicStroke(2.5f));
g2.setColor(Color.ORANGE);
for( int i = 0; i < set.size(); i++ ) {
PointIndex2D_F64 p = set.get(i);
if( showUndistorted ) {
remove_p_to_p.compute((float)p.x,(float)p.y,adj);
} else {
adj.set((float)p.x,(float)p.y);
}
double r = errorScale*result.pointError[i];
if( r < 1 )
continue;
VisualizeFeatures.drawCircle(g2, adj.x * scale, adj.y * scale, r);
}
}
}
public static void renderOrder(Graphics2D g2, double scale , List points ) {
g2.setStroke(new BasicStroke(5));
Line2D.Double l = new Line2D.Double();
for (int i = 0,j = 1; j < points.size(); i=j,j++) {
Point2D_F64 p0 = points.get(i);
Point2D_F64 p1 = points.get(j);
double fraction = i / ((double) points.size() - 2);
// fraction = fraction * 0.8 + 0.1;
int red = (int)(0xFF*fraction) + (int)(0x00*(1-fraction));
int green = 0x00;
int blue = (int)(0x00*fraction) + (int)(0xff*(1-fraction));
int lineRGB = red << 16 | green << 8 | blue;
l.setLine(scale * p0.x , scale * p0.y, scale * p1.x, scale * p1.y );
g2.setColor(new Color(lineRGB));
g2.draw(l);
}
}
public void setDistorted (CameraPinholeRadial param , DenseMatrix64F rect ) {
if( rect == null ) {
this.undoRadial = LensDistortionOps.imageRemoveDistortion(
AdjustmentType.FULL_VIEW, BorderType.ZERO, param, null, ImageType.single(GrayF32.class));
this.remove_p_to_p = LensDistortionOps.transform_F32(AdjustmentType.FULL_VIEW, param, null, false);
} else {
this.undoRadial =
RectifyImageOps.rectifyImage(param, rect, BorderType.ZERO, ImageType.single(GrayF32.class));
this.remove_p_to_p = RectifyImageOps.transformPixelToRect_F32(param, rect);
}
}
public void setLine( int y ) {
this.lineY = y;
}
public static void drawNumbers( Graphics2D g2 , CalibrationObservation foundTarget ,
Point2Transform2_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);
int gridIndex = foundTarget.get(i).index;
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",gridIndex);
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);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy