hawkes_bay.bmp
0.99MB
lenna.bmp
0.75MB

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

using namespace std;
using namespace cv;

#define TC 2

//TC1,2 == Histogram stretching
//TC3,4 == Histogram equalization

/*두 기법 모두 히스토그램이 그레이스케일 전체구간에서 픽셀값 분ㅊ포를 골고루 나타나도록 변경하게 해줌.. 히스토그램 평활화는 균등화, 균일화, 평탄화라고 불림*/
/*히스토그램 평활화위한 변환 함수 구하기: 정규화된 히스토그램 구하기  ->  누적분포 함수(cdf) 구하기  */

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

	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 getGrayHistImage(const Mat& hist) {
	CV_Assert(!hist.empty());
	CV_Assert(hist.type() == CV_32F);

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

	Mat imgHist(100, 256, CV_8UC1, Scalar(255));
	for (int x = 0; x < 256; ++x) {
		line(imgHist, Point(x, 100), Point(x, 100 - cvRound(hist.at<float>(x) * 100 / histMax)), Scalar(0));
	}
	return imgHist;
}
int main()
{
	//Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
	Mat src = imread("hawkes_bay.bmp", IMREAD_GRAYSCALE);
	if (src.empty()) {
		cerr << "Image laod failed!" << endl;
		return -1;
	}

#if TC == 1
	//히스토그램 스트레칭  직접 수식작성
	double gmin, gmax;
	minMaxLoc(src, &gmin, &gmax);

	Mat dst = (src - gmin) * 255 / (gmax - gmin);  //opencv 이용한 연산자 오버로딩으로 연산.

#elif TC == 2
	//TC1 을 OPENCV 내장함수 normalize 이용해서 구함.
	Mat dst;
	normalize(src, dst, 0, 255, NORM_MINMAX);

#elif TC == 3
	//equalizeHist 직접구현
	Mat dst(src.rows, src.cols, src.type());

	int hist[256] = {};
	for (int y = 0; y < src.rows; ++y) { 
		for (int x = 0; x < src.cols; ++x) {
			hist[src.at<uchar>(y, x)]++; // 
		}
	} //해당 코드 수행 시 hist배열에 입력영상 히스토그램 정보가 저장됨. 이를 이용해 히스토그램 그래프 그림.

	float cdf[256]{};
	cdf[0] = float(hist[0]) / src.total(); //누적분포 함수 계산 후
	for (int x = 1; x < 256; ++x) cdf[x] = cdf[x - 1] + float(hist[x]) / src.total(); //  cdf 배열에 저장

	for (int y = 0; y < src.rows; ++y) { //영상 전체 픽셀 차례대로 방문 후 입력영상 x,y 좌표를 cdf 배열로 지정해 그, 값을 grayscale 최대 255를 곱해 
		for (int x = 0; x < src.cols; ++x) { // uchar로 설정해 dst에 저장.
			dst.at<uchar>(y, x) = uchar(cdf[src.at<uchar>(y, x)] * 255);
		}
     }



#elif TC ==4
	Mat dst;
	equalizeHist(src, dst); //  입력영상 8비트 1채널 , dst src크기와 타입 동일
#endif

	imshow("src", src);
	imshow("dst", dst);
	imshow("hist_src", getGrayHistImage(calcGrayHist(src)));
	imshow("hist_dst", getGrayHistImage(calcGrayHist(dst))); // 명암비가 높아짐.
	waitKey();
}

히스토그램 스트레칭 직선의 방정식 을 사용해 뭉쳐진 픽셀 펴줌 ( 구간에따라 픽셀갯수가 많코 적고를 구분 가능, 픽셀간 펼쳐진 거리가 좁음)

 

히스토그램 평활화는 곡선에 가까운 변환함수 생성하여 결과물을 만듦 (픽셀간 펼쳐진 거리가 좀 넓음, 갯수가 작은건 전반적으로 펼쳐지지 않음)

둘다 공통적으로 입력영상보단 명암비가 좋아짐

 

사진과 코드를 활용해 두 변환함수 차이와 공통점을 구분하자.

'프로그래머스 > OPENCV' 카테고리의 다른 글

opencv 동영상 (1)  (0) 2022.12.02
영상의 산술 및 논리연산  (0) 2022.12.02
(4) 히스토그램분석  (0) 2022.12.01
영상의 명암비 조절  (0) 2022.12.01
영상의 밝기조절(2)  (3) 2022.12.01

+ Recent posts