FAST コーナー検出 Python 実装と opencv ベースの実装 (コーナー検出、非最大値抑制)

前に書かれている:

黄寧蘭、あなたが読んだアルゴリズム シリーズが終わりに近づいています。

参考街づくり:

[1] Deepak Geetha Viswanathan、高速セグメント テスト (FAST) の機能
[2] 火、鶏、コンピューター ビジョン (コーナー検出) - 3 - FAST コーナー検出
[3] zhaocj、Opencv2.4.9 ソース コード分析 - FAST .Note
: csdn 投稿アシスタントでは「外部リンクが多すぎます」というメッセージが表示されるため、ドキュメント リンクの URL についてはコメント領域を参照してください。

問題の原因:

作者のこだわり。

1. 原理の紹介

FAST (加速セグメント テストの特徴) オペレーターは、元々、Rosten と Drummond によって画像内の特徴点を検出するために使用されました [1]。こちらも SUSAN と同様に円形のテンプレートを使用し、テンプレート内のピクセルと中心位置のピクセルとのずれの度合いを判定することで、中心位置がコーナー点であるかどうかを判定します。円形のテンプレート領域を図 1 に示します。
ここに画像の説明を挿入
中心位置pは円の半径を3ピクセルとして円を描き、その円周上に16ピクセルを取ります。この16個の画素群と中心位置p画素とのずれの度合いを判定することにより、その中心位置がコーナー点であるか否かを判定する。具体的には、閾値 t を設定し、円周上に連続する N 個の点があり、ピクセル値と中心位置のピクセル値の差が t より大きい (または -t 未満) 場合、中心位置 p が考慮されます。はコーナー点であるため、条件は 2 つあります。
条件 1: I x − I p > t I_x-I_p>t×p>t
条件2:I x − I p < − t I_x-I_p<-t×p<t
N は通常 12 に選択されますが、N=9 の場合、多くの場合、より良い結果が得られます [2]。文献 [3] の opencv ソース コードの分析から、取得された値は 9 です。
中心位置pがコーナー点であるか否かを計算する際には、まず、4点p1、p9、p5、p13の条件を判定し、予備的な選別を行うことができる。N=12 の場合、p1、p9、p5、p13 の 4 点のうち少なくとも 3 点が条件 1 (または条件 2) を満たさなければなりません。N=9 の場合、p1 と p9 の少なくとも 1 点が条件 1 (または条件 2) を満たさなければなりません。条件2)、p5とp13の少なくとも1点が条件1(または条件2)を満たす必要があります。
一次審査を通過した後、円上の残りの点がテストされます。

2. 非最大抑制

上記の演算子に従って画像のコーナー点を計算した後、検出されたコーナー点が隣接していたり​​、狭い領域内に複数の繰り返し特徴点が存在したりする場合がある。これを行うには、非最大抑制を使用してコーナーをスクリーンします。具体的には、あるピクセル位置がコーナーポイントであると判定した後、コーナーポイントのスコア値、つまり円上の16点とその位置のピクセルとの差の絶対値の合計を計算します。センターポジション。
各コーナー ポイントのスコア値を計算した後、3*3 (または 5*5) 近傍を使用して各コーナー ポイントをフィルター処理します。つまり、近傍内で最高スコアを持つコーナー ポイントのみを保持し、他のコーナーは削除します。

3. Python ソースコードの実装

#coding=utf8
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import math
import cv2
import os,sys
import scipy.ndimage
import time
import scipy

パラメータを定義します。

fast_N =9#取9时,初筛条件是第1和第9个必须至少有一个满足,同时第5和第13个也必须至少有一个满足
detect_radius = 3
row_mask = np.array([0,0,1,2,3,4,5,6,6,6,5,4,3,2,1,0])#圆周上16个点的行坐标
col_mask = np.array([3,4,5,6,6,6,5,4,3,2,1,0,0,0,1,2])#圆周上16个点的列坐标

コーナー検出機能:

