WPF OpenCV 프로젝트 #7: WPF 이미지 확대 및 이동 구현 (Zoom/Pan)

이번 시간에는 WPF 이미지 확대 및 이동 기능을 본격적으로 구현해 보겠습니다. 지난 포스팅에서 BorderCanvas를 이용해 확대/축소를 위한 UI 그릇을 만들었습니다. 하지만 정작 실행해 보면 마우스 휠을 굴려도 WPF 이미지 확대 축소는 없었을 겁니다. 이벤트만 연결해 놓고 실제 코드를 작성하지 않았기 때문이죠.
이번 시간에는 MainWindow.xaml.cs에 생명을 불어넣어 보겠습니다. 따라서 WPF OpenCV 프로젝트 #7에서는 마우스 이벤트로 이미지를 확대/이동 구현하는 하도록 할게요.
본격적인 코딩에 앞서, MVVM 패턴을 공부하시는 분들이라면 한번쯤 고민해 보셨을 주제부터 짚고 넘어가겠습니다.

MVVM의 딜레마: “도대체 어디 까지 View의 일인가?”

MVVM(Model-View-ViewModel) 패턴을 처음 접할 때 가장 혼란스러운 부분이 바로 이것입니다. “화면 조작 로직을 ViewModel에 넣어야 하나, 아니면 View(Code Behind)에 남겨둬야 하나?”

저의 결론부터 말씀드리면 다음과 같습니다.

“마우스 좌표 추적, 줌/이동(Zoom/Pan)과 같은 순수 화면 조작은 View의 코드 비하인드(MainWindow.xaml.cs)에서 처리하는 것이 정석이다.”

이유는 효율성 때문입니다. 마우스를 움직일 때 발생하는 MouseMove 이벤트는 1초에도 수백 번씩 발생합니다. 만약 이것을 ViewModel로 보내서 처리하고 다시 View로 바인딩하여 업데이트한다면? 엄청난 오버헤드가 발생하고 화면이 버벅거리는 렉(Lag)이 생길 수밖에 없습니다.

ViewModel은 “이미지 데이터” 자체만 관리하고, 그 이미지를 “어떻게 보여줄지(확대/이동)”는 View가 알아서 하도록 맡기는 것, 이것이 진정한 의존성 분리입니다.

WPF 이미지 확대 기능을 위한 코드 구현

이제 서론은 접어두고, 텅 비어있던 MainWindow.xaml.cs를 꽉 채워보겠습니다. 이전 글에서 XAML에 정의했던 ZoomBorder_MouseWheel, FitImageToScreen 등의 기능이 모두 포함되어 있습니다.

기존 코드를 지우고 아래 내용을 그대로 붙여 넣으세요. 아마도 이 코드를 사용하면 WPF 이미지 확대가 부드럽게 작동합니다.

WPF 이미지 확대 축소를 위한 핵심 기능

코드가 꽤 길지만, 핵심 기능은 크게 3가지입니다.

① FitImageTosScreen(): 알아서 딱 맞게 맞춰주기

이미지를 처음 불러오거나 창 크기를 조절할 때 호출됩니다. 이미지의 너비/높이와 화면(Border)의 너비/높이 비율을 계산해서, 이미지가 잘리지 않게 자동으로 축소(Scale)하고 중앙으로 이동(Translate) 시킵니다.

② ZoomBorder_MouseWheel: 줌 인/아웃

마우스 휠을 굴리면 1.2배씩 커지거나 작아집니다. 여기서 중요한 점은 “마우스 포인터가 가리키던 지점”을 유지하는 보정 공식(p.X - (p.X - imgTranslate.X) * zoom)입니다. 이 공식이 없으면 확대할 때 이미지가 엉뚱한 곳으로 날아가는 현상을 겪게 됩니다.

③ ZoomBorder_MouseMove: 패닝(이동)

확대된 상태에서 마우스 휠 버튼(Middle Button)을 꾹 누르고 움직이면 이미지를 잡고 끄는 효과(Panning)를 냅니다. CaptureMouse()를 사용하여 마우스가 UI(메인 윈도우) 밖으로 나가더라도 드래그가 끊기지 않도록 처리한 것이 포인트입니다.

실행 결과

이제 F5를 눌러 실행해 보세요! 큰 이미지를 불러와도 화면에 딱 맞게 뜨고, 휠을 굴려 마음껏 확대하고 이동할 수 있습니다. 굉장하지 않나요? (ㅠㅠ)

1. 이미지 로딩(Image Loading)하여 View-Fitting.

Wafer Image Loading
(Image View Fitting)

2. 이미지 확대 (Image Zoom-In): Mouse Wheel

WPF 이미지 확대 실행 화면

3. 이미지 확대 (Scale): Mouse Wheel

이미지 확대: 현재 마우스 포인트 위치 기준으로 이미지를 더 확대.

4. 이미지 이동(Image Panning): Mouse Wheel

이미지 이동: 마우스 휠을 누른 상태에서 마우스 드래그.

5. 이미지 축소(Image Zoom-Out) : Mouse Wheel

이미지 축소: 마우스 휠로 둘려 이미지 축소. (마우스 포인트 현 위치를 기준으로 확대/축소)

6. 이미지 축소/이미지 이동: Mouse Wheel

이미지 축소 하여 마우스 이동에 따른 image Panning.

이 코드는 어떤 WPF 프로젝트에서도 “이미지 뷰어” 기능을 만들 때 그대로 복사해서 쓸 수 있는 강력한 패턴입니다. MVVM 구조를 해치지 않으면서 부드러운 UI 경험을 제공하고 싶다면, 이 방식을 강력 추천합니다!

댓글 남기기