이미지 히스토그램 분석은 OpenCV에서
이미지의 밝기 분포, 색상 특성, 명암 대비 조정 등에 활용되는 중요한 분석 기법입니다
히스토그램이란 무엇인가요?
히스토그램은 이미지에서 픽셀 값의 분포를 보여주는 그래프예요.
예를 들어 그레이스케일 이미지에서는 픽셀 밝기(0~255)가
얼마나 자주 등장하는지를 x축, 등장 빈도를 y축으로 나타내요.
히스토그램을 보면 이미지가 전체적으로 어두운지, 밝은지, 대비가 낮은지 등을 한눈에 알 수 있어요.
컬러 이미지에서는 채널별(B, G, R)로 히스토그램을 나눠서 분석합니다.
OpenCV로 히스토그램 계산하기
OpenCV에서는 cv::calcHist() 함수를 사용해서 간단히 히스토그램을 구할 수 있어요.
그레이스케일 이미지 기준으로 예를 들면 다음과 같아요.
cv::Mat gray = cv::imread("sample.jpg", cv::IMREAD_GRAYSCALE); int histSize = 256; // 밝기 단계 수 float range[] = { 0, 256 }; const float* histRange = { range }; cv::Mat hist; cv::calcHist(&gray, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange); |
이렇게 얻은 hist에는 각 밝기값(0~255)이 몇 번 등장했는지가 저장돼 있어요.
컬러 이미지라면 채널을 분리한 후 B, G, R 각각 따로 계산해야 해요.
히스토그램 시각화와 해석
히스토그램은 단순한 수치보다 시각화가 중요해요.
OpenCV로 직접 그릴 수도 있지만,
간단한 방법은 matplotlib(Python)이나 OpenCV의 그리기 함수(line, rectangle)를 활용하는 거예요.
예를 들어 픽셀이 0~50 사이에 몰려 있으면 어두운 이미지이고,
중간에 몰려 있으면 적당한 노출, 끝쪽에 몰려 있으면 과노출일 수 있어요.
히스토그램이 넓게 퍼져 있을수록 대비가 높고 선명한 이미지라는 뜻이에요.
컬러 이미지의 BGR 채널 히스토그램 시각화 방법
컬러 이미지의 히스토그램을 시각화하려면 B, G, R 각 채널을 분리한 후,
각각의 히스토그램을 계산하고, 다른 색상의 선으로 한 이미지 안에 그려주는 방식이 일반적이에요.
이렇게 하면 어떤 채널이 어떤 밝기값에 집중되어 있는지 시각적으로 쉽게 파악할 수 있어요.
아래는 OpenCV를 사용한 대표적인 C++ 예제 구조입니다.
cv::Mat image = cv::imread("sample.jpg"); std::vector<cv::Mat> bgr_planes; cv::split(image, bgr_planes); // B, G, R 분리 int histSize = 256; float range[] = { 0, 256 }; const float* histRange = { range }; cv::Mat b_hist, g_hist, r_hist; // 각 채널 히스토그램 계산 cv::calcHist(&bgr_planes[0], 1, 0, cv::Mat(), b_hist, 1, &histSize, &histRange); cv::calcHist(&bgr_planes[1], 1, 0, cv::Mat(), g_hist, 1, &histSize, &histRange); cv::calcHist(&bgr_planes[2], 1, 0, cv::Mat(), r_hist, 1, &histSize, &histRange); // 히스토그램 시각화를 위한 캔버스 생성 int hist_w = 512, hist_h = 400; int bin_w = cvRound((double)hist_w / histSize); cv::Mat histImage(hist_h, hist_w, CV_8UC3, cv::Scalar(0, 0, 0)); // 정규화 cv::normalize(b_hist, b_hist, 0, histImage.rows, cv::NORM_MINMAX); cv::normalize(g_hist, g_hist, 0, histImage.rows, cv::NORM_MINMAX); cv::normalize(r_hist, r_hist, 0, histImage.rows, cv::NORM_MINMAX); // 각 채널 히스토그램 그리기 for (int i = 1; i < histSize; i++) { cv::line(histImage, cv::Point(bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1))), cv::Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), cv::Scalar(255, 0, 0), 2); cv::line(histImage, cv::Point(bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1))), cv::Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))), cv::Scalar(0, 255, 0), 2); cv::line(histImage, cv::Point(bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1))), cv::Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))), cv::Scalar(0, 0, 255), 2); } cv::imshow("BGR Histogram", histImage); cv::waitKey(0); |
이를 통해 이미지의 색상 밸런스, 특정 색상 강조 유무 등을 시각적으로 빠르게 파악할 수 있어요
히스토그램 응용: 스트레칭과 평활화
히스토그램 분석은 단순히 분포를 보는 것에서 끝나지 않아요.
예를 들어 cv::equalizeHist()를 사용하면 히스토그램을 평탄화해 대비를 자동으로 향상시킬 수 있어요.
또, cv::normalize()로 히스토그램을 스트레칭하면 밝기 범위를 확장해 더 뚜렷한 이미지를 만들 수 있어요.
이 기법은 사진 보정, 문서 이미지 개선, 객체 탐지 전처리 등 실무에서도 널리 활용돼요.
이 블로그의 내용을 대화 형식인 음성으로 들으면서 정리하면, 보다 쉽게 이해할 수 있을 거예요.
다운받아 들어보세요~
'IT' 카테고리의 다른 글
OpenCV로 엣지 검출: Canny 알고리즘 설명과 활용 (0) | 2025.06.26 |
---|---|
OpenCV로 밝기 및 대비 조절하기 (0) | 2025.06.26 |
OpenCV 필터링: 블러, 가우시안, 미디언 필터 사용법 (0) | 2025.06.25 |
OpenCV로 이미지 자르기와 리사이징 (0) | 2025.06.25 |
OpenCV로 이미지 읽기, 저장, 표시하기 (0) | 2025.06.25 |