驗證碼識別(一)

     開始做簡單的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。 

過幾天繼續。。感冒了,休息。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章