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

[v0.18]์˜์ƒ์ฒ˜๋ฆฌ_ ์‹ค์Šตํ•˜๊ธฐ(๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ, ๋ฆฌํ€ดํŒŒ์ด, ์™œ๊ณก ๊ฑฐ์šธ ์ด๋ฏธ์ง€ ๋’คํ‹€๊ธฐ) ๋ณธ๋ฌธ

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

[v0.18]์˜์ƒ์ฒ˜๋ฆฌ_ ์‹ค์Šตํ•˜๊ธฐ(๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ, ๋ฆฌํ€ดํŒŒ์ด, ์™œ๊ณก ๊ฑฐ์šธ ์ด๋ฏธ์ง€ ๋’คํ‹€๊ธฐ)

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

220108 ์ž‘์„ฑ

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

https://bkshin.tistory.com/entry/OpenCV-16-%EB%AA%A8%EC%9E%90%EC%9D%B4%ED%81%AC-%EC%B2%98%EB%A6%ACMosaic-%EB%A6%AC%ED%80%B4%ED%8C%8C%EC%9D%B4Liquify-%EC%99%9C%EA%B3%A1-%EA%B1%B0%EC%9A%B8Distortion-Mirror?category=1148027 

 

OpenCV - 16. ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ(Mosaic), ๋ฆฌํ€ดํŒŒ์ด(Liquify), ์™œ๊ณก ๊ฑฐ์šธ(Distortion Mirror)

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

bkshin.tistory.com

 

 

 

 

1. ์‹ค์Šต 1 : ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ

: ์ด๋ฏธ์ง€์˜ ํŠน์ • ์˜์—ญ์„ ๋งˆ์šฐ์Šค๋กœ ํด๋ฆญํ•˜๋ฉด ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ

: ๋ชจ์ž์ดํฌ๋ฅผ ์ ์šฉํ•  ๊ด€์‹ฌ ์˜์—ญ์˜ ์ด๋ฏธ์ง€๋ฅผ ํŠน์ • ๋น„์œจ๋กœ ์ถ•์†Œ์‹œํ‚จ ๋’ค ๋‹ค์‹œ ํ™•๋Œ€

: ํฌ๊ธฐ๊ฐ€ ์ž‘์€ ์ด๋ฏธ์ง€๋ฅผ ์ตœ๋Œ€ ํ”ฝ์…€ ๊ฐ’ ์ด์ƒ์˜ ํฌ๊ธฐ๋กœ ํ™•๋Œ€ํ•˜๋ฉด ์ด๋ฏธ์ง€๊ฐ€ ๊นจ์ง€๋Š” ์›๋ฆฌ๋ฅผ ์ ์šฉ

: ๊ด€์‹ฌ ์˜์—ญ์„ ์ถ•์†Œํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ํ™•๋Œ€ํ•˜๋ฉด ์›๋ž˜์˜ ํ”ฝ์…€๊ณผ ๋น„์Šทํ•˜๊ธด ํ•˜์ง€๋งŒ,

๋ณด๊ฐ„๋ฒ•์— ์˜ํ•ด์„œ ์—ฐ์‚ฐํ•œ ๊ฒฐ๊ณผ๋ผ์„œ ์„ ๋ช…๋„๊ฐ€ ๋–จ์–ด์ ธ ๋ฟŒ์˜‡๊ฒŒ ๋ณด์ž„ (์ด๋•Œ ๋ณด๊ฐ„๋ฒ•์€ cv2.INTER_AREA๋ฅผ ์‚ฌ์šฉ)

# ๋ชจ์ž์ดํฌ ์ฒ˜๋ฆฌ
import cv2

rate = 15               # ๋ชจ์ž์ดํฌ์— ์‚ฌ์šฉํ•  ์ถ•์†Œ ๋น„์œจ (1/rate)
win_title = 'mosaic'    # ์ฐฝ ์ œ๋ชฉ
img = cv2.imread('img/sample.jpeg')    # ์ด๋ฏธ์ง€ ์ฝ๊ธฐ

