一、实验目的
掌握对图像直方图进行操作,实现图像的直方图均衡算法。
1、掌握求灰度图像归一化直方图方法
2、掌握灰度图像的直方图均衡算法
3、掌握对彩色图像进行直方图均衡的算法
二、实验内容
1、计算灰度图像的归一化直方图。
具体内容:利用 OpenCV 对图像像素进行操作,计算归一化直方图.并在
窗口中以图形的方式显示出来
2、灰度图像直方图均衡处理
具体内容:通过计算归一化直方图,设计算法实现直方图均衡化处理。
3、彩色图像直方图均衡处理
具体内容: 在灰度图像直方图均衡处理的基础上实现彩色直方图均衡处理。
三、实验完成情况
1、计算灰度图像的归一化直方图
核心代码
//计算归一化直方图
static Mat getHistogram(Mat img, double& min_value, double& max_value) {
//图像数量
int nimage = 1;
//通道标号序列,这里由于只需要灰度,因此队列只有一通道
int channels[] = { 0 };
//可选,如果不为空,即8-bit且与图像同尺寸的矩阵序列,此时第i个图像被mask[i]覆盖的区域才会参与统计,此处取默认空值
Mat mask;
//输出直方图矩阵
Mat hist;
//直方图的维度/通道数,如取4则代表(a,b,c,d)为在第一个通道上为a,第二个通道上为b,第三个通道上为c,第四个通道上为d的像素统计数
//此处只有灰度,因此只取1即可
int dims = 1;
//histSize[i]代表第i个维度/通道上直方图的直方条数量,这里采用256每个阶数占用一个直方条
const int histSize[] = { 256 };
//与uniform标记有关,如果uniform为true,则range[i]两个值代表直方图的第i个维度上每个直方条的上下限,如果为false则range[i]的histSize[i]+1个值分别代表每个直方条的上下限
float hrange[] = { 0,255 };
const float* range[] = { hrange };
//代表直方条是否均匀等宽,true为等宽,false为不等
bool uniform = true;
//标记直方图重新分配时是否清零,如果为否则可以进行累加
bool accumulate = false;
//计算直方图
calcHist(&img, nimage, channels, mask, hist, dims, histSize, range, uniform, accumulate);
//计算灰度最小和最大值
minMaxLoc(hist, &min_value, &max_value);
//直方图画布,采用8bit位深,无符号整型以及3通道图片进行绘制
Mat target = Mat::zeros(Size(256, 300), CV_8UC3);
//绘制直方图
for (int top, i = 0; i < 256; i++) {
//计算直方条上界
top = cvRound(hist.at(i)/max_value*256);
//绘制直方条
line(target, Point(i, target.rows - 1), Point(i, target.rows - 1 - top), Scalar::all(255));
}
return target;
}
实现截图
![](https://img2020.cnblogs.com/blog/2236853/202106/2236853-20210615211125061-717550557.png)
2、灰度图像直方图均衡处理
核心代码
//直方图均衡化处理
void channelEqualization(Mat &layer) {
//均衡化
equalizeHist(layer, layer);
}
//均衡化手动函数
void myChannelEqualization(Mat & layer) {
//总像素数
double sum = (double)img.rows * (double)img.cols;
//各灰度总和
double cnt[256] = { 0 };
//均衡化像素数
uchar equal[256];
//统计各灰度值总数
for (int i = 0; i < layer.rows; i++) {
uchar* ptr = layer.ptr(i);
for (int j = 0; j < layer.cols; j++) {
cnt[ptr[j]]++;
}
}
//获取均衡化像素密度
cnt[0] /= sum;
for (int i = 1; i < 256; i++)
cnt[i] = cnt[i] / sum + cnt[i - 1];
//获取均衡化后灰度值
for (int i = 0; i < 256; i++)
equal[i] = (uchar)(255 * cnt[i]);
//替换均衡化灰度
for (int i = 0; i < layer.rows; i++) {
uchar* ptr = layer.ptr(i);
for (int j = 0; j < layer.cols; j++) {
ptr[j] = equal[ptr[j]];
}
}
}
//均衡化预处理
Mat handleEqualization(bool hsv, bool my) {
Mat target = img.clone();
//彩色图像处理
if (color) {
Mat result;
vector channels;
//HSV方式处理
if (hsv) {
//转换为HSV图像
cvtColor(target, target, COLOR_BGR2HSV);
//分离通道
split(target, channels);
//处理亮度层,不影响色彩
my ? myChannelEqualization(channels[2]) : channelEqualization(channels[2]);
//将亮度层组合
merge(channels, result);
//转换回RGB图像
cvtColor(result, result, COLOR_HSV2BGR);
}
//RGB方式处理
else {
//分离RGB通道
split(target, channels);
//每个通道单独均衡化处理
for (int i = 0; i < channels.size(); i++)
my ? myChannelEqualization(channels[i]) : channelEqualization(channels[i]);
//将图层组合
merge(channels, result);
}
return result;
}
//灰阶图像处理
else {
my ? myChannelEqualization(target) : channelEqualization(target);
return target;
}
}
实现截图
![](https://img2020.cnblogs.com/blog/2236853/202106/2236853-20210615211634418-130974118.png)
3、彩色图像直方图均衡处理
核心代码
同灰度均衡处理代码,参数color为true即可。
实现截图
![HSV均衡直方图](https://img2020.cnblogs.com/blog/2236853/202106/2236853-20210615211902858-443305128.png)
四、实验中的问题
OpenCV中关于计算直方图的函数calcHist参数较多切较难理解。
灰度和彩色均衡化处理的过程有所区别,主要为通道数的不同,起初统一处理时出现均衡化失败或者只有单通道均衡化的问题。
五、实验结果
源码
lab2.cpp
#include
#include
#include
using namespace std;
using namespace cv;
const static std::string path = "F:\\Documents\\高级图像处理\\Image\\";
//图片路径组合
string getFullPath(string name) {
return path + name;
}
Mat show_h(Mat img) {
int channels = 0;
MatND dstHist;
//设定像素取值范围
int hisSize[] = { 256 };
float midRanges[] = { 0,255 };
const float* ranges[] = { midRanges };
//计算直方图
calcHist(&img, 1, &channels, Mat(), dstHist, 1, hisSize, ranges, true, false);
Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);
double MaxValue;
minMaxLoc(dstHist, 0, &MaxValue, 0, 0);//图像最小最大值
for (int i = 0; i < 256; i++) {
int value = cvRound((float)dstHist.at(i) * 256 * 0.9 / MaxValue);//四舍五入
//在直方图画布上画出直方图
line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - value), Scalar(255, 255, 255));
}
return drawImage;
}
//打开图片显示窗口
void openWindows(string win_name, Mat img, int x = 500, int y = 500) {
//窗口命名,指定大小,生成位置
namedWindow(win_name, WINDOW_AUTOSIZE);
moveWindow(win_name, x, y);
//生成窗口显示图片
imshow(win_name, img);
//等待键入
waitKey();
//关闭窗口
destroyWindow(win_name);
}
//统一数字输入函数
templateT inputNumber(string desc) {
system("cls");
T input;
cout > input;
cout img.channels() != 1;
}
//归一化直方图
void show() {
openWindows("直方图", Histogram::getHistogram(img, min_value, max_value));
}
//直方图均衡化处理
void equalization(bool hsv = false,bool my = false) {
Mat equal_img = handleEqualization(hsv,my);
openWindows("原图", img);
openWindows("均衡化图像", equal_img);
openWindows("均衡化直方图", Histogram::getHistogram(equal_img, min_value, max_value));
}
};
int main() {
string name = "test.jpg";
//灰度图像
GrayImage gray_img(name);
//灰阶直方图
Histogram ghist(gray_img);
//归一化直方图
ghist.show();
//均衡化
ghist.equalization();
//彩色图像
ColorImage color_img(name);
//彩色直方图
Histogram chist(color_img);
//均衡化
chist.equalization(false);
return 0;
}
|