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

[v0.17]์˜์ƒ์ฒ˜๋ฆฌ_๋ Œ์ฆˆ ์™œ๊ณกํ•˜๊ธฐ ๋ณธ๋ฌธ

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

[v0.17]์˜์ƒ์ฒ˜๋ฆฌ_๋ Œ์ฆˆ ์™œ๊ณกํ•˜๊ธฐ

์ง•์ง•์•ŒํŒŒ์นด 2022. 1. 8. 00:33
728x90
๋ฐ˜์‘ํ˜•

220108 ์ž‘์„ฑ

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

https://bkshin.tistory.com/entry/OpenCV-15-%EB%A6%AC%EB%A7%A4%ED%95%91Remapping-%EC%98%A4%EB%AA%A9%EB%B3%BC%EB%A1%9D-%EB%A0%8C%EC%A6%88-%EC%99%9C%EA%B3%A1Lens-Distortion-%EB%B0%A9%EC%82%AC-%EC%99%9C%EA%B3%A1Radial-Distortion?category=1148027 

 

OpenCV - 15. ๋ฆฌ๋งคํ•‘(Remapping), ์˜ค๋ชฉ/๋ณผ๋ก ๋ Œ์ฆˆ ์™œ๊ณก(Lens Distortion), ๋ฐฉ์‚ฌ ์™œ๊ณก(Radial Distortion)

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

bkshin.tistory.com

 

 

 

1. ๋ Œ์ฆˆ ์™œ๊ณก (Lens Distortion)

: ๋ Œ์ฆˆ ์™œ๊ณก ๋ณ€ํ™˜์ด ๋ฐ”๋กœ ๋ณ€ํ™˜ ํ–‰๋ ฌ๋กœ๋Š” ๊ตฌํ•  ์ˆ˜ ์—†๋Š” ๋ณ€ํ™˜

: ๋ Œ์ฆˆ ์™œ๊ณก ๋ณ€ํ™˜์—๋Š” ๋ฆฌ๋งคํ•‘, ์˜ค๋ชฉ ๋ Œ์ฆˆ/๋ณผ๋ก ๋ Œ์ฆˆ ์™œ๊ณก, ๋ฐฉ์‚ฌ ์™œ๊ณก ์žˆ์Œ

 

 

 

2. ๋ฆฌ๋งคํ•‘ (Remapping)

: ๊ทœ์น™์„ฑ ์—†์ด ๋งˆ์Œ๋Œ€๋กœ ์ด๋ฏธ์ง€์˜ ๋ชจ์–‘์„ ๋ณ€ํ™˜

 

dst = cv2.remap(src, mapx, mapy, interpolation, dst, borderMode, borderValue)

- src : ์ž…๋ ฅ ์ด๋ฏธ์ง€

mapx, mapy : x์ถ•๊ณผ y์ถ•์œผ๋กœ ์ด๋™ํ•  ์ขŒํ‘œ, src์™€ ๋™์ผํ•œ ํฌ๊ธฐ, dtype=float32

dst(optional) : ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€

๋‚˜๋จธ์ง€ ์ธ์ž๋Š” cv2.warpAffine()๊ณผ ๋™์ผ

- np.indices() ํ•จ์ˆ˜๋ฅผ ์“ฐ๋ฉด ๋น ๋ฅด๊ฒŒ ์ดˆ๊ธฐํ™”

- ๋ฐ˜ํ™˜๋œ ๊ฒฐ๊ณผ์˜ 0๋ฒˆ ์งธ๊ฐ€ ํ–‰ ๋ฐฐ์—ด, 1๋ฒˆ ์งธ๊ฐ€ ์—ด ๋ฐฐ์—ด

import numpy as np
print(np.indices((2,2)))
# [[[0 0]
#   [1 1]]

#  [[0 1]
#   [0 1]]]

print(np.indices((3, 3)))
# [[[0 0 0]
#   [1 1 1]
#   [2 2 2]]

