WPF OpenCV 프로젝트 #12: ROI(관심 영역) 크기 조절 및 이동 기능 구현 (Interaction)

이번 포스팅에서는 ROI(관심 영역) 크기 조절 및 이동 기능 구현(Interaction)WPF OpenCV 프로젝트에 구현하겠습니다. 지난 포스팅(#11)에서 ROI 사각형 주변에 8개의 크기 조절 핸들(Picker)을 예쁘게 배치했습니다. 하지만 아직은 핸들을 잡고 흔들어도 아무 반응이 없었죠? (그림의 떡이었죠.)

오늘은 드디어 이 Picker 핸들에 생명을 불어넣어 ROI 크기를 늘리고 줄이는 기능, 그리고 잘못 그린 ROI통째로 이동 시키는 기능을 구현해 보겠습니다.

Picker Handle 구현 목표 및 동작 흐름

코드를 짜기 전에, 우리가 무엇을 하려는지 머릿속으로 시뮬레이션을 한번 돌려보죠.

  1. Resizing (크기 조절):
    • 핸들 8개 중 하나를 클릭(MouseDown) → _isResizing 시작.
    • 마우스를 움직임(MouseMove) → 핸들 방향에 따라 사각형 좌표 계산.
    • 마우스를 놓음(MouseUp) → 조절 끝.
  2. Moving (이동):
    • ROI 사각형 내부를 클릭(MouseDown) → _isMovingRoi 시작.
    • 마우스를 움직임(MouseMove) → 마우스 이동 거리만큼 사각형 이동.
    • 마우스를 놓음(MouseUp) → 이동 끝.

자, 이 흐름대로 코드를 하나씩 채워 넣어 봅시다.

ROI Resizing

아무래도 이번 포스팅에 가장 복잡한 부분이 될 것 같습니다. ZoomBorder_MouseMove 함수에서 마우스가 움직일 때마다 좌표를 다시 계산되어야 하거든요.

지난 포스팅에서 핸들을 클릭했을 때 _resizeDirection에 방향(TopLeft, Bottom 등)을 저장해 뒀었죠? (기억하나요? 기억에 문제가 있다면 다시 한번 쓰윽~ 보고 와주세요!) 아무튼 그 방향에 따라 계산 식이 달라지게 됩니다. 그래서 기존 ZoomBorder_MouseMove 함수에 아래 내용을 추가해 주세요.

위 코드가 길어 보이지만 사실 패턴은 단순합니다. 예를 들어 TopLeft 핸들을 잡고 움직이면, 오른쪽(Right)과 바닥(Bottom) 좌표는 고정 시키고, 마우스 위치에 따라 왼쪽(X)과 위쪽(Y) 좌표만 갱신하는 방식입니다.

ROI Moving: ROI 사각형 이동

ROI 사각형 즉 관심 영역을 그리다가 “아, 크기는 딱 맞는데 위치가 조금 빗나갔네?” 이럴 때 다시 그리지 않고 슥~ 옮길 수 있어야 진짜 편리한 UI 가 되겠네요. 이제 이동 상태와 위치 오차를 저장할 변수를 선언하고 ROI 영역의 이동에 따른 이벤트 처리를 아래와 같이 진행 하겠습니다.

변수 선언

아래 코드와 같이 이동 상태와 클릭 위치의 오차(Offset)를 저장할 변수를 선언합니다.

MouseEvent: MouseDown/MouseMove

먼저 ZoomBorder_MouseDown 함수에 “ROI 내부를 클릭했는지” 확인하는 로직을 추가합니다.

이제 마우스를 움직이면 저장해둔 오차(_moveOffset)를 반영해서 ZoomBorder_MouseMove() 함수에서 위치를 옮기는 코드를 추가합니다.

MouseEvent: MouseUp

이제 클릭해서 드래그 하던 왼쪽 마우스 버튼을 떼면, Resizing이든 Moving이든 모든 동작을 멈추고 상태를 초기화해야 합니다. ZoomBorder_MouseUp() 함수에 아래의 코드로 업데이트 해주세요.

실행 결과

드디어 ROI 기능이 완성되었습니다! 이제 마우스로 ROI 관심 영역 사각형을 그리고, Picker 핸들을 잡아 늘리고, ROI 관심 영역이 마음에 안 들면 통째로 옮길 수도 있습니다. 잘 따라 왔다면 아래에 실행 영상처럼 자알~ 동작할 겁니다.

아래의 첫 번째 실행 영상은 프로젝트 빌드 후 Picker 핸들 조절 실행 영상입니다.

두 번째 실행 영상은 ROI 관심 영역 사각형의 이동과 이전 포스팅(#10)에서 작성했던 이미지 잘라내기 까지 동작하는 영상이니 참고하여 주세요.

단계 별로 코드를 추가하느라 꽤 긴 여정이었지만, WPF 좌표계 변환, 마우스 이벤트 처리, MVVM과의 연동까지 깊이 있게 다룰 수 있었습니다. 잘 따라오셨다면 에러 없이 아주 부드럽게 동작할 겁니다. (확신합니다!)

다음 포스팅에서는 또 다른 재미있는 WPF 기반의 OpenCV 기능을 WPF에 얹어보도록 하겠습니다. 기대해 주세요!

참조 자료

Vector 구조체: 점(Point)과 점 사이의 ‘거리와 방향’을 나타낼 때 사용되며,이동 로직에서 _moveOffset을 계산할 때 필요합니다.
https://learn.microsoft.com/ko-kr/dotnet/api/system.windows.vector
BitmapSource: WPF에서 이미지를 다루는 기본 class.
픽셀 너비/높이(PixelWidth, PixelHeight) 정보를 가져올 때 사용 합니다.
https://learn.microsoft.com/ko-kr/dotnet/api/system.windows.media.imaging.bitmapsource
Math.Min / Math.Max: 값의 범위를 제한(Clamping)할 때 필수적인 함수.
ROI가 이미지 밖으로 나가지 않게 막아줍니다.
https://learn.microsoft.com/ko-kr/dotnet/api/system.math.min

댓글 남기기