본문 바로가기

프로그래밍 강좌/C++ - OpenCV

[OpenCV][C++] 트랙바(trackbar) 사용하기 총정리 - createTrackbar convertTo slider control 슬라이더 waitkey 컨트롤

지난 번에는 마우스 이벤트를 처리하는 방법에 대해 알아봤습니다.

https://blog.naver.com/dorergiverny/223084092098

 

[OpenCV][C++] 마우스 이벤트 처리 총정리 - onMouse setMouseCallback EVENT_MOUSEMOVE LBUTTONDOWN

이전에는 윈도우 생성 방법과 키보드 입력을 받아 이벤트를 처리하는 방법에 대해 알아보았습니다. https:/...

blog.naver.com

이번에는 opencv 에서 제공하는 trackbar 사용하는 방법에 대해 알아보겠습니다.

trackbar 사용하기

우리가 영상처리를 하면서 threshold 와 같이 변수를 가변하면서 영상의 변화량을 실시간으로 보고 싶을 때가 있습니다.

이럴 때 사용할 수 있는 것이 trackbar 기능 입니다.

트랙바는 슬라이더 컨트롤(slider control)이라고도 부르기도 합니다.

 

1. 영상 읽어오기

영상처리할 영상을 읽어옵니다.

cv::Mat src = cv::imread("lena_gray.bmp", cv::IMREAD_UNCHANGED);
 

2. 영상을 보여줄 window 생성하기

Result라는 이름을 가진 창을 하나 생성합니다.

cv::namedWindow("Result");
 

3. Trackbar 생성하기

createTrackbar() 로 trackbar를 생성합니다.

cv::createTrackbar("threshold", "Result", 0, 255, trackbar, (void*)&src);
 

createTrackbar의 원형은 아래와 같습니다.

trackbarName
트랙바 이름
winName
트랙바 생성할 창(window) 이름
value
트랙바 위치를 받을 정수형 변수의 주소
count
트랙바 최대 위치
onChange
트랙바 변경시 불릴 콜백 함수, NULL을 넣을 경우 value로 지정된 값만 변경됨
userData
트랙바 콜백 함수에 전달할 데이터 포인터
반환값(int)
정상 동작 시 1, 실패하면 0 반환

 

4. trackbar의 초기 위치 설정

트랙바 생성 시 초기 위치를 설정합니다.

cv::setTrackbarPos("threshold", "Result", 128);
 
trackbarName
트랙바 이름
winName
트랙바 생성할 창(window) 이름
pos
트랙바 초기 위치

 

5. 콜백 함수 만들기

트랙바 변경 시 불릴 콜백 함수를 아래와 같이 만들면 됩니다.

콜백함수 인자는 두개가 되어야 하며, (int n, void* p) 를 인자로 받습니다.

이번에는 전달할 데이터 포인터를 영상의 포인터로 했고, 그 영상을 cv::Mat으로 변환한 후 cv::threshold 함수로 Thresholding을 하였습니다.

void trackbar(int pos, void* pImage)
{
	cv::Mat src = *(cv::Mat*)pImage;
	
	cv::Mat dst;
	cv::threshold(src, dst, pos, 255, cv::THRESH_BINARY);
	cv::imshow("Result", dst);
}
 

전체 소스는 아래와 같습니다.

#include <iostream>
#include <opencv2/opencv.hpp>

void trackbar(int pos, void* pImage)
{
	cv::Mat src = *(cv::Mat*)pImage;
	
	cv::Mat dst;
	cv::threshold(src, dst, pos, 255, cv::THRESH_BINARY);
	cv::imshow("Result", dst);
}

int main()
{
	cv::Mat src = cv::imread("lena_gray.bmp", cv::IMREAD_UNCHANGED);

	cv::namedWindow("Result");
	cv::createTrackbar("threshold", "Result", 0, 255, trackbar, (void*)&src);
	cv::setTrackbarPos("threshold", "Result", 128);
	cv::imshow("Result", src);
	cv::waitKey(0);

	return 0;
}
 

이 소스를 동작시키면 아래와 같은 창이 생성됩니다.

처음 실행 시에는 callback 함수를 생성하면서 한번 불리긴 하나 0을 인자로 넣었기 때문에움직이기 전까지는 threshold가 적용되지 않은 것처럼 보일 수 있습니다.

한번 움직여 볼께요. 살짝 움직이니까 바로 콜백함수(trackbar()) 에 값이 입력되면서 thresholding이 된 영상을 보실 수 있습니다.

trackbar를 여기에서 끝내면 아쉽겠죠? 응용 한번 해 볼께요.

두 개의 Trackbar를 사용하기

