开始做简单的ORC,从昨天到今天总算有个小小的成绩了。
图像的文字识别我拿验证码开刀,因为验证码稍微简单点,说说验证思路:
一、获取验证图片
二、程序加载要验证的字体库
三、程序加载需匹配的文字库(字符数组即可)
四、将验证码图片进行中值滤波处理,然后再将其锐化(也可进行取色彩最多的几个点进行采样再锐化)
五、将验证码的字符进行拆字(扫描行、列的间隙,然后就可以将字找出来),然后将拆分之后的图像保存到内存中,为以后提供匹配
六、此步骤为循环
6.0依次取字体库中的字符
6.1将取出的字符的字体设置成需验证的字体
6.2图像化此字符
6.3将内存的字与验证的字放大至同样的大小(高或者宽取最小公倍数)
6.4然后开始记录源与目标的验证点(用数组保存值,如果在像素点上有待验证的点,值为1,否则为0)
6.5然后将验证点进行匹配像素块,记录块的匹配度(我这里拿4方格,4个像素做匹配块,一个像素0.25个匹配度)
6.6累加匹配度,匹配完成之后再计算均值
6.7当均值大于某个值时则匹配成功
七、退出循环
八、××程序上的业务逻辑××
当然,思路是这样的,中间有几个地方在今天的代码中没有体现出来:
1.中值滤波(现在暂时还没有搞懂图像的计算公式)
2.字体库(这个确实不晓得我的电脑今天是不是大姨夫来了,字体库居然加载不上)
3.拆字(从图片中我都能够把字取出来,扫描行、列的文字也暂时不用实现)
4.字体缩放(节约时间没有做)
测试的来源是两个bmp的图片,一个作为匹配,一个作为待验证的,字体、大小不要太过于差异了,位置可以随便放,只要目测能够看出来是那个字。
当然,验证的时候不可能把验证库保存为图片文件,这是不科学的……
贴代码:
import java.awt.Color;
import java.awt.Point;
import java.awt.RenderingHints;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 读取验证码
* @author Administrator
*/
public class ReadSerCode {
public static final int east = 1;//东
public static final int south = 2;//南
public static final int west = 3;//西
public static final int north = 4;//北
public static final int northeast = 5;//东北
public static final int southwest = 6;//西南
public static final int southeast = 7;//东南
public static final int northwest = 8;//西北
/**
*
* @param sourceFile 源
* @param objectFile 目标
* @throws Exception
*/
public static void readImage(String sourceFile,String objectFile) throws Exception {
//读取源
java.awt.image.BufferedImage s_img = javax.imageio.ImageIO.read(new File(sourceFile));
int s_width = s_img.getWidth();
int s_height = s_img.getHeight();
java.util.HashMap<String, Integer> s_colors = new java.util.HashMap<String, Integer>();
java.util.HashMap<String, java.util.List<java.awt.Point>> s_colorP = new java.util.HashMap<String, java.util.List<java.awt.Point>>();
for (int i = 0; i < s_width; i++) {
for (int j = 0; j < s_height; j++) {
String c = "" + s_img.getRGB(i, j);
if (s_colors.get(c) == null) {
s_colors.put(c, 1);
java.util.List<java.awt.Point> plist = new java.util.ArrayList<java.awt.Point>();
s_colorP.put(c, plist);
} else {
s_colors.put(c, s_colors.get(c) + 1);
java.awt.Point p = new java.awt.Point(i, j);
s_colorP.get(c).add(p);
}
}
}
//将像素最多的几个色素排序
List<Map.Entry<String, Integer>> s_infoIds =
new ArrayList<Map.Entry<String, Integer>>(s_colors.entrySet());
Collections.sort(s_infoIds, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return (o2.getValue() - o1.getValue());
//return (o1.getKey()).toString().compareTo(o2.getKey());
}
});
//for(java.util.Map.Entry<String,Integer> m : s_infoIds){
// System.out.println("value:"+m.getValue()+" key:"+m.getKey());
//}
//开始处理点,将点规范在一个矩形框内
//java.util.List<Point> sourcePoints = s_colorP.get(s_infoIds.get(s_infoIds.size() - 1).getKey());
java.util.List<Point> sourcePoints = s_colorP.get(s_infoIds.get(1).getKey());
int s_left = -1;
int s_right = -1;
int s_top = -1;
int s_bottom = -1;
for (Point p : sourcePoints) {
//System.out.println("("+p.x+","+p.y+")");
if (s_left == -1) {
s_left = p.x;
}
if (s_top == -1) {
s_top = p.y;
}
if (p.x <= s_left) {
s_left = p.x;
}
if (p.x >= s_right) {
s_right = p.x;
}
if (p.y <= s_top) {
s_top = p.y;
}
if (p.y >= s_bottom) {
s_bottom = p.y;
}
}
System.out.println("匹配源s_top=" + s_top + "\ts_left=" + s_left + "\ts_bottom=" + s_bottom + "\ts_right=" + s_right);
//读目标
java.awt.image.BufferedImage o_img = javax.imageio.ImageIO.read(new File(objectFile));
int o_width = o_img.getWidth();
int o_height = o_img.getHeight();
java.util.HashMap<String, Integer> o_colors = new java.util.HashMap<String, Integer>();
java.util.HashMap<String, java.util.List<java.awt.Point>> o_colorP = new java.util.HashMap<String, java.util.List<java.awt.Point>>();
for (int i = 0; i < o_width; i++) {
for (int j = 0; j < o_height; j++) {
String c = "" + o_img.getRGB(i, j);
if (o_colors.get(c) == null) {
o_colors.put(c, 1);
java.util.List<java.awt.Point> plist = new java.util.ArrayList<java.awt.Point>();
o_colorP.put(c, plist);
} else {
o_colors.put(c, o_colors.get(c) + 1);
java.awt.Point p = new java.awt.Point(i, j);
o_colorP.get(c).add(p);
}
}
}
//将像素最多的几个色素排序
List<Map.Entry<String, Integer>> o_infoIds =
new ArrayList<Map.Entry<String, Integer>>(o_colors.entrySet());
Collections.sort(o_infoIds, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return (o2.getValue() - o1.getValue());
//return (o1.getKey()).toString().compareTo(o2.getKey());
}
});
//开始处理点,将点规范在一个矩形框内
//java.util.List<Point> objectPoints = o_colorP.get(o_infoIds.get(o_infoIds.size() - 1).getKey());
java.util.List<Point> objectPoints = o_colorP.get(o_infoIds.get(1).getKey());
int o_left = -1;
int o_right = -1;
int o_top = -1;
int o_bottom = -1;
for (Point p : objectPoints) {
if (o_left == -1) {
o_left = p.x;
}
if (o_top == -1) {
o_top = p.y;
}
if (p.x <= o_left) {
o_left = p.x;
}
if (p.x >= o_right) {
o_right = p.x;
}
if (p.y <= o_top) {
o_top = p.y;
}
if (p.y >= o_bottom) {
o_bottom = p.y;
}
}
System.out.println("目标o_top=" + o_top + "\to_left=" + o_left + "\to_bottom=" + o_bottom + "\to_right=" + o_right);
int sourceWidth = s_right + 1 - s_left;//匹配源的图片宽度
int sourceHeight = s_bottom + 1 - s_top;//匹配源的图片高度
System.out.println("匹配源 width=" + sourceWidth + "\theight=" + sourceHeight);
//数据初始化
int sourceData[][] = new int[sourceWidth][sourceHeight];
for (int i = 0; i < sourceWidth; i++) {
for (int j = 0; j < sourceHeight; j++) {
sourceData[i][j] = 0;
}
}
//开始赋值
for (Point p : sourcePoints) {
sourceData[p.x - s_left][p.y - s_top] = 1;
}
/*
for (int i = 0; i < sourceWidth; i++) {
for (int j = 0; j < sourceHeight; j++) {
System.out.print(sourceData[i][j] + ",");
}
System.out.println();
}
*/
int objectWidth = o_right + 1 - o_left;//目标的图片宽度
int objectHeight = o_bottom + 1 - o_top;//目标的图片高度
System.out.println("目标 width=" + objectWidth + "\theight=" + objectHeight);
//数据初始化
int objectData[][] = new int[objectWidth][objectHeight];
for (int i = 0; i < objectWidth; i++) {
for (int j = 0; j < objectHeight; j++) {
objectData[i][j] = 0;
}
}
//开始赋值
for (Point p : objectPoints) {
objectData[p.x - o_left][p.y - o_top] = 1;
}
/*
for (int i = 0; i < objectWidth; i++) {
for (int j = 0; j < objectHeight; j++) {
System.out.print(objectData[i][j] + ",");
}
System.out.println();
}
*
*/
//宽与高都取两者最大值
int maxWidth = objectWidth > sourceWidth ? objectWidth : sourceWidth;
int maxHeight = objectHeight > sourceHeight ? objectHeight : sourceHeight;
//按四方格扫描匹配
int scanColTimes = maxWidth / 2 + maxWidth % 2;//扫描列最大的次数
int scanRowTimes = maxHeight / 2 + maxHeight % 2;//扫描行最大的次数
float totalCount = 0.0f;//比对总共百分比
int count = 0;//比对次数
for (int row = 0; row < scanRowTimes; row++) {
for (int col = 0; col < scanColTimes; col++) {
System.out.print("匹配次数:"+count+" row:"+row+";col:"+col+"\t");
int s_d[] = new int[4];
int o_d[] = new int[4];
for (int i = 0; i < 4; i++) {
s_d[i] = 0;
o_d[i] = 0;
}
int morecol = 0;//轮询时多了多少列
int morerow = 0;//轮询时多了多少行
//源矩阵填充
if (col * 2+2 > sourceWidth) {
morecol = col * 2+2 - sourceWidth;
}
if (row * 2+2 > sourceHeight) {
morerow = row * 2+2 - sourceHeight;
}
if (morecol > 0 && morerow > 0) {
//s_d[0] = sourceData[col * 2 - morecol][row * 2 - morerow];
} else if (morecol > 0 && morerow <= 0) {
if (morecol == 2) {
} else if (morecol == 1) {
s_d[0] = sourceData[col*2][row*2];
s_d[3] = sourceData[col*2][row*2+1];
}
} else if (morerow > 0 && morecol <= 0) {
if (morerow == 2) {
} else if (morerow == 1) {
s_d[0] = sourceData[col*2][row*2];
s_d[1] = sourceData[col*2+1][row*2];
}
} else {
s_d[0] = sourceData[col*2][row*2];
s_d[1] = sourceData[col*2+1][row*2];
s_d[2] = sourceData[col*2][row*2+1];
s_d[3] = sourceData[col*2+1][row * 2 + 1];
}
System.out.print("[");
for (int i = 0; i < 4; i++) {
System.out.print(s_d[i] + ",");
}
System.out.print("]");
System.out.println();
morecol = 0;//轮询时多了多少列
morerow = 0;//轮询时多了多少行
//目标矩阵填充
if (col * 2+2 > objectWidth) {
morecol = col * 2+2 - objectWidth;
}
if (row * 2+2 > objectHeight) {
morerow = row * 2+2 - objectHeight;
}
if (morecol > 0 && morerow > 0) {
//o_d[0] = objectData[col * 2 - morecol][row * 2 - morerow];
} else if (morecol > 0 && morerow <= 0) {
if (morecol == 2) {
} else if (morecol == 1) {
o_d[0] = objectData[col*2][row*2];
o_d[3] = objectData[col*2][row*2+1];
}
} else if (morerow > 0 && morecol <= 0) {
if (morerow == 2) {
} else if (morerow == 1) {
o_d[0] = objectData[col*2][row*2];
o_d[1] = objectData[col*2+1][row*2];
}
} else {
o_d[0] = objectData[col*2][row*2];
o_d[1] = objectData[col*2+1][row*2];
o_d[2] = objectData[col*2][row*2+1];
o_d[3] = objectData[col*2+1][row * 2 + 1];
}
System.out.print("[");
for (int i = 0; i < 4; i++) {
System.out.print(o_d[i] + ",");
}
System.out.print("]");
System.out.println();
//开始对比
count++;
for (int i = 0; i < 4; i++) {
if (s_d[i] == o_d[i]) {
totalCount += 0.25f;
} else {
totalCount += 0f;
}
}
System.out.println("匹配比:" + totalCount);
}
}
totalCount = totalCount / count;
System.out.println("匹配度:" + totalCount);
}
public static void main(String[] args) throws Exception {
readImage("d:/matchImage/邹汶珂.bmp","d:/matchImage/邹汶珂3.bmp");
}
}
有点乱,整理下就ok。
过几天继续。。感冒了,休息。