#  [[0 1 2]
#   [0 1 2]
#   [0 1 2]]]

 

 

 

+) ์ด๋ฏธ์ง€๋ฅผ ๋’ค์ง‘๋Š” ์ฝ”๋“œ

: ๋ณ€ํ™˜ ํ–‰๋ ฌ๊ณผ cv2.remap() ํ•จ์ˆ˜ ์‚ฌ์šฉ

x' = cols - x - 1
y' = rows - y - 1

: ๋’ค์ง‘๊ธฐ ์œ„ํ•œ ์—ฐ์‚ฐ์‹

# ๋ณ€ํ™˜ํ–‰๋ ฌ๊ณผ ๋ฆฌ๋งคํ•‘์œผ๋กœ ์ด๋ฏธ์ง€ ๋’ค์ง‘๊ธฐ
import cv2
import numpy as np
import time

img = cv2.imread('img/night.jpg')
rows, cols = img.shape[:2]

# ๋’ค์ง‘๊ธฐ ๋ณ€ํ™˜ ํ–‰๋ ฌ๋กœ ๊ตฌํ˜„ ---โ‘ 
st = time.time()
mflip = np.float32([ [-1, 0, cols-1],[0, -1, rows-1]]) # ๋ณ€ํ™˜ ํ–‰๋ ฌ ์ƒ์„ฑ
fliped1 = cv2.warpAffine(img, mflip, (cols, rows))     # ๋ณ€ํ™˜ ์ ์šฉ
print('matrix:', time.time()-st)

# remap ํ•จ์ˆ˜๋กœ ๋’ค์ง‘๊ธฐ ๊ตฌํ˜„ ---โ‘ก
st2 = time.time()
mapy, mapx = np.indices((rows, cols),dtype=np.float32) # ๋งคํ•‘ ๋ฐฐ์—ด ์ดˆ๊ธฐํ™” ์ƒ์„ฑ
mapx = cols - mapx -1                                  # x์ถ• ์ขŒํ‘œ ๋’ค์ง‘๊ธฐ ์—ฐ์‚ฐ
mapy = rows - mapy -1                                  # y์ถ• ์ขŒํ‘œ ๋’ค์ง‘๊ธฐ ์—ฐ์‚ฐ
fliped2 = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)  # remap ์ ์šฉ
print('remap:', time.time()-st2)

# ๊ฒฐ๊ณผ ์ถœ๋ ฅ ---โ‘ข
cv2.imshow('origin', img)
cv2.imshow('fliped1',fliped1)
cv2.imshow('fliped2',fliped2)
cv2.waitKey()
cv2.destroyAllWindows()

                                              ๋’ค์ง‘๊ธฐ ๋ณ€ํ™˜ ํ–‰๋ ฌ               cv2.remap() ๋กœ ๋ฆฌ๋งคํ•‘

- ๋ณ€ํ™˜ํ–‰๋ ฌ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค cv2.remap()์˜ ์ˆ˜ํ–‰ ์†๋„๊ฐ€ ๋” ๋Š๋ฆผ

- ๋ณ€ํ™˜ํ–‰๋ ฌ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์—†๋Š” ๋น„์„ ํ˜• ๋ณ€ํ™˜์—๋งŒ cv2.remap() ์‚ฌ์šฉ

 

 

 

 

3. ์‚ผ๊ฐํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ ๋น„์„ ํ˜• ๋ฆฌ๋งคํ•‘

# ์‚ผ๊ฐํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ ๋น„์„ ํ˜• ๋ฆฌ๋งคํ•‘
import cv2
import numpy as np

l = 20      # ํŒŒ์žฅ(wave length)
amp = 15    # ์ง„ํญ(amplitude)

img = cv2.imread('img/taekwonv1.jpg')
rows, cols = img.shape[:2]

