๐Ÿ˜Ž ๊ณต๋ถ€ํ•˜๋Š” ์ง•์ง•์•ŒํŒŒ์นด๋Š” ์ฒ˜์Œ์ด์ง€?

[v0.24]์˜์ƒ์ฒ˜๋ฆฌ_์ปจํˆฌ์–ด (์˜์ƒ๋ถ„ํ• ๋ฐฉ๋ฒ•) ๋ณธ๋ฌธ

๐Ÿ‘ฉ‍๐Ÿ’ป IoT (Embedded)/Image Processing

[v0.24]์˜์ƒ์ฒ˜๋ฆฌ_์ปจํˆฌ์–ด (์˜์ƒ๋ถ„ํ• ๋ฐฉ๋ฒ•)

์ง•์ง•์•ŒํŒŒ์นด 2022. 1. 12. 18:30
728x90
๋ฐ˜์‘ํ˜•

220112 ์ž‘์„ฑ

<๋ณธ ๋ธ”๋กœ๊ทธ๋Š” ๊ท€ํ‰์ด ์„œ์žฌ๋‹˜์˜ ๋ธ”๋กœ๊ทธ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๊ณต๋ถ€ํ•˜๋ฉฐ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค>

https://bkshin.tistory.com/entry/OpenCV-22-%EC%BB%A8%ED%88%AC%EC%96%B4Contour?category=1148027 

 

OpenCV - 22. ์ปจํˆฌ์–ด(Contour)

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์˜์ƒ ๋ถ„ํ•  ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜์ธ ์ปจํˆฌ์–ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ… ์—ญ์‹œ 'ํŒŒ์ด์ฌ์œผ๋กœ ๋งŒ๋“œ๋Š” OpenCV ํ”„๋กœ์ ํŠธ(์ด์„ธ์šฐ ์ €)'๋ฅผ ์ •๋ฆฌํ•œ ๊ฒƒ์ž„์„ ๋ฐํž™๋‹ˆ๋‹ค. ์ฝ”๋“œ: github.com/BaekKyun

bkshin.tistory.com

 

 

 

 

1. ์ปจํˆฌ์–ด (Contour)

: ๋“ฑ๊ณ ์„ , ์ง€ํ˜•์˜ ๋†’์ด๊ฐ€ ๊ฐ™์€ ์˜์—ญ์„ ํ•˜๋‚˜์˜ ์„ ์œผ๋กœ ํ‘œ์‹œ

: ์ปจํˆฌ์–ด๋ฅผ ๊ทธ๋ฆฌ๋ฉด ๋ชจ์–‘์„ ์‰ฝ๊ฒŒ ์ธ์‹

 

dst, contours, hierarchy = cv2.findContours(src, mode, method, contours, hierarchy, offset)

: ์ปจํˆฌ์–ด๋ฅผ ์ฐพ์•„๋‚ด๊ธฐ

 

- src : ์ž…๋ ฅ ์˜์ƒ, ๊ฒ€์ •๊ณผ ํฐ์ƒ‰์œผ๋กœ ๊ตฌ์„ฑ๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ ์ด๋ฏธ์ง€

- mode : ์ปจํˆฌ์–ด ์ œ๊ณต ๋ฐฉ์‹

  • cv2.RETR_EXTERNA L: ๊ฐ€์žฅ ๋ฐ”๊นฅ์ชฝ ๋ผ์ธ๋งŒ ์ƒ์„ฑ
  • cv2.RETR_LIST : ๋ชจ๋“  ๋ผ์ธ์„ ๊ณ„์ธต ์—†์ด ์ƒ์„ฑ
  • cv2.RET_CCOMP : ๋ชจ๋“  ๋ผ์ธ์„ 2 ๊ณ„์ธต์œผ๋กœ ์ƒ์„ฑ
  • cv2.RETR_TREE : ๋ชจ๋“  ๋ผ์ธ์˜ ๋ชจ๋“  ๊ณ„์ธต ์ •๋ณด๋ฅผ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ์ƒ์„ฑ

- method : ๊ทผ์‚ฌ ๊ฐ’ ๋ฐฉ์‹

  • cv2.CHAIN_APPROX_NONE : ๊ทผ์‚ฌ ์—†์ด ๋ชจ๋“  ์ขŒํ‘œ ์ œ๊ณต
  • cv2.CHAIN_APPROX_SIMPLE : ์ปจํˆฌ์–ด ๊ผญ์ง“์  ์ขŒํ‘œ๋งŒ ์ œ๊ณต
  • cv2.CHAIN_APPROX_TC89_L1 : Teh-Chin ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์ขŒํ‘œ ๊ฐœ์ˆ˜ ์ถ•์†Œ
  • cv2.CHAIN_APPROX_TC89_KC0S : Teh-Chin ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์ขŒํ‘œ ๊ฐœ์ˆ˜ ์ถ•์†Œ

- contours(optional) : ๊ฒ€์ถœํ•œ ์ปจํˆฌ์–ด ์ขŒํ‘œ (list type)

- hierarchy(optional) : ์ปจํˆฌ์–ด ๊ณ„์ธต ์ •๋ณด (Next, Prev, FirstChild, Parent, -1 [ํ•ด๋‹น ์—†์Œ])

