본문 바로가기
공부공부/2024 쌓여가는 나의 지식~

이미지 워핑(Warping)에 대하여 [빔 프로젝터 영상 처리 관련 Python/OpenCv]

by Lee_story_.. 2024. 12. 27.
728x90

 

어찌어찌 올해가 넘어가는중...

 

거의 막바지에 새로운 먼가를 하기위해 또 배워가는중! 

 

그래서 이번엔 이미지 Warping에 대해서 알아보려 합니다.

그렇게 막 어렵거나 긴 내용은 아니지만, 작성한 코드부분도 있고, 이런 부분도 있구나... 싶어서 작성합니다!

 

 

그럼 시작!


먼저 Warping이란...?

특정한 이미지나 마크가 기울어지거나, 크기가 변한다던가... 일그러진다거나!

인식에 불편한 부분들이 생기게 될때 이를 재배열하여 정규화 하는 기법입니다.

 

...음... 아래처럼 특정 부분을 어디에서 찍느냐에 따라 완전히 다르게 보이기에 이 부분을 해결하기 위해 개발된 기법!

(사람은 구분가능하지만, 컴퓨터는 ....멍..)

 

 

 

 

이 부분에 대해서도 다양한 방법들이 존재하고, 완전히 일그러진 이미지에 대해서도 복원시키는걸 보니...

공부가 많이 필요할듯 하네요... (아래는 참고 블로그!)

 

Digital Image Processing - Warping

Image warping 이미지 워핑은 이미지의 형태를 변형하는 과정으로, 특정 알고리즘에 따라 이미지의 픽셀을 새로운 위치로 매핑함으로써 이미지의 모양을 변형시키는 과정이다. 아래와 같이 다양한

canvas4sh.tistory.com

 

 

이미지 워핑 (Image Warping)

서론 이미지 워핑이라는것은 쉽게 말해, 영상을 이렇게 찌그러트리는 기술이다. [그림 1] (좌) 원본 이미지 256x256 격자 이미지, (우) 워핑을 통해서 찌그러진 이미지 이쪽으로 유명한 책은 Randy Cran

paeton.tistory.com

 

 

 

그래서 일단은 접어두고..... 진행하던 부분에 대해서 마저 진행해 보았습니다!

저에게 필요한 부분은....

빔 프로젝터와 그에 맞게 설치된 탑뷰 웹캠을 통해 영상을 녹화할때,

프로젝터의 각도와 위치, 상관없이 정확한 영상의 정보만을 받아오기위한 이미지 워핑 방식이 필요했습니다. 

 

물론 이 정도는 프로젝터를 이동 시키면 충분히 맞춰 볼 수 있겠지만,

프로젝터가 이동될 수도 있고, 흐트러질 수 도 있다고 판단하여 찾아보게 되었습니다!

이건 좀 극단적이긴한데... 이런 부분을 워핑으로 잡아줄것!

 

그래서 위의 블로그들을 찾아보게 되고... 생각보다 어렵겠다고 생각하였지만....

이미 제가 원하는 정도의 warping은 Python의 OpenCv에 구현이 되어있어, 매우 쉽게 구현할 수 있었습니다!

 

 

 

그럼 일단 코드부터!

코드 자체는 간단하긴 한데, 제 실험환경에 맞춰 구성했기에... 불필요한 부분에 대해서는 수정해서 사용해주세요!

코드 실행 순서는 다음과 같습니다.

 

1. 웹캠의 첫번째 프레임을 받아온다

2. 그 프레임을 통해 각 빔 프로젝터의 꼭짓점을 체킹해준다.

3. 새로운 창에 웹캠의 영상을 Warping하여 출력한다.

 

 

가장 먼저 웹캠을 받아오는 부분은 웹캠의 해상도 부분과 전체화면으로 열어주는 부분만 추가해 주었습니다. 

import cv2
import numpy as np
import asyncio

