1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OpenCVのコーナー検出結果から、誤検出したエッジ点を除くフィルターを考えてみた

Last updated at Posted at 2024-01-14

はじめに

  • OpenCVには、画像のコーナー点を検出するcornerHarrisやgoodFeaturesToTrackなどの関数があります。
  • しかし、これらの関数には癖があるようで、長方形の形(左)だとコーナーをきれいに見つけましたが菱形の形(右)だと苦手でした。赤点が検出点です。

before.jpg

  • 感度を良くすればコーナーを見つけますが、エッジ上の点を誤検出するケースが増えます。感度を下げれば誤検出は減りますが、コーナーを見落としやすくなります。
  • そこで、感度良く検出したあとから、誤検出したエッジ点を除く方法を考えて、試しました。

工夫したこと

  1. goodFeaturesToTrackの結果からスタート
     画像の全各要素をフィルターすると時間がかかるので、途中から始めて処理量削減。

  2. 白図形の凸コーナーのみの検出に限定
     限定することで、フィルター精度向上。

  3. フィルターは対照点の周囲の明るさをチェックして判断
     Fastアルゴリズムのアイデアを借用しました。

内容

1. PC環境

 実施したPC環境は以下のとおりです。

CPU Celeron N4100
メモリ 8GB LPDDR4

2. 前準備

 Windowsで使えるようにするため、以下のツール / システムをインストールしました。
インストール時に参考にしたサイトも記載します。

  1. python(使用したのはVer.3.7 )
     実行時のベースシステムです。
    (参考)https://qiita.com/ssbb/items/b55ca899e0d5ce6ce963

  2. pip(使用したのはVer.21.2.4 )
     他のツールをダウンロードする際に使うツールです。
    (python3系ではバージョン3.4以降であれば、pythonのインストールと共にpipもインストールされます。)
    (参考)https://gammasoft.jp/python/python-library-install/

  3. OpenCV(使用したのはVer.4.5.3.56 )
     画像系処理するためのライブラリです。
    (参考)https://qiita.com/ideagear/items/3f0807b7bde05aa18240

  4. numpy(使用したのVer.4.7.0.72)
     行列計算が得意な数値計算モジュールです。
    (参考)https://qiita.com/butako/items/15d7cb5aaef90b09ccd8

3. pyファイルの作成

組んだコードは次のとおりです。

import numpy as np
import cv2 as cv

camera = cv.VideoCapture(0)                # カメラCh.(ここでは0)を指定

#周囲のリスト(中心点からの相対)#
l_2d_a = [ \
    [ 0, 3], \
    [ 1, 3], \
    [ 2, 2], \
    [ 3, 1], \
    [ 3, 0], \
    [ 3,-1], \
    [ 2,-2], \
    [ 1,-3], \
    [ 0,-3], \
    [-1,-3], \
    [-2,-2], \
    [-3,-1], \
    [-3, 0], \
    [-3, 1], \
    [-2, 2], \
    [-1, 3], \
    ]

ret, img = camera.read()              # フレームを取得
h, w, _ = img.shape              #フレームの高さと幅を取得

#フィルタリングのためのリスト変数
up_lst_a = list()              #周囲で黒→白に変わった場所のリスト変数
dwn_lst_a = list()              #周囲で白→黒に変わった場所のリスト変数
l_a = list()              #周囲の明るさのリスト変数

#フィルタリングのパラメータ
th3 = 15              #白と判断する下限値(中心点の明るさからの相対)
th5 = 0.40              #コーナーと判断する白エリアの最大割合
th6 = 0.6              #コーナーと判断する中心点の明るさ割合(周囲の明るさに対する相対)

try:
    while True:
        ret, img = camera.read()              #フレームを取得
        gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)              #モノクロ化
        gray = np.float32(gray)              #float32に型変換

#コーナー候補検出#
        corners= cv.goodFeaturesToTrack(gray, 300, 0.01, 1)

#各コーナー候補についてチェック#
        for corner in corners:
            x,y= corner[0]              #中心点座標を入手
            x= int(x)
            y= int(y)