- offset(optional) : ROI ๋“ฑ์œผ๋กœ ์ธํ•ด ์ด๋™ํ•œ ์ปจํˆฌ์–ด ์ขŒํ‘œ์˜ ์˜คํ”„์…‹

 

cv2.drawContours(img, contours, contourIdx, color, thickness)

: ์ปจํˆฌ์–ด ์„  ๊ทธ๋ฆฌ๊ธฐ

 

- img : ์ž…๋ ฅ ์˜์ƒ

- contours : ๊ทธ๋ฆผ ๊ทธ๋ฆด ์ปจํˆฌ์–ด ๋ฐฐ์—ด (cv2.findContours() ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๋ฉด ๋จ)

- contourIdx : ๊ทธ๋ฆผ ๊ทธ๋ฆด ์ปจํˆฌ์–ด ์ธ๋ฑ์Šค, -1: ๋ชจ๋“  ์ปจํˆฌ์–ด ํ‘œ์‹œ

- color : ์ƒ‰์ƒ ๊ฐ’

- thickness : ์„  ๋‘๊ป˜, 0: ์ฑ„์šฐ๊ธฐ

 

=> img์˜์ƒ์— contours ๋ฐฐ์—ด์— ์žˆ๋Š” ์ปจํˆฌ์–ด ์ค‘ contourIdx์— ํ•ด๋‹นํ•˜๋Š” ์ปจํˆฌ์–ด๋ฅผ

color ์ƒ‰์ƒ๊ณผ thickness ๋‘๊ป˜๋กœ ์„ ์„ ๊ทธ๋ฆฐ๋‹ค

# ์ปจํˆฌ์–ด ์ฐพ๊ธฐ์™€ ๊ทธ๋ฆฌ๊ธฐ
import cv2
import numpy as np

img = cv2.imread('img/shapes.JPG')
img2 = img.copy()

# ๊ทธ๋ ˆ์ด ์Šค์ผ€์ผ๋กœ ๋ณ€ํ™˜ ---โ‘ 
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# ์Šค๋ ˆ์‹œํ™€๋“œ๋กœ ๋ฐ”์ด๋„ˆ๋ฆฌ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์„œ ๊ฒ€์€๋ฐฐ๊ฒฝ์— ํฐ์ƒ‰์ „๊ฒฝ์œผ๋กœ ๋ฐ˜์ „ ---โ‘ก
ret, imthres = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY_INV)

# ๊ฐ€์žฅ ๋ฐ”๊นฅ์ชฝ ์ปจํˆฌ์–ด์— ๋Œ€ํ•ด ๋ชจ๋“  ์ขŒํ‘œ ๋ฐ˜ํ™˜ ---โ‘ข
im2, contour, hierarchy = cv2.findContours(imthres, cv2.RETR_EXTERNAL, \
                                                 cv2.CHAIN_APPROX_NONE)
# ๊ฐ€์žฅ ๋ฐ”๊นฅ์ชฝ ์ปจํˆฌ์–ด์— ๋Œ€ํ•ด ๊ผญ์ง€์  ์ขŒํ‘œ๋งŒ ๋ฐ˜ํ™˜ ---โ‘ฃ
im2, contour2, hierarchy = cv2.findContours(imthres, cv2.RETR_EXTERNAL, \
                                                cv2.CHAIN_APPROX_SIMPLE)
# ๊ฐ๊ฐ์˜ ์ปจํˆฌ์˜ ๊ฐฏ์ˆ˜ ์ถœ๋ ฅ ---โ‘ค
print('๋„ํ˜•์˜ ๊ฐฏ์ˆ˜: %d(%d)'% (len(contour), len(contour2)))

# ๋ชจ๋“  ์ขŒํ‘œ๋ฅผ ๊ฐ–๋Š” ์ปจํˆฌ์–ด ๊ทธ๋ฆฌ๊ธฐ, ์ดˆ๋ก์ƒ‰  ---โ‘ฅ
cv2.drawContours(img, contour, -1, (0,255,0), 4)
# ๊ผญ์ง€์  ์ขŒํ‘œ๋งŒ์„ ๊ฐ–๋Š” ์ปจํˆฌ์–ด ๊ทธ๋ฆฌ๊ธฐ, ์ดˆ๋ก์ƒ‰  ---โ‘ฆ
cv2.drawContours(img2, contour2, -1, (0,255,0), 4)

# ์ปจํˆฌ์–ด ๋ชจ๋“  ์ขŒํ‘œ๋ฅผ ์ž‘์€ ํŒŒ๋ž‘์ƒ‰ ์ (์›)์œผ๋กœ ํ‘œ์‹œ ---โ‘ง
for i in contour:
    for j in i:
        cv2.circle(img, tuple(j[0]), 1, (255,0,0), -1) 

# ์ปจํˆฌ์–ด ๊ผญ์ง€์  ์ขŒํ‘œ๋ฅผ ์ž‘์€ ํŒŒ๋ž‘์ƒ‰ ์ (์›)์œผ๋กœ ํ‘œ์‹œ ---โ‘จ
for i in contour2:
    for j in i:
        cv2.circle(img2, tuple(j[0]), 1, (255,0,0), -1) 

