TrainingDataGUI.java
package ac.essex.ooechs.imaging.commons.apps.training;
import ac.essex.ooechs.imaging.commons.Pixel;
import ac.essex.ooechs.imaging.commons.PixelLoader;
import ac.essex.ooechs.imaging.commons.Resizer;
import ac.essex.ooechs.imaging.commons.HaarRegions;
import ac.essex.ooechs.imaging.commons.cmu.GroundTruthReader;
import ac.essex.ooechs.imaging.commons.cmu.FaceDefinition;
import ac.essex.ooechs.imaging.commons.apps.training.strategies.*;
import ac.essex.ooechs.imaging.commons.util.*;
import ac.essex.ooechs.imaging.commons.util.panels.ImagePanel;
import ac.essex.ooechs.imaging.commons.evolved.FaceDetectorA;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import java.util.Vector;
import java.io.File;
import java.io.FilenameFilter;
/**
* <p/>
* Allows you to create cropped training data quickly. Downloads
* images from the internet, and then allows you to crop them
* to the correct dimensions before saving in the directory of your
* choice.
* </p>
* <p/>
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version,
* provided that any use properly credits the author.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details at http://www.gnu.org
* </p>
*
* @author Olly Oechsle, University of Essex, Date: 26-Sep-2006
* @version 1.11 Can load variety of image formats.
* @version 1.2 Supports auto cropping using truth files, and allows similar regions to be
* cropped without black squares coming into the original images.
*/
public class TrainingDataGUI extends JFrame implements ActionListener, ImageWaiter {
public static final String DEFAULT_FILENAME = "image";
File truthLocation = new File("/home/ooechs/ecj-training/faces/mit+cmu/truth.txt");
CroppingPanel panel;
int cropAllNumber = 5;
JLabel coordinates;
JLabel results;
JLabel createdCount;
int cropCount;
JTextField directory;
JTextField filename;
JButton nextButton, btnBrowse;
ImageDownloader downloader;
JMenuItem file_openFromWeb;
JMenuItem file_openFromFolder;
JMenuItem file_exit;
JMenuItem edit_saveLocation;
JMenuItem edit_cropSettings;
JMenuItem run_facedetector;
JMenuItem run_cropAll;
JMenuItem run_stopFaceDetector;
JMenuItem tools_autocropFaces;
JMenuItem tools_autocropNonFaces;
JMenuItem tools_autocropEyes;
JMenuItem tools_autocropMouths;
Vector<StrategyMenuItem> strategyMenus;
int segmentsX = 8;
int segmentsY = 10;
// the standard size
int width = 32;
int height = 40;
// the aspect ratio to maintain
double aspectRatio = 0.8;
// whether the crop window is resized to the width and height dimensions automatically
boolean autoResize = false;
boolean maintainCropRegionAspectRatio = true;
boolean crosshair = true;
int crossHairX = 4;
int crossHairY = 4;
Vector<Pixel> objects;
Vector<CroppingStrategy> strategies;
public static void main(String[] args) {
new TrainingDataGUI();
}
class StrategyMenuItem extends JCheckBoxMenuItem {
CroppingStrategy strategy;
public StrategyMenuItem(String name, CroppingStrategy strategy) {
super(name);
this.strategy = strategy;
}
public CroppingStrategy getStrategy() {
return strategy;
}
}
public TrainingDataGUI() {
super("Training Image Creator");
// Load Cropping Strategies here //
strategies = new Vector<CroppingStrategy>(10);
strategies.add(new FaceCroppingStrategy());
strategies.add(new MouthCroppingStrategy());
strategies.add(new EyeCroppingStrategy());
directory = new JTextField(System.getProperty("user.dir"));
images = new Vector<File>(100);
Container c = getContentPane();
panel = new CroppingPanel();
coordinates = new JLabel("");
JPanel topBar = new JPanel(new FlowLayout(FlowLayout.LEFT));
nextButton = new JButton("Next Image");
results = new JLabel("No Images Found.");
// FILE MENU
JMenu file = new JMenu("File");
file_openFromFolder = new JMenuItem("Acquire from local computer");
file_openFromWeb = new JMenuItem("Acquire from www");
file_exit = new JMenuItem("Exit");
file_openFromWeb.addActionListener(this);
file_openFromFolder.addActionListener(this);
file_exit.addActionListener(this);
file.add(file_openFromWeb);
file.add(file_openFromFolder);
file.add(file_exit);
// EDIT MENU
JMenu edit = new JMenu("Edit");
edit_saveLocation = new JMenuItem("Save Folder");
edit_cropSettings = new JMenuItem("Cropping Settings");
edit_saveLocation.addActionListener(this);
edit_cropSettings.addActionListener(this);
edit.add(edit_saveLocation);
edit.add(edit_cropSettings);
// RUN MENU
JMenu run = new JMenu("Run");
run_facedetector = new JMenuItem("Face Detector");
run_cropAll = new JMenuItem("Crop All");
run_stopFaceDetector = new JMenuItem("Stop");
run_facedetector.addActionListener(this);
run_cropAll.addActionListener(this);
run_stopFaceDetector.addActionListener(this);
run_cropAll.setEnabled(false);
run.add(run_facedetector);
run.add(run_cropAll);
run.add(run_stopFaceDetector);
// TOOLS MENU
JMenu crop = new JMenu("Crop");
strategyMenus = new Vector<StrategyMenuItem>(10);
StrategyMenuItem item = new StrategyMenuItem("Manual", null);
item.addActionListener(this);
item.setSelected(true);
crop.add(item);
strategyMenus.add(item);
for (int i = 0; i < strategies.size(); i++) {
CroppingStrategy strategy = strategies.elementAt(i);
StrategyMenuItem item2 = new StrategyMenuItem(strategy.getName(), strategy);
item2.addActionListener(this);
crop.add(item2);
strategyMenus.add(item2);
}
tools_autocropFaces = new JMenuItem("Auto Crop Faces");
tools_autocropFaces.addActionListener(this);
tools_autocropNonFaces = new JMenuItem("Auto Crop Non Faces");
tools_autocropNonFaces.addActionListener(this);
crop.addSeparator();
crop.add(tools_autocropFaces);
crop.add(tools_autocropNonFaces);
// MENU BAR
JMenuBar menuBar = new JMenuBar();
menuBar.add(file);
menuBar.add(edit);
menuBar.add(run);
menuBar.add(crop);
setJMenuBar(menuBar);
topBar.add(new JLabel("Saving to:"));
directory.setPreferredSize(new Dimension(350, 20));
topBar.add(directory);
btnBrowse = new JButton("...");
btnBrowse.setToolTipText("Choose another folder to save images to");
btnBrowse.addActionListener(this);
topBar.add(btnBrowse);
filename = new JTextField(DEFAULT_FILENAME);
filename.setPreferredSize(new Dimension(100, 20));
topBar.add(filename);
topBar.add(new JLabel(".bmp"));
nextButton.addActionListener(this);
c.add(topBar, BorderLayout.NORTH);
c.add(panel, BorderLayout.CENTER);
JPanel bottom = new JPanel(new GridLayout(1, 2));
JPanel status = new JPanel(new FlowLayout(FlowLayout.LEFT));
createdCount = new JLabel("");
status.add(results);
status.add(coordinates);
status.add(createdCount);
JPanel right = new JPanel(new FlowLayout(FlowLayout.RIGHT));
right.add(nextButton);
bottom.add(status);
bottom.add(right);
c.add(bottom, BorderLayout.SOUTH);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setSize(740, 480);
setVisible(true);
}
public void incrementCropCount() {
cropCount++;
createdCount.setText("Created " + cropCount + " images.");
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof StrategyMenuItem) {
StrategyMenuItem s = (StrategyMenuItem) e.getSource();
panel.nodes.clear();
panel.currentNode = null;
panel.repaint();
panel.currentStrategy = s.getStrategy();
if (s.getStrategy() != null) {
JOptionPane.showMessageDialog(this, s.getStrategy().getDescription());
}
for (int i = 0; i < strategyMenus.size(); i++) {
StrategyMenuItem strategyMenuItem = strategyMenus.elementAt(i);
strategyMenuItem.setSelected(strategyMenuItem == e.getSource());
}
}
if (e.getSource() == tools_autocropFaces) {
// autocrop faces
autoCropFaces();
}
if (e.getSource() == tools_autocropNonFaces) {
// autocrop non faces
autoCropNonFaces();
}
if (e.getSource() == file_openFromWeb) {
String searchQuery = (String) JOptionPane.showInputDialog(
this,
"Search For\n",
"Get Images from Web",
JOptionPane.PLAIN_MESSAGE,
null,
null,
"");
//If a string was returned, say so.
if ((searchQuery != null) && (searchQuery.length() > 0)) {
Object[] possibilities = {"10", "50", "100", "200", "500"};
String count = (String) JOptionPane.showInputDialog(
this,
"How many images required?\n",
"Get Images from Web",
JOptionPane.PLAIN_MESSAGE,
null,
possibilities,
"100");
if ((count != null) && (count.length() > 0)) {
images.setSize(0);
results.setText(images.size() + " images available");
try {
int searches = Integer.parseInt(count);
System.out.println("Searching for " + searches + " images");
downloader = new ImageDownloader(searchQuery, searches, 92, 112, ImageDownloader.LEAVE_ORIGINAL, this);
downloader.start();
} catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(this, "Please enter a number of images to search for.");
}
}
}
}
if (e.getSource() == edit_saveLocation || e.getSource() == btnBrowse) {
//Create a file chooser
final JFileChooser fc = new JFileChooser(directory.getText());
fc.setDialogTitle("Choose Save Folder");
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
//In response to a button click:
int returnVal = fc.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
directory.setText(fc.getSelectedFile().getAbsolutePath());
}
}
if (e.getSource() == run_facedetector) {
run_cropAll.setEnabled(true);
panel.showObjects();
}
if (e.getSource() == run_stopFaceDetector) {
run_cropAll.setEnabled(false);
panel.stopShowingObjects();
}
if (e.getSource() == run_cropAll) {
run_cropAll.setEnabled(false);
panel.cropAll();
}
if (e.getSource() == edit_cropSettings) {
if (cropDialog == null) {
cropDialog = new CropDialog();
} else {
cropDialog.synchronise();
cropDialog.setVisible(true);
}
}
if (e.getSource() == file_openFromFolder) {
//Create a file chooser
final JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
//In response to a button click:
int returnVal = fc.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
images.setSize(0);
results.setText(images.size() + " images available");
File directory = fc.getSelectedFile();
File[] imageFiles = directory.listFiles();
for (int i = 0; i < imageFiles.length; i++) {
File imageFile = imageFiles[i];
if (ImageFilenameFilter.isImage(imageFile)) {
try {
images.add(imageFile);
if (panel.getImage() == null) {
next();
}
results.setText(images.size() + " images available");
} catch (Exception e2) {
JOptionPane.showMessageDialog(this, "Error: " + e2.getMessage());
}
}
}
if (images.size() == 0) {
JOptionPane.showMessageDialog(this, "Could not find any images in this folder.");
}
}
}
if (e.getSource() == file_exit) {
System.exit(0);
}
if (e.getSource() == nextButton) {
next();
}
}
Vector<File> images;
CropDialog cropDialog;
class CropDialog extends JFrame implements ActionListener {
JButton ok, cancel;
JTextField segmentsXField, segmentsYField, widthField, heightField, crosshairXField, crosshairYField;
JCheckBox resize, maintainAspectRatio, showCrosshair;
public void synchronise() {
segmentsXField.setText(String.valueOf(segmentsX));
segmentsYField.setText(String.valueOf(segmentsY));
widthField.setText(String.valueOf(width));
heightField.setText(String.valueOf(height));
crosshairXField.setText(String.valueOf(crossHairX));
crosshairYField.setText(String.valueOf(crossHairY));
resize.setSelected(autoResize);
showCrosshair.setSelected(crosshair);
maintainAspectRatio.setSelected(maintainCropRegionAspectRatio);
}
public CropDialog() {
super("Crop Settings");
// MAIN FORM
JPanel main = new JPanel(new GridLayout(7, 1));
segmentsXField = new JTextField(String.valueOf(segmentsX));
segmentsYField = new JTextField(String.valueOf(segmentsY));
resize = new JCheckBox("Auto resize crop region to:", autoResize);
resize.addActionListener(this);
widthField = new JTextField(String.valueOf(width));
heightField = new JTextField(String.valueOf(height));
showCrosshair = new JCheckBox("Show Crosshair", crosshair);
crosshairXField = new JTextField(String.valueOf(crossHairX));
crosshairYField = new JTextField(String.valueOf(crossHairY));
maintainAspectRatio = new JCheckBox("Maintain Aspect Ratio", maintainCropRegionAspectRatio);
updateTextFields();
main.add(new JLabel("Segments X:"));
main.add(segmentsXField);
main.add(new JLabel("Segments Y:"));
main.add(segmentsYField);
main.add(new JLabel("Resize:"));
main.add(resize);
main.add(new JLabel("Width:"));
main.add(widthField);
main.add(new JLabel("Height"));
main.add(heightField);
main.add(new JLabel("Aspect Ratio:"));
main.add(maintainAspectRatio);
main.add(new JLabel("Special:"));
main.add(showCrosshair);
// BUTTONS
JPanel bottom = new JPanel(new FlowLayout(FlowLayout.RIGHT));
ok = new JButton("OK");
cancel = new JButton("Cancel");
ok.addActionListener(this);
cancel.addActionListener(this);
bottom.add(ok);
bottom.add(cancel);
// SWING STUFF
Container c = getContentPane();
c.add(main, BorderLayout.CENTER);
c.add(bottom, BorderLayout.SOUTH);
setSize(350, 200);
setVisible(true);
}
private void updateTextFields() {
widthField.setEnabled(resize.isSelected());
heightField.setEnabled(resize.isSelected());
crosshairXField.setEnabled(showCrosshair.isSelected());
crosshairYField.setEnabled(showCrosshair.isSelected());
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == resize || e.getSource() == showCrosshair) {
updateTextFields();
return;
}
if (e.getSource() == ok) {
try {
autoResize = resize.isSelected();
maintainCropRegionAspectRatio = maintainAspectRatio.isSelected();
crosshair = showCrosshair.isSelected();
segmentsX = Integer.parseInt(segmentsXField.getText());
segmentsY = Integer.parseInt(segmentsYField.getText());
if (resize.isSelected()) {
width = Integer.parseInt(widthField.getText());
height = Integer.parseInt(heightField.getText());
}
if (showCrosshair.isSelected()) {
crossHairX = Integer.parseInt(crosshairXField.getText());
crossHairY = Integer.parseInt(crosshairYField.getText());
}
} catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(this, "Can't read number:\n" + nfe.getMessage());
return;
}
}
setVisible(false);
}
}
public void recieveImage(File image) {
results.setText(images.size() + " images available");
images.add(image);
if (panel.getImage() == null) {
next();
}
}
int counter = 0;
Vector buffer;
final int BUFFER_SIZE = 5;
String currentFilename = "[NO FILE]";
public void next() {
objects = null;
run_cropAll.setEnabled(false);
if (images.size() == 0) {
return;
}
panel.cropRegion = null;
panel.nodes.clear();
panel.currentNode = null;
panel.previousCrops.setSize(0);
BufferedImage image = panel.getImage();
if (image != null) {
// free up memory
image = null;
if (counter > 20) {
counter = 0;
System.gc();
}
counter++;
}
try {
PixelLoader img = new PixelLoader(images.firstElement());
currentFilename = img.getFile().getName();
panel.setImage(img);
} catch (Exception e) {
System.err.println("Can't load image.");
}
images.removeElementAt(0);
results.setText(images.size() + " images available");
}
GroundTruthReader truth;
public void autoCropFaces() {
// get the truth
if (truth == null) truth = new GroundTruthReader(truthLocation);
// and get the file that matches
Vector<FaceDefinition> faces = truth.getFaces(currentFilename);
if (faces == null) {
JOptionPane.showMessageDialog(this, "Cannot find truth definitions for this image: " + currentFilename);
} else {
for (int i = 0; i < faces.size(); i++) {
FaceDefinition face = faces.elementAt(i);
panel.cropRegion = new FaceCroppingStrategy().getCroppingRegion(face.getLeftEye(), face.getRightEye());
panel.crop();
}
}
}
public void autoCropNonFaces() {
// get the truth
if (truth == null) truth = new GroundTruthReader(truthLocation);
// and get the file that matches
Vector<FaceDefinition> faces = truth.getFaces(currentFilename);
// Check we have truth for this image.
if (faces == null) {
JOptionPane.showMessageDialog(this, "Cannot find truth definitions for this image: " + currentFilename);
return;
}
// Convert this into a series of regions
Vector<Region> faceRegions = new Vector<Region>(50);
for (int i = 0; i < faces.size(); i++) {
FaceDefinition face = faces.elementAt(i);
faceRegions.add(new FaceCroppingStrategy().getCroppingRegion(face.getLeftEye(), face.getRightEye()));
}
// Now create my own crop region and move around the image
for (int y = 0; y < panel.getImage().getHeight() - height; y+=30) {
for (int x = 0; x < panel.getImage().getWidth() - width; x+=20) {
panel.cropRegion = new Region(x, y, width, height);
boolean dontUse = false;
for (int i = 0; i < faceRegions.size(); i++) {
Region face = faceRegions.elementAt(i);
if (panel.cropRegion.overlap(face) > 0) {
dontUse = true;
break;
}
}
if (!dontUse) panel.crop();
}
}
}
public void autoCropEyes() {
// get the truth
if (truth == null) truth = new GroundTruthReader(truthLocation);
// and get the file that matches
Vector<FaceDefinition> faces = truth.getFaces(currentFilename);
if (faces == null) {
JOptionPane.showMessageDialog(this, "Cannot find truth definitions for this image: " + currentFilename);
} else {
for (int i = 0; i < faces.size(); i++) {
FaceDefinition face = faces.elementAt(i);
panel.cropRegion = new FaceCroppingStrategy().getCroppingRegion(face.getLeftEye(), face.getRightEye());
panel.crop();
}
}
}
/**
* This class allows you to fill crop marks on the image
* and when you double click it saves an image to a given location
* and colours the cropped part of the image black.
*/
class CroppingPanel extends ImagePanel {
final int CROP = 0;
final int MOVE = 1;
int currentX, currentY;
int moveX, moveY;
boolean mouseDown = false;
int mode = CROP;
Region cropRegion;
Region previousPosition;
// handles around the crop region
Region ne, nw, se, sw, n, e, s, w;
CroppingStrategy currentStrategy = null;
Vector<Pixel> nodes;
Pixel currentNode = null;
/**
* Remembers where previous crops were taken from so they can
* be drawn on the screen later.
*/
Vector<Region> previousCrops;
public CroppingPanel() {
previousCrops = new Vector<Region>(20);
nodes = new Vector<Pixel>(10);
currentStrategy = null;
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent mousePos) {
requestFocusInWindow();
// update the coordinates
coordinates.setText("x=" + mousePos.getX() + ", y=" + mousePos.getY());
currentX = mousePos.getX();
currentY = mousePos.getY();
// indicate that the mouse button has been lifted
mouseDown = false;
if (cropRegion != null) {
if (cropRegion.contains(mousePos)) {
setCursor(new Cursor(Cursor.MOVE_CURSOR));
return;
}
if (ne != null && ne.contains(mousePos)) {
setCursor(new Cursor(Cursor.NE_RESIZE_CURSOR));
return;
}
if (se != null && se.contains(mousePos)) {
setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
return;
}
if (sw != null && sw.contains(mousePos)) {
setCursor(new Cursor(Cursor.SW_RESIZE_CURSOR));
return;
}
if (nw != null && nw.contains(mousePos)) {
setCursor(new Cursor(Cursor.NW_RESIZE_CURSOR));
return;
}
if (n != null && n.contains(mousePos)) {
setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
return;
}
if (s != null && s.contains(mousePos)) {
setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));
return;
}
if (e != null && e.contains(mousePos)) {
setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
return;
}
if (w != null && w.contains(mousePos)) {
setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
return;
}
}
// default drawing cursor
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
public void mouseDragged(MouseEvent e) {
if (!mouseDown) {
// save the point from which we're moving
moveX = e.getX();
moveY = e.getY();
// mouse wasn't down before
switch (getCursor().getType()) {
case Cursor.DEFAULT_CURSOR:
// create new crop region
cropRegion = new Region(e.getX(), e.getY());
break;
default:
// save where it used to be
previousPosition = new Region(cropRegion);
break;
}
} else {
// find the difference in moving
int dX = e.getX() - moveX;
int dY = e.getY() - moveY;
// mouse was down before
switch (getCursor().getType()) {
case Cursor.NW_RESIZE_CURSOR:
cropRegion.x1 = previousPosition.x1 + dX;
cropRegion.y1 = previousPosition.y1 + dY;
break;
case Cursor.NE_RESIZE_CURSOR:
cropRegion.x2 = previousPosition.x2 + dX;
cropRegion.y1 = previousPosition.y1 + dY;
break;
case Cursor.SE_RESIZE_CURSOR:
cropRegion.x2 = previousPosition.x2 + dX;
cropRegion.y2 = previousPosition.y2 + dY;
break;
case Cursor.SW_RESIZE_CURSOR:
cropRegion.x1 = previousPosition.x1 + dX;
cropRegion.y2 = previousPosition.y2 + dY;
break;
case Cursor.N_RESIZE_CURSOR:
cropRegion.y1 = previousPosition.y1 + dY;
break;
case Cursor.E_RESIZE_CURSOR:
cropRegion.x2 = previousPosition.x2 + dX;
break;
case Cursor.S_RESIZE_CURSOR:
cropRegion.y2 = previousPosition.y2 + dY;
break;
case Cursor.W_RESIZE_CURSOR:
cropRegion.x1 = previousPosition.x1 + dX;
break;
case Cursor.MOVE_CURSOR:
// move the cropped region
cropRegion.move(previousPosition, dX, dY);
break;
case Cursor.DEFAULT_CURSOR:
// expand the cropped region
cropRegion.x2 = e.getX();
cropRegion.y2 = e.getY();
}
}
// handles used for changing the size
placeHandles();
mouseDown = true;
repaint();
}
});
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
// right click - clear everything
cropRegion = null;
nodes.clear();
currentNode = null;
} else {
if (currentStrategy == null) {
// double click crops
if (e.getClickCount() == 2) crop();
// single click sets size
if (e.getClickCount() == 1) setSize();
} else {
// create a new node
currentNode = new Pixel(e.getX(), e.getY());
// how many nodes are there?
if (nodes.size() == currentStrategy.countNodes()) {
// replace the last node
nodes.setElementAt(currentNode, nodes.size() - 1);
} else {
// add another node
nodes.add(currentNode);
}
}
}
// redraw onto the canvas
repaint();
}
});
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == 's') {
setStandardisedSize();
}
if (e.getKeyChar() == 'f') {
autoCropFaces();
}
if (e.getKeyChar() == 'r') {
run_cropAll.setEnabled(true);
panel.showObjects();
}
if (e.getKeyChar() == 'c') {
run_cropAll.setEnabled(false);
panel.cropAll();
}
if (cropRegion != null) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
cropRegion.move(0, -1);
placeHandles();
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
cropRegion.move(0, 1);
placeHandles();
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
cropRegion.move(-1, 0);
placeHandles();
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
cropRegion.move(1, 0);
placeHandles();
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
cropRegion = null;
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
crop();
}
} else {
if (currentNode != null) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
currentNode.move(0, -1);
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
currentNode.move(0, 1);
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
currentNode.move(-1, 0);
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
currentNode.move(1, 0);
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
autoCreateCropRegion();
repaint();
}
return;
}
// crop region is null, use this as next button instead
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
next();
}
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
cropRegion = new Region(currentX, currentY);
setStandardisedSize();
crop();
}
}
});
}
private void autoCreateCropRegion() {
// use the current cropping strategy
try {
cropRegion = currentStrategy.getCropRegion(nodes);
// reset nodes
nodes.clear();
currentNode = null;
// place handles around the new cropping region
placeHandles();
// and fill
repaint();
} catch (StrategyException e) {
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
private void setStandardisedSize() {
if (cropRegion != null) {
cropRegion.setWidth(width);
cropRegion.setHeight(height);
placeHandles();
repaint();
}
}
private void placeHandles() {
int dist = 9;
int size = 6;
nw = new Region(cropRegion.getStartX() - dist, cropRegion.getStartY() - dist, size, size);
ne = new Region(cropRegion.getStartX() + cropRegion.getWidth() + (dist - size), cropRegion.getStartY() - dist, size, size);
n = new Region(cropRegion.getStartX(), cropRegion.getStartY(), size, size);
n.move((cropRegion.getWidth() - size) / 2, -dist);
w = new Region(cropRegion.getStartX(), cropRegion.getStartY(), size, size);
w.move(-dist, (cropRegion.getHeight() - size) / 2);
e = new Region(cropRegion.getStartX(), cropRegion.getStartY(), size, size);
e.move(cropRegion.getWidth() + (dist - size), (cropRegion.getHeight() - size) / 2);
s = new Region(cropRegion.getStartX(), cropRegion.getStartY(), size, size);
s.move((cropRegion.getWidth() - size) / 2, cropRegion.getHeight() + (dist - size));
sw = new Region(cropRegion.getStartX() - dist, cropRegion.getStartY() + cropRegion.getHeight() + (dist - size), size, size);
se = new Region(cropRegion.getStartX() + cropRegion.getWidth() + (dist - size), cropRegion.getStartY() + cropRegion.getHeight() + (dist - size), size, size);
}
public void setSize() {
if (cropRegion != null) {
int height = (cropRegion.getHeight() / segmentsY) * segmentsY;
double newWidth = (height * aspectRatio);
double dWidth = newWidth - cropRegion.getWidth();
cropRegion.setWidth((int) newWidth);
cropRegion.setHeight(height);
cropRegion.move((int) (-dWidth / 2), 0);
placeHandles();
repaint();
}
}
public void cropAll() {
if (objects == null) return;
double probability = cropAllNumber / (double) objects.size();
cropRegion = null;
Graphics g = getImage().getGraphics();
Vector<Pixel> cropped = new Vector<Pixel>(cropAllNumber);
for (int i = 0; i < objects.size(); i++) {
if (Math.random() < probability) {
Pixel pixel = objects.elementAt(i);
cropRegion = new Region(pixel.x, pixel.y, width, height);
crop();
cropped.add(pixel);
}
}
repaint();
}
public void crop() {
if (getImage() != null) {
try {
int width = (cropRegion.getWidth());
int height = (cropRegion.getHeight());
int rectStartX = cropRegion.getStartX();
int rectStartY = cropRegion.getStartY();
PixelLoader cropped = new PixelLoader(
getImage().getSubimage(rectStartX, rectStartY, width, height)
);
previousCrops.add(cropRegion);
save(cropped);
} catch (Exception e) {
JOptionPane.showMessageDialog(this, e.getMessage());
return;
}
} else {
JOptionPane.showMessageDialog(this, "No image selected. Search for an image first.");
}
cropRegion = null;
repaint();
}
public void save(PixelLoader cropped) {
try {
File saveDirectory = new File(directory.getText());
saveDirectory.mkdirs();
File[] existing = saveDirectory.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return (name.startsWith(filename.getText()));
}
});
int counter = 1;
while (true) {
File save = new File(saveDirectory, filename.getText() + counterToString(counter) + ".bmp");
boolean exists = false;
for (int i = 0; i < existing.length; i++) {
File existingFile = existing[i];
if (existingFile.getName().equals(save.getName())) exists = true;
}
counter++;
if (!exists) {
cropped.saveAs(save);
if (autoResize) {
Resizer.resize(save, width);
}
incrementCropCount();
break;
}
}
} catch (Exception e) {
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
private String counterToString(int counter) {
if (counter < 10) {
return "00" + counter;
}
if (counter < 100) {
return "0" + counter;
}
return String.valueOf(counter);
}
HaarRegions haar;
public void showObjects() {
if (image != null) {
// create a haar regions thingummy
haar = new HaarRegions(new PixelLoader(image));
haar.setWindowPosition(0, 0, width, height, segmentsX, segmentsY);
objects = new FaceDetectorA().getObjects(haar);
repaint();
} else {
JOptionPane.showMessageDialog(this, "No image loaded!");
}
}
public void stopShowingObjects() {
objects = null;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// drawPixels previous crops
g.setColor(Color.BLACK);
for (int j = 0; j < previousCrops.size(); j++) {
Region region = previousCrops.elementAt(j);
int width = (region.getWidth());
int height = (region.getHeight());
int rectStartX = region.getStartX();
int rectStartY = region.getStartY();
g.fillRect(rectStartX, rectStartY, width, height);
}
// fill the objects here
if (objects != null) new FaceDetectorA().drawObjects(objects, haar, g);
int crosshairSize = 5;
for (int i = 0; i < nodes.size(); i++) {
Pixel node = nodes.elementAt(i);
g.setColor(Color.WHITE);
g.drawLine(node.x, node.y - crosshairSize, node.x, node.y + crosshairSize);
g.drawLine(node.x + crosshairSize, node.y, node.x - crosshairSize, node.y);
}
if (cropRegion != null) {
int width = cropRegion.getWidth();
int height = cropRegion.getHeight();
int rectStartX = cropRegion.getStartX();
int rectStartY = cropRegion.getStartY();
Color c = Color.BLACK;
if (image != null) {
if (rectStartX + width > image.getWidth()) c = Color.RED;
if (rectStartY + height > image.getHeight()) c = Color.RED;
if (rectStartX < 0) c = Color.RED;
if (rectStartY < 0) c = Color.RED;
}
g.setColor(c);
// main outline
g.drawRect(rectStartX, rectStartY, width, height);
g.setColor(Color.GRAY);
// horizontal lines
for (int i = 1; i < segmentsY; i++) {
int yPosition = rectStartY + (int) (height * (i / (double) segmentsY));
g.setColor(Color.GRAY);
if (crosshair && i == crossHairX) g.setColor(c);
g.drawLine(rectStartX, yPosition, rectStartX + width, yPosition);
}
// vertical lines
for (int i = 1; i < segmentsX; i++) {
int xPosition = rectStartX + (int) (width * (i / (double) segmentsX));
g.setColor(Color.GRAY);
if (crosshair && i == crossHairY) g.setColor(c);
g.drawLine(xPosition, rectStartY, xPosition, rectStartY + height);
}
// fill handles
g.setColor(Color.BLACK);
if (ne != null) {
ne.fill(g);
nw.fill(g);
se.fill(g);
sw.fill(g);
n.fill(g);
w.fill(g);
e.fill(g);
s.fill(g);
}
}
}
}
}