지난 번에는 마우스 이벤트를 처리하는 방법에 대해 알아봤습니다.
https://blog.naver.com/dorergiverny/223084092098
이번에는 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를 변화시킨 효과를 내 본 거에요.