目录
1.计算图像的直方图
首先实现单通道灰度图像
class Histogram1D
{
public:
cv::MatND getHistogram(const cv::Mat &image);
cv::Mat getHistogramImage(const cv::Mat &image);
cv::Mat applyLookUp(const cv::Mat& image, const cv::MatND& lookup);
cv::Mat stretch(const cv::Mat &image, int minValue);
cv::Mat equalize(const cv::Mat &image);
Histogram1D(){
histSize[0] = 256;
hranges[0] = 0.0;
hranges[1] = 255.0;
ranges[0] = hranges;
channels[0] = 0;
}
private:
int histSize[1]; //项的数据
float hranges[2]; //像素最大最小
const float *ranges[1];
int channels[1];
};
类实现:
cv::MatND Histogram1D::getHistogram(const cv::Mat &image)
{
cv::MatND hist;
cv::calcHist(&image,
1, //计算单张图像
channels, //通道数量
cv::Mat(), //不使用图像作为掩码
hist, //返回的直方图
1, //这是1D的直方图
histSize, //项的数量
ranges); //像素值范围
return hist;
}
cv::Mat Histogram1D::getHistogramImage(const cv::Mat &image)
{
//首先计算直方图
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));
//设置最高点为nbins的90%
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;
}
// Stretches the source image.
cv::Mat Histogram1D::stretch(const cv::Mat &image, int minValue)
{
cv::MatND hist = getHistogram(image);
cv::Mat result;
int imin = 0, imax = histSize[0] - 1, dim = 256;
for (; imin < histSize[0]; imin++)
{
if (hist.at<float>(imin) > minValue)
{
break;
}
}
for (; imax >= 0; imax--)
{
if (hist.at<float>(imax) > minValue)
{
break;
}
}
cv::Mat lut(1, &dim, CV_8U);
for (int i = 0; i < 256; i++)
{
if (i < imin) lut.at<uchar>(i) = 0;
else if (i > imax) lut.at<uchar>(i) = 255;
else lut.at<uchar>(i) = static_cast<uchar>(255.0*(i - imin) / (imax - imin) + 0.5);
}
result = applyLookUp(image, lut);
return result;
}
// Applies a lookup table transforming an input image into a 1-channel image
cv::Mat Histogram1D::applyLookUp(const cv::Mat& image, const cv::MatND& lookup)
{
cv::Mat result;
cv::LUT(image, lookup, result);
return result;
}
cv::Mat Histogram1D::equalize(const cv::Mat &image)
{
cv::Mat result;
cv::Mat src = image;
cvtColor(src, src, CV_BGR2GRAY);
cv::equalizeHist(src,result);
return result;
}
应用实现:
void OpenCVQtGui::Histogram_clicked()
{
cv::Mat Result = hist1D.getHistogramImage(image);
cv::imshow("hist1DImage", Result);
cv::threshold(image, Result, 60, 255, cv::THRESH_BINARY);
cvtColor(Result, Result, CV_BGR2RGB);
QImage img1 = QImage((const unsigned char*)(Result.data), Result.cols, Result.rows, QImage::Format_RGB888);
ui.label_2->setPixmap(QPixmap::fromImage(img1));
ui.label_2->resize(QSize(img1.width(), img1.height()));
}
2.实现彩色直方图
class ColorHistogram
{
public:
ColorHistogram()
{
histSize[0] = histSize[1] = histSize[2] = 256;
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::SparseMat getSparseHistogram(const cv::Mat &image);
cv::Mat getHistogramImage(const cv::Mat &image);
private:
int histSize[3];
float hranges[2];
const float *ranges[3];
int channels[3];
};
类实现:
cv::MatND ColorHistogram::getHistogram(const cv::Mat &image)
{
cv::MatND hist;
cv::calcHist(&image,
1,
channels,
cv::Mat(),
hist,
3,
histSize,
ranges);
return hist;
}
cv::SparseMat ColorHistogram::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;
}
cv::Mat ColorHistogram::getHistogramImage(const cv::Mat &image)
{
// 首先计算直方图
cv::MatND hist;
std::vector<cv::Mat> b;
cv::split(image, b);
cv::Mat b_hist, r_hist, g_hist;
cv::calcHist(&b[0], 1, channels, cv::Mat(), b_hist, 1, histSize, ranges, true, false);
cv::calcHist(&b[1], 1, channels, cv::Mat(), g_hist, 1, histSize, ranges, true, false);
cv::calcHist(&b[2], 1, channels, cv::Mat(), r_hist, 1, histSize, ranges, true, false);
//创建相关变量
int hist_w = 512;
int hist_h = 400;
int bins = cvRound((double)image.cols / histSize[0]);
cv::Mat histImg = cv::Mat(image.cols, image.rows, CV_8UC3, cv::Scalar(0, 0, 0));
cv::normalize(b_hist, b_hist, 0, image.rows, cv::NORM_MINMAX, -1, cv::Mat());
cv::normalize(g_hist, g_hist, 0, image.rows, cv::NORM_MINMAX, -1, cv::Mat());
cv::normalize(r_hist, r_hist, 0, image.rows, cv::NORM_MINMAX, -1, cv::Mat());
//画图
for (size_t i = 0; i < histSize[0]-1; i++)
{
line(histImg, cv::Point(bins * i, image.rows - cvRound(b_hist.at<float>(i))),
cv::Point(bins * (i + 1), image.rows - cvRound(b_hist.at<float>(i+1))), cv::Scalar(0, 0, 255), 1, cv::LINE_AA);
line(histImg, cv::Point(bins * i, image.rows - cvRound(g_hist.at<float>(i))),
cv::Point(bins * (i + 1), image.rows - cvRound(g_hist.at<float>(i + 1))), cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
line(histImg, cv::Point(bins * i, image.rows - cvRound(r_hist.at<float>(i))),
cv::Point(bins *(i + 1), image.rows - cvRound(r_hist.at<float>(i + 1))), cv::Scalar(255, 0, 0), 1, cv::LINE_AA);
}
imshow("图像直方图", histImg);
return histImg;
}
运行效果:
2.使用查找表修改图像外观
void OpenCVQtGui::LookUp_clicked()
{
// Create an image inversion table
//uchar lookup[256];
// Create lookup table
int dims[1] = { 256 };
cv::MatND lookup(1, dims, CV_8U);
for (int i = 0; i < 256; i++) {
lookup.at<uchar>(i) = 255 - i;
}
cv::Mat Result = hist1D.applyLookUp(image, lookup);
cv::namedWindow("Image");
cv::imshow("Image", Result);
Result = hist1D.equalize(image);
cv::namedWindow("Image2");
cv::imshow("Image2", Result);
Result = hist1D.stretch(image, 30);
//cv::Mat Result2 = Chist.getHistogramImage(image);
// cv::namedWindow("Image2");
//
// cv::imshow("Image2", Result2);
// cv::SparseMat Result3 = Chist.getSparseHistogram(image);
//
// cv::namedWindow("Original Image3");
//
// cv::imshow("Original Image3", Result2);
//cv::threshold(image, Result, 60, 255, cv::THRESH_BINARY);
cvtColor(Result, Result, CV_BGR2RGB);
QImage img1 = QImage((const unsigned char*)(Result.data), Result.cols, Result.rows, QImage::Format_RGB888);
ui.label_2->setPixmap(QPixmap::fromImage(img1));
ui.label_2->resize(QSize(img1.width(), img1.height()));
}
3.反投影直方图以检测特定的图像内容
添加类:
class ContentFinder
{
public:
ContentFinder()
{
threshold = -1.0;
ranges[0] = hranges;
ranges[1] = hranges;
ranges[2] = hranges;
}
void setThreshold(float t);
float getThreshold();
void setHistogram(const cv::MatND &h);
cv::Mat find(const cv::Mat& image, float minValue, float maxValue, int *channels, int dim);
private:
float hranges[2];
const float *ranges[3];
float threshold;
int channels[3];
cv::MatND histogram;
};
类实现:
void ContentFinder::setThreshold(float t)
{
threshold = t;
}
float ContentFinder::getThreshold()
{
return threshold;
}
void ContentFinder::setHistogram(const cv::MatND &h)
{
histogram = h;
cv::normalize(histogram, histogram, 1.0);
}
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,
channels,
histogram,
result,
ranges,
255.0
);
if (threshold > 0.0)
{
cv::threshold(result, result, 255 * threshold, 255, cv::THRESH_BINARY);
}
return result;
}
应用实现:
void OpenCVQtGui::CalcBack_clicked()
{
cv::Mat Result = image;
cv::Mat ImageROI;
ImageROI = image(cv::Rect(120,70,150,150));
cv::MatND hist = Chist.getHistogram(ImageROI);
finder.setHistogram(hist);
finder.setThreshold(0.05);
int channels[3] = { 0, 1, 2 };
Result = finder.find(image, 0, 255, channels, 3);
cv::namedWindow("Image");
cv::imshow("Image", ImageROI);
cvtColor(Result, Result, CV_BGR2RGB);
//cv::addWeighted(Result, 1.0, ImageROI, 0.8, 0., Result);
// cvtColor(ImageROI, ImageROI, CV_BGR2RGB);
// cv::namedWindow("Image");
// cv::imshow("Image", ImageROI);
cvtColor(Result, Result, CV_BGR2RGB);
QImage img1 = QImage((const unsigned char*)(Result.data), Result.cols, Result.rows, QImage::Format_RGB888);
ui.label_2->setPixmap(QPixmap::fromImage(img1));
ui.label_2->resize(QSize(img1.width(), img1.height()));
}
效果: