io.github.jakejmattson.facialrecognition.ImageFrame.java Source code

Java tutorial

Introduction

Here is the source code for io.github.jakejmattson.facialrecognition.ImageFrame.java

Source

/*
 * The MIT License
 * Copyright  2016 Jake Mattson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package io.github.jakejmattson.facialrecognition;

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.lang.reflect.Field;
import java.util.Objects;

/**
 * Frame - GUI container for components (holds ImagePanel).
 *
 * @author JakeJMattson
 */
class ImageFrame implements ActionListener {
    /**
     * Whether or not the frame is currently open
     */
    private boolean isOpen;
    /**
     * Whether or not the face should be saved to the disk
     */
    private boolean shouldSave;
    /**
     * Color to draw components (boxes, text, etc) in
     */
    private Color color;
    /**
     * Panel to hold/display a BufferedImage
     */
    private ImagePanel imagePanel;

    private JFrame frame;
    private JTextField txtFileName;
    private JButton btnSaveFile;
    private JButton btnSetColor;
    private JComboBox<String> colorDropDown;

    private static final Color DEFAULT_COLOR = Color.BLUE;

    ImageFrame() {
        color = DEFAULT_COLOR;
        buildGUI();
    }

    /**
     * Construct the display and its children.
     */
    private void buildGUI() {
        imagePanel = new ImagePanel();
        isOpen = true;

        frame = new JFrame("Facial Recognition");
        frame.addWindowListener(createWindowListener());
        frame.setLayout(new BorderLayout());
        frame.add("Center", imagePanel);
        frame.add("South", createToolbarPanel());
        frame.setVisible(true);
    }

    /**
     * Create a listener to monitor the frame closing event.
     *
     * @return WindowListener
     */
    private WindowListener createWindowListener() {
        return new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent windowClosed) {
                isOpen = false;
            }
        };
    }

    /**
     * Create a panel to hold all non-image display elements.
     *
     * @return Panel
     */
    private JPanel createToolbarPanel() {
        JPanel toolbarPanel = new JPanel(new FlowLayout());
        JPanel savePanel = createSavePanel();
        JPanel colorPanel = createColorPanel();

        toolbarPanel.add(savePanel);
        toolbarPanel.add(colorPanel);

        return toolbarPanel;
    }

    /**
     * Create a panel to display saving options to the user.
     *
     * @return Panel
     */
    private JPanel createSavePanel() {
        JPanel namePanel = new JPanel(new GridLayout(0, 2));
        JPanel savePanel = new JPanel(new FlowLayout());
        savePanel.setBorder(BorderFactory.createLineBorder(Color.black));

        JLabel lblFileName = new JLabel("Name of person in frame: ");
        txtFileName = new JTextField("");
        btnSaveFile = new JButton("Save Face");
        btnSaveFile.addActionListener(this);

        namePanel.add(lblFileName);
        namePanel.add(txtFileName);
        savePanel.add(namePanel);
        savePanel.add(btnSaveFile);

        return savePanel;
    }

    /**
     * Create a panel to display color options to the user.
     *
     * @return Panel
     */
    private JPanel createColorPanel() {
        JPanel colorPanel = new JPanel();
        colorPanel.setBorder(BorderFactory.createLineBorder(Color.black));

        String[] colorOptions = { "BLUE", "CYAN", "GREEN", "MAGENTA", "ORANGE", "RED" };

        colorDropDown = new JComboBox<>();
        btnSetColor = new JButton("Set Color");
        btnSetColor.addActionListener(this);

        for (String option : colorOptions)
            colorDropDown.addItem(option);

        colorPanel.add(colorDropDown);
        colorPanel.add(btnSetColor);

        return colorPanel;
    }

    /**
     * Externally called to see if display frame is still open.
     *
     * @return Open status
     */
    boolean isOpen() {
        return isOpen;
    }

    /**
     * Return whether or not the face in frame should be saved to the disk.
     * Set the state to false.
     *
     * @return state
     */
    boolean shouldSave() {
        boolean prevState = shouldSave;
        shouldSave = false;
        return prevState;
    }

    /**
     * Get the name of the person in frame (user input).
     *
     * @return name
     */
    String getFileName() {
        return txtFileName.getText();
    }

    /**
     * Return the selected text color as an OpenCV Scalar.
     *
     * @return Scalar
     */
    Scalar getTextColor() {
        return new Scalar(color.getBlue(), color.getGreen(), color.getRed());
    }

    /**
     * Display an image in the frame.
     *
     * @param image
     *       Image to be shown
     */
    void showImage(Mat image) {
        imagePanel.setImage(convertMatToImage(image));
        frame.repaint();
        frame.pack();
    }

    /**
     * Convert an OpenCV Mat to a Java BufferedImage.
     *
     * @param matrix
     *       OpenCV Mat
     *
     * @return BufferedImage
     */
    private static BufferedImage convertMatToImage(Mat matrix) {
        int width = matrix.width();
        int height = matrix.height();
        int type = matrix.channels() != 1 ? BufferedImage.TYPE_3BYTE_BGR : BufferedImage.TYPE_BYTE_GRAY;

        if (type == BufferedImage.TYPE_3BYTE_BGR)
            Imgproc.cvtColor(matrix, matrix, Imgproc.COLOR_BGR2RGB);

        byte[] data = new byte[width * height * (int) matrix.elemSize()];
        matrix.get(0, 0, data);

        BufferedImage out = new BufferedImage(width, height, type);
        out.getRaster().setDataElements(0, 0, width, height, data);

        return out;
    }

    @Override
    public void actionPerformed(ActionEvent click) {
        Object src = click.getSource();

        if (src == btnSetColor)
            try {
                Field field = Color.class
                        .getField((String) Objects.requireNonNull(colorDropDown.getSelectedItem()));
                color = (Color) field.get(null);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                color = DEFAULT_COLOR;
            }
        else if (src == btnSaveFile)
            shouldSave = true;
    }
}