#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
class Histogram1D {
private:
int histSize[1]; // number of bins
float hranges[2]; // min and max pixel value
const float* ranges[1];
int channels[1]; // only 1 channel used here
public:
Histogram1D() {
// Prepare arguments for 1D histogram
histSize[0] = 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
channels[0] = 0; // by default, we look at channel 0
}
// Computes the 1D histogram
cv::MatND getHistogram(const cv::Mat &image);
// Computes the 1D histogram and returns an image of it.
cv::MatND getHistogramImage(const cv::Mat &image);
};
#include "Histgram1D.h"
// Computes the 1D histogram
cv::MatND Histogram1D::getHistogram(const cv::Mat &image) {
cv::MatND hist;
// Compute histogram
cv::calcHist(&image,
1, // histogram from 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
1, // it is a 1D histgram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
cv::Mat Histogram1D::getHistogramImage(const cv::Mat &image) {
// Compute histogram first
cv::MatND hist = getHistogram(image);
// Get min and max bin values
double maxVal = 0;
double minVal = 0;
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
// Image on which to display histogram
cv::Mat histImg(histSize[0], histSize[0], CV_8U, cv::Scalar(255));
// Set highest point at 90% of nbins
int hpt = static_cast <int >(0.9 * histSize[0]);
// Draw a vertical line for each bin
for ( int h = 0; h < histSize[0]; h++ ) {
float binVal = hist.at<float>(h);
int intensity = static_cast <int >(binVal * hpt / maxVal);
// This function draws a line between 2 points
cv::line(histImg, cv::Point(h, histSize[0]),
cv::Point(h, histSize[0] - intensity),
cv::Scalar::all(0));
}
return histImg;
}
main.cpp
#include <iostream>
#include "Histgram1D.h"
int main() {
// Read input image
cv::Mat image = cv::imread( "group.jpg", 0); // open in b&w
// The histogram object
Histogram1D h;
// Compute the histogram
cv::MatND histo = h.getHistogram(image);
// Loop over each bin
for (int i = 0; i < 256; i++) {
std::cout << "Value " << i << " = " <<
histo.at<float >(i) << std::endl;
}
// Draw histogram image
cv::Mat histoImage = h.getHistogramImage(image);
cv::namedWindow( "histogram", CV_WINDOW_AUTOSIZE);
cv::imshow( "histogram", histoImage);
// threshold the image
cv::Mat thresholded;
cv::threshold(image, thresholded, 60, 255, cv::THRESH_BINARY);
cv::namedWindow( "Binary image", CV_WINDOW_AUTOSIZE);
cv::imshow( "Binary image", thresholded);
cv::waitKey(0);
return 0;
}
the result as follows:


#include <iostream>
#include "Histgram1D.h"
int main() {
// Read input image
cv::Mat image = cv::imread( "group.jpg", 0); // open in b&w
// The histogram object
Histogram1D h;
// Compute the histogram
cv::MatND histo = h.getHistogram(image);
// Loop over each bin
for (int i = 0; i < 256; i++) {
std::cout << "Value " << i << " = " <<
histo.at<float >(i) << std::endl;
}
// Draw histogram image
cv::Mat histoImage = h.getHistogramImage(image);
cv::namedWindow( "histogram", CV_WINDOW_AUTOSIZE);
cv::imshow( "histogram", histoImage);
// threshold the image
cv::Mat thresholded;
cv::threshold(image, thresholded, 60, 255, cv::THRESH_BINARY);
cv::namedWindow( "Binary image", CV_WINDOW_AUTOSIZE);
cv::imshow( "Binary image", thresholded);
cv::waitKey(0);
return 0;
}
ColorHistogram.cpp
#include "ColorHistogram.h"
// Computes the 1D histogram
cv::MatND ColorHistogram::getHistogram(const cv::Mat &image) {
cv::MatND hist;
// Compute histogram
cv::calcHist(&image,
1, // histogram from 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
3, // it is a 3D histgram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
cv::SparseMat ColorHistogram::getSpareHistogram(const cv::Mat &image) {
// Compute histogram first
cv::SparseMat hist(3, histSize, CV_32F);
// Compute histogram
cv::calcHist(&image,
1, // histogram from 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
3, // it is a 3D histgram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
cv::Mat Histogram1D::applyLookUp(const cv::Mat& image, // input image
const cv::Mat& lookup) { // 1*256 uchar matrix
// the output image
cv::Mat result;
// apply the lookup table
cv::LUT(image, lookup, result);
return result;
}
cv::Mat Histogram1D::strech(const cv::Mat &image, int minValue /* = 0 */) {
// Compute histogram first
cv::MatND hist = getHistogram(image);
// find left extremity of the histogram
int imin = 0;
for ( ; imin < histSize[0]; imin ++) {
std::cout << hist.at<float>(imin) << std::endl;
if (hist.at<float >(imin) > minValue) {
break;
}
}
// find right extremity of the histogram
int imax = histSize[0] - 1;
for ( ; imax >= 0; imax --) {
if (hist.at<float >(imax) > minValue)
break;
}
// Create lookup table
int dim(256);
cv::Mat lookup(1, // 1 dimension
&dim, // 256 entries
CV_8U // uchar
);
// Build lookup table
for (int i = 0; i < 256; i++) {
// stretch between imin and imax
if (i < imin) lookup.at<uchar>(i) = 0;
else if (i > imax) lookup.at<uchar>(i) = 255;
//linear mapping
else lookup.at<uchar>(i) = static_cast <uchar>(255.0 * (i - imin) / (imax - imin) + 0.5);
}
// Apply lookup table
cv::Mat result;
result = applyLookUp(image, lookup);
return result;
}
Using the function as follows:
cv::Mat streched = h.strech(image, 100);
cv::namedWindow( "streched image", CV_WINDOW_AUTOSIZE);
cv::imshow( "streched image", streched);
cv::Mat strechedHistoImage = h.getHistogramImage(streched);
cv::namedWindow( "strechedHistoImage", CV_WINDOW_AUTOSIZE);
cv::imshow( "strechedHistoImage", strechedHistoImage);
results as follows:



cv::Mat Histogram1D::equalize(const cv::Mat &image) {
cv::Mat result;
cv::equalizeHist(image, result);
return result;
}
result as follows:


#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
class ContentFinder {
private:
float hranges[2];
const float* ranges[3];
int channels[3];
float threshold;
cv::MatND histogram;
public:
ContentFinder() : threshold(-1.0f) {
ranges[0] = hranges; // all channels have same range
ranges[1] = hranges;
ranges[2] = hranges;
}
// Sets the threshold on histogram values [0, 1]
void setThreshold(float t) {
threshold = t;
}
// Gets the threshold
float getThreshold() {
return threshold;
}
// Sets the reference histogram
void setHistogram(const cv::MatND &h) {
histogram = h;
cv::normalize(histogram, histogram, 1.0);
}
cv::Mat find(const cv::Mat &image, float minValue, float maxValue, int *channels, int dim);
};
ContentFinder.cpp
#include "ContentFinder.h"
cv::Mat ContentFinder::find(const cv::Mat &image,
float minValue,
float maxValue,
int *channels,
int dim) {
cv::Mat result;
hranges[0] = minValue;
hranges[1] = maxValue;
for (int i = 0; i < dim; i++) {
this->channels[i] = channels[i];
}
cv::calcBackProject(&image, 1, // input image
channels, // list of channels used
histogram, // the histogram we are using
result, // the resulting backprojection
ranges, // the range of values
255.0 // the scaling factor
);
// Threshold back projection to obtain a binary image
if (threshold > 0.0)
cv::threshold(result, result, 255 * threshold, 255, cv::THRESH_BINARY);
return result;
}
ColorHistogram hc;// load color imagecv::Mat color = cv::imread( "waves.jpg");//reduce colorscolor = hc.colorReduce(color, 32);// blue sky areacv::Mat imageROI = color(cv::Rect(0, 0, 165, 75));
cv::MatND hist = hc.getHistogram(imageROI);ContentFinder finder;finder.setHistogram(hist);finder.setThreshold(0.05f);//Get back-projection of color histogramcv::Mat result = finder.find(color);cv::namedWindow( "original image", CV_WINDOW_AUTOSIZE);cv::imshow( "original image", color);cv::namedWindow( "color back projection result", CV_WINDOW_AUTOSIZE);cv::imshow( "color back projection result", result);


#if !defined COLHISTOGRAM
#define COLHISTOGRAM
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
class ColorHistogram {
private:
int histSize[3];
float hranges[2];
const float* ranges[3];
int channels[3];
public:
ColorHistogram() {
// Prepare arguments for a color histogram
histSize[0]= histSize[1]= histSize[2]= 256;
hranges[0]= 0.0; // BRG range
hranges[1]= 255.0;
ranges[0]= hranges; // all channels have the same range
ranges[1]= hranges;
ranges[2]= hranges;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
}
// Computes the histogram.
cv::MatND getHistogram(const cv::Mat &image) {
cv::MatND hist;
// BGR color histogram
hranges[0]= 0.0; // BRG range
hranges[1]= 255.0;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
// Compute histogram
cv::calcHist(&image,
1, // histogram of 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
3, // it is a 3D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
// Computes the histogram.
cv::SparseMat getSparseHistogram(const cv::Mat &image) {
cv::SparseMat hist(3,histSize,CV_32F);
// BGR color histogram
hranges[0]= 0.0; // BRG range
hranges[1]= 255.0;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
// Compute histogram
cv::calcHist(&image,
1, // histogram of 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
3, // it is a 3D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
// Computes the 2D ab histogram.
// BGR source image is converted to Lab
cv::MatND getabHistogram(const cv::Mat &image) {
cv::MatND hist;
// Convert to Lab color space
cv::Mat lab;
cv::cvtColor(image, lab, CV_BGR2Lab);
// Prepare arguments for a 2D color histogram
hranges[0]= -128.0;
hranges[1]= 127.0;
channels[0]= 1; // the two channels used are ab
channels[1]= 2;
// Compute histogram
cv::calcHist(&lab,
1, // histogram of 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
2, // it is a 2D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
// Computes the 1D Hue histogram with a mask.
// BGR source image is converted to HSV
cv::MatND getHueHistogram(const cv::Mat &image) {
cv::MatND hist;
// Convert to Lab color space
cv::Mat hue;
cv::cvtColor(image, hue, CV_BGR2HSV);
// Prepare arguments for a 1D hue histogram
hranges[0]= 0.0;
hranges[1]= 180.0;
channels[0]= 0; // the hue channel
// Compute histogram
cv::calcHist(&hue,
1, // histogram of 1 image only
channels, // the channel used
cv::Mat(), // no mask is used
hist, // the resulting histogram
1, // it is a 1D histogram
histSize, // number of bins
ranges // pixel value range
);
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));
// mask used to round the pixel value
uchar mask= 0xFF<<n; // e.g. for 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>();
// Set output image (always 1-channel)
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;
}
// Computes the 1D Hue histogram with a mask.
// BGR source image is converted to HSV
// Pixels with low saturation are ignored
cv::MatND getHueHistogram(const cv::Mat &image,
int minSaturation=0) {
cv::MatND hist;
// Convert to HSV color space
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
// Mask to be used (or not)
cv::Mat mask;
if (minSaturation>0) {
// Spliting the 3 channels into 3 images
std::vector<cv::Mat> v;
cv::split(hsv,v);
// Mask out the low saturated pixels
cv::threshold(v[1],mask,minSaturation,255,
cv::THRESH_BINARY);
}
// Prepare arguments for a 1D hue histogram
hranges[0]= 0.0;
hranges[1]= 180.0;
channels[0]= 0; // the hue channel
// Compute histogram
cv::calcHist(&hsv,
1, // histogram of 1 image only
channels, // the channel used
mask, // binary mask
hist, // the resulting histogram
1, // it is a 1D histogram
histSize, // number of bins
ranges // pixel value range
);
return hist;
}
};
#endif
bojectFinder.h
#if !defined OFINDER
#define OFINDER
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
class ObjectFinder {
private:
float hranges[2];
const float* ranges[3];
int channels[3];
float threshold;
cv::MatND histogram;
cv::SparseMat shistogram;
bool isSparse;
public:
ObjectFinder() : threshold(0.1f), isSparse(false) {
ranges[0]= hranges; // all channels have the same range
ranges[1]= hranges;
ranges[2]= hranges;
}
// Sets the threshold on histogram values [0,1]
void setThreshold(float t) {
threshold= t;
}
// Gets the threshold
float getThreshold() {
return threshold;
}
// Sets the reference histogram
void setHistogram(const cv::MatND& h) {
isSparse= false;
histogram= h;
cv::normalize(histogram,histogram,1.0);
}
// Sets the reference histogram
void setHistogram(const cv::SparseMat& h) {
isSparse= true;
shistogram= h;
cv::normalize(shistogram,shistogram,1.0,cv::NORM_L2);
}
// Finds the pixels belonging to the histogram
cv::Mat find(const cv::Mat& image) {
cv::Mat result;
hranges[0]= 0.0; // range [0,255]
hranges[1]= 255.0;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
if (isSparse) { // call the right function based on histogram type
cv::calcBackProject(&image,
1, // one image
channels, // vector specifying what histogram dimensions belong to what image channels
shistogram, // the histogram we are using
result, // the resulting back projection image
ranges, // the range of values, for each dimension
255.0 // the scaling factor is chosen such that a histogram value of 1 maps to 255
);
} else {
cv::calcBackProject(&image,
1, // one image
channels, // vector specifying what histogram dimensions belong to what image channels
histogram, // the histogram we are using
result, // the resulting back projection image
ranges, // the range of values, for each dimension
255.0 // the scaling factor is chosen such that a histogram value of 1 maps to 255
);
}
// Threshold back projection to obtain a binary image
if (threshold>0.0)
cv::threshold(result, result, 255*threshold, 255, cv::THRESH_BINARY);
return result;
}
cv::Mat find(const cv::Mat& image, float minValue, float maxValue, int *channels, int dim) {
cv::Mat result;
hranges[0]= minValue;
hranges[1]= maxValue;
for (int i=0; i<dim; i++)
this->channels[i]= channels[i];
if (isSparse) { // call the right function based on histogram type
cv::calcBackProject(&image,
1, // we only use one image at a time
channels, // vector specifying what histogram dimensions belong to what image channels
shistogram, // the histogram we are using
result, // the resulting back projection image
ranges, // the range of values, for each dimension
255.0 // the scaling factor is chosen such that a histogram value of 1 maps to 255
);
} else {
cv::calcBackProject(&image,
1, // we only use one image at a time
channels, // vector specifying what histogram dimensions belong to what image channels
histogram, // the histogram we are using
result, // the resulting back projection image
ranges, // the range of values, for each dimension
255.0 // the scaling factor is chosen such that a histogram value of 1 maps to 255
);
}
// Threshold back projection to obtain a binary image
if (threshold>0.0)
cv::threshold(result, result, 255*threshold, 255, cv::THRESH_BINARY);
return result;
}
};
#endif
finder.cpp
#include <iostream>
#include <vector>
using namespace std;
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\video\tracking.hpp>
#include "objectFinder.h"
#include "colorhistogram.h"
int main()
{
// Read reference image
cv::Mat image= cv::imread("../baboon1.jpg" );
if (!image.data)
return 0;
// Define ROI
cv::Mat imageROI= image(cv::Rect(110,260,35,40));
cv::rectangle(image, cv::Rect(110,260,35,40),cv::Scalar(0,0,255));
// Display image
cv::namedWindow( "Image");
cv::imshow( "Image",image);
// Get the Hue histogram
int minSat=65;
ColorHistogram hc;
cv::MatND colorhist= hc.getHueHistogram(imageROI,minSat);
ObjectFinder finder;
finder.setHistogram(colorhist);
finder.setThreshold(0.2f);
// Convert to HSV space
cv::Mat hsv;
cv::cvtColor(image, hsv, CV_BGR2HSV);
// Split the image
vector<cv::Mat> v;
cv::split(hsv,v);
// Eliminate pixels with low saturation
cv::threshold(v[1],v[1],minSat,255,cv::THRESH_BINARY);
cv::namedWindow( "Saturation");
cv::imshow( "Saturation",v[1]);
// Get back-projection of hue histogram
int ch[1]={0};
cv::Mat result= finder.find(hsv,0.0f,180.0f,ch,1);
cv::namedWindow( "Result Hue");
cv::imshow( "Result Hue",result);
cv::bitwise_and(result,v[1],result);
cv::namedWindow( "Result Hue and");
cv::imshow( "Result Hue and",result);
// Second image
image= cv::imread("../baboon3.jpg");
// Display image
cv::namedWindow( "Image 2");
cv::imshow( "Image 2",image);
// Convert to HSV space
cv::cvtColor(image, hsv, CV_BGR2HSV);
// Split the image
cv::split(hsv,v);
// Eliminate pixels with low saturation
cv::threshold(v[1],v[1],minSat,255,cv::THRESH_BINARY);
cv::namedWindow( "Saturation");
cv::imshow( "Saturation",v[1]);
// Get back-projection of hue histogram
result= finder.find(hsv,0.0f,180.0f,ch,1);
cv::namedWindow( "Result Hue");
cv::imshow( "Result Hue",result);
// Eliminate low stauration pixels
cv::bitwise_and(result,v[1],result);
cv::namedWindow( "Result Hue and");
cv::imshow( "Result Hue and",result);
// Get back-projection of hue histogram
finder.setThreshold(-1.0f);
result= finder.find(hsv,0.0f,180.0f,ch,1);
cv::bitwise_and(result,v[1],result);
cv::namedWindow( "Result Hue and raw");
cv::imshow( "Result Hue and raw",result);
cv::Rect rect(110,260,35,40);
cv::rectangle(image, rect, cv::Scalar(0,0,255));
cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER,10,0.01);
cout << "meanshift= " << cv::meanShift(result,rect,criteria) << endl;
cv::rectangle(image, rect, cv::Scalar(0,255,0));
// Display image
cv::namedWindow( "Image 2 result");
cv::imshow( "Image 2 result",image);
cv::waitKey();
return 0;
}
results:


#if !defined ICOMPARATOR
#define ICOMPARATOR
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include "colorhistogram.h"
class ImageComparator {
private:
cv::Mat reference;
cv::Mat input;
cv::MatND refH;
cv::MatND inputH;
ColorHistogram hist;
int div;
public:
ImageComparator() : div(32) {
}
// Color reduction factor
// The comparaison will be made on images with
// color space reduced by this factor in each dimension
void setColorReduction( int factor) {
div= factor;
}
int getColorReduction() {
return div;
}
void setReferenceImage(const cv::Mat& image) {
reference= hist.colorReduce(image,div);
refH= hist.getHistogram(reference);
}
double compare(const cv::Mat& image) {
input= hist.colorReduce(image,div);
inputH= hist.getHistogram(input);
return cv::compareHist(refH,inputH,CV_COMP_INTERSECT);
}
};
#endif
retrieve.cpp
#include <iostream>
using namespace std;
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include "imageComparator.h"
int main()
{
// Read reference image
cv::Mat image= cv::imread("../waves.jpg" );
if (!image.data)
return 0;
// Display image
cv::namedWindow( "Query Image");
cv::imshow( "Query Image",image);
ImageComparator c;
c.setReferenceImage(image);
// Read an image and compare it with reference
cv::Mat input= cv::imread("../dog.jpg" );
cout << "waves vs dog: " << c.compare(input) << endl;
// Read an image and compare it with reference
input= cv::imread("../marais.jpg");
cout << "waves vs marais: " << c.compare(input) << endl;
// Read an image and compare it with reference
input= cv::imread("../bear.jpg");
cout << "waves vs bear: " << c.compare(input) << endl;
// Read an image and compare it with reference
input= cv::imread("../beach.jpg");
cout << "waves vs beach: " << c.compare(input) << endl;
// Read an image and compare it with reference
input= cv::imread("../polar.jpg");
cout << "waves vs polar: " << c.compare(input) << endl;
// Read an image and compare it with reference
input= cv::imread("../moose.jpg");
cout << "waves vs moose: " << c.compare(input) << endl;
// Read an image and compare it with reference
input= cv::imread("../lake.jpg");
cout << "waves vs lake: " << c.compare(input) << endl;
// Read an image and compare it with reference
input= cv::imread("../fundy.jpg");
cout << "waves vs fundy: " << c.compare(input) << endl;
cv::waitKey();
return 0;
}
results:


Learning OpenCV Lecture 3 (Counting the Pixels with Histograms),布布扣,bubuko.com
Learning OpenCV Lecture 3 (Counting the Pixels with Histograms)
原文:http://www.cnblogs.com/starlitnext/p/3861364.html