# ๊ฒฐ๊ณผ ์ถœ๋ ฅ ---โ‘ฉ
cv2.imshow('CHAIN_APPROX_NONE', img)
cv2.imshow('CHAIN_APPROX_SIMPLE', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

ValueError: not enough values to unpack (expected 3, got 2)

ํ  ๋„Œ ๋ญ” ์—๋Ÿฌ๋ƒ!

 

cv2.CHAIN_APPROX_SIMPLE ๊ผญ์ง“์ ๋งŒ ํ‘œ์‹œ
cv2.CHAIN_APPROX_NONE ๋ชจ๋“  ์ขŒํ‘œ์— ์ปจํˆฌ์–ด๊ทธ๋ฆฌ๊ธฐ

- ์œ„ : cv2.CHAIN_APPROX_SIMPLE์„ ์‚ฌ์šฉํ•ด์„œ ๊ผญ์ง“์ ๋งŒ ํ‘œ์‹œ

- ์•„๋ž˜ : cv2.CHAIN_APPROX_NONE์„ ์‚ฌ์šฉํ•ด์„œ ๋ชจ๋“  ์ขŒํ‘œ์— ์ปจํˆฌ์–ด๋ฅผ ๊ทธ๋ฆฌ๊ธฐ

 

 

 

 

 

+)  ํŠธ๋ฆฌ ๊ณ„์ธต์˜ ์ปจํˆฌ์–ด

# ์ปจํˆฌ์–ด ๊ณ„์ธต ํŠธ๋ฆฌ
import cv2
import numpy as np

# ์˜์ƒ ์ฝ๊ธฐ
img = cv2.imread('img/shapes_donut.png')
img2 = img.copy()
# ๋ฐ”์ด๋„ˆ๋ฆฌ ์ด๋ฏธ์ง€๋กœ ๋ณ€ํ™˜
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, imthres = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY_INV)

# ๊ฐ€์žฅ ๋ฐ”๊นฅ ์ปจํˆฌ์–ด๋งŒ ์ˆ˜์ง‘   --- โ‘ 
im2, contour, hierarchy = cv2.findContours(imthres, cv2.RETR_EXTERNAL, \
                                                cv2.CHAIN_APPROX_NONE)
# ์ปจํˆฌ์–ด ๊ฐฏ์ˆ˜์™€ ๊ณ„์ธต ํŠธ๋ฆฌ ์ถœ๋ ฅ --- โ‘ก
print(len(contour), hierarchy)

# ๋ชจ๋“  ์ปจํˆฌ์–ด๋ฅผ ํŠธ๋ฆฌ ๊ณ„์ธต ์œผ๋กœ ์ˆ˜์ง‘ ---โ‘ข
im2, contour2, hierarchy = cv2.findContours(imthres, cv2.RETR_TREE, \
                                            cv2.CHAIN_APPROX_SIMPLE)
# ์ปจํˆฌ์–ด ๊ฐฏ์ˆ˜์™€ ๊ณ„์ธต ํŠธ๋ฆฌ ์ถœ๋ ฅ ---โ‘ฃ
print(len(contour2), hierarchy)

# ๊ฐ€์žฅ ๋ฐ”๊นฅ ์ปจํˆฌ์–ด๋งŒ ๊ทธ๋ฆฌ๊ธฐ ---โ‘ค
cv2.drawContours(img, contour, -1, (0,255,0), 3)
# ๋ชจ๋“  ์ปจํˆฌ์–ด ๊ทธ๋ฆฌ๊ธฐ ---โ‘ฅ
for idx, cont in enumerate(contour2): 
    # ๋žœ๋คํ•œ ์ปฌ๋Ÿฌ ์ถ”์ถœ ---โ‘ฆ
    color = [int(i) for i in np.random.randint(0,255, 3)]
    # ์ปจํˆฌ์–ด ์ธ๋ฑ์Šค ๋งˆ๋‹ค ๋žœ๋คํ•œ ์ƒ‰์ƒ์œผ๋กœ ๊ทธ๋ฆฌ๊ธฐ ---โ‘ง
    cv2.drawContours(img2, contour2, idx, color, 3)
    # ์ปจํˆฌ์–ด ์ฒซ ์ขŒํ‘œ์— ์ธ๋ฑ์Šค ์ˆซ์ž ํ‘œ์‹œ ---โ‘จ
    cv2.putText(img2, str(idx), tuple(cont[0][0]), cv2.FONT_HERSHEY_PLAIN, \
                                                            1, (0,0,255))

