'keypoint'에 해당되는 글 1건

  1. 2021.09.08 opencv SimpleBlobDetector, blob size 정리

1. SimpleBlobDetector

parameter로 넣어준 조건에 따라 blob을 찾아줌.

알고리즘

  1. source image에 threshold를 적용.
    - parameter에 넣은 minThreshold 값(포함)과 maxThreshold 값(불포함) 사이를 thresholdStep으로 나누어 각각의 threshold를 사용해서 binary image로 바꾼다. 처음부터 binary를 넣어주려는 경우 기본 파라미터에서는 minThreshold=50, maxThreshold=220, thresholdStep=10 으로 설정이 되어있기에 이를 만져주어야 한다.
    binary image를 0과 255로 구성되도록 설정하고, minThreshold=253, maxThreshold=255, thresholdStep=1로 설정하면 최소한의 threshold 연산만 사용할 수 있다.
  2. 각각의 binary image에 대해서 findContours 함수를 적용해서 center를 계산.
  3. 각각의 binary image에서 찾은 contour들을 하나로 묶어줌.
    이때 minDistBetweenBlobs parameter를 사용한다.
  4. 찾아낸 Contour를 사용해서 blob의 최종 center와 radius를 확정. 이를 keypoint로 return

예시코드

import cv2 as cv

parameter = cv.SimpleBlobDetector_Params()
parameter.filterByArea = True
parameter.filterByConvexity = True
parameter.filterByCircularity = True
parameter.filterByInertia = False
parameter.filterByColor = False
parameter.minArea = 500  # this value defines the minimum size of the blob
parameter.maxArea = 10000  # this value defines the maximum size of the blob
parameter.minDistBetweenBlobs = 1 # not used in binary image
parameter.minConvexity = 0.3
parameter.minCircularity = 0.3

detector = cv.SimpleBlobDetector_create(parameter)
detected_blob = detector.detect(denoised_mask)
print(len(detected_blob))

2. keypoint size

keypoint는 pt 값과 size 값을 가지고 있는데 (다른 값들도 있지만 이 연산에서는 무의미한 것으로 추정) pt는 blob center의 x, y 좌표를 의미하지만 도무지 size에 대한 이야기가 없다.

내가 원하는 정보는 찾아낸 blob의 크기 (이를 둘러쌀 수 있는 최소한의 원의 반지름 이라던가 실제 blob의 픽셀 수라던가...)인데 나오는 size 값은 blob의 모양에 따라서 제각각이다.

blob detection 을 한뒤 pt를 기준으로 size/2 만큼의 radius를 가지는 원을 그린 결과물

4번째 스텝인 "찾아낸 Contour를 사용해서 blob의 최종 center와 radius를 확정." 에서 대체 무슨일이 일어나는 것이길래 이런 값이 출력되는지 모르겠다. 원 같은 경우는 그나마 비슷하긴 하지만 실제 위의 그림에서 볼 수 있듯이 지름 100px짜리 원의 blob 크기는 99.0151로 나온다. 여러 contour 들을 합치는 알고리즘을 들여다봐야 알겠지만 SimpleBlobDetector가 return하는 keypoint의 값만 사용해서 실제 blob의 크기를 알아낼 방법은 없는 것으로 보인다.

3. parameter의 minArea / maxArea

한 가지 주목할 점은 parameter로 사용하는 minArea / maxArea의 경우는 실제 blob으로 잡힌 object의 크기를 비교한다는 것이다. 한 변의 길이가 100px인 정사각형에 대한 keypoint의 size 값은 111.8034이지만 filterByArea 옵션을 켜고 minArea를 10000(100 * 100)으로 잡으면 정사각형을 찾지만, 10001을 사용하는 경우 정사각형을 찾지 못한다. circle의 경우는 사용한 radius를 사용해 수학적으로 계산한 넓이와 10 이하로 차이가 나는 것으로 보아 실제 pixel 수를 기준으로 filter 하는 것으로 보인다.

 

4. findContours 함수를 사용한 정확한 blob detection

때문에 내부에서 찾아낸 blob의 정확한 사이즈를 뽑아낼 수 있을 것이라고 기대했으나 실패했다.

사실 실제 4단계 step 중에서 사용하는 부분이 두 번째 step 뿐이기에 이쯤되면 그냥 findContous 함수를 써서 raw level에서 처리하는 것이 더 나을 것으로 보인다.

 

cnt = cv.findContours(binary_image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]

# Some basic features of the contour object
(x,y), radius = cv.minEnclosingCircle(k)
rect = cv.minAreaRect(k) # ((center x, center y), (width, height), rotation)
size = cv.contourArea(k)

뽑아내야 하는 blob의 수를 알고 있다면 area, 둘러싸는 직사각형의 가로 세로 사이즈 등등의 값을 얻은 뒤 단계적으로 filter를 적용하는 방법도 사용할 수 있다.

 

 

Posted by Knowblesse