저번 포스트에서 walkaroundthedevelop.tistory.com/56
어떻게 하면 두 이미지의 차이를 알 수 있는지에 대해서 알아보았습니다.
그럼 두 개의 이미지를 이용해서 차이를 표시해낼 수 있을까요?
일단 두 개의 이미지를 사용해서 얻어낸 diff를 디스플레이 해 봅시다.
두 개의 이미지에다가 diff를 구하면, 이렇게 됩니다.
이 diff를 보면, 포스트잇을 붙인 곳이 검은색으로 된 것을 볼 수 있습니다.
# 이전 포스트에서 diff 가져옴!
thresh = cv2.threshold(diff, 100, 255, cv2.THRESH_BINARY_INV)[1]
# get contours
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area > sens_int:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(imageA, (x, y), (x + w, y + h), (51, 255, 102), 2)
cv2.rectangle(imageB, (x, y), (x + w, y + h), (51, 255, 102), 2)
#imageA = cv2.resize(imageA, (550, 350))
#imageB = cv2.resize(imageB, (550, 350))
#cv2.imshow('Original', imageA)
#cv2.imshow('Modified', imageB)
#cv2.imshow('CroppedA', imageA)
#cv2.imshow('CroppedB', imageB)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
threshold 에는 여러가지 활용법이 있는데,
크게는 simple threshold와 adaptive threshold로 나눌 수 있습니다.
threshold에 대해서는 python-opencv documentation 홈페이지에 잘 나와있습니다.
opencv-python.readthedocs.io/en/latest/doc/09.imageThresholding/imageThresholding.html
등등 레퍼런스를 참고해도 좋을 것 같습니다.
simple threshold는 전체 이미지를 대상으로 하였고,
adaptive threshold는 각각의 지역에 대해서 주변의 픽셀과 비교해서 threshold 값을 구하는 것을 말합니다.
simple threshold 관련 function의 documentation:
docs.opencv.org/master/d7/d1b/group__imgproc__misc.html#gae8a4a146d1ca78c626a53577199e9c57
Simple threshold를 사용할 때의 함수는
threshold(src, dst, threshold_value, Max_value, threshold_type)
threshold(src, dst, threshold_value, Max_value, threshold_type)
이렇게 구성되어 있는데, dst는 optional이고,
- threshold_value : 사용하는 임계값
- Max_value : THRESH_BINARY and THRESH_BINARY_INV를 사용할 때 사용하는 값. 임계 값 이상의 픽셀들에 적용할 값,
0 또는 Max_value 의 두 값으로만 이미지를 표현하게 됨, 보통 255 를 사용합니다.
- threshold_type : 5가지의 int type으로 이루어져 있으며, 어떻게 binary를 처리하는지에 대한 방법에 대한 내용입니다.
현재는 저 검은색인 부분을 하얀색으로 만들고 나머지를 검은색으로 만들기 위해서, THRESH_BINARY_INV를 사용했고,
다른 threshold type에 대해서는 깊게 다루지 않겠습니다.
- cv2.THRESH_BINARY : 픽셀값 > min_value max_value, 작으면 0
- cv2.THRESH_BIANRY_INV : 픽셀값 > min_value 0, 작으면 max_value
- cv2.THRESH_TRUNC : 픽셀값 > min_value min_value , 작으면 픽셀값
- cv2.THRESH_TOZERO : 픽셀값 > max_value 픽셀값 , 작으면 0
- cv2.THRESH_TOZERO_INV : 픽셀값 > max_value 0 , 작으면 픽셀
이렇게 있다고 알고 넘어가면 좋을 것 같습니다.
그럼 이렇게 나오게 됩니다.
여기서 저 흰색의 박스를 잡기위해서 쓰는 함수가 cv2.findContours 입니다.
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
Contour는 한국어로 윤곽이란 뜻으로, 특히 opencv에서 윤곽이란 검은색 바탕에서 하얀색 물체를 찾는 걸 의미한다고 합니다.
참조 : blog.naver.com/samsjang/220516697251
그러기 때문에 우리가 threshold함수를 사용해서 binary 이미지를 만든 게 딱 맞는다고 할 수 있겠죠.
findContours는 원본 이미지를 변형하기 때문에 copy를 사용하는 게 좋습니다.
findContours의 documentation을 보면, 다음과 같이 되어 있습니다.
contours, hierarchy = cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
- image : binary image
- mode :
- cv2.RETR_EXTERNAL : contours line중 가장 바같쪽 Line만 찾음.
- cv2.RETR_LIST : 모든 contours line을 찾지만, hierachy 관계를 구성하지 않음.
- cv2.RETR_CCOMP : 모든 contours line을 찾으며, hieracy관계는 2-level로 구성함.
- cv2.RETR_TREE : 모든 contours line을 찾으며, 모든 hieracy관계를 구성함.
- method : contours를 찾을 때 사용하는 근사치 방법
- cv2.CHAIN_APPROX_NONE : 모든 contours point를 저장.
- cv2.CHAIN_APPROX_SIMPLE : contours line을 그릴 수 있는 point 만 저장. (ex; 사각형이면 4개 point)
- cv2.CHAIN_APPROX_TC89_L1 : contours point를 찾는 algorithm
- cv2.CHAIN_APPROX_TC89_KCOS : contours point를 찾는 algorithm
Returns: image, contours, hierarchy
참조 : opencv-python.readthedocs.io/en/latest/doc/15.imageContours/imageContours.html#contours
사실 이 findContours 함수는 opencv 버전 2, 4에서와 3에서의 활용이 다릅니다.
# check to see if we are using OpenCV 2.X or OpenCV 4
if imutils.is_cv2() or imutils.is_cv4():
(cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# check to see if we are using OpenCV 3
elif imutils.is_cv3():
(_, cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
확인해 주도록 합니다.
또 하나 주의할 점은, findContours는 두 개의 값들을 list 형태로 return하기 때문에, (버전 2, 4일 경우)
contour만 활용할 경우 cnts[1]를 사용해서 가져와야 한다는 점입니다.
contourArea 함수는 contour의 영역을 계산합니다.
그래서 count영역값이 sens_int 값보다 작으면 무시하고, sens_int값보다 클 경우만 박스를 쳐 주도록 합니다.
cv2.boundingRect() 는 그 영역에 맞는 박스값을 찾아주고,
cv2.rectangle() 은 실제 박스를 쳐 주는 역할을 합니다.
'Image Processing > Cv2' 카테고리의 다른 글
opencv waitkey 설명 (0) | 2021.07.16 |
---|---|
opencv 를 이용해서 rtsp 동영상 받기(ft. multithreading) (0) | 2021.06.18 |
OpenCV를 이용해서 두 개의 이미지 비교하기 (SSIM) (0) | 2021.03.10 |
Cv2 를 이용해서 multiple 이미지 crop하고 나머지 mask 하기 (0) | 2021.03.03 |
Cv2 를 이용해서 이미지 crop하고 나머지 mask 하기 (0) | 2021.03.03 |