[2023-04-20] 1. 영상의 밝기 조절
영상의 밝기 조절
그레이스케일 영상 다루기
- 많은 CV 알고리즘이 그레이스케일 영상을 사용
-
그레이스케일 영상은 픽셀당 밝기 정보 하나만 포함으로 단순하고 메모리를 적게 사용하여 연산 시간을 감소시킴
- OpenCV에서 그레이스케일 영상을 다루는 코드
Mat img1 = imread("lenna.bmp", IMREAD_GRAYSCALE);
Mat img2(rows, cols, CV_8UC1)
Mat img3("lenna.bmp", IMREAD_COLOR);
Mat img4;
cvtColor(img3, img4, COLOR_BGR2GRAY)
영상의 화소 처리(point processing)
- 입력 영상의 특정 좌표 픽셀 값을 변경하여 출력 영상의 해당 좌표 픽셀 값으로 설정하는 연산
- 반전, 밝기 조절, 명암비 조절, 이진화등이 가능함
- 결과 영상의 픽셀 값이 정해진 범위에 있어야함
영상의 밝기 조절
- 영상 전체 밝기를 일괄적으로 밝게 만들거나 어둡게 만드는 연산
- 밝기 조절 수식
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
// Mat dst = src + 50; 대신 아래와 같이
Mat dst;
dst = src + 50; // add(Src,50,dst); 와 같음
imshow("src", src);
imshow("dst", dst);
waitKey();
}
영상의 반전
- 영상 내의 모든 픽셀 값을 각각 그레이스케일 최댓값에서 뺀 값으로 설정
- 밝은 픽셀은 어둡게, 어두운 픽셀은 밝게 변경하는 연산
- 컬러 영상에 대해서는 각각의 색상 성분에 대해 반전
- 영상 반전 수식
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
Mat dst = 255 - src;
imshow("src", src);
imshow("dst", dst);
waitKey();
}
영상의 밝기 조절 직접 구현
int main()
{
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
#if 0
Mat dst = src + 50;
#else
Mat dst(src.rows, src.cols, src.type()); // src의 영상과 동일한 크기의 영상 dst 만들기
for (int j = 0; j < src.rows; j++) {
for (int i = 0; i < src.cols; i++) {
int v = src.at<uchar>(j,i) - 50;
// if (v > 255) v = 255;
// if (v < 0) v = 0;
// v = (v > 255) ? 255 : (v < 0) ? 0 : v;
dst.at<uchar>(j, i) = saturate_cast<uchar>(src.at<uchar>(j, i) + 50); // src의 각 픽셀에 50을 더한 값을 dst에 저장
// 행인 j 먼저 열인 i는 두번째
// 포화 연산 함수를 사용하는 이유는?
// uchar형인 src.at<uchar>(j,i)과 int형인 50을 더하면 int 형의 변수가 나오는데 dst.at<uchar>(j,i)는 또 uchar 형임
// 두 개의 합인 int형이 uchar 형으로 변환이 되면서 값의 변화가 생김
// src.at<uchar>이 210 로 설정하고 2개를 더하면 260이므로 256를 넘어버려서 uchar에는 저장이 안되서 260-256 = 4 값이 저장됨
// 따라서 기존 이미지의 밝은 부분에 대해서 포화 연산이 제대로 적용되지 않아 이상한 값이 나오는 것을 확인 할 수 있음
// 0 보다 작아질때도 마찬가지임
// 따라서 saturate_cast() 포화 연산 함수를 사용해 간단하게 해결 할 수 있음
}
}
#endif
imshow("src", src);
imshow("dst", dst);
waitKey();
}
- 포화 연산 함수를 적용 안했을 때 결과
- 포화 연산 함수를 적용했을 때 결과
평균 밝기 보정 프로그램
-
입력 영상의 평균 밝기가 그레이스케일 128이 되도록 보정
-
입력 영상에(128 - 평균 밝기) 값을 더함
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
if (argc < 2) {
cerr << "Usage: adjmean.exe <filename>" << endl;
return -1;
}
Mat src = imread(argv[1], IMREAD_GRAYSCALE); // argv[1] 영상을 그레이스케일 형태로 불러와 src에 저장
if (src.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
int s = 0;
for (int j = 0; j < src.rows; j++) {
for (int i = 0; i < src.cols; i++) {
s += src.at<uchar>(j, i); // 입력 영상인 src의 평균 밝기 구하기
}
}
int m = s / (src.rows * src.cols);
//int m = sum(src)[0] / src.total();
//int m = mean(src)[0];
cout << "Mean value: " << m << endl;
Mat dst = src + (128 - m); // 평균 밝기가 128이 되도록 밝기 보정하기
imshow("src", src);
imshow("dst", dst);
waitKey();
}
- lenna.bmp의 평균 밝기는 124이므로 src에 4를 더해서 dst 값으로 저장한 것이므로 사람 눈으로 구별이 어려움
- columbia.bmp의 평균 밝기는 84로 src에 44를 더해서 dst 값으로 저장한 것으로 입력 영상보다 전체적으로 밝아진 출력 영상을 확인할 수 있음
- tiffany.bmp의 평균 밝기는 211이므로 src에 83을 빼서 dst 값으로 저장한 것으로 입력 영상보다 전체적으로 어두워진 출력 영상을 확인할 수 있음