OpenCV2.X向けのヒストグラムクラス。
1Dとカラーのやつは「
OpenCV 2 Computer Vision Application Programming Cookbook」に載っているやつ。これを基に、2次元ヒストグラム画像作成など自分なりに手を入れているけれど、まだ中途半端。
#include <opencv2/opencv.hpp>
class Histogram1D {
private:
int histSize[1];
float hranges[2];
const float* ranges[1];
int channels[1];
public:
Histogram1D(int hsize = 256) {
histSize[0] = hsize; //number of bins
hranges[0] = 0.0; //min pixel value
hranges[1] = 255.0; //max pixel value
ranges[0] = hranges;
channels[0] = 0; //by default, we lookup channel 0
}
void setHistSize(int hsize) {
histSize[0] = hsize;
}
void setRanges(float min, float max) {
hranges[0] = min;
hranges[1] = max;
ranges[0] = hranges;
if(max-min<histSize[0]) {
histSize[0] = (int)(max-min);
}
}
cv::MatND getHistogram(const cv::Mat &image, int ch = 0) {
cv::MatND hist;
channels[0] = ch;
cv::calcHist(&image, 1, channels, cv::Mat(), hist, 1, histSize, ranges);
return hist;
}
cv::Mat getHistogramImage(const cv::Mat &image, int channel = 0) {
cv::MatND hist= getHistogram(image, channel);
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]);
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;
}
};
class Histogram2D {
private:
int histSize[2];
float hranges[2];
const float* ranges[2];
int channels[2];
public:
Histogram2D(int h1size=256, int h2size = 256) {
histSize[0] = h1size;
histSize[1] = h2size;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
ranges[1] = hranges;
channels[0] = 0;
channels[1] = 1;
}
cv::MatND getHistogram(const cv::Mat &img1, const cv::Mat &img2) {
cv::Mat planes[2];
img1.copyTo(planes[0]);
img2.copyTo(planes[1]);
cv::MatND hist;
cv::calcHist(planes, 2, channels, cv::Mat(), hist, 2, histSize, ranges);
return hist;
}
cv::Mat getHistogramImage(const cv::Mat &img1, const cv::Mat &img2) {
cv::MatND hist= getHistogram(img1, img2);
double maxVal = 0;
double minVal = 0;
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
cv::Mat histImg(histSize[0], histSize[1], CV_8U, cv::Scalar(0));
for(int h=0; h<histSize[0]; h++) {
for(int i=0; i<histSize[1]; i++) {
float binVal = hist.at<float>(h,i);
uchar intensity = static_cast<uchar>(binVal*255/maxVal);
histImg.at<uchar>(h,i) = intensity;
}
}
return histImg;
}
};
class ColorHistogram {
private:
int histSize[3];
float hranges[2];
const float* ranges[3];
int channels[3];
public:
ColorHistogram(int hSize = 256) {
histSize[0] = histSize[1] = histSize[2] = hSize;
hranges[0] = 0.0;
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;
cv::calcHist(&image, 1, channels, cv::Mat(), hist, 3, histSize, ranges);
return hist;
}
cv::SparseMat getSparseHistogram(const cv::Mat &image) {
cv::SparseMat hist(3, histSize, CV_32F);
cv::calcHist(&image, 1, channels, cv::Mat(), hist, 3, histSize, ranges);
return hist;
}
};
呼び出す側のソース例。
#include <opencv2/opencv.hpp>
#include "histogram.hpp"
#ifdef _DEBUG
#pragma comment(lib,"opencv_core230d.lib")
#pragma comment(lib,"opencv_highgui230d.lib")
#pragma comment(lib,"opencv_imgproc230d.lib")
#else
#pragma comment(lib,"opencv_core230.lib")
#pragma comment(lib,"opencv_highgui230d.lib")
#pragma comment(lib,"opencv_imgproc230d.lib")
#endif
using namespace cv;
using std::cout;
using std::endl;
int main()
{
//モノクロ画像のヒストグラム表示
Mat gray_img = imread("d:/test1.bmp", 0);
imshow("gray", gray_img);
Histogram1D h1(256);
imshow("Histogram", h1.getHistogramImage(gray_img));
//カラー画像のチャネル別ヒストグラム画像表示j
Mat cimg = imread("d:/test2.bmp");
imshow("color", cimg);
imshow("B", h1.getHistogramImage(cimg));
imshow("G", h1.getHistogramImage(cimg, 1));
imshow("R", h1.getHistogramImage(cimg, 2));
Mat hsvImg;
cvtColor(cimg, hsvImg, CV_BGR2HSV_FULL);
imshow("H", h1.getHistogramImage(hsvImg, 0));
imshow("S", h1.getHistogramImage(hsvImg, 1));
imshow("V", h1.getHistogramImage(hsvImg, 2));
//h1.setRanges(0.0, 180.0);
//imshow("H", h1.getHistogramImage(hsvImg));
//2チャンネル2次元ヒストグラム画像表示
std::vector<cv::Mat> planes;
cv::split(cimg, planes);
Histogram2D h2(128,128);
imshow("2Dhist", h2.getHistogramImage(planes[0], planes[1]));
//各ヒストグラムを得る。
MatND hist1 = h1.getHistogram(gray_img);
MatND hist2 = h2.getHistogram(planes[0], planes[1]);
//cout << hist2 << endl;
waitKey();
}