/*
* Artificial Intelligence for Humans
* Volume 1: Fundamental Algorithms
* Java Version
* http://www.aifh.org
* http://www.jeffheaton.com
*
* Code repository:
* https://github.com/jeffheaton/aifh
* Copyright 2013 by Jeff Heaton
*
* 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.
*
* For more information on Heaton Research copyrights, licenses
* and trademarks visit:
* http://www.heatonresearch.com/copyright
*/
package com.heatonresearch.aifh.examples.distance;
import com.heatonresearch.aifh.distance.CalculateDistance;
import com.heatonresearch.aifh.distance.EuclideanDistance;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.*;
/**
* OCR: Main form that allows the user to interact with the OCR application.
*/
public class OCRExample extends JFrame {
/**
* The downsample width for the application.
*/
static final int DOWNSAMPLE_WIDTH = 5;
/**
* The down sample height for the application.
*/
static final int DOWNSAMPLE_HEIGHT = 7;
/**
* Serial id for this class.
*/
private static final long serialVersionUID = -6779380961875907013L;
/**
* The entry component for the user to draw into.
*/
private final Entry entry;
/**
* The down sample component to display the drawing downsampled.
*/
private final Sample sample;
/**
* The letters that have been defined.
*/
private final DefaultListModel letterListModel = new DefaultListModel();
/**
* THe downsample button.
*/
private final JButton downSample = new JButton();
/**
* The add button.
*/
private final JButton add = new JButton();
/**
* The clear button
*/
private final JButton clear = new JButton();
/**
* The recognize button
*/
private final JButton recognize = new JButton();
/**
* The letters list box
*/
private final JList letters = new JList();
/**
* The delete button
*/
private final JButton del = new JButton();
/**
* The load button
*/
private final JButton load = new JButton();
/**
* The save button
*/
private final JButton save = new JButton();
final JLabel JLabel3 = new JLabel();
final JLabel JLabel8 = new JLabel();
final JLabel JLabel5 = new JLabel();
private final CalculateDistance distanceCalc = new EuclideanDistance();
/**
* The constructor.
*/
OCRExample() {
getContentPane().setLayout(null);
this.entry = new Entry();
this.entry.setLocation(168, 25);
this.entry.setSize(200, 128);
getContentPane().add(this.entry);
this.sample = new Sample(OCRExample.DOWNSAMPLE_WIDTH, OCRExample.DOWNSAMPLE_HEIGHT);
this.sample.setLocation(307, 210);
this.sample.setSize(65, 70);
this.entry.setSample(this.sample);
getContentPane().add(this.sample);
setTitle("OCR");
getContentPane().setLayout(null);
setSize(405, 382);
setVisible(false);
final JLabel JLabel1 = new JLabel();
JLabel1.setText("Letters Known");
getContentPane().add(JLabel1);
JLabel1.setBounds(12, 12, 100, 12);
final JLabel JLabel2 = new JLabel();
JLabel2.setBounds(12, 264, 72, 24);
this.downSample.setText("D Sample");
this.downSample.setActionCommand("Down Sample");
getContentPane().add(this.downSample);
this.downSample.setBounds(252, 180, 120, 24);
this.add.setText("Add");
this.add.setActionCommand("Add");
getContentPane().add(this.add);
this.add.setBounds(168, 156, 84, 24);
this.clear.setText("Clear");
this.clear.setActionCommand("Clear");
getContentPane().add(this.clear);
this.clear.setBounds(168, 180, 84, 24);
this.recognize.setText("Recognize");
this.recognize.setActionCommand("Recognize");
getContentPane().add(this.recognize);
this.recognize.setBounds(252, 156, 120, 24);
final JScrollPane JScrollPane1 = new JScrollPane();
JScrollPane1
.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
JScrollPane1.setOpaque(true);
getContentPane().add(JScrollPane1);
JScrollPane1.setBounds(12, 24, 144, 132);
JScrollPane1.getViewport().add(this.letters);
this.letters.setBounds(0, 0, 126, 129);
this.del.setText("Delete");
this.del.setActionCommand("Delete");
getContentPane().add(this.del);
this.del.setBounds(12, 156, 144, 24);
this.load.setText("Load");
this.load.setActionCommand("Load");
getContentPane().add(this.load);
this.load.setBounds(12, 180, 75, 24);
this.save.setText("Save");
this.save.setActionCommand("Save");
getContentPane().add(this.save);
this.save.setBounds(84, 180, 72, 24);
this.JLabel3.setBounds(12, 288, 72, 24);
this.JLabel8.setHorizontalTextPosition(SwingConstants.CENTER);
this.JLabel8.setHorizontalAlignment(SwingConstants.CENTER);
this.JLabel8.setFont(new Font("Dialog", Font.BOLD, 14));
this.JLabel8.setBounds(12, 240, 120, 24);
this.JLabel5.setText("Draw Letters Here");
getContentPane().add(this.JLabel5);
this.JLabel5.setBounds(204, 12, 144, 12);
final SymAction lSymAction = new SymAction();
this.downSample.addActionListener(lSymAction);
this.clear.addActionListener(lSymAction);
this.add.addActionListener(lSymAction);
this.del.addActionListener(lSymAction);
final SymListSelection lSymListSelection = new SymListSelection();
this.letters.addListSelectionListener(lSymListSelection);
this.load.addActionListener(lSymAction);
this.save.addActionListener(lSymAction);
this.recognize.addActionListener(lSymAction);
this.letters.setModel(this.letterListModel);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/**
* The main method.
*
* @param args Args not really used.
*/
public static void main(final String args[]) {
(new OCRExample()).setVisible(true);
}
/**
* Called to add the current image to the training set
*/
void add_actionPerformed() {
int i;
final String letter = JOptionPane
.showInputDialog("Please enter a letter you would like to assign this sample to.");
if (letter == null) {
return;
}
if (letter.length() > 1) {
JOptionPane.showMessageDialog(this,
"Please enter only a single letter.", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
this.entry.downSample();
final SampleData sampleData = (SampleData) this.sample.getData()
.clone();
sampleData.setLetter(letter.charAt(0));
for (i = 0; i < this.letterListModel.size(); i++) {
final String str = "" + ((SampleData) this.letterListModel
.getElementAt(i)).getLetter();
if (str.equals(letter)) {
JOptionPane.showMessageDialog(this,
"That letter is already defined, delete it first!",
"Error", JOptionPane.ERROR_MESSAGE);
return;
}
final String l = "" + sampleData.getLetter();
if (str.compareTo(l) > 0) {
this.letterListModel.add(i, sampleData);
return;
}
}
this.letterListModel.add(this.letterListModel.size(), sampleData);
this.entry.clear();
this.sample.repaint();
}
/**
* Called to clear the image.
*/
void clear_actionPerformed() {
this.entry.clear();
this.sample.getData().clear();
this.sample.repaint();
}
/**
* Called when the del button is pressed.
*/
void del_actionPerformed() {
final int i = this.letters.getSelectedIndex();
if (i == -1) {
JOptionPane.showMessageDialog(this,
"Please select a letter to delete.", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
this.letterListModel.remove(i);
}
/**
* Called to downsample the image.
*/
void downSample_actionPerformed() {
this.entry.downSample();
}
/**
* Called when a letter is selected from the list box.
*/
void letters_valueChanged() {
if (this.letters.getSelectedIndex() == -1) {
return;
}
final SampleData selected = (SampleData) this.letterListModel
.getElementAt(this.letters.getSelectedIndex());
this.sample.setData((SampleData) selected.clone());
this.sample.repaint();
this.entry.clear();
}
/**
* Called when the load button is pressed.
*/
void load_actionPerformed() {
try {
final FileReader f;// the actual file stream
final BufferedReader r;// used to read the file line by line
f = new FileReader(new File("./sample.dat"));
r = new BufferedReader(f);
String line;
int i = 0;
this.letterListModel.clear();
while ((line = r.readLine()) != null) {
final SampleData ds = new SampleData(line.charAt(0),
OCRExample.DOWNSAMPLE_WIDTH, OCRExample.DOWNSAMPLE_HEIGHT);
this.letterListModel.add(i++, ds);
int idx = 2;
for (int y = 0; y < ds.getHeight(); y++) {
for (int x = 0; x < ds.getWidth(); x++) {
ds.setData(x, y, line.charAt(idx++) == '1');
}
}
}
r.close();
f.close();
clear_actionPerformed();
JOptionPane.showMessageDialog(this, "Loaded from 'sample.dat'.",
"Training", JOptionPane.PLAIN_MESSAGE);
} catch (final Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, "Error: " + e, "Training",
JOptionPane.ERROR_MESSAGE);
}
}
/**
* Called when the recognize button is pressed.
*/
void recognize_actionPerformed() {
this.entry.downSample();
double bestPosition = Double.POSITIVE_INFINITY;
String letter = "?";
final double[] letterToRecognize = this.sample.getData().getPosition();
for (int i = 0; i < this.letterListModel.size(); i++) {
final SampleData ds = (SampleData) this.letterListModel
.getElementAt(i);
final double dist = this.distanceCalc.calculate(letterToRecognize, ds.getPosition());
if (dist < bestPosition) {
bestPosition = dist;
letter = "" + ds.getLetter();
}
}
JOptionPane
.showMessageDialog(this, letter, "That Letter Is",
JOptionPane.PLAIN_MESSAGE);
clear_actionPerformed();
}
/**
* Called when the save button is clicked.
*/
void save_actionPerformed() {
try {
final OutputStream os;// the actual file stream
final PrintStream ps;// used to read the file line by line
os = new FileOutputStream("./sample.dat", false);
ps = new PrintStream(os);
for (int i = 0; i < this.letterListModel.size(); i++) {
final SampleData ds = (SampleData) this.letterListModel
.elementAt(i);
ps.print(ds.getLetter() + ":");
for (int y = 0; y < ds.getHeight(); y++) {
for (int x = 0; x < ds.getWidth(); x++) {
ps.print(ds.getData(x, y) ? "1" : "0");
}
}
ps.println("");
}
ps.close();
os.close();
clear_actionPerformed();
JOptionPane.showMessageDialog(this, "Saved to 'sample.dat'.",
"Training", JOptionPane.PLAIN_MESSAGE);
} catch (final Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, "Error: " + e, "Training",
JOptionPane.ERROR_MESSAGE);
}
}
class SymAction implements java.awt.event.ActionListener {
public void actionPerformed(final ActionEvent event) {
final Object object = event.getSource();
if (object == OCRExample.this.downSample) {
downSample_actionPerformed();
} else if (object == OCRExample.this.clear) {
clear_actionPerformed();
} else if (object == OCRExample.this.add) {
add_actionPerformed();
} else if (object == OCRExample.this.del) {
del_actionPerformed();
} else if (object == OCRExample.this.save) {
save_actionPerformed();
} else if (object == OCRExample.this.load) {
load_actionPerformed();
} else if (object == OCRExample.this.recognize) {
recognize_actionPerformed();
}
}
}
class SymListSelection implements javax.swing.event.ListSelectionListener {
public void valueChanged(
final javax.swing.event.ListSelectionEvent event) {
final Object object = event.getSource();
if (object == OCRExample.this.letters) {
letters_valueChanged();
}
}
}
}