# ํ™”๋ฉด ์ถœ๋ ฅ
cv2.imshow('RETR_EXTERNAL', img)
cv2.imshow('RETR_TREE', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.RETR_EXTERNAL ๊ทธ๋ฆผ์˜ ์™ธ๊ณฝ ๋ถ€๋ถ„์—๋งŒ ์ปจํˆฌ์–ด๋ฅผ ๊ทธ๋ฆฌ๊ธฐ
cv2.RETR_TREE์„ ์‚ฌ์šฉํ•ด์„œ ๋ชจ๋“  ๊ฒฝ๊ณ„์— ์ปจํˆฌ์–ด๋ฅผ ๊ทธ๋ฆฌ๊ธฐ

- ์œ„ : cv2.RETR_EXTERNAL์„ ์‚ฌ์šฉํ•ด์„œ ๊ทธ๋ฆผ์˜ ์™ธ๊ณฝ ๋ถ€๋ถ„์—๋งŒ ์ปจํˆฌ์–ด๋ฅผ ๊ทธ๋ฆฌ๊ธฐ

- ์•„๋ž˜ : cv2.RETR_TREE์„ ์‚ฌ์šฉํ•ด์„œ ๋ชจ๋“  ๊ฒฝ๊ณ„์— ์ปจํˆฌ์–ด๋ฅผ ๊ทธ๋ฆฌ๊ธฐ

- ์ด๋ฅผ ํŠธ๋ฆฌ ๊ณ„์ธต ์ปจํˆฌ์–ด

 

 

 

 

2. ์ปจํˆฌ์–ด๋ฅผ ๊ฐ์‹ธ๋Š” ๋„ํ˜• ๊ทธ๋ฆฌ๊ธฐ

x, y, w, h = cv2.boundingRect(contour)

: ์ขŒํ‘œ๋ฅผ ๊ฐ์‹ธ๋Š” ์‚ฌ๊ฐํ˜• ๋ฐ˜ํ™˜

- x, y : ์‚ฌ๊ฐํ˜•์˜ ์™ผ์ชฝ ์ƒ๋‹จ ์ขŒํ‘œ

- w, h : ์‚ฌ๊ฐํ˜•์˜ ํญ๊ณผ ๋†’์ด

 

rotateRect = cv2.minAreaRect(contour)

: ์ขŒํ‘œ๋ฅผ ๊ฐ์‹ธ๋Š” ์ตœ์†Œํ•œ์˜ ์‚ฌ๊ฐํ˜• ๊ณ„์‚ฐ

 

vertex = cv2.boxPoints(rotateRect)

: rotateRect๋กœ๋ถ€ํ„ฐ ๊ผญ์ง“์  ์ขŒํ‘œ ๊ณ„์‚ฐ

- vertex : 4๊ฐœ์˜ ๊ผญ์ง“์  ์ขŒํ‘œ, ์†Œ์ˆ˜์  ํฌํ•จ์ด๋ฏ€๋กœ ์ •์ˆ˜ ๋ณ€ํ™˜ ํ•„์š”

 

center, radius = cv2.minEnclosingCircle(contour)

: ์ขŒํ‘œ๋ฅผ ๊ฐ์‹ธ๋Š” ์ตœ์†Œํ•œ์˜ ๋™๊ทธ๋ผ๋ฏธ ๊ณ„์‚ฐ

- center : ์›์  ์ขŒํ‘œ(x, y)

- radius : ๋ฐ˜์ง€๋ฆ„

 

area, triangle = cv2.minEnclosingTriangle(points)

: ์ขŒํ‘œ๋ฅผ ๊ฐ์‹ธ๋Š” ์ตœ์†Œํ•œ์˜ ์‚ผ๊ฐํ˜• ๊ฒŒ์‚ฐ

- area : ๋„“์ด

- triangle : 3๊ฐœ์˜ ๊ผญ์ง“์  ์ขŒํ‘œ

 

ellipse = cv2.fitEllipse(points)

: ์ขŒํ‘œ๋ฅผ ๊ฐ์‹ธ๋Š” ์ตœ์†Œํ•œ์˜ ํƒ€์› ๊ณ„์‚ฐ

 

line = cv2.fitLine(points, distType, param, reps, aeps, line)

: ์ค‘์‹ฌ์ ์„ ํ†ต๊ณผํ•˜๋Š” ์ง์„  ๊ณ„์‚ฐ

- distType : ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ ๋ฐฉ์‹

  • cv2.DIST_L2
  • cv2.DIST_L1
  • cv2.DIST_L12
  • cv2.DIST_FAIR
  • cv2.DIST_WELSCH
  • cv2.DIST_HUBER

- param : distType์— ์ „๋‹ฌํ•  ์ธ์ž, 0 = ์ตœ์  ๊ฐ’ ์„ ํƒ

- reps : ๋ฐ˜์ง€๋ฆ„ ์ •ํ™•๋„, ์„ ๊ณผ ์›๋ณธ ์ขŒํ‘œ์˜ ๊ฑฐ๋ฆฌ, 0.01 ๊ถŒ์žฅ

- aeps : ๊ฐ๋„ ์ •ํ™•๋„, 0.01 ๊ถŒ์žฅ

- line(optional) : vx, vy ์ •๊ทœํ™”๋œ ๋‹จ์œ„ ๋ฒกํ„ฐ, x0, y0: ์ค‘์‹ฌ์  ์ขŒํ‘œ

# ์ปจํˆฌ์–ด๋ฅผ ๊ฐ์‹ธ๋Š” ๋„ํ˜• ๊ทธ๋ฆฌ๊ธฐ
import cv2
import numpy as np

# ์ด๋ฏธ์ง€ ์ฝ์–ด์„œ ๊ทธ๋ ˆ์ด์Šค์ผ€์ผ ๋ณ€ํ™˜, ๋ฐ”์ด๋„ˆ๋ฆฌ ์Šค์ผ€์ผ ๋ณ€ํ™˜
img = cv2.imread("img/lighting.JPG")
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, th = cv2.threshold(imgray, 127,255,cv2.THRESH_BINARY_INV)

# ์ปจํŠœ์–ด ์ฐพ๊ธฐ
im, contours, hr = cv2.findContours(th, cv2.RETR_EXTERNAL, \
                                        cv2.CHAIN_APPROX_SIMPLE)
contr = contours[0]

# ๊ฐ์‹ธ๋Š” ์‚ฌ๊ฐํ˜• ํ‘œ์‹œ(๊ฒ€์ •์ƒ‰)
x,y,w,h = cv2.boundingRect(contr)
cv2.rectangle(img, (x,y), (x+w, y+h), (0,0,0), 3)

# ์ตœ์†Œํ•œ์˜ ์‚ฌ๊ฐํ˜• ํ‘œ์‹œ(์ดˆ๋ก์ƒ‰)
rect = cv2.minAreaRect(contr)
box = cv2.boxPoints(rect)   # ์ค‘์‹ฌ์ ๊ณผ ๊ฐ๋„๋ฅผ 4๊ฐœ์˜ ๊ผญ์ง€์  ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜
box = np.int0(box)          # ์ •์ˆ˜๋กœ ๋ณ€ํ™˜
cv2.drawContours(img, [box], -1, (0,255,0), 3)

# ์ตœ์†Œํ•œ์˜ ์› ํ‘œ์‹œ(ํŒŒ๋ž‘์ƒ‰)
(x,y), radius = cv2.minEnclosingCircle(contr)
cv2.circle(img, (int(x), int(y)), int(radius), (255,0,0), 2)

# ์ตœ์†Œํ•œ์˜ ์‚ผ๊ฐํ˜• ํ‘œ์‹œ(๋ถ„ํ™์ƒ‰)
ret, tri = cv2.minEnclosingTriangle(contr)
cv2.polylines(img, [np.int32(tri)], True, (255,0,255), 2)

# ์ตœ์†Œํ•œ์˜ ํƒ€์› ํ‘œ์‹œ(๋…ธ๋ž‘์ƒ‰)
ellipse = cv2.fitEllipse(contr)
cv2.ellipse(img, ellipse, (0,255,255), 3)

# ์ค‘์‹ฌ์  ํ†ต๊ณผํ•˜๋Š” ์ง์„  ํ‘œ์‹œ(๋นจ๊ฐ•์ƒ‰)
[vx,vy,x,y] = cv2.fitLine(contr, cv2.DIST_L2,0,0.01,0.01)
cols,rows = img.shape[:2]
cv2.line(img,(0, 0-x*(vy/vx) + y), (cols-1, (cols-x)*(vy/vx) + y), \
                                                        (0,0,255),2)

# ๊ฒฐ๊ณผ ์ถœ๋ ฅ
cv2.imshow('Bound Fit shapes', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

๋˜ ์•ˆ๋จ ใ…กใ…ก

๊นŒ๋งŒ ๋ฒˆ๊ฐœ ๋‘˜๋Ÿฌ์‹ผ ์—ฌ๋Ÿฌ ๋„ํ˜• ๊ทธ๋ฆฌ๊ธฐ

 

 

 

 

 

3. ์ปจํˆฌ์–ด ๋‹จ์ˆœํ™”

: ๊ทผ์‚ฌ ๊ฐ’์œผ๋กœ ์ปจํˆฌ์–ด ๊ณ„์‚ฐ

 

approx = cv2.approxPolyDP(contour, epsilon, closed)
- contour : ๋Œ€์ƒ ์ปจํˆฌ์–ด ์ขŒํ‘œ
- epsilon : ๊ทผ์‚ฌ ๊ฐ’ ์ •ํ™•๋„, ์˜ค์ฐจ ๋ฒ”์œ„
- closed : ์ปจํˆฌ์–ด์˜ ๋‹ซํž˜ ์—ฌ๋ถ€
- approx : ๊ทผ์‚ฌ ๊ณ„์‚ฐํ•œ ์ปจํˆฌ์–ด ์ขŒํ‘œ

# ๊ทผ์‚ฌ ์ปจํˆฌ์–ด
import cv2
import numpy as np

img = cv2.imread('img/bad_rect.png')
img2 = img.copy()

# ๊ทธ๋ ˆ์ด์Šค์ผ€์ผ๊ณผ ๋ฐ”์ด๋„ˆ๋ฆฌ ์Šค์ผ€์ผ ๋ณ€ํ™˜
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 
ret, th = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY)

# ์ปจํˆฌ์–ด ์ฐพ๊ธฐ ---โ‘ 
temp, contours, hierachy = cv2.findContours(th, cv2.RETR_EXTERNAL, \
                                     cv2.CHAIN_APPROX_SIMPLE)


contour = contours[0]
# ์ „์ฒด ๋‘˜๋ ˆ์˜ 0.05๋กœ ์˜ค์ฐจ ๋ฒ”์œ„ ์ง€์ • ---โ‘ก
epsilon = 0.05 * cv2.arcLength(contour, True)
# ๊ทผ์‚ฌ ์ปจํˆฌ์–ด ๊ณ„์‚ฐ ---โ‘ข
approx = cv2.approxPolyDP(contour, epsilon, True)

# ๊ฐ๊ฐ ์ปจํˆฌ์–ด ์„  ๊ทธ๋ฆฌ๊ธฐ ---โ‘ฃ
cv2.drawContours(img, [contour], -1, (0,255,0), 3)
cv2.drawContours(img2, [approx], -1, (0,255,0), 3)

# ๊ฒฐ๊ณผ ์ถœ๋ ฅ
cv2.imshow('contour', img)
cv2.imshow('approx', img2)
cv2.waitKey()
cv2.destroyAllWindows()

ValueError: not enough values to unpack (expected 3, got 2)

cv2 ๋ฒ„์ „์ด ๋‹ค๋ฅด๋ฉด,, ์•ˆ๋˜๋Š”๊ฑด๊ฐ€

์ปจํˆฌ์–ด
cv2.approPolyDP()๋กœ ๋‚˜๋จธ์ง€ ๋ฌด์‹œ!

- cv2.approPolyDP() ๋Š” ์š”์ฒ  ๋ถ€๋ถ„ ๋ฌด์‹œํ•˜๊ณ  ์ปจํˆฌ์–ด ๊ณ„์‚ฐ

 

 

 

+) ์ปจํˆฌ์–ด ๋‹จ์ˆœํ™”_ ๋ณผ๋ก ์„ ์ฒด(convex hull)

