๐ ๊ณต๋ถํ๋ ์ง์ง์ํ์นด๋ ์ฒ์์ด์ง?
[v0.17]์์์ฒ๋ฆฌ_๋ ์ฆ ์๊ณกํ๊ธฐ ๋ณธ๋ฌธ
[v0.17]์์์ฒ๋ฆฌ_๋ ์ฆ ์๊ณกํ๊ธฐ
์ง์ง์ํ์นด 2022. 1. 8. 00:33220108 ์์ฑ
<๋ณธ ๋ธ๋ก๊ทธ๋ ๊ทํ์ด ์์ฌ๋์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํด์ ๊ณต๋ถํ๋ฉฐ ์์ฑํ์์ต๋๋ค>
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() ์ฌ์ฉ
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()
- cv2.BORDER_REPLICATE ํ๋ผ๋ฏธํฐ๋ก ์ธ๊ณฝ ๋ณด์ ๊น์ง ํด์ฃผ์ด ์ธ๊ณฝ์ ์ฌ๋ผ์ง ์์ญ์ด ๋ณด์
4. ์ค๋ชฉ ๋ ์ฆ์ ๋ณผ๋ก ๋ ์ฆ ์๊ณก
์ขํ ์์คํ ์ ์ง๊ต ์ขํ๊ณ(Cartesian coordinate system)
: x์ถ๊ณผ y์ถ์ ์ง๊ฐ์ผ๋ก ๊ฐ๊ฐ ์ ์ ๊ทธ์ด์ ๋ง๋๋ ์ง์ ์ ์ขํ (x, y)๋ก ๋ํ๋ด๊ธฐ
: ๊ธฐ์ค์ ์ ์ข์ธก ์๋จ์ ์์ (0, 0)์ผ๋ก ์ ํ๊ธฐ
๊ทน์ขํ๊ณ(Polar coordinate system)
: ์์ ์ผ๋ก๋ถํฐ์ ๊ฑฐ๋ฆฌ(r)์ ์ฌ์๊ฐ(Θ)์ ์ด์ฉํด์ (r, Θ)๋ก ๋ํ๋ด๋ ๋ฐฉ๋ฒ
: ๊ธฐ์ค์ ์ ์ด๋ฏธ์ง์ ์ค์์ ์์ ์ผ๋ก ์ ํ๊ธฐ ( ์ขํ์ ๊ฐ์ -1 ~ +1 ๋ก ์ ํ๋ค )
: 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()
- exp๋ ์ด๋ฏธ์ง์ ์๊ณก ์ง์๋ฅผ ๋ํ๋ด๋ ๋ณ์
- scale์ ์ด๋ฏธ์ง์์ ๋ ์ฆ ํจ๊ณผ๋ฅผ ์ฃผ๊ณ ์ถ์ ์ ๋ชจ์ ์์ญ์ ํฌ๊ธฐ๋ฅผ ๋น์จ๋ก ๋ํ๋ธ ๊ฒ
5. ๋ฐฉ์ฌ ์๊ณก
๋ฐฐ๋ด ์๊ณก(barrel distortiaon)
: ์นด๋ฉ๋ผ๋ฅผ ํตํด ์ด๋ฏธ์ง๋ฅผ ์ดฌ์ํ ๋ ์นด๋ฉ๋ผ ๊ฐ์ฅ์๋ฆฌ ๋ถ๋ถ์์ ์ฝ๊ฐ์ ์๊ณก
ํ์ฟ ์ ์๊ณก(pinsushion distortion)
: ๊ฐ์ฅ์๋ฆฌ ๋ถ๋ถ์ด ์์ชฝ์ผ๋ก ๋ค์ด๊ฐ๋ ํํ์ ์๊ณก
# ๋ฐฐ๋ด ์๊ณก, ํ์ฟ ์
์๊ณก
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 ํ์ฟ ์ ์๊ณก์ด ๊ฐ๋ฅํ๋ค
์ ๊ธฐ๋ฐฉ๊ธฐ~
๋ฐฐ๊ณ ํ๋น