- 유사하게 BGR 영상의 히스토그램을 계산하기 위한 클래스를 정의할 수 있음.
- Example
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
// 멤버 변수 정의
class ColorHistogram {
private:
int histSize[3]; // 빈도수
float hranges[2]; // 최소/최대 화소값
const float* ranges[3];
int channels[3]; // 3채널 사용
public :
ColorHistogram() { // 컬러 히스토그램을 위한 인자 준비
// 3차원 히스토그램 (각 차원의 범위 설정해 줌)
// BGR 영상의 경우 세가지 채널은 같은 [0, 255] 범위를 갖음.
histSize[0] = histSize[1] = histSize[2] = 256;
hranges[0]= 0.0; // BGR 범위
hranges[1]= 255.0;
ranges[0]= hranges; // 모든 채널은 같은 범위를 가짐
ranges[1]= hranges;
ranges[2]= hranges;
channels[0]= 0; // 세 가지 채널
channels[1]= 1;
channels[2]= 2;
}
// 정의한 멤버 변수로 영상의 히스토그램을 계산할 때 다음 메소드를 사용해 수행
// 다음 메소드에서 컬러 히스토그램을 계산
cv::MatND getHistogram(const cv::Mat &image) {
cv::MatND hist;
hranges[0] = 0.0; // BGR 범위
hranges[1] = 255.0;
channels[0] = 0; // 세 가지 채널
channels[1] = 1;
channels[1] = 2;
cv::calcHist(&image, // 히스토그램 계산
1, // 단일 영상의 히스토그램만
channels, // 대상 채널
cv::Mat(), // 마스크 사용하지 않음
hist, // 결과 히스토그램
3, // 3차원(3D) 히스토그램
histSize, // 빈도수
ranges // 화소값 범위
);
return hist;
} // 3차원 cv::Mat 인스턴스를 반환.
// (256)x3 요소를 갖으며, 1,600만 개 이상의 항목을 나타냄.
// 큰 히스토그램을 위해 컬러개수를 감추갛는 것이 좋음.
// 큰 희소행렬을 표한하기 위해 cv::SparseMat 데이터 구조 사용 가능
// calcHist 함수는 하나의 행렬을 반환하는 버전이 있음.
// 즉, cv::SparseMatrix를 사용하기 위한 이전 메소드를 수정하는 것이 간단.
/*
cv::SparseMat getSparseHistogram(const cv::Mat &image) {
cv::SparseMat hist(3,histSize,CV_32F);
// BGR 컬러 히스토그램
hranges[0]= 0.0; // BRG 범위
hranges[1]= 255.0;
channels[0]= 0; // 세 가지 채널
channels[1]= 1;
channels[2]= 2;
cv::calcHist(&image, // 히스토그램 계산
1, // 단일 영상의 히스토그램만
channels, // 대상 채널
cv::Mat(), // 마스크 사용하지 않음
hist, // 결과 히스토그램
3, // 3D 히스토그램
histSize, // 빈도수
ranges // 화소값 범위
);
return hist;
}
*/
cv::Mat colorReduce(const cv::Mat &image, int div=64) {
int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
// 화소값 반올림 하기 위해 사용하는 마스크
uchar mask= 0xFF<<n; // 예, div=16이면 mask= 0xF0
cv::Mat_<cv::Vec3b>::const_iterator it= image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator itend= image.end<cv::Vec3b>();
// 결과 영상 설정(항상 1-채널)
cv::Mat result(image.rows,image.cols,image.type());
cv::Mat_<cv::Vec3b>::iterator itr= result.begin<cv::Vec3b>();
for ( ; it!=itend; ++it, ++itr) {
(*itr)[0]= ((*it)[0]&mask) + div/2;
(*itr)[1]= ((*it)[1]&mask) + div/2;
(*itr)[2]= ((*it)[2]&mask) + div/2;
}
return result;
}
// 값의 순서만으로 의미를 파악하기 어려우므로 바 그래프를 사용
// 그래프를 생성하는 메소드
/*
cv::Mat getHistogramImage(const cv::Mat &image){
// 1차원(1D) 히스토그램을 계산하고, 영상으로 반환
cv::MatND hist= getHistogram(image); // 먼저 히스토그램 계산
double maxVal=0; // 최대 빈도수 가져오기
double minVal=0; // 최소 빈도수 가져오기
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
cv::Mat histImg(histSize[0], histSize[0], CV_8U,cv::Scalar(255));
// 히스토그램을 출력하기 위한 영상
int hpt = static_cast<int>(0.9*histSize[0]);
// nbins의 90%를 최대점으로 설정
for(int h=0; h<histSize[0]; h++){ // 각 빈도에 대한 수직선을 그리기
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt/maxVal);
cv::line(histImg,cv::Point(h,histSize[0]),cv::Point(h,histSize[0]-intensity),cv::Scalar::all(0));
// 두 점 간의 거리를 그리는 함수
}
return histImg;
}
*/
};
int main()
{
ColorHistogram hc; // 히스토그램 객체
cv::Mat color = cv::imread("batgirl.jpg");
color = hc.colorReduce(color, 32);
cv::namedWindow("Color Image");
cv::imshow("Color Image", color);
cv::MatND shist= hc.getHistogram(color);
// cv::SparseMat shist= hc.getSparseHistogram(color);
// OpenCV2.1에서 SparseMat이 있는 히스토그램을 수행하지 않음.
/*
cv::MatND histo = h.getHistogram(image); // 히스토그램 계산
for(int i=0 ; i<256 ; i++) // 각 빈도 조회
std::cout << "Value " << i << " = " << histo.at<float>(i) << std::endl;
cv::namedWindow("Histogram");
cv::imshow("Histogram", h.getHistogramImage(image));
// 히스토그램을 영상으로 띄우기
// 가운데를 중심으로 왼쪽이 검정색, 오른쪽이 흰색값
// 가운데 봉우리 부분은 중간 명암도 값
// 왼쪽이 영상의 전경, 오른쪽이 배경
// 영상을 두 그룹으로 나누는 부분을 경계값으로 처리해 확인
cv::Mat thresholded; // 경계값으로 이진 영상 생성
cv::threshold(image,thresholded,60,255,cv::THRESH_BINARY);
// 영상을 경계화 하기 위해 히스토그램의
// 높은 봉우리(명암값 60) 방향으로 증가하기 직전인 최소값으로 정함.
cv::namedWindow("Binary Image"); // 경계화된 영상 띄워 보기
cv::imshow("Binary Image",thresholded); // 배경과 전경이 분할됨
*/
cv::waitKey(0);
return 0;
}
보류...
- 참고문헌 : OpenCV 2 Computer Vision Application Programming Cookbook