: ๋ณผ๋ก ์„ ์ฒด๋ž€ ์–ด๋Š ํ•œ ๋ถ€๋ถ„๋„ ์˜ค๋ชฉํ•˜์ง€ ์•Š์€ ๋„ํ˜•์„ ์˜๋ฏธ

: ๋Œ€์ƒ์„ ์™„์ „ํžˆ ํฌํ•จํ•˜๋Š” ์™ธ๊ณฝ ์˜์—ญ์„ ์ฐพ๋Š”๋ฐ ์œ ์šฉ

 

hull = cv2.convexHull(points, hull, clockwise, returnPoints)

: ๋ณผ๋ก ์„ ์ฒด ๊ณ„์‚ฐ
- points : ์ž…๋ ฅ ์ปจํˆฌ์–ด
- hull(optional) : ๋ณผ๋ก ์„ ์ฒด ๊ฒฐ๊ณผ
- clockwise(optional) : ๋ฐฉํ–ฅ ์ง€์ • (True: ์‹œ๊ณ„ ๋ฐฉํ–ฅ)
- returnPoints(optional) : ๊ฒฐ๊ณผ ์ขŒํ‘œ ํ˜•์‹ ์„ ํƒ (True: ๋ณผ๋ก ์„ ์ฒด ์ขŒํ‘œ ๋ณ€ํ™˜, False: ์ž…๋ ฅ ์ปจํˆฌ์–ด ์ค‘์— ๋ณผ๋ก ์„ ์ฒด์— ํ•ด๋‹นํ•˜๋Š” ์ธ๋ฑ์Šค ๋ฐ˜ํ™˜)

 