트랙바 두개를 사용하기 위해서

이번엔 입력 영상을 인자로 보내지 않고 전역 변수로 선언해보겠습니다.

여기서 convertTo() 함수를 간단하게 설명하면요

함수 원형은 아래와 같아요.

src 영상을 type에 맞게 convert 하여 dst를 만드는데 alpha 를 곱하고 beta 더하라는 뜻 입니다.

type에 -1이 들어갈경우 src와 같은 타입으로 선언됩니다.

앞에서 한번 했으니 여러 줄씩 설명 드릴께요.

1. 영상 읽고 window 생성하기

이번에는 여러 함수에서 src 를 접근하기 위해 전역 변수로 선언했어요.

#include <iostream>
#include <opencv2/opencv.hpp>

// 전역 변수 선언
cv::Mat src;
 

그리고 만약 영상이 읽히지 않았다면 return -1을 하는 코드를 삽입해서 코드의 안정성을 확보했죠.

그리고 이번에는 color 영상을 읽어봤어요.

src = cv::imread("lena_color.bmp", cv::IMREAD_UNCHANGED);
if (src.empty()) return -1;

cv::namedWindow("Result");
 

2. createTrackbar 입력 인자 선언하기

int 형 변수 2개를 선언합니다.

int bright_val = 10;
int cont_val = 1;
 

3. 트랙바 생성 및 첫 position 설정하기

createTrackbar 세번째 인자 변수의 주소값을 넘기고(변수 읽고 쓰기 위해)

trackbar의 max 값을 설정하고 콜백함수명을 설정하고 void*에 현재 트랙바에서 입력되지 않는 변수의 주소값을 넣어서 그 변수를 콜백함수 내에서 접근할 수 있도록 했어요.

cv::createTrackbar("Bright", "Result", &bright_val, 100, trackbar_brightness, &cont_val);
cv::createTrackbar("Contrast", "Result", &cont_val, 100, trackbar_contrast, &bright_val);
cv::setTrackbarPos("Bright", "Result", 10);
cv::setTrackbarPos("Contrast", "Result", 1);
 

4. 콜백 함수 생성

두 개의 콜백함수를 만들었어요.

void*로 들어온 주소값을 static_cast로 명시적 변환을 하여 값으로 얻어오고

convertTo() 함수를 써서 src 영상의 밝기를 변경하였어요

void trackbar_brightness(int bright_val, void* pData)
{
	int cont_val = *(static_cast<int*>(pData));
	double dContVal = static_cast<double>(cont_val / 10.0);
	
	cv::Mat dst;

	src.convertTo(dst, -1, dContVal, bright_val);
	cv::imshow("Result", dst);
}

void trackbar_contrast(int cont_val, void* pData)
{
	int bright_val = *(static_cast<int*>(pData));

	cv::Mat dst;
	double dContVal = static_cast<double>(cont_val / 10.0);

	src.convertTo(dst, -1, dContVal, bright_val);
	cv::imshow("Result", dst);
}
 

전체 소스를 한번 볼께요.

#include <iostream>
#include <opencv2/opencv.hpp>

// 전역 변수 선언
cv::Mat src;

void trackbar_brightness(int bright_val, void* pData)
{
	int cont_val = *(static_cast<int*>(pData));
	double dContVal = static_cast<double>(cont_val / 10.0);
	
	cv::Mat dst;

	src.convertTo(dst, -1, dContVal, bright_val);
	cv::imshow("Result", dst);
}

void trackbar_contrast(int cont_val, void* pData)
{
	int bright_val = *(static_cast<int*>(pData));

	cv::Mat dst;
	double dContVal = static_cast<double>(cont_val / 10.0);

	src.convertTo(dst, -1, dContVal, bright_val);
	cv::imshow("Result", dst);
}

int main()
{
	src = cv::imread("lena_color.bmp", cv::IMREAD_UNCHANGED);
	if (src.empty()) return -1;

	cv::namedWindow("Result");
	
	int bright_val = 10;
	int cont_val = 1;

	cv::createTrackbar("Bright", "Result", &bright_val, 100, trackbar_brightness, &cont_val);
	cv::createTrackbar("Contrast", "Result", &cont_val, 100, trackbar_contrast, &bright_val);
	cv::setTrackbarPos("Bright", "Result", 10);
	cv::setTrackbarPos("Contrast", "Result", 1);
	cv::imshow("Result", src);
	cv::waitKey(0);

	return 0;
}
 

실행을 시켜보면

아래와 같이 트랙바 2개가 생성됩니다.

덧셈과 곱셈을 이용하여 마치 brightness contrast를 변화시킨 효과를 내 본 거에요.