我们将从基础出发使用C语言进行图像处理与分析,重点讨论图像增强和平滑技术。图像增强技术旨在通过增加对比度、亮度和整体清晰度来改善图像的视觉质量。另一方面,图像平滑方法则用于减少噪声并减少图像中的突变,使图像更加均匀和视觉上吸引人。
使用C语言作为实现方式是因为只有当你手敲一遍这些代码,你才会对这些方法有更加深刻的理解
我们在前两次的笔记中已经实现了图像处理的基本操作
分别是
- 图像每一个像素灰度值的读入
- 图像灰度值直方图的显示
今天的目标实际上也很小,我们的目标就是实现图像增强
书上一共讲了两种办法,分别是
- 灰度线性拉伸算法
- 直方图均衡化
我们一个一个来尝试
灰度线性拉伸算法
我们先来看代码
void LinearStretchDemo(BYTE* pGryImg, int width, int height, double k, double b)
{
BYTE* pCur, * pEnd;
for(pCur = pGryImg,pEnd = pGryImg + width + height;pCur < pEnd;)
//这个地方书上是这么写的,我在下面还是写成了标准写法
{
*(pCur++) = LUT[ * pCur];
}
return;
}
总体上来看还是比较简单,我们来试着写成C语言版本
void LinearStretchDemo(uint8_t* pGryImg, int width, int height, double k, double b)
{
uint8_t* pCur, * pEnd;
for (pCur = pGryImg, pEnd = pGryImg + width * height; pCur < pEnd; pCur++)
{
*pCur = LUT[*pCur];
}
}
这个代码前面讲过好多了,这里就不再多讲了,有兴趣可以去看看C语言图像的读入那一篇笔记
但是这里面LUT是什么意思呢?
LUT 是 Look-Up Table 的缩写,中文意思是查找表或者映射表。在图像处理中,LUT 是一种非常常见的技机,用于对图像进行颜色或灰度值的映射和调整。
具体来说,LUT 是一个数组或者表格,其中存储了输入值到输出值的对应关系。在图像处理中,通常用 LUT 来实现颜色校正、对比度调整、灰度拉伸等操作。例如,在灰度拉伸中,LUT 存储了原始灰度值到拉伸后的灰度值之间的映射关系。
使用 LUT 的好处在于,它可以提高图像处理的效率,并且允许我们通过简单的表格查询来实现复杂的颜色或灰度值调整。同时,LUT 也可以在不同的图像处理算法中重复使用,提高了算法的复用性和可维护性。
总而言之,LUT 是图像处理中非常有用的工具,它通过预先计算和存储输入值到输出值的映射关系,帮助我们快速、高效地对图像进行颜色和灰度值的调整。
这里如果每个灰度值都有一个映射值,那么就不用进行重复大量的计算了,只需要计算255次即可
这么说不是很好理解,我们直接来看书上下一个算法
这里我直接写成C语言版本
void LinearStretchDemo(uint8_t* pGryImg, int width, int height, double k, double b)
{
uint8_t* pCur, * pEnd;
int LUT[256]; //因为只有[0,255]共256个灰度值
//step1. 生成查找表
for (int g = 0; g < 256; g++)
{
LUT[g] = max(0, min(255, k * g + b));
}
//step2. 进行变换
for (pCur = pGryImg, pEnd = pGryImg + width * height; pCur < pEnd; pCur++)
{
*pCur = LUT[*pCur];
}
//step3. 结束
return;
}
这段代码是一个实现灰度图像线性拉伸处理的函数 LinearStretchDemo。让我来逐步解释这段代码的具体实现:
uint8_t* pCur, * pEnd;:定义了两个指针变量,pCur用于指向当前处理的像素值,pEnd指向图像数据的末尾。int LUT[256];:定义了一个大小为 256 的整型数组,用于存储灰度值的映射关系。- 生成查找表部分:
for (int g = 0; g < 256; g++):遍历所有可能的灰度值(0 到 255)。LUT[g] = max(0, min(255, k * g + b));:对于每个灰度值,根据线性拉伸的公式k * g + b计算新的灰度值,并确保其范围在 0 到 255 之间,以防止越界。
- 进行变换部分:
for (pCur = pGryImg, pEnd = pGryImg + width * height; pCur < pEnd; pCur++):遍历图像数据中的每个像素。*pCur = LUT[*pCur];:使用查找表LUT将当前像素的灰度值映射为线性拉伸后的新灰度值。
- 返回处理结果并结束函数。
我们来试一下
首先来讲一下传参