retval = cv2.isContourConvex(contour)

: ๋ณผ๋ก ์„ ์ฒด ๋งŒ์กฑ ์—ฌ๋ถ€ ํ™•์ธ
- retval : True์ธ ๊ฒฝ์šฐ ๋ณผ๋ก ์„ ์ฒด์ž„

 

defects = cv2.convexityDefects(contour, convexhull)

: ๋ณผ๋ก ์„ ์ฒด ๊ฒฐํ•จ ์ฐพ๊ธฐ
- contour : ์ž…๋ ฅ ์ปจํˆฌ์–ด
- convexhull : ๋ณผ๋ก ์„ ์ฒด์— ํ•ด๋‹นํ•˜๋Š” ์ปจํˆฌ์–ด์˜ ์ธ๋ฑ์Šค
- defects : ๋ณผ๋ก ์„ ์ฒด ๊ฒฐํ•จ์ด ์žˆ๋Š” ์ปจํˆฌ์–ด์˜ ๋ฐฐ์—ด ์ธ๋ฑ์Šค, N x 1 x 4 ๋ฐฐ์—ด, [starts, end, farthest, distance]
- start : ์˜ค๋ชฉํ•œ ๊ฐ์ด ์‹œ์ž‘๋˜๋Š” ์ปจํˆฌ์–ด์˜ ์ธ๋ฑ์Šค
- end : ์˜ค๋ชฉํ•œ ๊ฐ์ด ๋๋‚˜๋Š” ์ปจํˆฌ์–ด์˜ ์ธ๋ฑ์Šค
- farthest : ๋ณผ๋ก ์„ ์ฒด์—์„œ ๊ฐ€์žฅ ๋จผ ์˜ค๋ชฉํ•œ ์ง€์ ์˜ ์ปจํˆฌ์–ด ์ธ๋ฑ์Šค
- distance : farthest์™€ ๋ณผ๋ก ์„ ์ฒด์™€์˜ ๊ฑฐ๋ฆฌ

