opencvを使ってデジタル認識をする.

9367 ワード

opencvを使ってデジタル認識をする.
時間 2013-01-05 22:51:00 
 I code it
テキスト  http://icodeit.org/2013/01/basic-digits-recognization/
最終的な効果図はこうです.
図中の小さいウィンドウの中には、resizeの後に見つかったすべてのピクチャのリストがあります.このcaseには、3つの数字があります.
図中のデジタル認識は、コンピュータアルゴリズムによってテキストとして識別される.最初から識別器を書くには、多くの実践が必要であり、大きな精力が必要であり、また良好な数学的基礎が必要であるが、opencvで提供される豊富なAPIとアルゴリズムを使って実現すれば、比較的容易に実行でき、しかも高い精度を得ることができる.
デジタル認識はモード認識の特例であり、ここで議論するのは比較的簡単な実現であり、最も簡単で最も理解しやすいKNNアルゴリズムに基づいている(参照してください. 前の文章 ).
デジタル認識と他のすべてのコンピュータ視覚に関するアプリケーションは、ROI抽出と識別の二つのステップに分けられます.
1. ROI                    ,         ,      
2.                       ,                
画像前処理
元の写真にはターゲットに関係のない情報がたくさんあります.例えば、顔検出において、背景にはテーブルや椅子、壁の絵、あるいは屋外の木、動物などがあります.これらの目標とは関係のない情報は騒音やノイズと呼ばれます.分類する前に特定のステップで消します.計算量を減らすだけでなく、計算量を高めることもできます.正確さ
グレースケール
通常のカラーパターンは3つの(RGB)または4つの(RGBA)チャネルからなり、コンピュータから見て、1つのカラー画像は3/4つの行列からなり、各行列にはいくつかの点(例えば1024×768)が含まれている.各チャネルが演算に参加すると、計算量が多すぎるので、カラー画像をグレースケールに変換するのが一般的です.
1
2
def grayify(image):
    return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
二値図
グレースケールマップは、元の画像と比較して、3次元の行列を一つの次元に変えて、部分的に簡略化しましたが、アルゴリズムでは、ノイズは解消されていません.グレースケール図では、各点は依然として8ビットで表しています.各点の可能な階調は0-255で、2値図はもうすぐ白黒図に変換されます.各点は2つの可能性があります..
opencvは、しきい値調整のAPIを提供し、階調図を二値図に変換することができる.あるしきい値より高い点は白とみなされ、逆に黒とされる.
1
2
3
4
5
6
7
def thresholding_inv(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    ret, bin = cv2.threshold(gray, 48, 255, cv.CV_THRESH_BINARY_INV)
    bin = cv2.medianBlur(bin, 3)

    return bin
上記のコードのうち、48は閾値であり、48以上の階調であれば、変更点は255と見なされ、さもなければ0となります.
輪郭検出アルゴリズムは黒の背景から白い輪郭を検索する必要があるので、ここのすべての  thresholdの最後のパラメータは  cv.CV_THRESH_BINARY_INV ,つまり白黒を反転させます.
輪郭検出
輪郭検出は、2値図中の連結可能な領域(多角形)を一連の点で記述し、デフォルトの輪郭検査は1点のシーケンスを返します.たとえば、4点で1つの矩形を記述しますが、精度を設定することでより多くの点を返すことができます.ここでは矩形に戻るだけでいいです.
興味深いことに、ここの数字8は、8の形の中に2つの円がありますので、デフォルトの輪郭検査では、この2つの円が検出されます.8は3つの輪郭があります.このような場合もあります.数字は4,6,9です.
1
2
contours, heirs = cv2.findContours(thres.copy(), \
cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
したがって指定が必要です  findContours 関数は、内部に出現する可能性のある輪郭に注目せず、最外層の輪郭のみを検索します.
1
2
contours, heirs = cv2.findContours(thres.copy(), \
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
KNN分類アルゴリズム
KNNアルゴリズムの原理は前のものを参照することができる. 一つの文章 .ここの実装は主にopencvの例示的なプログラムを参照している.
1
2
3
4
5
6
7
8
9
10
11
12
13
class KNearest(StatModel):
    def __init__(self, k = 3):
        self.k = k
        self.model = cv2.KNearest()

    def train(self, samples, responses):
        self.model = cv2.KNearest()
        self.model.train(samples, responses)

    def predict(self, samples):
        retval, results, neigh_resp, dists = \
        self.model.find_nearest(samples, self.k)
        return results.ravel()
数字の順番
もう一つの面白いことは輪郭検査の時、アルゴリズムは必ずしも左から右までとは限らないです.上から下までの方向で行います.始めは簡単に反復の順に結果をリストに挿入します.しかし、このようなリストの結果は乱れています.午後はチームの中に画像処理の背景がある楊眉さんの支持を得ました.輪郭を検索する時、このようにします.のposition情報を輪郭と一緒に記録し、検索が完了したら、リストをx座標で並べ替えます.(カードの数字は左から右に書く):
1
2
3
4
5
6
7
8
9
10
class PosImage(object):
    def __init__(self, pos, image):
        self.pos = pos
        self.image = image

    def get_position(self):
        return self.pos

    def get_image(self):
        return self.image
その後、position情報を反復中に記録する.
1
2
3
4
5
cropped = gray[y:y+h, x:x+w]
resized = cv2.resize(cropped, (20, 20))
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 3)
pos_image = PosImage((x, y), resized)
images.append(pos_image)
最後に新しいarrangeを作ります.
1
2
3
def rearrange(images):
    return sorted(images, cmp=lambda x, y:
    cmp(x.get_position()[0], y.get_position()[0]))