def fast_corner_detect(img_src,t=10):
	score_arr = np.zeros(img_src.shape,dtype=np.float32)#用来存储得分情况,得分为0时,表示不是角点
	img = img_src.copy()
	img = img.astype(np.float32)
	row_s,col_s = detect_radius,detect_radius
	row_e,col_e = img_src.shape[0]-detect_radius,img.shape[1]-detect_radius
	for r in range(row_s,row_e):#遍历所有行
		for c in range(col_s,col_e):#遍历所有列
			fast_zone = img[r-detect_radius:r+detect_radius+1,c-detect_radius:c+detect_radius+1]#获取矩形区域
			data = (fast_zone[row_mask,col_mask]).astype(np.float32)#获取圆周上的16个点
			r0 = img[r,c].astype(np.float32)
			condition1 = ((data-r0)>t).astype(int)#将bool转成0-1的int
			condition2 = ((r0-data)>t ).astype(int)#将bool转成0-1的int
			# 先快速判断第15913
			if ( (condition1[0] + condition1[8])>=1 and (condition1[4]+condition1[12])>=1 ):
				temp = condition1.copy()
				temp = np.concatenate((temp,temp[0:fast_N-1]),axis=0)#考虑到循环判断,需复制扩展
				temp_s = ''.join(str(i)for i in temp)#将0-1的int转为string
				temp_s = temp_s.replace("0"," ")#将0替换为空格,方便分割
				temp_s_arr = temp_s.split() #分割每一段含有1的部分
				temp_d_arr = np.array([len(s) for s in temp_s_arr])#计算每一段的长度,即连续满足条件的点数
				if(max(temp_d_arr)>=fast_N): #如果最大连续满足条件的点数,达到N,则判定为角点
					score = np.sum(np.abs(data-r0)) #计算得分情况
					score_arr[r,c]=score
					continue#已检测到角点,后续不再执行
			if ((condition2[0] + condition2[8]) >= 1 and (condition2[4] + condition2[12]) >= 1):
				temp = condition2.copy()
				temp = np.concatenate((temp, temp[0:fast_N - 1]), axis=0)
				temp_s = ''.join(str(i) for i in temp)
				temp_s = temp_s.replace("0", " ")
				temp_s_arr = temp_s.split()
				temp_d_arr = np.array([len(s) for s in temp_s_arr])
				if (max(temp_d_arr) >= fast_N):
					score = np.sum(np.abs(data - r0))
					score_arr[r, c] = score
	return score_arr

非最大抑制関数:
220719 更新: nms コードにはいくつかの欠点があります。詳細については、フォローアップのブログ投稿を参照してください (https://blog.csdn.net/xiaohuolong1827/article/details/125859795)

def corner_nms(corner,kernal=3):
	out = corner.copy()
	row_s = int(kernal/2)
	row_e = out.shape[0] - int(kernal/2)
	col_s,col_e = int(kernal/2),out.shape[1] - int(kernal/2)
	for r in range(row_s,row_e):
		for c in range(col_s,col_e):
			if corner[r,c]==0: #不是可能的角点
				continue
			zone = corner[r-int(kernal/2):r+int(kernal/2)+1,c-int(kernal/2):c+int(kernal/2)+1]
			index = corner[r,c]<zone
			(x,y) = np.where(index==True)
			if len(x)>0 : #说明corner[r,c]不是最大,直接归零将其抑制
				out[r,c] = 0
			else:
				out[r,c] = 255
	return out

円周ピクセル位置関数をテストします。

def mask_test():
	temp = np.array([
		[0, 0, 16, 1, 2, 0, 0],
		[0, 15, 0, 0, 0, 3, 0],
		[14, 0, 0, 0, 0, 0, 4],
		[13, 0, 0, 0, 0, 0, 5],
		[12, 0, 0, 0, 0, 0, 6],
		[0, 11, 0, 0, 0, 7, 0],
		[0, 0, 10, 9, 8, 0, 0]
	])
	data = temp[row_mask,col_mask]
	print(data)
	return

メイン関数呼び出し:

if __name__ == '__main__':
	img_src = cv2.imread('susan_input1.png',cv2.IMREAD_GRAYSCALE)
	score_arr = fast_corner_detect(img_src, t=10)
	img_show = img_src.copy()
	if(len(img_show.shape)==2):
		img_show = cv2.cvtColor(img_show,cv2.COLOR_GRAY2BGR)
	img_show[score_arr!=0] = (255,0,0)
	print(len(np.where(score_arr!=0)[0]))
	plt.figure()
	plt.title("corners-raw")
	plt.imshow(img_show, cmap=cm.gray)


	img_show2 = img_src.copy()
	if (len(img_show2.shape) == 2):
		img_show2 = cv2.cvtColor(img_show2, cv2.COLOR_GRAY2BGR)
	score_nms = corner_nms(score_arr)
	img_show2[score_nms != 0] = (255, 0, 0)
	plt.figure()
	plt.title("corners-nms")
	plt.imshow(img_show2, cmap=cm.gray)
	
	plt.show()
	print('end')

試験結果:
ここに画像の説明を挿入
ここに画像の説明を挿入

4. OpenCVの実装

Opencv には独自の FAST オペレーターがあり、FAST のコーナー検出を簡単に実現できます。
使用した OpenCV バージョン: 3.4.2.16 (4.4.0.42 も実行可能)
メイン コードはわずか数行です。

fast = cv2.FastFeatureDetector_create(threshold=10,type=cv2.FastFeatureDetector_TYPE_9_16)
kps3 = fast.detect(img_src)
img_show3 = cv2.drawKeypoints(image=img_src,keypoints=kps3,outImage=None,color=(0,0,255))

メインプログラムで呼び出されます:

if __name__ == '__main__':
	img_src = cv2.imread('susan_input1.png',cv2.IMREAD_GRAYSCALE)
	score_arr = fast_corner_detect(img_src, t=10)
	img_show = img_src.copy()
	if(len(img_show.shape)==2):
		img_show = cv2.cvtColor(img_show,cv2.COLOR_GRAY2BGR)
	img_show[score_arr!=0] = (255,0,0)
	print(len(np.where(score_arr!=0)[0]))
	plt.figure()
	plt.title("corners-raw")
	plt.imshow(img_show, cmap=cm.gray)

	img_show2 = img_src.copy()
	if (len(img_show2.shape) == 2):
		img_show2 = cv2.cvtColor(img_show2, cv2.COLOR_GRAY2BGR)
	score_nms = corner_nms(score_arr)
	img_show2[score_nms != 0] = (255, 0, 0)
	plt.figure()
	plt.title("corners-nms")
	plt.imshow(img_show2, cmap=cm.gray)

	fast = cv2.FastFeatureDetector_create(threshold=10,type=cv2.FastFeatureDetector_TYPE_9_16)
	fast.setNonmaxSuppression(False)
	kps3 = fast.detect(img_src)
	print(len(kps3))
	img_show3 = cv2.drawKeypoints(image=img_src,keypoints=kps3,outImage=None,color=(0,0,255))
	plt.figure()
	plt.title("corners-opencv-raw")
	plt.imshow(img_show3, cmap=cm.gray)

	fast.setNonmaxSuppression(True)
	kps4 = fast.detect(img_src)
	img4 = cv2.drawKeypoints(image=img_src, keypoints=kps4, outImage=None, color=(0, 0, 255))
	plt.figure()
	plt.title("corners-opencv-nms")
	plt.imshow(img4, cmap=cm.gray)

	plt.show()

	print('end')

テスト結果:
ここに画像の説明を挿入
ここに画像の説明を挿入
非最大値抑制を使用しない場合、自分で書いたコードは opencv で検出されたコーナーポイントの数と同じですが、opencv が非最大値抑制をオンにした後、パラメーターが適切に設定されず、結果的にオーバーになる可能性があります。 -抑制。nmsのパラメータの設定方法がわかりません。ただし、他の画像でテストする場合は、nms をオンにすると、検出された角は許容されます。

5. ソースコードのダウンロード

https://download.csdn.net/download/xiaohuolong1827/85726475

6. その他

6月下旬だよ、黄寧蘭、なぜまだwしないの?

おすすめ

転載: blog.csdn.net/xiaohuolong1827/article/details/125398614