이 번역 페이지는 최신 내용을 담고 있지 않습니다. 최신 내용을 영문으로 보려면 여기를 클릭하십시오.
영상에서 원형 객체를 검출하고 측정하기
이 예제에서는 영상에서 원 또는 원형 객체를 자동으로 검출하고 검출된 원을 시각화하는 방법을 보여줍니다.
1단계: 영상 불러오기
다양한 색의 둥근 플라스틱 칩의 영상을 읽어 들여서 표시합니다. 이 영상에는 검출할 원이 많다는 점 외에도, 원 검출 측면에서 흥미로운 점도 몇 가지 있습니다.
다양한 색의 칩이 있으며, 배경과의 대비도 다양합니다. 파란색과 빨간색 칩은 배경과 강하게 대비됩니다. 반면, 노란색 칩 중 일부는 배경과 그다지 대비되지 않습니다.
서로 겹쳐진 칩도 있고, 서로 가까이 있는 칩과 거의 닿는 칩도 있습니다. 객체 경계선 겹침과 객체 가림은 객체 검출을 까다롭게 만듭니다.
rgb = imread("coloredChips.png");
imshow(rgb)
2단계: 원을 찾기 위해 반지름 범위 구하기
drawline
함수를 사용하여 원의 적절한 반지름 범위를 구합니다. 칩의 대략적인 지름 위에 선을 그립니다.
d = drawline;
선 ROI의 길이는 칩의 지름입니다. 일반적인 칩의 지름 범위는 40~50 픽셀입니다.
pos = d.Position; diffPos = diff(pos); diameter = hypot(diffPos(1),diffPos(2))
diameter = 45.4533
3단계: 원을 찾기 위한 첫 번째 시도
imfindcircles
함수는 반지름 범위를 사용하여 원을 검색합니다. 반지름 범위가 20~25 픽셀인 원을 검색합니다. 그 전에, 객체를 배경보다 더 밝게 할지 아니면 더 어둡게 할지 정해 두는 것이 좋습니다. 그 답을 찾기 위해, 이 영상의 회색조 버전을 표시하겠습니다.
gray_image = im2gray(rgb); imshow(gray_image)
배경이 상당히 밝고, 칩 대부분이 배경보다 더 어둡습니다. 그러나 기본적으로 imfindcircles
는 배경보다 더 밝은 원형 객체를 찾습니다. 그러므로 어두운 원을 찾기 위해 imfindcircles
에서 파라미터 "ObjectPolarity"를 "dark"로 설정합니다.
[centers,radii] = imfindcircles(rgb,[20 25],"ObjectPolarity","dark")
centers = [] radii = []
출력 인수 centers
와 radii
가 비어 있습니다. 이는 발견된 원이 없다는 뜻입니다. 이 현상은 자주 발생합니다. imfindcircles
는 원 검출기이고, 다른 검출기와 마찬가지로 imfindcircles
는 감도를 확인하는 내부 검출 임계값을 갖기 때문입니다. 간단히 말하면, 특정 (원) 검출이 유효할 수 있으려면 그 검출에서 검출기의 신뢰가 특정 수준보다 커야 합니다. imfindcircles
에는 이 내부 임계값을 조정(결과적으로, 알고리즘의 감도 조정)하는 데 사용할 수 있는 파라미터 "Sensitivity"가 있습니다. "Sensitivity" 값을 높이면 검출 임계값이 더 낮게 설정되어 더 많은 원을 검출하게 됩니다. 이는 주택 보안 시스템에 사용되는 동작 감지기의 감도 조정과 비슷합니다.
4단계: 검출 감도 늘리기
다시 칩 영상으로 돌아와 보면, 디폴트 감도 수준에서 모든 원이 내부 임계값보다 낮을 수 있습니다. 원이 검출되지 않은 이유가 바로 이 때문입니다. 기본적으로 "Sensitivity"(0과 1 사이의 숫자)는 0.85로 설정되어 있습니다. "Sensitivity"를 0.9로 늘립니다.
[centers,radii] = imfindcircles(rgb,[20 25],"ObjectPolarity","dark", ... "Sensitivity",0.9)
centers = 8×2
146.1895 198.5824
328.8132 135.5883
130.3134 43.8039
175.2698 297.0583
312.2831 192.3709
327.1316 297.0077
243.9893 166.4538
271.5873 280.8920
radii = 8×1
23.1604
22.5710
22.9576
23.7356
22.9551
22.9995
22.9055
23.0298
이번에는 imfindcircles
가 원을 몇 개(정확하게는 8개) 찾았습니다. centers
에는 원의 중심의 위치가 들어 있고, radii
에는 그 원의 추정 반지름이 들어 있습니다.
5단계: 영상에 원 그리기
함수 viscircles
를 사용하여 영상에 원을 그릴 수 있습니다. imfindcircles
의 출력 변수 centers
와 radii
는 viscircles
에 바로 전달할 수 있습니다.
imshow(rgb) h = viscircles(centers,radii);
원의 중심의 위치가 정확한 것 같고, 해당 반지름도 실제 칩에 잘 맞는 것 같습니다. 그러나 아직도 상당히 많은 칩이 누락되었습니다. "Sensitivity"를 0.92로 더 늘려 봅니다.
[centers,radii] = imfindcircles(rgb,[20 25],"ObjectPolarity","dark", ... "Sensitivity",0.92); length(centers)
ans = 16
"Sensitivity"를 늘려 훨씬 더 많은 원을 찾을 수 있습니다. 이 원들을 다시 영상에 플로팅합니다.
delete(h) % Delete previously drawn circles
h = viscircles(centers,radii);
6단계: 원을 찾기 위해 두 번째 방법(2단계) 사용하기
이 결과가 더 좋아 보입니다. imfindcircles
에는 원을 찾을 수 있는 방법이 두 가지 있습니다. 지금까지는 원을 검출하는 데 위상 코딩(phase coding)이라는 디폴트 방법을 사용했습니다. imfindcircles
에서는 2단계(two-stage) 방법이라고 하는 또 다른 방법도 사용할 수 있습니다. 2단계 방법을 사용하여 결과를 표시합니다.
[centers,radii] = imfindcircles(rgb,[20 25],"ObjectPolarity","dark", ... "Sensitivity",0.92,"Method","twostage"); delete(h) h = viscircles(centers,radii);
2단계 방법은 Sensitivity가 0.92일 때 더 많은 원을 검출했습니다. 대체로 이 두 방법은 장점이 서로 다르기 때문에 상호 보완적입니다. 위상 코딩 방법은 일반적으로 2단계 방법보다 속도가 빠르고 잡음에 조금 더 강합니다. 그러나 2단계 방법의 검출 개수와 동일하려면 "Sensitivity" 수준을 더 올려야 할 수도 있습니다. 예를 들어, "Sensitivity" 수준을 더 올리면 즉, 0.95로 올리면, 위상 코딩 방법도 같은 개수의 칩을 찾게 됩니다.
[centers,radii] = imfindcircles(rgb,[20 25],"ObjectPolarity","dark", ... "Sensitivity",0.95); delete(h) viscircles(centers,radii);
imfindcircles
의 두 방법은 일부만 보이는(가린) 칩의 중심과 반지름을 정확하게 찾습니다.
7단계: 왜 아직도 일부 원이 누락되는 걸까요?
마지막 결과를 보면, 의아스럽게도 imfindcircles
는 영상의 노란색 칩을 찾지 못합니다. 노란색 칩은 배경과 강한 대비를 이루지 않습니다. 실제로 노란색 칩은 배경과 명암이 상당히 유사한 것 같습니다. 가정한 대로, 노란색 칩이 배경보다 실제로 "더 어두울" 가능성은 없을까요? 확인하기 위해, 이 영상의 회색조 버전을 다시 표시합니다.
imshow(gray_image)
8단계: 영상에서 "밝은" 원 찾기
노란색 칩은 배경과 비교하여 명암이 거의 같거나, 조금 더 밝을 수 있습니다. 따라서 노란색 칩을 검출하기 위해 "ObjectPolarity"를 "bright"로 변경합니다.
[centersBright,radiiBright] = imfindcircles(rgb,[20 25], ... "ObjectPolarity","bright","Sensitivity",0.92);
9단계: 서로 다른 색으로 "밝은" 원 그리기
viscircles
에서 "Color" 파라미터를 변경하여, 서로 다른 색으로 밝은 원을 그립니다.
imshow(rgb) hBright = viscircles(centersBright, radiiBright,"Color","b");
누락된 노란색 칩 중 세 개는 찾았지만, 한 개는 여전히 찾지 못하고 있습니다. 그 칩은 이 배경에서 다른 칩과 함께 두드러지지 않기 때문에 찾기 힘듭니다.
10단계: "EdgeThreshold" 값 낮추기
imfindcircles
에는 "EdgeThreshold"라는 또 다른 파라미터가 있습니다. 여기서 유용할 수 있는 파라미터입니다. imfindcircles
는 원을 찾을 때 영상의 경계 픽셀만 사용합니다. 이러한 경계 픽셀은 기본적으로 기울기 값이 큰 픽셀입니다. 픽셀을 경계 픽셀로 간주하여 계산에 넣기 전에, "EdgeThreshold" 파라미터를 사용하여 해당 픽셀의 기울기 값을 얼마나 높일지 조정할 수 있습니다. 이 파라미터에 높은 값(1에 근접)을 사용하면 강한 경계(기울기 값이 더 높음)만 포함할 수 있는 반면, 낮은 값(0에 근접)은 좀 더 관대하여 약한 경계(기울기 값이 더 낮음)도 계산에 포함합니다. 누락된 노란색 칩의 경우, 대비가 낮아 (칩의 원주에서) 경계선 픽셀 중 일부의 기울기 값이 낮을 것입니다. 따라서 노란색 칩의 경계 픽셀 대부분을 계산에 넣으려면 "EdgeThreshold" 파라미터를 낮추어야 합니다.
[centersBright,radiiBright,metricBright] = imfindcircles(rgb,[20 25], ... "ObjectPolarity","bright","Sensitivity",0.92,"EdgeThreshold",0.1); delete(hBright) hBright = viscircles(centersBright, radiiBright,"Color","b");
11단계: "어두운" 원과 "밝은" 원을 함께 그리기
이제 imfindcircles
는 모든 노란색 칩과 녹색 칩도 찾았습니다. 이러한 칩은 파란색으로 그리고, 이전에 찾은 다른 칩("ObjectPolarity"가 "dark"로 설정됨)은 빨간색으로 함께 그립니다.
h = viscircles(centers,radii);
모든 원을 검출했습니다. 마지막으로 한 가지 유의할 점을 덧붙이자면, 검출 시 파라미터를 좀 더 공격적으로 변경하면 원을 더 많이 찾을지 모르지만, 원을 잘못 찾을 가능성도 늘어납니다. 정확하게 찾을 수 있는 원(검출률)이 있으면, 그와 함께 잘못 찾는 원(오검출률)도 있는 법입니다.
즐겁게 원을 찾으시길 바랍니다!