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); 
                } 
            } 
 
        } 
 
 
    } 
 
}