본문 바로가기
런닝머신 (ML)

[컴퓨터 비전 & 머신러닝] 영상의 밝기 조절

728x90

그레이스케일 영상 만들기

Mat img1 = imread("lenna.bmp", IMREAD_GRAYSCALE);
Mat img2(480, 640, CV_8UC1, Scalar(0));
//CV_8UC1 타입, 모든 픽셀 값이 0으로 초기화된 640x480 그레이스케일 영상 생성
Mat img3 = imread("lenna.bmp", IMREAD_COLOR);
Mat img4;
cvtColor(img3, img4, COLOR_BGR2GRAY); //색상 정보를 변경하는 함수
//3채널 컬러 영상을 1채널 그레이스케일 영상으로 변환

영상의 밝기 조절

 

scr은 입력 영상, dst는 출력 영상, n은 조절할 밝기 값을 나타낸다. n이 양수이면 출력 영상 dst의 전체적인 밝기가 증가하고 반대로 n이 음수이면 밝기가 감소한다 

그래프를 자세히 보면 0보다 작아지거나 255보다 커지는 부분에서 직선이 꺾이는 것을 볼 수 있다 이러한 것을 포화 연산이라고 한다.

포화 연산 수식

실제로 영상 밝기 조절을 구현할 때에는 포화연산을 고려해야 한다

dst(x, y) = saturate(src(x, y) + n))
void brightness1()
{
	//그레이스케일로 영상 불러오기
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Mat dst1 = src + 100; //밝기 증기
	Mat dst2 = src - 100; //밝기 감소
    //add() 함수도 사용가능 add(src, 100, dst);

	imshow("src", src);
	imshow("dst1", dst1);
	imshow("dst2", dst2);
	waitKey();

	destroyAllWindows();
}


void brightness2()
{
	//그레이스케일로 영상 불러오기
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	//입력 영상 src와 크기, 타입이 같은 결과 영상 dst를 생성
	Mat dst(src.rows, src.cols, src.type());

	//영상 전체를 스캔하면서 영상의 픽셀 값에 100을 더한다
	for (int j = 0; j < src.rows; j++) {
		for (int i = 0; i < src.cols; i++) {
			dst.at<uchar>(j, i) = src.at<uchar>(j, i) + 100;
		}
	}

	imshow("src", src);
	imshow("dst", dst);
	waitKey();

	destroyAllWindows();
}

결과 영상을 보면 사진의 밝기를 올렸는데도 불구하고 밝은 부분과 어두운 부분이 비정상적으로 섞여있는 것을 볼 수 있다

앞서 설명했던 포화 연산이 수행되지 않았기 때문이다. 255보다 큰 수가 0으로 인지되어 어두운 색으로 바뀌게 되는 것이다

for (int j = 0; j < src.rows; j++) {
	for (int i = 0; i < src.cols; i++) {
		int v = src.at<uchar>(j, i) + 100;
		dst.at<uchar>(j, i) = v > 255 ? 255 : v < 0 ? 0 : v;
	}
}

변수를 int 형으로 저장하면서 255보다 큰 정수를 저장할 수 있게 되므로 255보다 큰 값이면 255를 대입하고 0보다 작으면 0을 대입하는 식이다

for (int j = 0; j < src.rows; j++) {
	for (int i = 0; i < src.cols; i++) {
		dst.at<uchar>(j, i) = saturate_cast<uchar>(src.at<uchar>(j, i) + 100);
	}
}

saturate_cast() 함수를 사용해 행렬의 자료형에 맞게끔 포화연산을 수행 할 수도 있다


트랙바를 이요하여 영상의 밝기 조절

void brightness4()
{
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	namedWindow("dst"); //결과 영상을 출력하고 트랙바를 부착할 dst 창을 미리 생성
    //dst 창에 트랙바를 부착하고 콜백함수 on_brightness를 등록, 입력 영상 scr의 주소를 트랙바 콜백 함수의 사용자 데이터로 설정
	createTrackbar("Brightness", "dst", 0, 100, on_brightness, (void*)&src);
    //위와 마찬가지로 on_darkness등록
	createTrackbar("Darkness", "dst", 0, 100, on_darkness, (void*)&src);
    //프로그램 실행 시 dst 창에 레나 영상이 정상적으로 표시되도록 강제로 on_brightness() 함수를 호출
	on_brightness(0, (void*)&src);
    on_darkness(0, (void*)&src);

	waitKey();
	destroyAllWindows();
}

void on_brightness(int pos, void* userdata)
{
	Mat src = *(Mat*)userdata;
	Mat dst = src + pos;

	imshow("dst", dst);
}

void on_darkness(int pos, void* userdata)
{
	Mat src = *(Mat*)userdata;
	Mat dst = src - pos;

	imshow("dst", dst);
}

728x90