/*
* 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.distort;
import boofcv.alg.distort.AdjustmentType;
import boofcv.alg.distort.ImageDistort;
import boofcv.alg.distort.LensDistortionOps;
import boofcv.core.image.border.BorderType;
import boofcv.gui.SelectInputPanel;
import boofcv.gui.image.ImagePanel;
import boofcv.gui.image.ShowImages;
import boofcv.io.PathLabel;
import boofcv.io.ProgressMonitorThread;
import boofcv.io.UtilIO;
import boofcv.io.image.ConvertBufferedImage;
import boofcv.struct.calib.IntrinsicParameters;
import boofcv.struct.image.GrayU8;
import boofcv.struct.image.ImageGray;
import boofcv.struct.image.Planar;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
/**
* Shows lens distortion with different amounts of radial distortion
*
* @author Peter Abeles
*/
public class ShowLensDistortion
extends SelectInputPanel implements ChangeListener, ItemListener
{
double radial1 = 0;
double radial2 = 0;
double tangential1 = 0;
double tangential2 = 0;
boolean fullView = false;
Class imageType;
JSpinner radialOrder1;
JSpinner radialOrder2;
JSpinner tangentialOrder1;
JSpinner tangentialOrder2;
JCheckBox showFullImage;
ImagePanel gui = new ImagePanel();
boolean processedImage = false;
Planar input;
Planar output;
// rendered in main thread
BufferedImage renderedImage;
// rendered is copied to this in a GUI thread
BufferedImage outputImage;
// tells progress monitor the current progress
volatile int progress;
public ShowLensDistortion(Class imageType) {
this.imageType = imageType;
input = new Planar(imageType, 1, 1 , 3);
output = new Planar(imageType, 1, 1 , 3);
addToToolbar(createRadialSelect());
setMainGUI(gui);
}
private JPanel createRadialSelect() {
JPanel ret = new JPanel();
ret.setLayout(new BoxLayout(ret, BoxLayout.X_AXIS));
radialOrder1 = new JSpinner(new SpinnerNumberModel(radial1,-1.0,2.0,0.05));
radialOrder1.addChangeListener(this);
int h = radialOrder1.getPreferredSize().height;
radialOrder1.setPreferredSize(new Dimension(50, h));
radialOrder1.setMaximumSize(radialOrder1.getPreferredSize());
radialOrder2 = new JSpinner(new SpinnerNumberModel(radial2,-1.0,2.0,0.05));
radialOrder2.addChangeListener(this);
radialOrder2.setPreferredSize(new Dimension(50, h));
radialOrder2.setMaximumSize(radialOrder1.getPreferredSize());
tangentialOrder1 = new JSpinner(new SpinnerNumberModel(tangential1,-1.0,1.0,0.01));
tangentialOrder1.addChangeListener(this);
tangentialOrder1.setPreferredSize(new Dimension(50, h));
tangentialOrder1.setMaximumSize(tangentialOrder1.getPreferredSize());
tangentialOrder2 = new JSpinner(new SpinnerNumberModel(tangential2,-1.0,1.0,0.01));
tangentialOrder2.addChangeListener(this);
tangentialOrder2.setPreferredSize(new Dimension(50, h));
tangentialOrder2.setMaximumSize(tangentialOrder2.getPreferredSize());
showFullImage = new JCheckBox();
showFullImage.setSelected(fullView);
showFullImage.addItemListener(this);
ret.add(Box.createRigidArea(new Dimension(10, 1)));
ret.add(new JLabel("Radial 1:"));
ret.add(radialOrder1);
ret.add(Box.createRigidArea(new Dimension(10,1)));
ret.add(new JLabel("Radial 2:"));
ret.add(radialOrder2);
ret.add(Box.createRigidArea(new Dimension(10,1)));
ret.add(new JLabel("T1:"));
ret.add(tangentialOrder1);
ret.add(Box.createRigidArea(new Dimension(10,1)));
ret.add(new JLabel("T2:"));
ret.add(tangentialOrder2);
ret.add(Box.createRigidArea(new Dimension(10,1)));
ret.add(new JLabel("Full:"));
ret.add(showFullImage);
// change the enabled status of the spinner
ret.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if( evt.getPropertyName().equals("enabled")) {
JPanel src = (JPanel)evt.getSource();
boolean value = (Boolean)evt.getNewValue();
for( int i = 0; i < src.getComponentCount(); i++ ) {
src.getComponent(i).setEnabled(value);
}
}
}
});
return ret;
}
public void process( final BufferedImage image ) {
input.reshape(image.getWidth(),image.getHeight());
output.reshape(image.getWidth(),image.getHeight());
ConvertBufferedImage.convertFromMulti(image, input, true, imageType);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setInputImage(image);
outputImage = new BufferedImage(input.width, input.height,BufferedImage.TYPE_INT_BGR);
renderedImage = new BufferedImage(input.width, input.height,BufferedImage.TYPE_INT_BGR);
gui.setBufferedImage(outputImage);
gui.setPreferredSize(new Dimension(input.width,input.height));
gui.repaint();
processedImage = true;
doRefreshAll();
}});
}
@Override
public void loadConfigurationFile(String fileName) {}
@Override
public boolean getHasProcessedImage() {
return processedImage;
}
@Override
public void refreshAll(Object[] cookies) {
performUpdate();
}
private synchronized void performUpdate() {
if( input == null || output == null )
return;
progress = 0;
ProgressMonitorThread thread = new MyMonitorThread(this);
thread.start();
IntrinsicParameters param = new IntrinsicParameters().fsetK(input.width * 0.8, input.width * 0.8, 0,
input.width / 2, input.height / 2, input.width, input.height).fsetRadial(radial1, radial2).
fsetTangental(tangential1, tangential2);
AdjustmentType type = fullView ? AdjustmentType.FULL_VIEW : AdjustmentType.NONE;
ImageDistort distort = LensDistortionOps.imageRemoveDistortion(type, BorderType.ZERO, param, null, input.getImageType());
distort.apply(input,output);
thread.stopThread();
ConvertBufferedImage.convertTo(output, renderedImage, true);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
outputImage.createGraphics().drawImage(renderedImage,0,0,null);
gui.repaint();
}
});
}
@Override
public void changeInput(String name, int index) {
BufferedImage image = media.openImage(inputRefs.get(index).getPath());
if (image != null) {
process(image);
} else {
System.err.println("Can't open "+inputRefs.get(index).getPath());
System.exit(1);
}
}
@Override
public synchronized void stateChanged(ChangeEvent e) {
if( e.getSource() == radialOrder1 )
radial1 = ((Number) radialOrder1.getValue()).doubleValue();
else if( e.getSource() == radialOrder2 )
radial2 = ((Number) radialOrder2.getValue()).doubleValue();
else if( e.getSource() == tangentialOrder1 )
tangential1 = ((Number) tangentialOrder1.getValue()).doubleValue();
else if( e.getSource() == tangentialOrder2 )
tangential2 = ((Number) tangentialOrder2.getValue()).doubleValue();
performUpdate();
}
@Override
public void itemStateChanged(ItemEvent e) {
fullView = showFullImage.isSelected();
performUpdate();
}
private class MyMonitorThread extends ProgressMonitorThread {
protected MyMonitorThread(Component comp) {
super(new ProgressMonitor(comp,
"Applying Distortion",
"", 0, input.getNumBands()));
}
@Override
public void doRun() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
monitor.setProgress(progress);
}});
}
}
public static void main(String args[]) {
// ShowImageBlurApp app
// = new ShowImageBlurApp(GrayF32.class);
ShowLensDistortion app
= new ShowLensDistortion(GrayU8.class);
List inputs = new ArrayList();
inputs.add(new PathLabel("shapes", UtilIO.pathExample("shapes/shapes01.png")));
inputs.add(new PathLabel("beach",UtilIO.pathExample("scale/beach02.jpg")));
inputs.add(new PathLabel("sunflowers",UtilIO.pathExample("sunflowers.jpg")));
app.setInputList(inputs);
// wait for it to process one image so that the size isn't all screwed up
while( !app.getHasProcessedImage() ) {
Thread.yield();
}
ShowImages.showWindow(app, "Lens Distortion", true);
}
}
Ads help maintain this website.