StatusBar 구현과 실시간 좌표 표시 기능을 이번 WPF OpenCV 프로젝트에 구현하도록 하겠습니다. 지난 포스팅까지 우리는 기본적인 UI 틀을 만들고, 마우스를 이용해 이미지를 확대/축소/이동(Zoom/Pan) 하는 기능까지 구현했습니다.
혹시 기억하시나요? 맨 처음 MainWindow.xaml에서 Grid를 구성할 때, Row를 2개(RowDefinition) 만들어 놓고 정작 1개만 썼던 진실을 눈치 채셨나요? 그리고 MainWindow.xaml.cs의 ZoomBorder_MouseMove함수 마지막에 “// 좌표 출력”이라고 주석만 달아 놓고 아무 코드도 작성하지 않았던 것도 눈치 채셨나요?
“아니, 왜 만들어 놓고 안 써? 코딩 실수인가?”
라고 욕… 하셨을지도 모르겠지만, 사실 이 모든 것은 상태 바(StatusBar)를 위한 저의 ‘큰 그림’이었습니다. (믿거나 말거나 입니다.)
오늘은 이 숨겨진 공간에 상태 바를 추가해서 현재 진행 상태를 보여주고, 마우스가 움직일 때마다 이미지의 픽셀 좌표를 실시간으로 찍어보는 기능을 완성해 보겠습니다.
StatusBar Grid
가장 먼저 할 일은 UI(MainWindow.xaml)에 상태 바를 집어넣는 것입니다. 우리가 비워두었던 Grid.Row="1" 자리가 드디어 주인을 만날 시간입니다. 기존 Grid 닫는 태그 </Grid> 바로 위에 아래 코드를 추가해 주세요.
AnalysisResult: 이건 이미 MainViewModel에 만들어 둔 프로퍼티입니다. 이미지 로드 성공 여부나 에러 메시지를 보여줍니다.
MouseCoordinationInfo: 이건 새로 만들어야 할 녀석입니다. 마우스 좌표 (X, Y) 값을 문자열로 보여줄 예정입니다.
ViewModel 업데이트: 좌표 데이터 바인딩
UI에서 MouseCoordinationInfo라는 이름을 불렀으니, ViewModel에서 대답해 줘야겠죠? MainViewModel.cs 파일을 열고, Properties 영역에 아래 코드를 추가합니다.
private string _mouseCoordinationInfo = "(X: 0, Y: 0)";
public string MouseCoordinationInfo
{
get => _mouseCoordinationInfo;
set
{
if (_mouseCoordinationInfo == value) return;
_mouseCoordinationInfo = value;
OnPropertyChanged();
}
}
이제 ViewModel은 좌표 값을 받아 UI에 뿌려줄 준비가 끝났습니다.
Code Behind: 마우스 좌표 추적
이제 가장 중요한 부분입니다. “마우스가 현재 이미지의 어느 픽셀 위에 있는가?“를 계산해야 합니다.
단순히 화면 상의 마우스 위치를 구하는 건 의미가 없습니다. 우리가 필요한 건 원본 이미지 기준의 좌표입니다. 이미지가 확대되든, 이동하든 상관없이 정확히 그 픽셀의 위치를 찾아야 나중에 ROI(관심 영역) 지정이나 정밀 검사를 할 수 있으니까요.
MainWindow.xaml.cs로 가서 ZoomBorder_MouseMove 함수를 완성해 보죠.
private void ZoomBorder_MouseMove(object sender, MouseEventArgs e)
{
// 1. 이미지 이동(Pan) 로직 (이전 시간에 작성함)
if (_isDragging)
{
var border = sender as Border;
Point v = e.GetPosition(border);
imgTranslate.X = _origin.X + (v.X - _start.X);
imgTranslate.Y = _origin.Y + (v.Y - _start.Y);
}
// 2. [NEW] 좌표 출력 로직 추가
var vm = this.DataContext as MainViewModel;
if (vm != null)
{
// ImgView의 소스가 비트맵 이미지인지 확인
if (ImgView.Source is BitmapSource bitmap)
{
// 중요: ZoomBorder가 아니라 'ImgView(이미지 컨트롤)' 기준으로 좌표를 가져옴
Point p = e.GetPosition(ImgView);
int currentX = (int)p.X;
int currentY = (int)p.Y;
// 마우스가 실제 이미지 영역 안에 있을 때만 좌표 표시
if (currentX >= 0 && currentX < bitmap.PixelWidth &&
currentY >= 0 && currentY < bitmap.PixelHeight)
{
vm.MouseCoordinationInfo = $"(X: {currentX}, Y: {currentY})";
}
else
{
// 이미지 밖으로 나가면 (0,0) 처리
vm.MouseCoordinationInfo = "(X: 0, Y: 0)";
}
}
}
}
핵심 포인트:
e.GetPosition(ImgView):ZoomBorder가 아니라 ImgView를 기준으로 좌표를 구해야, 확대/축소 변환이 적용된 후의 상대 좌표를 자동으로 계산해 줍니다. 덕분에 복잡한 수학 공식 없이도 정확한 픽셀 위치를 얻을 수 있습니다.
실행 결과
이제 빌드(F5)를 하고 이미지를 불러와 보세요. 화면 하단 상태 바에 “Image Loaded Successfully” 같은 메시지와 함께, 마우스를 움직일 때마다 우측 하단에 좌표(X, Y)가 실시간으로 변하는 것을 볼 수 있습니다.
처음 실행 시 상태 바 모습 (Ready)
이미지 로드 후 메시지 표시 (Image Loaded Successfully)
이미지 위에서 마우스 이동 시 좌표 변화
이제 이미지를 아무리 확대하고 이리저리 옮겨도, 마우스가 가리키는 곳의 정확한 픽셀 좌표를 알 수 있게 되었습니다.
다음 포스팅에서는 이 좌표 기능을 활용해서 영상 처리의 꽃이라 할 수 있는 ROI(Region of Interest, 관심 영역)를 설정하고 이미지를 획득하는 기능을 구현해 볼까 합니다.