# ์ดˆ๊ธฐ ๋งคํ•‘ ๋ฐฐ์—ด ์ƒ์„ฑ ---โ‘ 
mapy, mapx = np.indices((rows, cols),dtype=np.float32)

# sin, cos ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•œ ๋ณ€ํ˜• ๋งคํ•‘ ์—ฐ์‚ฐ ---โ‘ก
sinx = mapx + amp * np.sin(mapy/l)  
cosy = mapy + amp * np.cos(mapx/l)

# ์˜์ƒ ๋งคํ•‘ ---โ‘ข

img_sinx=cv2.remap(img, sinx, mapy, cv2.INTER_LINEAR) # x์ถ•๋งŒ sin ๊ณก์„  ์ ์šฉ
img_cosy=cv2.remap(img, mapx, cosy, cv2.INTER_LINEAR) # y์ถ•๋งŒ cos ๊ณก์„  ์ ์šฉ
# x,y ์ถ• ๋ชจ๋‘ sin, cos ๊ณก์„  ์ ์šฉ ๋ฐ ์™ธ๊ณฝ ์˜์—ญ ๋ณด์ •
img_both=cv2.remap(img, sinx, cosy, cv2.INTER_LINEAR, \
                    None, cv2.BORDER_REPLICATE)
# ๊ฒฐ๊ณผ ์ถœ๋ ฅ 
cv2.imshow('origin', img)
cv2.imshow('sin x', img_sinx)
cv2.imshow('cos y', img_cosy)
cv2.imshow('sin cos', img_both)

cv2.waitKey()
cv2.destroyAllWindows()

x์ขŒํ‘œ, y์ขŒํ‘œ์— sin, cos ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•œ ์™œ๊ณก๋œ ์ด๋ฏธ์ง€

- cv2.BORDER_REPLICATE ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์™ธ๊ณฝ ๋ณด์ •๊นŒ์ง€ ํ•ด์ฃผ์–ด ์™ธ๊ณฝ์˜ ์‚ฌ๋ผ์ง„ ์˜์—ญ์ด ๋ณด์ •

 

 

 

 

 

4. ์˜ค๋ชฉ ๋ Œ์ฆˆ์™€ ๋ณผ๋ก ๋ Œ์ฆˆ ์™œ๊ณก

์ขŒํ‘œ ์‹œ์Šคํ…œ์„ ์ง๊ต ์ขŒํ‘œ๊ณ„(Cartesian coordinate system)

: x์ถ•๊ณผ y์ถ•์˜ ์ง๊ฐ์œผ๋กœ ๊ฐ๊ฐ ์„ ์„ ๊ทธ์–ด์„œ ๋งŒ๋‚˜๋Š” ์ง€์ ์„ ์ขŒํ‘œ (x, y)๋กœ ๋‚˜ํƒ€๋‚ด๊ธฐ

: ๊ธฐ์ค€์ ์„ ์ขŒ์ธก ์ƒ๋‹จ์„ ์›์ (0, 0)์œผ๋กœ ์ •ํ•˜๊ธฐ

 

๊ทน์ขŒํ‘œ๊ณ„(Polar coordinate system)

: ์›์ ์œผ๋กœ๋ถ€ํ„ฐ์˜ ๊ฑฐ๋ฆฌ(r)์™€ ์‚ฌ์ž‡๊ฐ(Θ)์„ ์ด์šฉํ•ด์„œ (r, Θ)๋กœ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฉ๋ฒ•

: ๊ธฐ์ค€์ ์„ ์ด๋ฏธ์ง€์˜ ์ค‘์•™์„ ์›์ ์œผ๋กœ ์ •ํ•˜๊ธฐ ( ์ขŒํ‘œ์˜ ๊ฐ’์„ -1 ~ +1 ๋กœ ์ •ํ•œ๋‹ค ) 

์ถœ์ฒ˜: https://suhak.tistory.com/161

