2014年6月3日火曜日

scikit-learnを使って数字認識(1) サンプル取得

OCRはフリーのものもあるけど、数値データを起こしたいときには無駄に高機能になってしう。それだけでなくご認識も増える。

手書きでない数値(0-9, "-", ".")を認識するだけならそんなに苦労しないのでは?と思ったのでちょっと実験してみた。

フツウの人は手書き文字認識に興味があるやろけど、
調べてみるとStackoverflowに以下のような投稿があって結構盛り上がっている。
https://stackoverflow.com/questions/9413216/simple-digit-recognition-ocr-in-opencv-python

今回は

  1. 上のリンクの方法で数値を切り取り
  2. scikit-learnを使って学習
  3. 学習データを元に新しい予測
ということを行う。

まず、以下のように切り取られた画像から数値を取得したい。


イメージしている成果物は、WebやPDF上をマウスで矩形選択するとそこの数値をテキストデータに変換するツールだ。
ほぼ上のサイトと同じことをしているが、一つだけ違うところfindContoursで輪郭の取得オプションだ。opencvでは輪郭の取得のみならず、それら輪郭の関係まで返してくれる。今回はcv2.RETR_CCOMPを指定した。(一番外側の輪郭とするとなぜか図の枠が検出されたので)輪郭についてはこのページがわかりやすかった。輪郭の階層を指定することで輪郭の大きさによる分類など無駄な作業が省ける。
下のプログラムを実行するとこうなる。


if __name__ ==  "__main__":
    sample_dir = "fonts"
    sample_file = "sample03.png"
    im = cv2.imread(os.path.join(sample_dir, sample_file))
    im_copy = im.copy()
    gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray,(5,5),0)
    thresh = cv2.adaptiveThreshold( src=blur, 
                                    maxValue=255, 
                                    adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C,#cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                    thresholdType=cv2.THRESH_BINARY,
                                    blockSize=5,
                                    C=3)
    thresh_copy = thresh.copy()  #thresh are destroyed when findCountours

    cv2.imshow('threshold', thresh)
    cv2.waitKey(0)


    contours,hierarchy = cv2.findContours(thresh_copy, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
    print "%d contours are found" % len(contours)


    i = 0
    for con, hie in zip(contours, hierarchy[0]):
        if hie[3] != -1: #2:first child, 3:parent
            (x,y,w,h) = cv2.boundingRect(con)
            #roi = thresh[y:y+h,x:x+w]
            roi = im[y:y+h, x:x+w]

            cv2.rectangle(im_copy,(x,y),(x+w,y+h),(0,0,255),2)
            cv2.imshow('rect',im_copy)
            #cv2.imshow("threshold", roi)
            
            key = cv2.waitKey(0)
            if key == 27: # (escape to quit)
                sys.exit()

            c = chr(key)

            if c == ".":
                c = "dot"
            elif c == "-":
                c = "bar"
            elif c == "n": #negative
                c = "negative"

            file_head = sample_file.replace(".png", "")
            if c == "negative":
                fname = os.path.join(c, file_head + "_" + c + ("%02d.png"%i))
                i+=1
            else:
                fname = os.path.join(c, file_head + "_" + c + ".png")

            #write ROI 
            print fname
            #cv2.imwrite(fname, roi)









0 件のコメント:

コメントを投稿