# ๋ณผ๋ก ์„ ์ฒด
import cv2
import numpy as np

img = cv2.imread('img/hand.png')
img2 = img.copy()
# ๊ทธ๋ ˆ์ด ์Šค์ผ€์ผ ๋ฐ ๋ฐ”์ด๋„ˆ๋ฆฌ ์Šค์ผ€์ผ ๋ณ€ํ™˜ ---โ‘ 
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, th = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)

# ์ปจํˆฌ์–ด ์ฐพ๊ธฐ์™€ ๊ทธ๋ฆฌ๊ธฐ ---โ‘ก
temp, contours, heiarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, \
                                         cv2.CHAIN_APPROX_SIMPLE)
cntr = contours[0]
cv2.drawContours(img, [cntr], -1, (0, 255,0), 1)

# ๋ณผ๋ก ์„ ์ฒด ์ฐพ๊ธฐ(์ขŒํ‘œ ๊ธฐ์ค€)์™€ ๊ทธ๋ฆฌ๊ธฐ ---โ‘ข
hull = cv2.convexHull(cntr)
cv2.drawContours(img2, [hull], -1, (0,255,0), 1)
# ๋ณผ๋ก ์„ ์ฒด ๋งŒ์กฑ ์—ฌ๋ถ€ ํ™•์ธ ---โ‘ฃ
print(cv2.isContourConvex(cntr), cv2.isContourConvex(hull))

# ๋ณผ๋ก ์„ ์ฒด ์ฐพ๊ธฐ(์ธ๋ฑ์Šค ๊ธฐ์ค€) ---โ‘ค
hull2 = cv2.convexHull(cntr, returnPoints=False)
# ๋ณผ๋ก ์„ ์ฒด ๊ฒฐํ•จ ์ฐพ๊ธฐ ---โ‘ฅ
defects = cv2.convexityDefects(cntr, hull2)
# ๋ณผ๋ก ์„ ์ฒด ๊ฒฐํ•จ ์ˆœํšŒ
for i in range(defects.shape[0]):
    # ์‹œ์ž‘, ์ข…๋ฃŒ, ๊ฐ€์žฅ ๋จผ ์ง€์ , ๊ฑฐ๋ฆฌ ---โ‘ฆ
    startP, endP, farthestP, distance = defects[i, 0]
    # ๊ฐ€์žฅ ๋จผ ์ง€์ ์˜ ์ขŒํ‘œ ๊ตฌํ•˜๊ธฐ ---โ‘ง
    farthest = tuple(cntr[farthestP][0])
    # ๊ฑฐ๋ฆฌ๋ฅผ ๋ถ€๋™ ์†Œ์ˆ˜์ ์œผ๋กœ ๋ณ€ํ™˜ ---โ‘จ
    dist = distance/256.0
    # ๊ฑฐ๋ฆฌ๊ฐ€ 1๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ ---โ‘ฉ
    if dist > 1 :
        # ๋นจ๊ฐ•์ƒ‰ ์  ํ‘œ์‹œ 
        cv2.circle(img2, farthest, 3, (0,0,255), -1)
# ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ํ‘œ์‹œ
cv2.imshow('contour', img)
cv2.imshow('convex hull', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

ํ›„ํ›„.. ์ด๋ ‡๊ฒŒ ๋‚˜์˜ค๋ฉด ์•ˆ๋œ๋‹น!!
์ด๋ ‡๊ฒŒ ๋‚˜์™€์•ผ๋จ,,

- ๋ฐ‘ ์™ผ์ชฝ : ์† ๋ชจ์–‘ ์ปจํˆฌ์–ด

- ๋ฐ‘ ์˜ค๋ฅธ์ชฝ : ๋ณผ๋ก ์„ ์ฒด + ์„ ์ฒด์˜ ๊ฒฐ์ 

 

 

 

 

 

 

4. ์ปจํˆฌ์–ด์™€ ๋„ํ˜• ๋งค์นญ

: ์„œ๋กœ ๋‹ค๋ฅธ ๋ฌผ์ฒด์˜ ์ปจํˆฌ์–ด๋ฅผ ๋น„๊ตํ•˜๋ฉด ๋‘ ๋ฌผ์ฒด๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋น„์Šทํ•œ์ง€ ์•Œ์ˆ˜ ์žˆ๋‹ค

 

retval = cv2.matchShapes(contour1, contour2, method, parameter)

: ๋‘ ๊ฐœ์˜ ์ปจํˆฌ์–ด๋กœ ๋„ํ˜• ๋งค์นญ
- contour1, contour2 : ๋น„๊ตํ•  ๋‘ ๊ฐœ์˜ ์ปจํˆฌ์–ด
- method : ํœด ๋ชจ๋ฉ˜ํŠธ ๋น„๊ต ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ ํƒ ํ”Œ๋ž˜๊ทธ

  • cv2.CONTOURS_MATCH_I1
  • cv2.CONTOURS_MATCH_I2
  • cv2.CONTOURS_MATCH_I3

- parameter : ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ์ „๋‹ฌ์„ ์œ„ํ•œ ์˜ˆ๋น„ ์ธ์ˆ˜๋กœ 0์œผ๋กœ ๊ณ ์ •

- retval : ๋‘ ๋„ํ˜•์˜ ๋‹ฎ์€ ์ •๋„ (0=๋™์ผ, ์ˆซ์ž๊ฐ€ ํด์ˆ˜๋ก ๋‹ค๋ฆ„)

# ๋„ํ˜• ๋งค์นญ์œผ๋กœ ๋น„์Šทํ•œ ๋„ํ˜• ์ฐพ๊ธฐ
import cv2
import numpy as np

# ๋งค์นญ์„ ์œ„ํ•œ ์ด๋ฏธ์ง€ ์ฝ๊ธฐ
target = cv2.imread('img/4star.jpg') # ๋งค์นญ ๋Œ€์ƒ
shapes = cv2.imread('img/shapestomatch.jpg') # ์—ฌ๋Ÿฌ ๋„ํ˜•
# ๊ทธ๋ ˆ์ด ์Šค์ผ€์ผ ๋ณ€ํ™˜
targetGray = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
shapesGray = cv2.cvtColor(shapes, cv2.COLOR_BGR2GRAY)
# ๋ฐ”์ด๋„ˆ๋ฆฌ ์Šค์ผ€์ผ ๋ณ€ํ™˜
ret, targetTh = cv2.threshold(targetGray, 127, 255, cv2.THRESH_BINARY_INV)
ret, shapesTh = cv2.threshold(shapesGray, 127, 255, cv2.THRESH_BINARY_INV)
# ์ปจํˆฌ์–ด ์ฐพ๊ธฐ
_, cntrs_target, _ = cv2.findContours(targetTh, cv2.RETR_EXTERNAL, \
                                            cv2.CHAIN_APPROX_SIMPLE)
_, cntrs_shapes, _ = cv2.findContours(shapesTh, cv2.RETR_EXTERNAL, \
                                            cv2.CHAIN_APPROX_SIMPLE)

# ๊ฐ ๋„ํ˜•๊ณผ ๋งค์นญ์„ ์œ„ํ•œ ๋ฐ˜๋ณต๋ฌธ
matchs = [] # ์ปจํˆฌ์–ด์™€ ๋งค์นญ ์ ์ˆ˜๋ฅผ ๋ณด๊ด€ํ•  ๋ฆฌ์ŠคํŠธ
for contr in cntrs_shapes:
    # ๋Œ€์ƒ ๋„ํ˜•๊ณผ ์—ฌ๋Ÿฌ ๋„ํ˜• ์ค‘ ํ•˜๋‚˜์™€ ๋งค์นญ ์‹คํ–‰ ---โ‘ 
    match = cv2.matchShapes(cntrs_target[0], contr, cv2.CONTOURS_MATCH_I2, 0.0)
    # ํ•ด๋‹น ๋„ํ˜•์˜ ๋งค์นญ ์ ์ˆ˜์™€ ์ปจํˆฌ์–ด๋ฅผ ์Œ์œผ๋กœ ์ €์žฅ ---โ‘ก
    matchs.append( (match, contr) )
    # ํ•ด๋‹น ๋„ํ˜•์˜ ์ปจํˆฌ์–ด ์‹œ์ž‘์ง€์ ์— ๋งค์นญ ์ ์ˆ˜ ํ‘œ์‹œ ---โ‘ข
    cv2.putText(shapes, '%.2f'%match, tuple(contr[0][0]),\
                    cv2.FONT_HERSHEY_PLAIN, 1,(0,0,255),1 )
# ๋งค์นญ ์ ์ˆ˜๋กœ ์ •๋ ฌ ---โ‘ฃ
matchs.sort(key=lambda x : x[0])
# ๊ฐ€์žฅ ์ ์€ ๋งค์นญ ์ ์ˆ˜๋ฅผ ์–ป๋Š” ๋„ํ˜•์˜ ์ปจํˆฌ์–ด์— ์„  ๊ทธ๋ฆฌ๊ธฐ ---โ‘ค
cv2.drawContours(shapes, [matchs[0][1]], -1, (0,255,0), 3)
cv2.imshow('target', target)
cv2.imshow('Match Shape', shapes)
cv2.waitKey()
cv2.destroyAllWindows()

๋ฐ‘ target ์— ๊ฐ€์žฅ ์œ ์‚ฌํ•œ ๋„ํ˜• ์ฐพ๊ธฐ
target

- ์ˆซ์ž๊ฐ€ ์ž‘์„ ์ˆ˜๋ก ์„œ๋กœ ๋‹ฎ์€ ๋„ํ˜•

- ๊ฐ€์žฅ ๋‹ฎ์€ ๋„ํ˜• ์ฃผ์œ„์— ์ดˆ๋ก์ƒ‰ ์ปจํˆฌ์–ด ๊ทธ๋ฆฌ๊ธฐ

 

 

 

 

 

์†์ƒํ•ด ใ… ใ… 

์ปจํˆฌ์–ด ์‹คํ–‰์ด ์•ˆ๋œ๋‹ค ใ… ใ… 

728x90
๋ฐ˜์‘ํ˜•
Comments