21.3.10 이후 업로드된 본 블로그의 openCV 게시글은 모두 < OPENCV 4로 배우는 컴퓨터 비전과 머신러닝 > 도서를 정리한 내용입니다.
입력 영상의 모든 픽셀에 일정 값을 더하거나 빼면 영상의 밝기를 조절할 수 있다. 양수 값을 더하면 영상이 밝아지고, 양수 값을 빼면 영상이 어두워 지는 것이다.
dst(x, y) = src(x, y) + n
이 수식은 영상의 밝기조절을 표현한 것이다. src는 입력영상, dst는 출력영상이고, n은 조절할 밝기 값을 나타낸다.
이때 각 픽셀의 값은 그레이스케일 값의 최댓값인 255를 넘지 않아야 하며 예로 특정 픽셀값이 200이고, 밝기를 100만큼 높인다면 결과 영상의 픽셀값을 300대신 255로 설정하는 것이다.
void brightness1() {
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
Mat dst = src + 100;
imshow("src", src);
imshow("dst", dst);
waitKey();
destroyAllWindows();
}
Mat dst = src + 100;
위 코드에서 Mat 클래스 타입인 src, dst 변수가 설정되어있고, dst를 src의 각 원소값에 100을 더한 값을 행렬에 저장한것이다.
OpenCV가 제공하는 연산자 함수를 사용하지 않고 직접 코드를 작성해본다. 입력 영상의 모든 픽셀을 방문하며 일정한 상수를 더하거나 빼는 방식이다.
void brightness2() {
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
Mat dst(src.rows, src.cols, src.type());
for (int i = 0; i < src.rows; i++) {
for (int j = 0; j < src.cols; j++) {
dst.at<uchar>(i, j) = src.at<uchar>(i, j) + 100;
}
}
imshow("src", src);
imshow("dst", dst);
waitKey();
destroyAllWindows();
}
그러나 결과영상을 확인하면 어두운 부분이 이상하게 섞여있는 것을 확인할 수 있다. 이것은 포화연산을 수행하지 않았기때문인데 여기서 만약 원소가 256으로 설정되면 최댓값인 255가 아닌 0으로 설정된다. 따라서 for문에서 원소에 접근할때 조건들을 추가해야 한다.
int v = src.at<uchar>(i,j) + 100;
dst.at<uchar>(i,j) = v > 255 ? 255 : v < 0 ? 0 : v;
위 코드를 추가하여 255보다 크면 255, 0보다 작으면 0, 그 사이 값이면 그대로 출력하도록 하는 것이다.
또 다른 방법으로는 saturate_cast() 함수를 사용하는 것인데, 파라미터로 범위의 정수를 넣어 0-255 사이의 정수로만 반환하도록 한다.
그 결과 제대로된 밝기 조절이 된 것을 확인할 수 있다.
createTrackbar("Brightness", "dst", 0, 100, on_brightness, (void*)&src);
createTrackbar 함수를 통해 트랙바를 추가해 줄 수 있다. 먼저 "Brightness" 라는 이름을 트랙바에 붙여줄 수 있고, "dst" 창에 트랙바를 생성한다. 최저값 0, 최댓값 100으로 설정하고 트랙바를 움직일때마다 on_brightness 함수를 콜 하여 결과값을 바꾸어 준다.
void on_brightness(int pos, void* userdata) {
Mat src = *(Mat*)userdata;
Mat dst = src + pos;
imshow("dst", dst);
}
on_brightness() 함수는 위와 같이 정의되었고 트랙바의 값만큼 원소값을 더해주고 그 결과를 바로바로 imshow 하여 보여주는 것이다.