: r, theta = cv2.cartToPolar(x, y) : ์ง๊ต ์ขŒํ‘œ → ๊ทน์ขŒํ‘œ ๋ณ€ํ™˜

: x, y = cv2.polarToCart(r, theta) : ๊ทน์ขŒํ‘œ → ์ง๊ต ์ขŒํ‘œ ๋ณ€ํ™˜

# ๋ณผ๋ก/์˜ค๋ชฌ ๋ Œ์ฆˆ ์™œ๊ณก ํšจ๊ณผ
import cv2
import numpy as np

img = cv2.imread('img/taekwonv1.jpg')
print(img.shape)
rows, cols = img.shape[:2]

# ---โ‘  ์„ค์ • ๊ฐ’ ์…‹ํŒ…
exp = 0.5       # ๋ณผ๋ก, ์˜ค๋ชฉ ์ง€์ˆ˜ (์˜ค๋ชฉ : 0.1 ~ 1, ๋ณผ๋ก : 1.1~)
scale = 1           # ๋ณ€ํ™˜ ์˜์—ญ ํฌ๊ธฐ (0 ~ 1)

# ๋งคํ•‘ ๋ฐฐ์—ด ์ƒ์„ฑ ---โ‘ก
mapy, mapx = np.indices((rows, cols),dtype=np.float32)

# ์ขŒ์ƒ๋‹จ ๊ธฐ์ค€์ขŒํ‘œ์—์„œ -1~1๋กœ ์ •๊ทœํ™”๋œ ์ค‘์‹ฌ์  ๊ธฐ์ค€ ์ขŒํ‘œ๋กœ ๋ณ€๊ฒฝ ---โ‘ข
mapx = 2*mapx/(cols-1)-1
mapy = 2*mapy/(rows-1)-1

# ์ง๊ต์ขŒํ‘œ๋ฅผ ๊ทน ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ ---โ‘ฃ
r, theta = cv2.cartToPolar(mapx, mapy)

# ์™œ๊ณก ์˜์—ญ๋งŒ ์ค‘์‹ฌํ™•๋Œ€/์ถ•์†Œ ์ง€์ˆ˜ ์ ์šฉ ---โ‘ค
r[r< scale] = r[r<scale] **exp  

# ๊ทน ์ขŒํ‘œ๋ฅผ ์ง๊ต์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ ---โ‘ฅ
mapx, mapy = cv2.polarToCart(r, theta)

# ์ค‘์‹ฌ์  ๊ธฐ์ค€์—์„œ ์ขŒ์ƒ๋‹จ ๊ธฐ์ค€์œผ๋กœ ๋ณ€๊ฒฝ ---โ‘ฆ
mapx = ((mapx + 1)*cols-1)/2
mapy = ((mapy + 1)*rows-1)/2
# ์žฌ๋งคํ•‘ ๋ณ€ํ™˜
distorted = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)

cv2.imshow('origin', img)
cv2.imshow('distorted', distorted)
cv2.waitKey()
cv2.destroyAllWindows()

์™œ๊ณก ์ง€์ˆ˜ ๋ณ€์ˆ˜๋ฅผ 1 : ์›๋ณธ                1๋ณด๋‹ค ์ž‘์œผ๋ฉด ์˜ค๋ชฉ๋ Œ์ฆˆ             1๋ณด๋‹ค ํฌ๋ฉด ๋ณผ๋ก๋ Œ์ฆˆ       

- exp๋Š” ์ด๋ฏธ์ง€์˜ ์™œ๊ณก ์ง€์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ณ€์ˆ˜

- scale์€ ์ด๋ฏธ์ง€์—์„œ ๋ Œ์ฆˆ ํšจ๊ณผ๋ฅผ ์ฃผ๊ณ  ์‹ถ์€ ์› ๋ชจ์–‘ ์˜์—ญ์˜ ํฌ๊ธฐ๋ฅผ ๋น„์œจ๋กœ ๋‚˜ํƒ€๋‚ธ ๊ฒƒ

 

 

 

 