- pGryImg:这是一个指向灰度图像数据的指针。灰度图像是一个二维数组,存储了图像中每个像素的灰度值。通过这个指针,函数能够访问图像的像素数据。
- width:这是图像的宽度,表示图像中每行像素的数量。它告诉函数每行有多少像素数据。
- height:这是图像的高度,表示图像中有多少行像素。它告诉函数图像有多少行数据。
- k:这是一个
double类型的参数,代表线性拉伸的斜率。它控制着拉伸的速率或程度。当 ( k ) 大于 1 时,图像的对比度增加;当 ( k ) 小于 1 时,对比度降低。 - b:这也是一个
double类型的参数,代表线性拉伸的偏移。它控制着拉伸后灰度值的起始位置。当 ( b ) 大于 0 时,图像的整体亮度增加;当 ( b ) 小于 0 时,整体亮度减小。
看效果

简单的处理以后效果其实还是不错的
我们用这两个函数看一下数值
这两个函数的讲解在这篇文章
//统计图像灰度值
//pImg:灰度图像数据的指针。
//width:图像的宽度。
//height:图像的高度。
//* histogram:数组首元素地址,需要一个能储存256个变量的整型数组
void GetHistogram(uint8_t* pImg, int width, int height, int* histogram)
{
uint8_t* pCur;
uint8_t* pEnd = pImg + width * height;
// 初始化直方图数组
memset(histogram, 0, sizeof(int) * 256);
// 直方图统计
for (pCur = pImg; pCur < pEnd;)
{
histogram[*pCur]++;
pCur++;
}
// 函数结束
return;
}
//亮度和对比度
//储存histogram灰度直方图的指针
//接收亮度的变量地址
//接收对比度的变量地址
void GetBrightContrast(int* histogram, double* bright, double* contrast)
{
int g;
double sum, num; //书上说图像很亮时,int有可能会溢出,所以我这里直接用double
double fsum;
//step.1 求亮度
for (sum = num = 0, g = 0; g < 256; g++)
{
sum += histogram[g] * g;
num += histogram[g];
}
*bright = sum * 1.0 / num;
//step.2 求对比度
for (fsum = 0.0, g = 0; g < 256; g++)
{
fsum += histogram[g] * (g - *bright) * (g - *bright);
}
*contrast = sqrt(fsum / (num - 1)); //即Std Dev
//step.3 结束
return;
}

直方图的均衡化与规定化

其实很好理解,就是把集中在某一区域的灰度值均匀的平铺在整体区域
我们还是先来看书上的代码
void RmwHistogramEqualizeDemo(BYTE *pGryImg, int width, int height)
{
// 定义变量
BYTE *pCur, *pEnd = pGryImg + width * height; // 指针变量,指向当前像素和图像末尾
int histogram[256], A[256], LUT[256], g; // 直方图数组、累积直方图数组、查找表和灰度级
// step.1-------------求直方图--------------------------//
memset(histogram, 0, sizeof(int) * 256); // 初始化直方图数组为0
for (pCur = pGryImg; pCur < pEnd;)
histogram[*(pCur++)]++; // 统计每个灰度级出现的频率
// step.2-------------求A[g],N-------------------------//
for (g = 1, A[0] = histogram[0]; g < 256; g++)
{
A[g] = A[g - 1] + histogram[g]; // 计算累积直方图数组
}
// step.3-------------求LUT[g]-------------------------//
for (g = 0; g < 256; g++)
LUT[g] = 255 * A[g] / (width * height); // 计算直方图均衡化后的灰度级
// step.4-------------查表------------------------------//
for (pCur = pGryImg; pCur < pEnd;)
*(pCur++) = LUT[*pCur]

本文使用C语言进行图像处理与分析,重点讨论图像增强技术,包括灰度线性拉伸算法、直方图均衡化与规定化、对数变换。介绍了LUT在图像处理中的应用,还给出了各算法的C语言代码实现及效果展示,下次将讲解图像平滑及噪声处理方法。
最低0.47元/天 解锁文章
260

被折叠的 条评论
为什么被折叠?



