利用Spark mllib识别点阵文本
2017-09-21 11:09
323 查看
Step 1
准备手写字体,生成图片;总共写了10个字:你、我、他、分、布、式、计、算、框、架,每个写了10遍
然后写了5个待识别的字:你、我、好、世、界、框、架
图片如下(手机上写的,字丑见谅!)
Step 2
切割图片(抠图),对齐大小至64*64,输出二值化(0-1)点阵,参考了网上的部分代码,java源码如下:import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import javax.imageio.ImageIO; public class ImageTest { static int NORMAL_WIDTH = 64; static int NORMAL_HEIGHT = 64; static String FILE_DIR = "/Users/bluejoe/testdata/pics"; public static BufferedImage validateArea(File file) throws IOException { BufferedImage bi = ImageIO.read(file); // 获取当前图片的高,宽,ARGB int h = bi.getHeight(); int w = bi.getWidth(); int arr[][] = new int[w][h]; // 获取图片每一像素点的灰度值 for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { // getRGB()返回默认的RGB颜色模型(十进制) arr[i][j] = getImageRgb(bi.getRGB(i, j));// 该点的灰度值 } } int left = w - 1, top = h - 1, right = 0, bottom = 0; int FZ = 130; for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { if (getGray(arr, i, j, w, h) > FZ) { if (i > right) right = i; if (j > bottom) bottom = j; if (i < left) left = i; if (j < top) top = j; } } } BufferedImage croped = bi.getSubimage(left, top, right - left + 1, bottom - top + 1); BufferedImage resized = new BufferedImage(NORMAL_WIDTH, NORMAL_HEIGHT, BufferedImage.TYPE_INT_ARGB); resized.getGraphics().drawImage(croped, 0, 0, NORMAL_WIDTH, NORMAL_HEIGHT, null); /* * File file1 = new File(file.getPath() + ".1_.jpg"); * ImageIO.write(resized, "png", file1); * * return ImageIO.read(file1); */ return resized; } public static void main(String[] args) throws IOException { File dir = new File(FILE_DIR); HashMap<String, ArrayList<Integer>> filePoints = new HashMap<String, ArrayList<Integer>>(); for (File file : dir.listFiles()) { if (!file.isFile() || file.isHidden() || file.getPath().endsWith("_.jpg")) continue; try { BufferedImage bi = validateArea(file); // 获取当前图片的高,宽,ARGB int h = bi.getHeight(); int w = bi.getWidth(); int arr[][] = new int[w][h]; // 获取图片每一像素点的灰度值 for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { // getRGB()返回默认的RGB颜色模型(十进制) arr[i][j] = getImageRgb(bi.getRGB(i, j));// 该点的灰度值 } } BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY);// 构造一个类型为预定义图像类型之一的 // BufferedImage,TYPE_BYTE_BINARY(表示一个不透明的以字节打包的 // 1、2 或 4 位图像。) // ArrayList<ArrayList<Integer>> arr2 = new // ArrayList<ArrayList<Integer>>(); int FZ = 130; // System.err.println(file.getPath()); ArrayList<Integer> points = new ArrayList<Integer>(); for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (getGray(arr, j, i, w, h) > FZ) { int black = new Color(255, 255, 255).getRGB(); bufferedImage.setRGB(j, i, black); points.add(0); } else { int white = new Color(0, 0, 0).getRGB(); bufferedImage.setRGB(j, i, white); points.add(1); } } } filePoints.put(file.getName(), points); System.err.println(String.format("(%s,%s)", file.getName().charAt(0) - '0', points)); /* * File file2 = new File(file.getPath() + ".2_.jpg"); * ImageIO.write(bufferedImage, "jpg", file2); */ } catch (Throwable e) { e.printStackTrace(); } } } private static int getImageRgb(int i) { String argb = Integer.toHexString(i);// 将十进制的颜色值转为十六进制 // argb分别代表透明,红,绿,蓝 分别占16进制2位 int r = Integer.parseInt(argb.substring(2, 4), 16);// 后面参数为使用进制 int g = Integer.parseInt(argb.substring(4, 6), 16); int b = Integer.parseInt(argb.substring(6, 8), 16); int result = (int) ((r + g + b) / 3); return result; } // 自己加周围8个灰度值再除以9,算出其相对灰度值 public static int getGray(int gray[][], int x, int y, int w, int h) { int rs = gray[x][y] + (x == 0 ? 255 : gray[x - 1][y]) + (x == 0 || y == 0 ? 255 : gray[x - 1][y - 1]) + (x == 0 || y == h - 1 ? 255 : gray[x - 1][y + 1]) + (y == 0 ? 255 : gray[x][y - 1]) + (y == h - 1 ? 255 : gray[x][y + 1]) + (x == w - 1 ? 255 : gray[x + 1][y]) + (x == w - 1 || y == 0 ? 255 : gray[x + 1][y - 1]) + (x == w - 1 || y == h - 1 ? 255 : gray[x + 1][y + 1]); return rs / 9; } }
抠完的图很多很多,见下图:
Step 3
将如上输出分别存入2个文件,一个points.txt(10个汉字的手写点阵),一个query.txt(待识别的汉字点阵);文件下载地址:文本点阵文件
Step 4
启动spark-shell,加载并采用LogisticRegressionWithLBFGS算法识别:val data = MLUtils.loadLabeledPoints(sc,"file:///Users/bluejoe/testdata/points.txt"); val query = MLUtils.loadLabeledPoints(sc,"file:///Users/bluejoe/testdata/query.txt").collect.map(_.features) val model = new LogisticRegressionWithLBFGS().setNumClasses(10).run(data)
识别第1、5个字(我,框)看看:
scala> model.predict(query.collect()(1)) res91: Double = 1.0 scala> model.predict(query.collect()(5)) res92: Double = 8.0
全部识别出来看看:
scala> model.predict(query).collect res82: Array[Double] = Array(0.0, 1.0, 8.0, 8.0, 4.0, 8.0, 9.0)
结果是,存在的字被正确识别了,不存在的字识别失败!仔细看了一下源码,LogisticRegressionWithLBFGS没有一个同时输出匹配率的方法,它只是简单的挑选了一个匹配度比较高的分类,所以它总能输出一个分类。
相关文章推荐
- 利用Cbutton创建Tab功能Tab页
- 利用字典实现多级菜单效果
- 利用FireBug使JQuery的学习更加轻松愉快
- centos7利用yum安装lnmp的教程(linux+nginx+php7.1+mysql5.7)
- 利用中国气象网开发的天气预报接口
- 利用远程数据库存储过程的OUTPUT参数来获得返回值
- Java+Selenium3.0基础篇2-利用geckodirver启动firefox
- 利用加速度求解位置的算法——三轴传感器
- Centos6.5利用RubyGems的fpm制作zabbix_agent的rpm包,并使用ansible批量部署
- 基于流量的CVE-2014-0160漏洞利用检测方法
- Windows下利用Windbg 分析dump
- sql server利用cte递归查询
- 利用Python中的输入和输出功能进行读取和写入的教程
- 利用 WMI 修改计算机的网络设置
- 利用GetInvalidFileNameChars()得到有效的文件名
- CentOS 7上利用systemctl添加自定义系统服务
- 利用 LibWebP-NET 解码与编码 WebP 格式图片
- GMail Drive shell extension,在Windows下面利用Gmail做网络硬盘的工具
- 利用Java Reflection(反射)原理,在hibernate里面实现对单表、视图的动态组合查询
- 利用Fragment创建动态UI 之 使用Support Library