(OpencvC++)数字图像处理--图像灰度变换、图像平滑、图
像锐化
我们将从以下三个⽅⾯来实现空域增强:
⼀、图象灰度变换;
⼆、图象平滑;
三、图象锐化;
⼀、图象灰度变换;
(1)、显⽰直⽅图;
(2)、对灰度图像进⾏直⽅图均衡化;
(3)、对灰度图像进⾏直⽅图拉伸;
主要⽤到的库函数如下:
void calcHist( const Mat* images, int nimages,const int* channels, InputArray mask,OutputArray hist, int dims, const int* histSize,onst float** ranges, bool u
void minMaxLoc(InputArray src, CV_OUT double* minVal, CV_OUT double* maxVal = 0, CV_OUT Point* minLoc = 0,CV_OUT Point* maxLoc = 0, InputArray mas void rectangle(InputOutputArray img, Point pt1, Point pt2,const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);//统计直⽅图函数。
void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );//将RGB图像转化为灰度图;
⾸先得到直⽅图函数如下:
// 得到图像的直⽅图
MatND getHistogram(Mat &image)
{
MatND hist;
int channels[] = { 0 };
int dims = 1;
int histSize[] = { 256 };
float granges[] = { 0, 255 };
const float *ranges[] = { granges };
calcHist(&image, 1, channels, Mat(), hist, dims, histSize, ranges);
return hist;
}
// 将图像直⽅图展⽰出来
Mat getHistogramImage(Mat &image)
{
MatND hist = getHistogram(image);
Mat showImage(256, 256, CV_8U, Scalar(0));
int i;
double maxValue = 0;
minMaxLoc(hist, 0, &maxValue, 0, 0);
for (i = 0; i < 256; i++)
{
float value = hist.at<float>(i);
int intensity = saturate_cast<int>(256 - 256 * (value / maxValue));
rectangle(showImage, Point(i, 256 - 1), Point((i + 1) - 1, intensity), Scalar(255));
}
return showImage;
}
效果图如下:
直⽅图均衡化:计算出直⽅图,遍历直⽅图,得到归⼀化直⽅图和积分图,以积分图为查表得到均衡化后的图。
其函数如下:
//得到直⽅图均衡函数
Mat getHistogram_Equalization(Mat &image)
{
Mat grayImg;
cvtColor(image, grayImg, CV_RGB2GRAY);//将rgb图像转化为灰度图
int rowNumber = ws;//得到⾏
int colNumber = ls;//得到列
int sumNumber = rowNumber * colNumber;//得到图像整个像素个数
Mat dstImg(rowNumber, colNumber, CV_8UC1, Scalar(0, 0, 0));//初始化直⽅图均衡化后的图 double hist[256] = { 0.00 };//直⽅图
double dhist[256] = { 0.00 };//直⽅图归⼀化图
double Dhist[256] = { 0.00 };//直⽅图积分图,每⼀个像素点
for (int i = 0; i < rowNumber; i++)//遍历原始图像,得到直⽅图
{
uchar* data = grayImg.ptr<uchar>(i);
for (int j = 0; j < colNumber; j++)
{
int temp = data[j];//得到图像像素值
hist[temp] = hist[temp] + 1;//将相应像素值在直⽅图中加1
}
}
for (int i = 0; i < 256; i++)//遍历直⽅图,得到归⼀化直⽅图和积分图
{
dhist[i] = hist[i] / sumNumber;//得到归⼀化图
for (int j = 0; j <= i; j++)
{
Dhist[i] = Dhist[i] + dhist[j]; //得到积分图
}
}
for (int i = 0; i < rowNumber; i++)//以积分图为查表得到均衡化后的图
{
uchar* data1 = dstImg.ptr<uchar>(i);
uchar* data2 = grayImg.ptr<uchar>(i);
rectangle函数opencvfor (int j = 0; j < colNumber; j++)
{
int temp1 = data2[j]; //查到原始图相应位置的像素值
int temp2 = (int)(Dhist[temp1] * 255); //在积分图中到相应像素值的映射值
data1[j] = temp2;//将映射值赋值给⽬标图像相应值
}
}
return dstImg;
}
/
/ 使⽤Rect绘制直⽅图
void drawHist_Rect(const cv::Mat& hist, cv::Mat& canvas, const cv::Scalar& color)
{
CV_Assert(!pty() && ls == 1);
CV_Assert(hist.depth() == CV_32F && hist.channels() == 1);
CV_Assert(!pty() && ls >= ws);
const int width = ls;
const int height = ws;
// 获取最⼤值
double dMax = 0.0;
cv::minMaxLoc(hist, nullptr, &dMax);
/
/ 计算直线的宽度
float thickness = float(width) / ws);
// 绘制直⽅图
// 绘制直⽅图
for (int i = 1; i < ws; ++i)
{
double h = hist.at<float>(i, 0) / dMax * 0.9 * height; // 最⾼显⽰为画布的90%
cv::rectangle(canvas,
cv::Point(static_cast<int>((i - 1) * thickness), height),
cv::Point(static_cast<int>(i * thickness), static_cast<int>(height - h)),
color,
static_cast<int>(thickness));
}
}
效果如下:
下⾯进⾏直⽅图拉伸:
直⽅图拉伸的流程如下:
·1.计算出直⽅图;
·2.计算出左边界值;
·3.计算出右边界值;
·4.进⾏直⽅图拉伸;
其函数如下:
// 直⽅图拉伸
// grayImage - 要拉伸的单通道灰度图像
// hist - grayImage的直⽅图
// minValue - 忽略像数个数⼩于此值的灰度级
void histStretch(cv::Mat& grayImage, const cv::Mat& hist, int minValue)
{
CV_Assert(!pty() && grayImage.channels() == 1 && grayImage.depth() == CV_8U); CV_Assert(!pty() && ws == 256 && ls == 1 && hist.depth() == CV_32F);
CV_Assert(minValue >= 0);
// 求左边界
uchar grayMin = 0;
for (int i = 0; i < ws; ++i)
{
if (hist.at<float>(i, 0) > minValue)
{
grayMin = static_cast<uchar>(i);
break;
}
}
/
/ 求右边界
uchar grayMax = 0;
for (int i = ws - 1; i >= 0; --i)
{
if (hist.at<float>(i, 0) > minValue)
{
grayMax = static_cast<uchar>(i);
break;
}
}
if (grayMin >= grayMax)
{
return;
}
const int w = ls;
const int h = ws;
for (int y = 0; y < h; ++y)
{
uchar* imageData = grayImage.ptr<uchar>(y);
for (int x = 0; x < w; ++x)
{
if (imageData[x] < grayMin)
{
imageData[x] = 0;
}
else if (imageData[x] > grayMax)
{
imageData[x] = 255;
}
else
{
imageData[x] = static_cast<uchar>(std::round((imageData[x] - grayMin) * 255.0 / (grayMax - grayMin))); }
}
}
}
//直⽅图拉伸函数
void getHistogram_Stetch(Mat& image)
{
Mat grayImage;
cvtColor(image, grayImage, COLOR_BGR2GRAY);
Mat hist;
Mat histCanvas(400, 512, CV_8UC3, Scalar(255, 255, 255));
int channels[1] = { 0 };
int histSize = 256;
float range[2] = { 0, 256 };
const float* ranges[1] = { range };
calcHist(&grayImage, 1, channels, Mat(), hist, 1, &histSize, ranges);
drawHist_Rect(hist, histCanvas, Scalar(255, 0, 0));
// 显⽰原始灰度图像及其直⽅图
imshow("Gray image", grayImage);
imshow("Gray image's histogram", histCanvas);
// 直⽅图拉伸
cv::Mat grayImageStretched = grayImage.clone();
histStretch(grayImageStretched, hist, 20);
// 计算直⽅图并绘制
cv::Mat histStretched;
cv::Mat histCanvasStretched(400, 512, CV_8UC3, cv::Scalar(255, 255, 255));
cv::calcHist(&grayImageStretched, 1, channels, cv::Mat(), histStretched, 1, &histSize, ranges);
drawHist_Rect(histStretched, histCanvasStretched, cv::Scalar(255, 0, 0));
// 显⽰拉伸后的灰度图像及其直⽅图
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论