히스토그램 스트레칭과 평활화

전종원·2022년 10월 19일
0

1. 히스토그램 스트레칭

히스토그램 스트레칭

  • 영상의 히스토그램이 그레이스케일 전 구간에서 걸쳐 나타나도록 변경하는 선형변환 기법
  • 특정구간에 집중되어 나타나는 히스토그램을 마치 고무줄을 늘이듯 펼쳐서 그레이스케일 범위 전 구간에서 히스토그램이 골고루 나타나도록 변환

변환 함수의 직선의방정식 구하기

  • 기울기: 255 / (Gmax - Gmin)
  • y절편: 255xGmin / Gmax - Gmin

실습코드

int main()
{
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

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

	double gmin, gmax;
	minMaxLoc(src, &gmin, &gmax); //src에 나타난 픽셀밝기값의 최대 최솟값 구하기

	Mat dst = (src - gmin) * 255 / (gmax - gmin);
	
    // 위 3줄의 코드와 같은작업
    // normalize(src, dst, 0, 255, NORM_MINMAX);
    
	imshow("src", src);
	imshow("dst", dst);

	waitKey();
}

2. 히스토그램 평활화

히스토그램 평활화란

  • 히스토그램이 그레이스케일 전체 구간에서 균일한 분포로 나타나도록 변경하는 명암비 향상기법

평활화 변환함수 구하기

  • 히스토그램을 구한다.
  • 구한 히스토그램을 정규화 시킨다.
  • 누적분포함수(cdf)를 구한다.
  • 누적분포함수에 픽셀값의 최댓값을 곱하고 반올림한다.

실습코드

#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;
using namespace cv;

Mat calcGrayHist(const Mat& img)
{
	CV_Assert(img.type() == CV_8UC1);

	Mat hist;
	int channels[] = { 0 };
	int dims = 1;
	const int histSize[] = { 256 };
	float graylevel[] = { 0, 256 };
	const float* ranges[] = { graylevel };

	calcHist(&img, 1, channels, noArray(), hist, dims, histSize, ranges, true);

	return hist;
}

Mat histImage(const Mat& hist)
{
	CV_Assert(!hist.empty());
	CV_Assert(hist.type() == CV_32FC1);
	CV_Assert(hist.size() == Size(1, 256));

	double histMax = 0.;
	minMaxLoc(hist, 0, &histMax);

	Mat imgHist(100, 256, CV_8U, Scalar(255));
	for (int i = 0; i < 256; i++) {
		line(imgHist, Point(i, 100),
			Point(i, 100 - cvRound(hist.at<float>(i) * 100 / histMax)), Scalar(0));
	}

	return imgHist;
}

int main(int argc, char* argv[])
{
	Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return -1;
	}

	Mat dst(src.rows, src.cols, src.type());

#if 1
	equalizeHist(src, dst);
#else
	int hist[256] = { 0, };
	for (int j = 0; j < src.rows; j++)
		for (int i = 0; i < src.cols; i++)
			hist[src.at<uchar>(j, i)]++;

	int size = (int)src.total();
	float cdf[256] = { 0.0f, };
	cdf[0] = float(hist[0]) / size;
	for (int i = 1; i < 256; i++)
		cdf[i] = cdf[i - 1] + float(hist[i]) / size;

	for (int j = 0; j < src.rows; j++) {
		for (int i = 0; i < src.cols; i++) {
			dst.at<uchar>(j, i) = uchar(cdf[src.at<uchar>(j, i)] * 255);
		}
	}
#endif

	imshow("src", src);
	imshow("dst", dst);
	imshow("hist_src", histImage(calcGrayHist(src)));
	imshow("hist_dst", histImage(calcGrayHist(dst)));
	waitKey();
}

히스토그램 스트레칭과 평활화 결과 비교

0개의 댓글