while True:
    x,y,w,h = cv2.selectROI(win_title, img, False) # ๊ด€์‹ฌ์˜์—ญ ์„ ํƒ
    if w and h:
        roi = img[y:y+h, x:x+w]   # ๊ด€์‹ฌ์˜์—ญ ์ง€์ •
        roi = cv2.resize(roi, (w//rate, h//rate)) # 1/rate ๋น„์œจ๋กœ ์ถ•์†Œ
        # ์›๋ž˜ ํฌ๊ธฐ๋กœ ํ™•๋Œ€
        roi = cv2.resize(roi, (w,h), interpolation=cv2.INTER_AREA)  
        img[y:y+h, x:x+w] = roi   # ์›๋ณธ ์ด๋ฏธ์ง€์— ์ ์šฉ
        cv2.imshow(win_title, img)
    else:
        break
cv2.destroyAllWindows()

rate = 5&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rate = 15&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rate = 25

- rate ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋” ํฐ ๋น„์œจ๋กœ ์ถ•์†Œํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ํ™•๋Œ€๋˜์–ด ํ”ฝ์…€์ด ๋งŽ์ด ๊นจ์ง„๋‹ค

 

 

 

 

2. ์‹ค์Šต 2 : ๋ฆฌํ€ดํŒŒ์ด ๋„๊ตฌ

: ๋ฆฌํ€ดํŒŒ์ด, ์ด๋ฏธ์ง€์˜ ์›ํ•˜๋Š” ๋ถ€๋ถ„๋งŒ ์ž‘๊ฒŒ ํ•˜๊ฑฐ๋‚˜ ํฌ๊ฒŒ ํ•˜๋Š” ๊ธฐ๋Šฅ

: Liquify๋Š” '์•ก์ฒด๋กœ ๋งŒ๋“ค๋‹ค'๋ผ๋Š” ๋œป์œผ๋กœ ์ด๋ฏธ์ง€์˜ ์ผ๋ถ€๋ถ„์„ ์•ก์ฒด์ฒ˜๋Ÿผ ํ๋ฌผ๊ฑฐ๋ฆฌ๊ฒŒ ๋ฐ”๊พธ๋Š” ํšจ๊ณผ

 

- ์‚ฌ๊ฐํ˜• ์˜์—ญ์„ 4๊ฐœ์˜ ์‚ผ๊ฐํ˜• ์˜์—ญ์œผ๋กœ ๋‚˜๋ˆ„๊ธฐ

- ๋งˆ์šฐ์Šค์˜ ์œ„์น˜๋ฅผ ๊ฐ€์šด๋ฐ ๊ต์ฐจ์ ์œผ๋กœ ๋‘๊ธฐ

- ๋งˆ์šฐ์Šค๋ฅผ ๋“œ๋ž˜๊ทธํ•˜๋ฉด ๊ต์ฐจ์ ์˜ ์œ„์น˜๊ฐ€ ์˜ค๋ฅธ์ชฝ๊ณผ ๊ฐ™์ด ๋ณ€ํ•˜๊ธฐ

- ๊ฐ 4๊ฐœ์˜ ์‚ผ๊ฐํ˜•์˜ ํฌ๊ธฐ๊ฐ€ ๋ฐ”๋€๋‹ค

- 4๊ฐœ์˜ ์‚ผ๊ฐํ˜•์— ๋Œ€ํ•ด์„œ ๊ฐ๊ฐ ์–ดํ•€ ๋ณ€ํ™˜

# ํฌํ† ์ƒต ๋ฆฌํ€ดํŒŒ์ด ๋„๊ตฌ
import cv2
import numpy as np

win_title = 'Liquify'   # ์ฐฝ ์ด๋ฆ„
half = 50               # ๊ด€์‹ฌ ์˜์—ญ ์ ˆ๋ฐ˜ ํฌ๊ธฐ
isDragging = False      # ๋“œ๋ž˜๊ทธ ์—ฌ๋ถ€ ํ”Œ๋ž˜๊ทธ

# ๋ฆฌํ€ดํŒŒ์ด ํ•จ์ˆ˜
def liquify(img, cx1,cy1, cx2,cy2) :
    # ๋Œ€์ƒ ์˜์—ญ ์ขŒํ‘œ์™€ ํฌ๊ธฐ ์„ค์ •
    x, y, w, h = cx1-half, cy1-half, half*2, half*2
    # ๊ด€์‹ฌ ์˜์—ญ ์„ค์ •
    roi = img[y:y+h, x:x+w].copy()
    out = roi.copy()

    # ๊ด€์‹ฌ์˜์—ญ ๊ธฐ์ค€์œผ๋กœ ์ขŒํ‘œ ์žฌ ์„ค์ •
    offset_cx1,offset_cy1 = cx1-x, cy1-y
    offset_cx2,offset_cy2 = cx2-x, cy2-y
    
    # ๋ณ€ํ™˜ ์ด์ „ 4๊ฐœ์˜ ์‚ผ๊ฐํ˜• ์ขŒํ‘œ
    tri1 = [[ (0,0), (w, 0), (offset_cx1, offset_cy1)], # ์ƒ,top
            [ [0,0], [0, h], [offset_cx1, offset_cy1]], # ์ขŒ,left
            [ [w, 0], [offset_cx1, offset_cy1], [w, h]], # ์šฐ, right
            [ [0, h], [offset_cx1, offset_cy1], [w, h]]] # ํ•˜, bottom

    # ๋ณ€ํ™˜ ์ดํ›„ 4๊ฐœ์˜ ์‚ผ๊ฐํ˜• ์ขŒํ‘œ
    tri2 = [[ [0,0], [w,0], [offset_cx2, offset_cy2]], # ์ƒ, top
            [ [0,0], [0, h], [offset_cx2, offset_cy2]], # ์ขŒ, left
            [ [w,0], [offset_cx2, offset_cy2], [w, h]], # ์šฐ, right
            [ [0,h], [offset_cx2, offset_cy2], [w, h]]] # ํ•˜, bottom

    
    for i in range(4):
        # ๊ฐ๊ฐ์˜ ์‚ผ๊ฐํ˜• ์ขŒํ‘œ์— ๋Œ€ํ•ด ์–ดํ•€ ๋ณ€ํ™˜ ์ ์šฉ
        matrix = cv2.getAffineTransform( np.float32(tri1[i]), \
                                         np.float32(tri2[i]))
        warped = cv2.warpAffine( roi.copy(), matrix, (w, h), \
            None, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101)
        # ์‚ผ๊ฐํ˜• ๋ชจ์–‘์˜ ๋งˆ์Šคํฌ ์ƒ์„ฑ
        mask = np.zeros((h, w), dtype = np.uint8)
        cv2.fillConvexPoly(mask, np.int32(tri2[i]), (255,255,255))
        
        # ๋งˆ์Šคํ‚น ํ›„ ํ•ฉ์„ฑ
        warped = cv2.bitwise_and(warped, warped, mask=mask)
        out = cv2.bitwise_and(out, out, mask=cv2.bitwise_not(mask))
        out = out + warped

    # ๊ด€์‹ฌ ์˜์—ญ์„ ์›๋ณธ ์˜์ƒ์— ํ•ฉ์„ฑ
    img[y:y+h, x:x+w] = out
    return img 

# ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ ํ•ธ๋“ค ํ•จ์ˆ˜
def onMouse(event,x,y,flags,param):     
    global cx1, cy1, isDragging, img      # ์ „์—ญ๋ณ€์ˆ˜ ์ฐธ์กฐ
    # ๋งˆ์šฐ์Šค ์ค‘์‹ฌ ์ ์„ ๊ธฐ์ค€์œผ๋กœ ๋Œ€์ƒ ์˜์—ญ ๋”ฐ๋ผ๋‹ค๋‹ˆ๊ธฐ
    if event == cv2.EVENT_MOUSEMOVE:  
        if not isDragging :
            img_draw = img.copy()       
            # ๋“œ๋ž˜๊ทธ ์˜์—ญ ํ‘œ์‹œ
            cv2.rectangle(img_draw, (x-half, y-half), \
                    (x+half, y+half), (0,255,0)) 
            cv2.imshow(win_title, img_draw) # ์‚ฌ๊ฐํ˜• ํ‘œ์‹œ๋œ ๊ทธ๋ฆผ ํ™”๋ฉด ์ถœ๋ ฅ
    elif event == cv2.EVENT_LBUTTONDOWN :   
        isDragging = True                   # ๋“œ๋ž˜๊ทธ ์‹œ์ž‘
        cx1, cy1 = x, y                     # ๋“œ๋ž˜๊ทธ ์‹œ์ž‘๋œ ์›๋ž˜์˜ ์œ„์น˜ ์ขŒํ‘œ ์ €์žฅ
    elif event == cv2.EVENT_LBUTTONUP :
        if isDragging:
            isDragging = False              # ๋“œ๋ž˜๊ทธ ๋
            # ๋“œ๋ž˜๊ทธ ์‹œ์ž‘ ์ขŒํ‘œ์™€ ๋๋‚œ ์ขŒํ‘œ๋กœ ๋ฆฌํ€ดํŒŒ์ด ์ ์šฉ ํ•จ์ˆ˜ ํ˜ธ์ถœ
            liquify(img, cx1, cy1, x, y)    
            cv2.imshow(win_title, img)

if __name__ == '__main__' :
    img = cv2.imread("img/jam.jpeg")
    h, w = img.shape[:2]

    cv2.namedWindow(win_title)
    cv2.setMouseCallback(win_title, onMouse) 
    cv2.imshow(win_title, img)
    while True:
        key = cv2.waitKey(1)
        if key & 0xFF == 27:
            break
    cv2.destroyAllWindows()

๋งˆ์šฐ์Šค๋กœ ์–ผ๊ตด ๋ณด์ •ํ•˜๊ธฐ (๋ฆฌํ€ดํŒŒ์ด ํšจ๊ณผ)

 

 

 

 

3. ์‹ค์Šต 3 : ์™œ๊ณก ๊ฑฐ์šธ ์นด๋ฉ”๋ผ

# ์™œ๊ณก ๊ฑฐ์šธ ์นด๋ฉ”๋ผ
import cv2
import numpy as np

cap = cv2.VideoCapture(0)
WIDTH = 500
HEIGHT = 300
cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
rows, cols = HEIGHT, WIDTH
map_y, map_x = np.indices((rows, cols), dtype=np.float32)

# ๊ฑฐ์šธ ์™œ๊ณก ํšจ๊ณผ 
map_mirrorh_x,map_mirrorh_y = map_x.copy(), map_y.copy() 
map_mirrorv_x,map_mirrorv_y = map_x.copy(), map_y.copy()    
## ์ขŒ์šฐ ๋Œ€์นญ ๊ฑฐ์šธ ์ขŒํ‘œ ์—ฐ์‚ฐ
map_mirrorh_x[: , cols//2:] = cols - map_mirrorh_x[:, cols//2:]-1
## ์ƒํ•˜ ๋Œ€์นญ ๊ฑฐ์šธ ์ขŒํ‘œ ์—ฐ์‚ฐ
map_mirrorv_y[rows//2:, :] = rows - map_mirrorv_y[rows//2:, :]-1
# ๋ฌผ๊ฒฐ ํšจ๊ณผ
map_wave_x, map_wave_y = map_x.copy(), map_y.copy()
map_wave_x = map_wave_x + 15*np.sin(map_y/20)
map_wave_y = map_wave_y + 15*np.sin(map_x/20)    


# ๋ Œ์ฆˆ ํšจ๊ณผ
## ๋ Œ์ฆˆ ํšจ๊ณผ, ์ค‘์‹ฌ์  ์ด๋™
map_lenz_x = 2*map_x/(cols-1)-1
map_lenz_y = 2*map_y/(rows-1)-1
## ๋ Œ์ฆˆ ํšจ๊ณผ, ๊ทน์ขŒํ‘œ ๋ณ€ํ™˜
r, theta = cv2.cartToPolar(map_lenz_x, map_lenz_y)
r_convex = r.copy()
r_concave = r.copy()
## ๋ณผ๋ก ๋ Œ์ฆˆ ํšจ๊ณผ ๋งคํ•‘ ์ขŒํ‘œ ์—ฐ์‚ฐ
r_convex[r< 1] = r_convex[r<1] **2  
print(r.shape, r_convex[r<1].shape)
## ์˜ค๋ชฉ ๋ Œ์ฆˆ ํšจ๊ณผ ๋งคํ•‘ ์ขŒํ‘œ ์—ฐ์‚ฐ
r_concave[r< 1] = r_concave[r<1] **0.5
## ๋ Œ์ฆˆ ํšจ๊ณผ, ์ง๊ต ์ขŒํ‘œ ๋ณต์›
map_convex_x, map_convex_y = cv2.polarToCart(r_convex, theta)
map_concave_x, map_concave_y = cv2.polarToCart(r_concave, theta)
## ๋ Œ์ฆˆ ํšจ๊ณผ, ์ขŒ์ƒ๋‹จ ์ขŒํ‘œ ๋ณต์›
map_convex_x = ((map_convex_x + 1)*cols-1)/2
map_convex_y = ((map_convex_y + 1)*rows-1)/2
map_concave_x = ((map_concave_x + 1)*cols-1)/2
map_concave_y = ((map_concave_y + 1)*rows-1)/2

while True:
    ret, frame = cap.read()
    frame = frame[:HEIGHT, :WIDTH]
    # ์ค€๋น„ํ•œ ๋งคํ•‘ ์ขŒํ‘œ๋กœ ์˜์ƒ ํšจ๊ณผ ์ ์šฉ
    mirrorh=cv2.remap(frame,map_mirrorh_x,map_mirrorh_y,cv2.INTER_LINEAR)
    mirrorv=cv2.remap(frame,map_mirrorv_x,map_mirrorv_y,cv2.INTER_LINEAR)
    wave = cv2.remap(frame,map_wave_x,map_wave_y,cv2.INTER_LINEAR, \
                    None, cv2.BORDER_REPLICATE)
    convex = cv2.remap(frame,map_convex_x,map_convex_y,cv2.INTER_LINEAR)
    concave = cv2.remap(frame,map_concave_x,map_concave_y,cv2.INTER_LINEAR)
    # ์˜์ƒ ํ•ฉ์น˜๊ธฐ
    r1 = np.hstack(( frame, mirrorh, mirrorv))
    r2 = np.hstack(( wave, convex, concave))
    merged = np.vstack((r1, r2))

    cv2.imshow('distorted', merged)
    if cv2.waitKey(1) & 0xFF== 27:
        break
cap.release
cv2.destroyAllWindows()

์ผ๋ฐ˜ ์นด๋ฉ”๋ผ, ์ขŒ์šฐ ๋Œ€์นญ ์นด๋ฉ”๋ผ, ์ƒํ•˜ ๋Œ€์นญ ์นด๋ฉ”๋ผ, ๋ฌผ๊ฒฝ ์™œ๊ณก ์นด๋ฉ”๋ผ, ๋ณผ๋ก ๋ Œ์ฆˆ ์นด๋ฉ”๋ผ, ์˜ค๋ชฉ ๋ Œ์ฆˆ ์นด๋ฉ”๋ผ

 

 

 

 

 

์žฌ๋ฐŒ๋‘ใ…

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