내맘대로 공부기록.

[ C# ]

[opencvSharp] setMouseCallback 함수 사용 방법

fwanggus 2022. 4. 30. 22:30

작업환경 

- C# 환경에서 데스크탑 윈도우 프로그램을 작성하는 경우

- opencvSharp 라이브러리를 참조

- OS : Windows 11 Pro

개념

이미지에 대해서 유저의 조작을 반영하고 싶을 경우, 마우스 핸들러의 개념으로 사용할 수 있습니다. 마우스의 좌/우 버튼 및 휠 버튼 클릭에 대해서 이벤트 정보를 가져올 수 있으며, 발생한 이벤트에 대해서 하고 싶은 작업들을 추가할 수 있습니다. 웹 기반의 프로그래밍에도 이벤트를 핸들링할 수 있는 구조가 있는 걸로 알고 있는데, 같은 개념인 것 같습니다.

 

마우스 이벤트 리스트

1. MouseEventTypes

출처 : https://shimat.github.io/opencvsharp/api/OpenCvSharp.MouseEventTypes.html

 

2. MouseEventFlags

출처 : https://shimat.github.io/opencvsharp/api/OpenCvSharp.MouseEventFlags.html

 

콜백 함수를 적용하는 개념

- 필요 조건 : 이미지 소스를 표시할 윈도우 객체가 필요

- 이미지를 표시하는 윈도우 내에서 콜백 함수가 적용된다

- 해당 윈도우를 Destroy(유저가 특정 조건을 설정) 하지 않는 한 콜백 함수는 무한 루프로 마우스의 이벤트를 추적합니다.

 

콜백 함수의 형태

조사한 결과로는 다음과 같은 정해진 인수의 조합으로 콜백 함수를 정의해야 합니다. 그리고, 각 이벤트 조건을 설정해서 하고 싶은 작업을 세팅하면 됩니다. 아래의 예에서는 마우스 각 버튼을 Down 할 때를 대상으로 합니다.

public void myCallBack(MouseEventTypes @event, int x, int y, MouseEventFlags flags, IntPtr userData)
{
  if (@event == MouseEventTypes.LButtonDown) {
    Console.WriteLine("x : " + x + ", \t y : " + y);
  }else if(@event == MouseEventTypes.MButtonUp) {
    // do something...
  }else if(@event == MouseEventTypes.RButtonDown) {
    // do something...
  }
}

 

여기서 event 앞에 @를 꼭 붙여줘야 에러없이 컴파일이 되었다. 공식문서에서는 @가 없는 event로 나와있어서 한참 헤맸었는데 @를 꼭 붙이자.

그 외에는 x, y 좌표값과 마우스 이벤트 타입과 플래그 그리고 유저 데이터(integer 타입)를 포인터로 건네줄 수 있습니다. 유저 데이터는 사용해보지 않았지만, 사용할 기회가 있으면 써보고 다시 설명을 추가하기로 합니다.

 

Delegate MouseCallback

Delegate MouseCallback Delegate to be called every time mouse event occurs in the specified window. Assembly: OpenCvSharp.dll Syntax public delegate void MouseCallback(MouseEventTypes event, int x, int y, MouseEventFlags flags, IntPtr userData); Parameters

shimat.github.io

 

콜백 함수를 대입하는 구조 및 원리 ?

 

순서적인 개념을 얘기하자면, 다음과 같습니다.

  1. 윈도우 생성
  2. 윈도우에 콜백함수 붙이기
  3. 윈도우에 이미지 입력
  4. 윈도우 출력
  5. 윈도우에서 마우스 조작(세팅한 이벤트)
  6. 윈도우의 이미지 업데이트

콜백 함수는 SetMouseCallback이라는 메서드를 이용해서 설정할 수 있습니다. 이때 첫 번째 인수로 특정 윈도우를 지정해줘야 하며, 지정한 윈도우에서 마우스 이벤트를 컨트롤할 수 있게 됩니다.

  	    ...
  	    // create window...
            window winCut = new window(WINDOW_CUT);
            winCut.setWindow(imgRead, sender);

            // make callback instance.
            mousecallback_imgcut mcImgCut = new mousecallback_imgcut();

            // set mouse event handler...
            imgWork = imgRead.Clone();
            Cv2.SetMouseCallback(WINDOW_CUT, mcImgCut.callBackFunc);
            Cv2.ImShow(WINDOW_CUT, imgWork);
            ...

 

위 코드에서 window, mousecallback_imgcut의 이름으로 각각 클래스를 작성하고 윈도우와 마우스콜백 함수를 생성/작성했습니다. 특정 윈도우를 지정하기 위해서 WINDOW_CUT 변수에 스트링 타입의 윈도우 이름을 할당해주었습니다.

콜백 함수는 함수 이름만 대입해 주는 방식으로 대입해주면 됩니다. 호출하는 방식인 괄호()를 붙여 주지 않았습니다.

 

	...
	Cv2.SetMouseCallback(WINDOW_CUT, mcImgCut.callBackFunc);
	...

 

필요에 따라 마우스 조작 후 피드백을 윈도우에 표시하는 경우, 예를 들어 선택한 위치를 원으로 표시하거나, 선택한 위치를 기준으로 직선을 그리고 싶을때, 선택을 계속함에 따라 윈도우에 표시되는 이미지를 업데이트 시켜줘야 합니다. 이럴 경우 이벤트에 따른 이미지 처리가 끝난 후, 윈도우에 표시되어 지는 이미지를 업데이트해서 보여줘야 합니다. 간단하게 Imshow를 끝에 적어주면 같은 윈도우에 표시되는 이미지를 업데이트 하게 됩니다. 이때 윈도우 이름을 변수로 지정해서 같은 윈도우에 대해서 작업이 계속해서 이루어 줘야 하는 점을 명심합시다.

 

윈도우의 이미지를 업데이트(Cv2.Imshow)

 

CODE.

1. 콜백 함수를 호출하는 소스코드

2. 콜백함수를 정의하는 소스코드

 

다음은 두 점을 연속으로 선택하여 사각형을 그리는 조작을 보여줍니다.

 

작성한 윈도우 폼 형태(참고용)

클릭 순서 : CASE A - Load(이미지 불러오기) - Cut with 2P.(이미지 조작을 위한 새로운 윈도우 창 열림)

클릭 순서 : CASE A - Load - Cut with 2P.

 

반응형