5. ๋ฐฉ์‚ฌ ์™œ๊ณก

๋ฐฐ๋Ÿด ์™œ๊ณก(barrel distortiaon)

์นด๋ฉ”๋ผ๋ฅผ ํ†ตํ•ด ์ด๋ฏธ์ง€๋ฅผ ์ดฌ์˜ํ•  ๋•Œ ์นด๋ฉ”๋ผ ๊ฐ€์žฅ์ž๋ฆฌ ๋ถ€๋ถ„์—์„œ ์•ฝ๊ฐ„์˜ ์™œ๊ณก

์ถœ์ฒ˜: http://truemind1.blogspot.com/2016/10/06-2-vr-distortion.html

ํ•€์ฟ ์…˜ ์™œ๊ณก(pinsushion distortion)

: ๊ฐ€์žฅ์ž๋ฆฌ ๋ถ€๋ถ„์ด ์•ˆ์ชฝ์œผ๋กœ ๋“ค์–ด๊ฐ€๋Š” ํ˜•ํƒœ์˜ ์™œ๊ณก

์ถœ์ฒ˜: http://egloos.zum.com/eggry/v/4122911

# ๋ฐฐ๋Ÿด ์™œ๊ณก, ํ•€์ฟ ์…˜ ์™œ๊ณก
import cv2
import numpy as np

# ์™œ๊ณก ๊ณ„์ˆ˜ ์„ค์ • ---โ‘ 
#k1, k2, k3 = 0.5, 0.2, 0.0 # ๋ฐฐ๋Ÿด ์™œ๊ณก
k1, k2, k3 = -0.3, 0, 0    # ํ•€ํ์…˜ ์™œ๊ณก

img = cv2.imread('img/night.jpg')
rows, cols = img.shape[:2]

# ๋งคํ•‘ ๋ฐฐ์—ด ์ƒ์„ฑ ---โ‘ก
mapy, mapx = np.indices((rows, cols),dtype=np.float32)

# ์ค‘์•™์  ์ขŒํ‘œ๋กœ -1~1 ์ •๊ทœํ™” ๋ฐ ๊ทน์ขŒํ‘œ ๋ณ€ํ™˜ ---โ‘ข
mapx = 2*mapx/(cols-1)-1
mapy = 2*mapy/(rows-1)-1
r, theta = cv2.cartToPolar(mapx, mapy)

# ๋ฐฉ์‚ฌ ์™œ๊ณก ๋ณ€์˜ ์—ฐ์‚ฐ ---โ‘ฃ
ru = r*(1+k1*(r**2) + k2*(r**4) + k3*(r**6)) 

# ์ง๊ต์ขŒํ‘œ ๋ฐ ์ขŒ์ƒ๋‹จ ๊ธฐ์ค€์œผ๋กœ ๋ณต์› ---โ‘ค
mapx, mapy = cv2.polarToCart(ru, theta)
mapx = ((mapx + 1)*cols-1)/2
mapy = ((mapy + 1)*rows-1)/2
# ๋ฆฌ๋งคํ•‘ ---โ‘ฅ
distored = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)

cv2.imshow('original', img)
cv2.imshow('pinsushion distortion', distored)
cv2.waitKey()
cv2.destroyAllWindows()

   ์›๋ณธ                                   ๋ฐฐ๋Ÿด ์™œ๊ณก                               ํ•€์ฟ ์…˜ ์™œ๊ณก

 -  k1, k2, k3 ๊ฐ’์— ๋”ฐ๋ผ ๋ฐฐ๋Ÿด ์™œ๊ณก or ํ•€์ฟ ์…˜ ์™œ๊ณก์ด ๊ฐ€๋Šฅํ•˜๋‹ค

 

 

 

 

 

์‹ ๊ธฐ๋ฐฉ๊ธฐ~

๋ฐฐ๊ณ ํ”„๋‹น

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