π 곡λΆνλ μ§μ§μνμΉ΄λ μ²μμ΄μ§?
[v0.16]μμμ²λ¦¬_μ΄λ―Έμ§ λ€νκΈ° λ³Έλ¬Έ
[v0.16]μμμ²λ¦¬_μ΄λ―Έμ§ λ€νκΈ°
μ§μ§μνμΉ΄ 2022. 1. 7. 23:56220107 μμ±
<λ³Έ λΈλ‘κ·Έλ κ·νμ΄ μμ¬λμ λΈλ‘κ·Έλ₯Ό μ°Έκ³ ν΄μ 곡λΆνλ©° μμ±νμμ΅λλ€>
OpenCV - 14. μ΄λ―Έμ§ λ€νκΈ°(μ΄ν λ³ν, μκ·Ό λ³ν)
μ΄λ² ν¬μ€ν μμλ μ΄λ―Έμ§λ₯Ό λ€νΈλ λ°©λ²μ λν΄ μμλ³΄κ² μ΅λλ€. μ΄λ² ν¬μ€ν μμ 'νμ΄μ¬μΌλ‘ λ§λλ OpenCV νλ‘μ νΈ(μ΄μΈμ° μ )'λ₯Ό μ 리ν κ²μμ λ°νλλ€. μ½λ: github.com/BaekKyunShin/OpenCV_Pr
bkshin.tistory.com
1. μ΄ν λ³ν (Affine Transform)
: λ€νκΈ°
martix = cv2.getAffineTransform(pts1, pts2)
: μ΄λ―Έμ§λ₯Ό 2μ°¨μμΌλ‘ λ€νΈλ λ³ν
: 3κ°μ μ’νμΈ pts1μ΄ pts2λ‘ μμΉκ° λ³ν λ§νΌ μ΄λ―Έμ§λ₯Ό λ€νΌλ€
- pts1 : λ³ν μ μμμ μ’ν 3κ°, 3 x 2 λ°°μ΄
- pts2 : λ³ν ν μμμ μ’ν 3κ°, 3 x 2 λ°°μ΄
- matrix : λ³ν νλ ¬ λ°ν, 2 x 3 νλ ¬
# μ΄ν λ³ν
import cv2
import numpy as np
from matplotlib import pyplot as plt
file_name = 'img/hobbang2.jpeg'
img = cv2.imread(file_name)
rows, cols = img.shape[:2]
# ---β λ³ν μ , ν κ° 3κ°μ μ’ν μμ±
pts1 = np.float32([[100, 50], [200, 50], [100, 200]])
pts2 = np.float32([[80, 70], [210, 60], [250, 120]])
# ---β‘ λ³ν μ μ’νλ₯Ό μ΄λ―Έμ§μ νμ
cv2.circle(img, (100,50), 5, (255,0), -1)
cv2.circle(img, (200,50), 5, (0,255,0), -1)
cv2.circle(img, (100,200), 5, (0,0,255), -1)
#---β’ μ§μ§μ 3κ°μ μ’νλ‘ λ³ν νλ ¬ κ³μ°
mtrx = cv2.getAffineTransform(pts1, pts2)
#---β£ μ΄ν λ³ν μ μ©
dst = cv2.warpAffine(img, mtrx, (int(cols*1.5), rows))
#---β€ κ²°κ³Ό μΆλ ₯
cv2.imshow('origin',img)
cv2.imshow('affin', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
- μ΄ν λ³ν μ ν 3κ°μ μ’νλ§ μ§μ ν΄μ£Όλ©΄ λ³ν νλ ¬ κ°λ₯
2. μκ·Ό λ³ν (Perspective Transform)
: μ΄λ―Έμ§λ₯Ό 3μ°¨μμΌλ‘ λ³ν
: λ©λ¦¬ μλ κ²μ μκ² λ³΄μ΄κ³ , κ°κΉμ΄ μλ κ²μ ν¬κ² 보μ΄λ κ² μκ·Όλ²
: μκ·Όλ²μ μ리λ₯Ό μ μ©ν΄ λ³ννλ λ°©μμ΄ μκ·Ό λ³ν
mtrx = cv2.getPerspectiveTransform(pts1, pts2)
- pts1 : λ³ν μ΄μ μμμ μ’ν 4κ°, 4 x 2 λ°°μ΄
- pts2 : λ³ν μ΄ν μμμ μ’ν 4κ°, 4 x 2 λ°°μ΄
- mtrx : λ³ννλ ¬ λ°ν, 3 x 3 νλ ¬
- μκ·Ό λ³νμ λ³λμ ν¨μ cv2.warpPerspective() ν¨μμ°κΈ°
# μκ·Ό λ³ν
import cv2
import numpy as np
file_name = 'img/hobbang2.jpeg'
img = cv2.imread(file_name)
rows, cols = img.shape[:2]
#---β μκ·Ό λ³ν μ ν 4κ° μ’ν
pts1 = np.float32([[0,0], [0,rows], [cols, 0], [cols,rows]])
pts2 = np.float32([[100,50], [10,rows-50], [cols-100, 50], [cols-10,rows-50]])
#---β‘ λ³ν μ μ’νλ₯Ό μλ³Έ μ΄λ―Έμ§μ νμ
cv2.circle(img, (0,0), 10, (255,0,0), -1)
cv2.circle(img, (0,rows), 10, (0,255,0), -1)
cv2.circle(img, (cols,0), 10, (0,0,255), -1)
cv2.circle(img, (cols,rows), 10, (0,255,255), -1)
#---β’ μκ·Ό λ³ν νλ ¬ κ³μ°
mtrx = cv2.getPerspectiveTransform(pts1, pts2)
#---β£ μκ·Ό λ³ν μ μ©
dst = cv2.warpPerspective(img, mtrx, (cols, rows))
cv2.imshow("origin", img)
cv2.imshow('perspective', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
- λ€ κ°μ μ’νλ‘ μκ·Όλ² μ²λΌ μ΄λ―Έμ§ λ³κ²½!
+) μκ·Ό λ³νμΌλ‘ μκ·Όκ° μ΄λ―Έμ§λ₯Ό νλ©΄ μ΄λ―Έμ§λ‘ λ³κ²½νκΈ°
# λ§μ°μ€μ μκ·Ό λ³νμΌλ‘ λ¬Έμ μ€μΊ ν¨κ³Ό λ΄κΈ°
import cv2
import numpy as np
win_name = "scanning"
img = cv2.imread("img/Perspective1.jpg")
rows, cols = img.shape[:2]
draw = img.copy()
pts_cnt = 0
pts = np.zeros((4,2), dtype=np.float32)
def onMouse(event, x, y, flags, param): #λ§μ°μ€ μ΄λ²€νΈ μ½λ°± ν¨μ ꡬν ---β
global pts_cnt # λ§μ°μ€λ‘ μ°μ μ’νμ κ°―μ μ μ₯
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(draw, (x,y), 10, (0,255,0), -1) # μ’νμ μ΄λ‘μ λκ·ΈλΌλ―Έ νμ
cv2.imshow(win_name, draw)
pts[pts_cnt] = [x,y] # λ§μ°μ€ μ’ν μ μ₯
pts_cnt+=1
if pts_cnt == 4: # μ’νκ° 4κ° μμ§λ¨
# μ’ν 4κ° μ€ μνμ’μ° μ°ΎκΈ° ---β‘
sm = pts.sum(axis=1) # 4μμ μ’ν κ°κ° x+y κ³μ°
diff = np.diff(pts, axis = 1) # 4μμ μ’ν κ°κ° x-y κ³μ°
topLeft = pts[np.argmin(sm)] # x+yκ° κ°μ₯ κ°μ΄ μ’μλ¨ μ’ν
bottomRight = pts[np.argmax(sm)] # x+yκ° κ°μ₯ ν° κ°μ΄ μ°νλ¨ μ’ν
topRight = pts[np.argmin(diff)] # x-yκ° κ°μ₯ μμ κ²μ΄ μ°μλ¨ μ’ν
bottomLeft = pts[np.argmax(diff)] # x-yκ° κ°μ₯ ν° κ°μ΄ μ’νλ¨ μ’ν
# λ³ν μ 4κ° μ’ν
pts1 = np.float32([topLeft, topRight, bottomRight , bottomLeft])
# λ³ν ν μμμ μ¬μ©ν μλ₯μ νκ³Ό λμ΄ κ³μ° ---β’
w1 = abs(bottomRight[0] - bottomLeft[0]) # μλ¨ μ’μ° μ’νκ°μ 거리
w2 = abs(topRight[0] - topLeft[0]) # νλΉ μ’μ° μ’νκ°μ 거리
h1 = abs(topRight[1] - bottomRight[1]) # μ°μΈ‘ μν μ’νκ°μ 거리
h2 = abs(topLeft[1] - bottomLeft[1]) # μ’μΈ‘ μν μ’νκ°μ 거리
width = max([w1, w2]) # λ μ’μ° κ±°λ¦¬κ°μ μ΅λκ°μ΄ μλ₯μ ν
height = max([h1, h2]) # λ μν 거리κ°μ μ΅λκ°μ΄ μλ₯μ λμ΄
# λ³ν ν 4κ° μ’ν
pts2 = np.float32([[0,0], [width-1,0],
[width-1,height-1], [0,height-1]])
# λ³ν νλ ¬ κ³μ°
mtrx = cv2.getPerspectiveTransform(pts1, pts2)
# μκ·Ό λ³ν μ μ©
result = cv2.warpPerspective(img, mtrx, (width, height))
cv2.imshow('scanned', result)
cv2.imshow(win_name, img)
cv2.setMouseCallback(win_name, onMouse) # λ§μ°μ€ μ½λ°± ν¨μλ₯Ό GUI μλμ°μ λ±λ‘ ---β£
cv2.waitKey(0)
cv2.destroyAllWindows()
- μ μ°μΌλ©΄ λλ κ±° μλκ°μ ...
- IndexError: index 4 is out of bounds for axis 0 with size 4 μλ¬λ¬λΉ..
3. μΌκ°ν μ΄ν λ³ν
1) OpenCVκ° μ 곡νλ κΈ°ννμ λ³νμ κΈ°λ³Έμ μΌλ‘ μ¬κ°νμ΄ κΈ°μ€
2) μΌκ°ν λͺ¨μμ λ³ν
- 1. μ΄ν λ³ν μ μΌκ°ν μ’ν 3κ°λ₯Ό μ νλ€.
- 2. μ΄ν λ³ν ν μΌκ°ν μ’ν 3κ°λ₯Ό μ νλ€.
- 3. λ³ν μ μΌκ°ν μ’νλ₯Ό κ°μΈλ μΈμ μ¬κ°ν μ’νλ₯Ό ꡬνλ€.
- 4. λ³ν ν μΌκ°ν μ’νλ₯Ό κ°μΈλ μΈμ μ¬κ°ν μ’νλ₯Ό ꡬνλ€.
- 5. κ³Όμ 3, 4μ μ¬κ°ν μμμ κ΄μ¬ μμ(ROI, regison of interest)μΌλ‘ μ§μ νλ€.
- 6. κ³Όμ 5μ κ΄μ¬ μμμ κΈ°μ€μΌλ‘ λ³ν μ , νμ μΌκ°ν μ’νλ₯Ό λ€μ κ³μ°νλ€.
- 7. κ³Όμ 6μ λ³ν μ μΌκ°ν μ’νλ₯Ό λ³ν ν μΌκ°ν μ’νλ‘ μ΄ν λ³νν΄μ£Όλ λ³ν νλ ¬μ ꡬνλ€.
- 8. κ³Όμ 7μμ ꡬν λ³ννλ ¬μ μ μ©ν΄ μ΄ν λ³νμ νλ€.
- 9. κ³Όμ 8μμ λ³νλ κ΄μ¬ μμμμ κ³Όμ 2μ μΌκ°ν μ’νλ§ λ§μ€νΉνλ€.
- 10. κ³Όμ 9μμ ꡬν λ§μ€ν¬λ₯Ό μ΄μ©ν΄μ μ΄ν λ³νν μ΄λ―Έμ§μ μλ³Έ μ΄λ―Έμ§λ₯Ό ν©μ±νλ€.
x, y, w, h = cv2.boudingRect(pts)
: μΌκ°ν μ’νλ₯Ό κ°μΈλ μΈμ μ¬κ°ν μ’νλ₯Ό ꡬνκΈ°
- pts : λ€κ°ν μ’ν
- x, y, w, h = μΈμ μ¬κ°νμ μ’νμ νκ³Ό λμ΄
cv2.fillConvexPoly(img, pts, color, lineTypes)
: κ³Όμ 9μ λ§μ€ν¬λ₯Ό ꡬνκΈ°
- img : μ
λ ₯ μ΄λ―Έμ§
- pts : λ€κ°ν μ’ν
- color : λ€κ°νμ μ±μΈ μμ
- lineType(optional) : μ 그리기 μκ³ λ¦¬μ¦ μ ν νλκ·Έ
# μΌκ°ν μ΄ν λ³ν
import cv2
import numpy as np
img = cv2.imread("img/taekwonv1.jpg")
img2 = img.copy()
draw = img.copy()
# λ³ν μ ,ν μΌκ°ν μ’ν ---β
pts1 = np.float32([[188,14], [85,202], [294,216]])
pts2 = np.float32([[128,40], [85,307], [306,167]])
# κ° μΌκ°νμ μμ ν κ°μΈλ μ¬κ°ν μ’ν ꡬνκΈ° ---β‘
x1,y1,w1,h1 = cv2.boundingRect(pts1)
x2,y2,w2,h2 = cv2.boundingRect(pts2)
# μ¬κ°νμ μ΄μ©ν κ΄μ¬μμ μ€μ ---β’
roi1 = img[y1:y1+h1, x1:x1+w1]
roi2 = img2[y2:y2+h2, x2:x2+w2]
# κ΄μ¬μμμ κΈ°μ€μΌλ‘ μ’ν κ³μ° ---β£
offset1 = np.zeros((3,2), dtype=np.float32)
offset2 = np.zeros((3,2), dtype=np.float32)
for i in range(3):
offset1[i][0], offset1[i][1] = pts1[i][0]-x1, pts1[i][1]-y1
offset2[i][0], offset2[i][1] = pts2[i][0]-x2, pts2[i][1]-y2
# κ΄μ¬ μμμ μ£Όμ΄μ§ μΌκ°ν μ’νλ‘ μ΄ν λ³ν ---β€
mtrx = cv2.getAffineTransform(offset1, offset2)
warped = cv2.warpAffine( roi1, mtrx, (w2, h2), None, \
cv2.INTER_LINEAR, cv2.BORDER_REFLECT_101)
# μ΄ν λ³ν ν μΌκ°νλ§ κ³¨λΌ λ΄κΈ° μν λ§μ€ν¬ μμ± ---β₯
mask = np.zeros((h2, w2), dtype = np.uint8)
cv2.fillConvexPoly(mask, np.int32(offset2), (255))
# μΌκ°ν μμλ§ λ§μ€νΉν΄μ ν©μ± ---β¦
warped_masked = cv2.bitwise_and(warped, warped, mask=mask)
roi2_masked = cv2.bitwise_and(roi2, roi2, mask=cv2.bitwise_not(mask))
roi2_masked = roi2_masked + warped_masked
img2[y2:y2+h2, x2:x2+w2] = roi2_masked
# κ΄μ¬ μμκ³Ό μΌκ°νμ μ κ·Έλ €μ μΆλ ₯ ---β§
cv2.rectangle(draw, (x1, y1), (x1+w1, y1+h1), (0,255,0), 1)
cv2.polylines(draw, [pts1.astype(np.int32)], True, (255,0,0), 1)
cv2.rectangle(img2, (x2, y2), (x2+w2, y2+h2), (0,255,0), 1)
cv2.imshow('origin', draw)
cv2.imshow('warped triangle', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
- μ μ κΈ°νκ΅°
μΌλ°
'π©βπ» IoT (Embedded) > Image Processing' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[v0.18]μμμ²λ¦¬_ μ€μ΅νκΈ°(λͺ¨μμ΄ν¬ μ²λ¦¬, 리ν΄νμ΄, μ곑 κ±°μΈ μ΄λ―Έμ§ λ€νκΈ°) (0) | 2022.01.08 |
---|---|
[v0.17]μμμ²λ¦¬_λ μ¦ μ곑νκΈ° (0) | 2022.01.08 |
[v0.15]μμμ²λ¦¬_μ΄λ―Έμ§ μ΄λ, νλ/μΆμ, νμ (0) | 2022.01.06 |
[v0.14]μμμ²λ¦¬_μ΄λ―Έμ§ μ μ¬λ λΉκ΅ μΈ μ€μ΅ (2) | 2022.01.05 |
[v0.13]μμμ²λ¦¬_2μ°¨μ νμ€ν κ·Έλ¨κ³Ό μν¬μ (0) | 2022.01.05 |