히스토그램 그리기 - OpenCV(C++)

Updated:

OpenCV를 이용해 이미지를 받은 후 히스토그램 그리고 visualization

Visual Studio 2017을 사용하였습니다.

컬러 image를 입력받아 히스토그램을 그려보고 보는 것을 포스팅하겠습니다.

저번 포스팅에서는 채널을 분리하여 흑백으로 보았는데요. 이번엔 흑백도 보고 실제 해당하는 채널 색깔을 보는 것도 추가하였습니다.

히스토그램 그래프와 비교하여 보면 편할 것 같습니다.

key 함수 : calcHist, normalize, line

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

using namespace std;
using namespace cv;

int main()
{
	Mat image = imread("Sky.jpg");

	imshow("Image", image);

	Mat BGR[3];
	split(image, BGR);

	const int ch_B[] = { 0 }, ch_G[] = { 1 }, ch_R[] = { 2 };
	const int size = 256;
	float ch_range[] = { 0, 255 };
	const float *range = { ch_range };

	// BGR 채널 각각 보기(gray)
	imshow("RGB_B_gray", BGR[0]);
	imshow("RGB_G_gray", BGR[1]);
	imshow("RGB_R_gray", BGR[2]);

	// 히스토그램과 같이 보려고 만든 코드
	Mat zeros_mat = Mat::zeros(image.size(), CV_8UC1);
	Mat BGR_B[] = { BGR[0], zeros_mat, zeros_mat};
	Mat BGR_G[] = { zeros_mat, BGR[1], zeros_mat };
	Mat BGR_R[] = { zeros_mat, zeros_mat, BGR[2] };
	// 각각 BGR 채널을 컬러로 보기
	merge(BGR_B, 3, BGR[0]);
	merge(BGR_G, 3, BGR[1]);
	merge(BGR_R, 3, BGR[2]);
	imshow("RGB_B", BGR[0]);
	imshow("RGB_G", BGR[1]);
	imshow("RGB_R", BGR[2]);


	// BGR 히스토그램 계산
	Mat Hist_G, Hist_B, Hist_R;
	calcHist(&image, 1, ch_B, Mat(), Hist_B, 1, &size, &range);
	calcHist(&image, 1, ch_G, Mat(), Hist_G, 1, &size, &range);
	calcHist(&image, 1, ch_R, Mat(), Hist_R, 1, &size, &range);


	int hist_w = 512;
	int hist_h = 400;
	int bin_w = cvRound((double)hist_w / 256);

	// CV_8UC3 : 8bit,unsigned, channel = 3
	// Mat (세로 행, 가로 행, 채널 타입, 초기 값)
	Mat hist_Image(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));
	// normalize( 입력 값, 출력 값, 변환 최소값, 변환 최대값, 변환 방식);
	normalize(Hist_B, Hist_B, 0, hist_Image.rows, NORM_MINMAX);
	normalize(Hist_G, Hist_G, 0, hist_Image.rows, NORM_MINMAX);
	normalize(Hist_R, Hist_R, 0, hist_Image.rows, NORM_MINMAX);

	/// 히스토그램을 각각 채널에 대해 따로 그리고 싶을 땐 다음과 같이 mat을 추가로 선언한 후
	/// line에함수에서 각 채널에서 각 Mat 값을 넣으면 됩니다.
	//Mat hist_Image_B(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));
	//Mat hist_Image_G(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));
	//Mat hist_Image_R(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));

	for (int i = 1; i < 256; i++)
	{
		// Line(img:선분이 그려질 이미지, (x1, y1):선분의 시작점, (x2, y2):선분의 끝점, color, thickness, lineType = cv.LINE_8, shift = 0);
		// B
		line(hist_Image, Point(bin_w*(i - 1), hist_h - cvRound(Hist_B.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(Hist_B.at<float>(i))),
			Scalar(255, 0, 0), 2, 0);
		// G
		line(hist_Image, Point(bin_w*(i - 1), hist_h - cvRound(Hist_G.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(Hist_G.at<float>(i))),
			Scalar(0, 255, 0), 2, 0);
		// R
		line(hist_Image, Point(bin_w*(i - 1), hist_h - cvRound(Hist_R.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(Hist_R.at<float>(i))),
			Scalar(0, 0, 255), 2, 0);
	}

	imshow("BGR Histogram", hist_Image);
	/// 각 채널에 대해 히스토그램을 그렸을 때
	//imshow("B Histogram", histImage_B);
	//imshow("G Histogram", histImage_G);
	//imshow("R Histogram", histImage_R);

	waitKey(0);
	return 0;
}

결과

원본 이미지
원본 이미지

B 채널
결과

G 채널
결과

R 채널
결과

히스토그램
결과

Leave a comment