# 마우스 클릭으로 얻은 점들 저장
points = []

....

# 메인 실행 함수
async def Asy_main():
    global frame_copy
    
    cap = cv2.VideoCapture(0)
    if not cap.isOpened():
        print("Cannot open webcam")
        return

    frame_width = 1280
    frame_height = 960
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, frame_width)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, frame_height)

    ret, frame = cap.read()
    if not ret:
        cap.release()
        return

    window_name = "CheckPoint"
    cv2.namedWindow(window_name, cv2.WND_PROP_FULLSCREEN)
    cv2.setWindowProperty(window_name, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
    frame_copy = frame.copy()
    cv2.imshow(window_name, frame_copy)

    # 초기 화면 출력
    cv2.imshow(window_name, frame_copy)
    cv2.setMouseCallback(window_name, get_points)

 

 

그리고 웹캠의 장면에서 꼭짓점을 체킹해주는 부분에서는 점을 4개찍을때까지 대기하게 만들고, 

이 점들이 실제로 화면에 표시되게끔 구성해 주었습니다. 

def get_points(event, x, y, flags, param):
    global points
    if event == cv2.EVENT_LBUTTONDOWN:
        if len(points) < 4:
            points.append((x, y))

......


 # 마우스 클릭으로 4개의 점을 얻을 때까지 대기
    while len(points) < 4:
        cv2.imshow(window_name, frame_copy)
        await asyncio.sleep(0.01)

 

 

마지막으로 Warping하는 부분에서는 앞선 4개의 지점을 토대로 웹캠의 영상을 계속해서 Warping하고 

그 결과이미지의 크기에 맞춰 화면을 새로 출력해주었습니다. 

# Warping 처리 함수
def perform_warping(frame, points, w, h):
    src_pts = np.array(points, dtype=np.float32)
    dst_pts = np.array([[0, 0], [w, 0], [w, h], [0, h]], dtype=np.float32)

    trans_mat = cv2.getPerspectiveTransform(src_pts, dst_pts)
    warped_image = cv2.warpPerspective(frame, trans_mat, (w, h))
    return warped_image


def WarpingCalculate():
    w_Cal = max(abs(points[0][0] - points[1][0]), abs(points[2][0] - points[3][0]))
    h_Cal = max(abs(points[0][1] - points[2][1]), abs(points[1][1] - points[3][1]))

    return w_Cal, h_Cal

.....

# Warping 계산된 크기
    w, h = WarpingCalculate()

    # 실시간 Warping 처리
    while True:
        ret, frame = cap.read()
        if not ret:
            cap.release()
            cv2.destroyAllWindows()
            return

        warped_image = perform_warping(frame, points, w, h)
        cv2.imshow("Warped Image", warped_image)

        # ESC 키로 종료
        if cv2.waitKey(1) & 0xFF == 27:
            cap.release()
            cv2.destroyAllWindows()
            return


# asyncio 실행
if __name__ == "__main__":
    asyncio.run(Asy_main())

 

 

아래는 결과!

(조명때문에... 웹캠에서 아래처럼 찍히네요...)

 

 

 

워핑에 주요 함수! warpPerspective()함수의 내용은 아래에서!

 

OpenCV: Geometric Image Transformations

The functions in this section perform various geometrical transformations of 2D images. They do not change the image content but deform the pixel grid and map this deformed grid to the destination image. In fact, to avoid sampling artifacts, the mapping is

docs.opencv.org

 

 

개념과 심화 부분은 많이 어려웠지만...

 특정 지점들을 통해 재배열하고 원본이미지나, 원하는 데이터로써 정규화 시킨다는 부분이 핵심인 것 같습니다! 

위 코드는 4개의 지점만을 사용했지만, 이 부분이 늘어나면 늘어날수록 좀 더 정교하게 재배열할 수 있을것 같네요..

 

 

일단 이번글은 여기서 끝!

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글