開始做簡單的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;
一、獲取驗證圖片
二、程序加載要驗證的字體庫
三、程序加載需匹配的文字庫(字符數組即可)
四、將驗證碼圖片進行中值濾波處理,然後再將其銳化(也可進行取色彩最多的幾個點進行採樣再銳化)
五、將驗證碼的字符進行拆字(掃描行、列的間隙,然後就可以將字找出來),然後將拆分之後的圖像保存到內存中,爲以後提供匹配
六、此步驟爲循環
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。
有點亂,整理下就ok。
過幾天繼續。。感冒了,休息。