首先特别感谢师弟问我关于图像处理的问题。
之前我就提到过灰度直方图,但是我讲的时候却发现自己都感觉混乱。
今天就重新梳理一遍,做图像处理,首先要明确你要处理对象的特性,如果你不了解,那么处理就是乱处理。
首先明确直方图的概念,然后学会计算各样的直方图,用直方图修改图像的外观,还可以用直方图来标识图像的内容,在图像中检测特定物体或纹理。
首先明确几个概念:
图像是由不同数值(颜色)的像素构成的,像素值在整幅图像中的分布情况是该图像的一个重要属性。
每个像素有不同的数值。
在单通道的灰度图像中,每个像素都有一个0(黑)~255(白)的数值。对于每个灰度,都有不同数量的像素分布在图像内,具体取决于图片内容。
例如:
在opencv中提供了calcHist()函数计算图像的直方图,计算完成后可以采用前面提到的opencv中的绘图函数如rectangle、line()等绘制显示出来.calcHist()函数原型如下:
void cv::calcHist ( const Mat * images,
int nimages,
const int * channels,
InputArray mask,
OutputArray hist,
int dims,
const int * histSize,
const float ** ranges,
bool uniform = true,
bool accumulate = false
)
参数解释
. images: 输入的图像或数组,它们的深度必须为CV_8U, CV_16U或CV_32F中的一类,尺寸必须相同。
. nimages: 输入数组个数,也就是第一个参数中存放了几张图像,有几个原数组。
. channels: 需要统计的通道dim,第一个数组通道从0到image[0].channels()-1,第二个数组从image[0].channels()到images[0].channels()+images[1].channels()-1,以后的数组以此类推
. mask: 可选的操作掩码。如果此掩码不为空,那么它必须为8位并且尺寸要和输入图像images[i]一致。非零掩码用于标记出统计直方图的数组元素数据。
. hist: 输出的目标直方图,一个二维数组
. dims: 需要计算直方图的维度,必须是正数且并不大于CV_MAX_DIMS(在opencv中等于32)
. histSize: 每个维度的直方图尺寸的数组
. ranges: 每个维度中bin的取值范围
. uniform: 直方图是否均匀的标识符,有默认值true
. accumulate: 累积标识符,有默认值false,若为true,直方图再分配阶段不会清零。此功能主要是允许从多个阵列中计算单个直方图或者用于再特定的时间更新直方图。
这个函数是一个通用的直方图计算函数,可处理包含任何值类型和范围的多通道图像。为了简化,这里我们制定一个专门用于处理单通道灰度图像的类。
这个类如下图,我就不打了,直接拍照:
程序:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include
using namespace cv;
using namespace std;
int main()
{
Mat srcImage = imread("D:\\abc\\1.jpg", 0);
imshow("原图", srcImage);
if (!srcImage.data) { cout
system("color 1F");
MatND dstHist; // 在cv中用CvHistogram *hist = cvCreateHist
int dims = 1;
float hranges[2] = { 0, 255 };
const float *ranges[1] = { hranges }; // 这里需要为const类型
int size = 256;
int channels = 0;
//计算图像的直方图
calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges); // cv 中是cvCalcHist
int scale = 1;
Mat dstImage(size * scale, size, CV_8U, Scalar(0));
//获取最大值和最小值
double minValue = 0;
double maxValue = 0;
minMaxLoc(dstHist, &minValue, &maxValue, 0, 0); // 在cv中用的是cvGetMinMaxHistValue
//绘制出直方图
int hpt = saturate_cast(0.9 * size);
for (int i = 0; i
{
float binValue = dstHist.at(i); // 注意hist中是float类型
int realValue = saturate_cast(binValue * hpt / maxValue);
//rectangle(dstImage,Point(i*scale, size - 1), Point((i+1)*scale - 1, size - realValue), Scalar(255));
line(dstImage, Point(i*scale, size - 1), Point((i + 1)*scale - 1, size - realValue), Scalar(255));
}
imshow("一维直方图", dstImage);
waitKey(0);
return 0;
}
运行结果:
今天有事出去了,明天继续。
领取专属 10元无门槛券
私享最新 技术干货