5.30. 템플릿 매칭¶
지금까지 다룬 검출기는 단일 프레임의 내용에 대한 질문에 답합니다. 즉, 블롭이 어디에 있는지, 선이 어디로 향하는지, 인쇄된 코드가 무엇을 의미하는지 같은 것들입니다. 이와는 다른 부류의 질문은 한 이미지를 다른 이미지와 비교합니다. 캡처한 프레임의 이 영역이 보정 시점에 저장해 둔 참조 패치처럼 보이는가? 매칭 메서드가 바로 이 질문에 답합니다.
색조 및 통계 분석에서는 관련된 질문, 즉 같은 크기의 두 이미지가 전체적으로 얼마나 비슷한가?에 대해 SSIM을 기반 지표로 사용하는 get_similarity() 를 소개했습니다. 남은 매칭 질문은 위치 파악에 관한 것입니다. 즉 “이 두 이미지가 얼마나 비슷한가”가 아니라 “이 더 큰 이미지 안에서 그 더 작은 패치가 어디에 나타나는가”입니다. 위치 파악 질문에 알맞은 도구는 템플릿 매칭입니다.
5.30.1. 기본 호출¶
find_template() 은 작은 템플릿 이미지가 캡처한 프레임 안에서 처음으로 나타나는 위치를 찾습니다. 구현은 정규화된 상호 상관(normalised cross-correlation, NCC)을 사용합니다. 템플릿이 프레임 위를 미끄러지며 이동하고, 각 위치의 매칭 점수는 템플릿 픽셀과 그 아래에 있는 프레임 픽셀 간의 상관관계로부터 계산되며(게인 변화가 매칭을 속이지 못하도록 국소 평균과 분산에 대해 정규화됨), 점수가 threshold 를 넘는 첫 번째 위치가 경계 상자로 반환됩니다:
template = image.Image("/sdcard/template.bmp", copy_to_fb=False)
template.to_grayscale()
match = img.find_template(template, threshold=0.7,
search=image.SEARCH_DS)
if match is not None:
img.draw_rectangle(match, color=(255, 0, 0))
이 메서드는 그레이스케일 이미지에서만 동작합니다. 그레이스케일로 캡처하거나(색상 센서가 없는 모든 카메라에서 자연스러운 선택입니다), 호출 전에 to_grayscale() 를 통해 제자리에서 변환하십시오. 디스크에서 불러온 템플릿에도 동일하게 적용됩니다. 색상 템플릿은 같은 메서드로 변환되며, 그 결과가 매처가 기대하는 형식입니다.
threshold 는 0.0 부터 1.0 까지의 float 값입니다. 1.0 값은 픽셀 단위로 완벽하게 일치하기를 요구하며(실제로 캡처된 이미지에서는 결코 일어나지 않습니다), 0.0 은 무엇이든 받아들이고, 0.6 과 0.8 사이의 값은 템플릿이 비슷한 조명에서 캡처되었고 장면이 크게 변하지 않은 일반적인 경우를 포괄합니다. 오탐을 억제하려면 임계값을 높이고, 더 많은 잘못된 히트를 감수하면서 더 잡음이 많은 매칭을 받아들이려면 임계값을 낮추십시오.
5.30.2. 검색 전략¶
search 는 두 가지 전략 중에서 선택합니다. image.SEARCH_EX 는 완전 탐색입니다. 템플릿이 프레임 안의 모든 step 픽셀 위치를 미끄러지며 이동하고 임계값을 넘는 첫 번째 히트를 반환합니다. image.SEARCH_DS 는 다이아몬드 탐색입니다. 매처가 먼저 거칠게 샘플링한 다음 가장 높은 점수 주변을 정밀하게 다듬는데, 이는 극적으로 빠르지만 거친 단계가 우연히 전역 최댓값을 능가하는 국소 최댓값 근처에 도달했다면 진짜 매칭을 놓칠 수 있습니다. 템플릿이 잘 정의되어 있고 혼동될 가능성이 낮은 실시간 파이프라인에서는 SEARCH_DS 가 알맞은 기본값입니다. 놓침의 비용이 더 느린 스캔의 비용보다 큰 일회성 보정에서는 SEARCH_EX 가 더 안전합니다.
step 은 완전 탐색 단계에서의 픽셀 건너뛰기를 제어합니다(다이아몬드 탐색은 자체 step을 관리합니다). step 값이 클수록 서브픽셀 정확도를 희생하는 대신 스캔 속도가 빨라집니다. roi 는 검색을 프레임의 한 영역으로 제한하여, 매처가 고려하는 범위를 좁히는 동시에 작업량을 줄입니다.
반환 값은 가장 잘 맞는 매칭을 식별하는 (x, y, w, h) 경계 상자 튜플이거나, 임계값을 넘는 위치가 없을 경우 None 입니다. 경계 상자는 다음 처리 단계를 위해 draw_rectangle() 이나 crop() 에 곧바로 넣을 수 있습니다.
5.30.3. 스케일과 회전의 함정¶
템플릿 매칭의 고전적인 함정은 스케일 및 회전 민감성입니다. 매처는 템플릿을 프레임과 픽셀 단위로 비교합니다. 한 거리에서 캡처한 템플릿은 다른 거리에서 캡처한 같은 물체와 일치하지 않으며, 정면에서 캡처한 템플릿은 비스듬히 본 같은 물체와 일치하지 않습니다. 물체가 사람의 눈에 분명히 보이는 경우에도 임계값이 조용히 매칭 수준 아래로 떨어지고, 메서드는 None 을 반환합니다.
단순한 경우에 대한 몇 가지 우회 방법이 있습니다. 애플리케이션은 서로 다른 스케일에서 여러 템플릿을 캡처하고 각각에 대해 find_template() 을 순차적으로 실행하여 임계값을 넘는 첫 번째 것을 받아들일 수 있습니다. 비용은 템플릿 수에 비례하여 늘어납니다. 또한 애플리케이션은 매칭이 실행되기 전에 rotation_corr() 이나 극좌표 변환(기하 변환)으로 프레임을 전처리하여 문제가 되는 회전을 제거할 수 있습니다. 매칭된 템플릿은 여전히 보정된 기하 구조와 일치해야 합니다.
QA 검사 파이프라인에 유용한 관용구는 템플릿 매처를 색조 및 통계 분석에서 소개한 유사도 채점기와 짝짓는 것입니다. find_template() 이 캡처한 프레임에서 부품을 찾아내고, 반환된 경계 상자가 잘려 나와 참조 패치와 비교하기 위해 get_similarity() 에 전달됩니다. 템플릿 매칭 단계는 부품이 어디에 있는지를 결정하고, 유사도 채점 단계는 부품이 허용 가능한지를 결정합니다. 두 단계는 매 프레임마다 실행되고, mean 에 대한 임계값이 합격/불합격 게이트이며, 프레임에 다시 그려진 매칭된 경계 상자는 작업자가 지켜보는 IDE 미리보기입니다.