您的位置:首页 > 编程语言 > Java开发

[置顶] java实现基于Mnist数据集的手写数字识别

2018-02-06 11:29 926 查看
最近空下来学习了简单的图像识别基础,做了这个算是一个小入门吧,就当为之后的毕设铺铺路了。这个原理实现起来很简单,我用的是20*20大小的图片,主要就是将待识别图片的400个像素的灰度值提取出来与训练样本进行比对,找到灰度值相减绝对值最小的样本,即为待识别图片的数字值,效果如下:



接下来就一步一步的来实现这个小程序。

一、外观设计

外观主要是采用java的WindowBuilder,如果没有的话可以去下一个http://www.eclipse.org/windowbuilder/download.php,具体如何安装这里就不做介绍了。
页面采用一个大的Jpanel,一个顶部菜单JMenuBar操作,菜单中包含三个小菜单JMenuItem,分别为识别,加载图像,退出
在大的Jpanel里面有一个小的Jpanel,用来刷新加载图片,右侧有一个JButton,实现识别功能,下方JLabel为识别结果
下面来具体实现代码部分

(1)顶部菜单

setTitle("数字识别");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭按钮
setResizable(false);//不能修改窗口大小
setBounds(0,0,600,600);
JMenuBar menuBar = new JMenuBar();//绑定菜单栏
setJMenuBar(menuBar);
JMenu menu = new JMenu("操作");
menuBar.add(menu);//加入操作菜单
JMenuItem importItem = new JMenuItem("加载图片");
JMenuItem serach = new JMenuItem("识别");
JMenuItem exit = new JMenuItem("退出");
menu.add(importItem);
menu.add(serach);
menu.add(exit);

(2)主面板

contentPane = new JPanel();//加入面板
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel label = new JLabel("识别结果:");
label.setBounds(10,450,97,15);
contentPane.add(label);
JLabel result = new JLabel("");
result.setBounds(90,450,97,15);
contentPane.add(result);
JButton button = new JButton("识别");
button.setBounds(450, 300, 100, 25);
contentPane.add(button);

(3)图片面板

imagePanel viewPanel = new imagePanel();
viewPanel.setBounds(10, 10, 300, 300);//280
contentPane.add(viewPanel);//添加到主面板

(4)加载图片

/*
* 面板,预览加载图片
*/
public class imagePanel extends JPanel{

private Image image;
public imagePanel() {
setLayout(null);
}
public void loadImage(BufferedImage src){
image = src.getScaledInstance(300, 300, Image.SCALE_SMOOTH);//创建缩略图400*400   280
repaint();
}
@Overrid
4000
e
public void paint(Graphics g) {
//如何重绘面板
if (image != null) {
//清除上次加载的图片
g.clearRect(0, 0, getWidth(), getHeight());
g.drawImage(image, 0, 0, this);
}

}

}


(5)监听事件

/*
* 加入点击事件监听器
*/
importItem.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
System.out.println("加载");
JFileChooser chooser =new JFileChooser();
int result = chooser.showDialog(null, "导入图片");
if(result == 0){
file = chooser.getSelectedFile();
try {
BufferedImage src = ImageIO.read(file);
viewPanel.loadImage(src);//将图片重新绘制

} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
System.out.println(result);
}
});

/*
* 加载训练数据
*/
DistinguishUtil distinguishUtil = new DistinguishUtil();
distinguishUtil.loadData(new File("traindata2.csv"));
setTitle("数字图像识别---加载数据完成");

serach.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
System.out.println("识别");
String resultString = distinguishUtil.distinguish(file);
result.setText(resultString);
}
});

exit.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
System.out.println("退出");
}
});
button.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮");
String resultString = distinguishUtil.distinguish(file);
result.setText(resultString);
}
});

二、数据处理

(1)获取图片的灰度特征值

public int[] getDigest(File targetImage) throws IOException{
BufferedImage image = ImageIO.read(targetImage);
int[] digest = new int[image.getHeight()*image.getWidth()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), digest, 0, image.getWidth());//将灰度特征值保存进数组
//255 -(r*30 + g*59 + b*11)/100
for (int i = 0; i < digest.length; i++) {
int color = digest[i];
int r  = color << 8 >>> 24;
int g  = color << 16 >>> 24;
int b  = color << 24 >>> 24;

int gray = 255 -(r*30 + g*59 + b*11)/100;

digest[i] = gray;
}
return digest;
}

(2)数据对象

/*
* 该类的一个对象封装一条数据
*/

public class trainData {

private String targetString;//识别结果
private int[] digestString;//长度为28*28的灰度特征值

public String getTargetString() {
return targetString;
}
public void setTargetString(String targetString) {
this.targetString = targetString;
}
public int[] getDigestString() {
return digestString;
}
public void setDigestString(int[] digestString) {
this.digestString = digestString;
}

}

(3)加载训练数据

ExcelUtil util = new ExcelUtil();

try {
 for(int i = 0; i <= 1200 ; i++){
int[] dataInt = util.readRdx(i+1);
String target = util.readTarget(i+1);
trainData traindata = new trainData();
traindata.setDigestString(dataInt);
traindata.setTargetString(target);
datas.add(traindata);
}
} catch (EncryptedDocumentException e) {
e.printStackTrace();
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
 }

(4)比对数据

public String  distinguish(File targetImage) {
int[] digest;
int index = 0;
try {
digest = getDigest(targetImage);

if (digest != null) {

int minDif = getDif(digest, datas.get(0).getDigestString());//与第一个训练数据集进行比对
for (int i = 1; i < datas.size(); i++) {
int dif = getDif(digest, datas.get(i).getDigestString());

if(dif < minDif){
minDif = dif;
index = i;
}
}

}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return datas.get(index).getTargetString();

}


//获取特征值差值
public int getDif(int[] imageDigest,int[] trainingDigest){
int dif = 0;
for (int i = 0; i < trainingDigest.length; i++) {
dif += Math.abs((imageDigest[i]-trainingDigest[i]));
}
return dif;
}


这里要说明一下,训练数据分为两部分,一部分就是5000张手写的数字图片,另一部分是5000张图片的灰度值,由第一部分提取出来的csv格式的数据,每条数据包含401个内容,分别为本条数据代表的数字以及400个像素的灰度值,可以用Excel打开如下图



欢迎大家随时批评指正,一起交流学习,可以加我q 504334357

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