#フィルタリング#
            if x > 2 and x < w-3 and y > 2 and y < h-3 :
                #初期化#
                up_lst_a.clear()
                dwn_lst_a.clear()
                l_a.clear()
                cnt = 0
                if gray[y,x] > gray[y + l_2d_a[-1][0], x + l_2d_a[-1][1]] + th3:
                    sg= -1
                else:
                    sg = 1

                #周囲をチェック#
                for pt in l_2d_a:
                    if gray[y,x] > gray[y + pt[0], x + pt[1]] + th3:
                        if sg > 0:
                            dwn_lst_a.append(cnt)              #白→黒に変わってたらリストに追加
                        sg = -1
                    else:
                        if sg < 0:
                            up_lst_a.append(cnt)              #黒→白に変わってたらリストに追加
                        sg = 1
                    l_a.append(gray[y + pt[0], x + pt[1]])              #周囲の明るさをリストに追加
                    cnt = cnt + 1

                if len(up_lst_a) == 1 and len(dwn_lst_a) == 1 :              #黒→白、白→黒が1回だけ。つまり白エリアが1つ
                            #白エリアの割合を計算#
                            siro_a = (dwn_lst_a[0]-up_lst_a[0])/len(l_2d_a)
                            if siro_a<0:
                                siro_a = siro_a + 1

                            if siro_a<th5:              #白エリアの割合がth5より小さい
                                if (gray[y,x]-min(l_a))/(max(l_a)-min(l_a))>th6:              #中心点の明るさが周囲の明るさの幅に対し、下限からth6より明るい
                                    cv.rectangle(img, (x-1,y-1),(x+1,y+1),(0,255,0),-1)             #フィルタリングをクリアした点を■マーク

        cv.imshow('frame',img)             #チェック結果を表示

        if cv.waitKey(1) & 0xFF == ord('q'):             #’q’キーを押したら、LOOPから抜ける
            break
    cv.destroyWindow('frame')
    camera.release()
except KeyboardInterrupt:
    cv.destroyWindow('frame')
    camera.release()

4. 説明

1. フィルターで使用する周囲の点

 対象点の周囲半径3ピクセルのあたりの点、16点を使いました。

FilterArea.png

2. フィルターの3つの条件

1)明るい範囲(白エリア)と暗い範囲(黒エリア)が1つずつ
 周囲の点を順に並べたときに白→黒と黒→白の変化点の数がそれぞれ1つなこと。
 白と黒の境目は対照点の明るさよりth3だけ暗いところとしました。
 境目を越えたら、その点をlistに追加して、数をカウントして調べてます。

#周囲をチェック#
for pt in l_2d_a:
    if gray[y,x] > gray[y + pt[0], x + pt[1]] + th3:
        if sg > 0:
            dwn_lst_a.append(cnt)              #白→黒に変わってたらリストに追加
        sg = -1
    else:
        if sg < 0:
            up_lst_a.append(cnt)              #黒→白に変わってたらリストに追加
        sg = 1
    cnt = cnt + 1

if len(up_lst_a) == 1 and len(dwn_lst_a) == 1 :              #黒→白、白→黒が1回だけ。つまり白エリアが1つ

2)白エリアの方が小さい
 白の凸角のみ探すため、この条件をつけました。
 周囲の点を順に並べたときに白→黒と黒→白の変化点の位置で白エリアの幅を計算してます。
 周囲の点数(=16)に対する白エリアの幅の割合がth5より小さいならOKとしてます。

#白エリアの割合を計算#
siro_a = (dwn_lst_a[0]-up_lst_a[0])/len(l_2d_a)
if siro_a<0:
    siro_a = siro_a + 1

if siro_a<th5:              #白エリアの割合がth5より小さい

3)対象点の明るさは白エリアに近い
 調べてみると、エッジ点は暗くなりがちなことがわかりました。
 周囲の点の明るさの最大値-最小値の間のどのあたりに対象点があるかで判断してます。
 明るさの最大値-最小値の幅に対して対象点の明るさ-最小値の割合がth6より大きいならOKとしてます。

if (gray[y,x]-min(l_a))/(max(l_a)-min(l_a))>th6:              #中心点の明るさが周囲の明るさの幅に対し、下限からth6より明るい

5. 結果

 環境によって適切値は変わると思いますが、パラメータを
  th3=15、th5=0.40、th6=0.6
 に調整しました。
 100%ではないです(除けてないエッジ点、除かれたコーナー点がでます)が、向きによらず、かなり精度よくコーナー点だけ抜き出せるようになりました。緑点が検出点です。

after.jpg

参考

参考記事
goodFeaturesToTrack)
https://qiita.com/hoshianaaa/items/d22fcb67d940e08b242b

FASTアルゴリズム)
http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_feature2d/py_fast/py_fast.html

参考書籍
画像認識 (機械学習プロフェッショナルシリーズ) 原田達也 (著) 講談社

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?