数字图像处理入门(c++实现)

目录

    • 直方图计算
    • 直方图均衡
    • 均值/高斯 低通滤波
    • 中值滤波
    • 数学形态学处理
      • 腐蚀
      • 膨胀
      • 开运算
      • 闭运算
    • 总结
    • 资料

我是看着这个学习的,在此推荐一下:

北交图像处理与机器学习

在此记录一下自己的学习过程

直方图计算

灰度直方图反映了图像灰度的分布(统计)特征

计算公式:

h ( r k ) = n k h(r_{k})=n_{k} h(rk)=nk
r k 为 灰 度 级 , n 为 该 灰 度 级 的 像 素 个 数 r_{k}为灰度级,n为该灰度级的像素个数 rk,n

之后我们来写这部分的代码:

首先有初始化:

// 计算图像直方图
int histFlag;
int hist[256]; //存储图像直方图,256灰度级
void histCompute(BYTE*, int, int);//计算图像直方图函数

添加好事件处理函数,调用求取直方图函数,更新窗口,显示直方图

//计算图像直方图
void CMFCApplication1View::HistCompute()
{
	// TODO: 在此添加命令处理程序代码

	histCompute(image, width, height);
	histFlag = 1;

	OnInitialUpdate();
	CRect ClientRect;
	GetClientRect(&ClientRect);
	InvalidateRect(&ClientRect);
}

计算直方图部分:

void CMFCApplication1View::histCompute(BYTE*image, int width, int height)
{
	//计算直方图
	int n;
	for (n = 0; n < 256; n++) 
	{
		hist[n] = 0;
	}
	int i, j;
	BYTE gray;
	for (i = 0; i < height; i++) 
	{
		for (j = 0; j < width; j++) 
		{
			gray = image[i * width + j];
			//根据定义来求就好
			hist[gray]++;
		}
	}
}

最后成功显示出结果
数字图像处理入门(c++实现)_第1张图片
核心代码位置:
数字图像处理入门(c++实现)_第2张图片

直方图均衡

H A ( D A ) H_{A}\left( D_{A}\right) HA(DA) H B ( D B ) H_{B}\left( D_{B}\right) HB(DB)分布代表均衡前后图像直方图,改变后使每个灰度级拥有相同的像素个数,即
H B ( D B ) = 常 数 = A 0 D m H_{B}\left( D_{B}\right)=常数=\dfrac{A_{0}}{D_{m}} HB(DB)==DmA0
通过积分得到:
D B = D m A 0 ⋅ ∑ 0 D A H A ( D A ) D_{B}=\dfrac{D_{m}}{A_{0}}\cdot \sum ^{DA}_{0}H_{A}\left( D_{A}\right) DB=A0Dm0DAHA(DA)
其中, D m D_{m} Dm代表灰度级, A 0 A_{0} A0代表图像像素总数

这种技术可应用于人脸识别

我们来研究一下代码,共有3步:

  1. 计算输入图像直方图
  2. 计算像素新的灰度级
  3. 新灰度级替换原灰度级
void CMFCApplication1View::hisEqualiz(BYTE* image, int w, int h, BYTE* outImg)
{
	//直方图均衡
	//计算输入图像直方图
	int his[256];
	int n,i,j;
	for (n = 0; n < 256; n++)
	{
		his[n] = 0;
	}
	for (i = 0; i < h; i++)
		for (j = 0; j < w; j++)
			his[image[i * w + j]]++;
	//计算像素新的灰度级
	for (n = 1; n < 256; n++)
		his[n] += his[n - 1];
	BYTE gray[256];
	float cons;
	cons = 255.0 / his[255];
	for (n = 0; n < 256; n++)
		gray[n] = (BYTE)(cons * his[n]);
	//新灰度级替换原灰度级
	for (i = 0; i < h; i++)
		for (j = 0; j < w; j++)
			outImg[i * w + j]=gray[image[i * w + j]];
}

成功显示出结果:
数字图像处理入门(c++实现)_第3张图片
核心代码位置:
数字图像处理入门(c++实现)_第4张图片

均值/高斯 低通滤波

数字图像处理入门(c++实现)_第5张图片
代码部分:

首先是卷积运算:

int CMFCApplication1View::convolution(int* operatr, BYTE* block)
{
	int value;
	int i, j;
	value = 0;
	//卷积运算
	for (i = 0; i < 3; i++)
		for (j = 0; j < 3; j++)
			value += operatr[i * 3 + j] * block[i * 3 + j];
	return value;
}

然后均值滤波:

void CMFCApplication1View::meanFilter(BYTE* image, int width, int heigth, BYTE* outImg)
{
	//均值滤波
	int smth[9];
	int i, j, m, n;
	BYTE block[9];
	int value;
	for (i = 0; i < 9; i++)
		smth[i] = 1;
	for (i = 0; i < height; i++)
	{
		for (j = 0; j < width; j++)
		{
			if (i == 0 || j == 0 || i == height - 1 || j == width - 1)
				outImg[i * width + j] = 0;
			else
			{
				for (m = -1; m < 2; m++)
					for (n = -1; n < 2; n++)
						block[(m + 1) * 3 + n + 1] = image[(i + m) * width + j + n];
				value = convolution(smth, block);
				outImg[i * width + j] = BYTE(value / 9.);
			}

		}
	}
}

高斯滤波:

void CMFCApplication1View::gaussian(BYTE* image, int width, int heigth, BYTE* outImg)
{
	//高斯滤波
	int smth[9];
	int i, j, m, n;
	BYTE block[9];
	int value;

	smth[0] = 1; smth[4] = 4;
	smth[1] = 2; smth[5] = 2;
	smth[2] = 1; smth[6] = 1;
	smth[3] = 2; smth[7] = 2;
				 smth[8] = 1;
	for (i = 0; i < height; i++)
	{
		for (j = 0; j < width; j++)
		{
			if (i == 0 || j == 0 || i == height - 1 || j == width - 1)
				outImg[i * width + j] = 0;
			else
			{
				for (m = -1; m < 2; m++)
					for (n = -1; n < 2; n++)
						block[(m + 1) * 3 + n + 1] = image[(i + m) * width + j + n];
				value = convolution(smth, block);
				outImg[i * width + j] = BYTE(value / 16.);
			}

		}
	}
}

均值滤波:
数字图像处理入门(c++实现)_第6张图片

高斯滤波:
数字图像处理入门(c++实现)_第7张图片

附上直方图均衡:
数字图像处理入门(c++实现)_第8张图片

中值滤波

数字图像处理入门(c++实现)_第9张图片
代码部分:

中值滤波函数:

void CMFCApplication1View::midFindFiltering(BYTE* image, int width, int heigth, BYTE* outImg)
{
	//中值滤波
	int i, j, m, n;
	BYTE block[9];
	int value;
	int blockNum = 9;

	for (i = 0; i < height; i++)
	{
		for (j = 0; j < width; j++)
		{
			if (i == 0 || j == 0 || i == height - 1 || j == width - 1)
				outImg[i * width + j] = 0;
			else
			{
				for (m = -1; m < 2; m++)
					for (n = -1; n < 2; n++)
						block[(m + 1) * 3 + n + 1] = image[(i + m) * width + j + n];
				value = MidValueFind(blockNum, block);
				outImg[i * width + j] = value;
			}

		}
	}
}

O ( n 2 ) O(n^2) O(n2)的排序函数,有兴趣推荐改成 O ( l o g n ) O(logn) O(logn)

int CMFCApplication1View::MidValueFind(int num, BYTE* d)
{
	int value;

	int i, j;
	int temp;
	for (i = 0; i < num - 1; i++)
		for (j = i + 1; j < num; j++)
		{
			if (d[i] < d[j])
			{
				temp = d[i];
				d[i] = d[j];
				d[j] = temp;
			}
		}

	return d[num / 2];

}

中值滤波:
数字图像处理入门(c++实现)_第10张图片

数学形态学处理

腐蚀

  • 一种消除边界点,使边界向内部收缩的过程,用来消除小且无意义的物体
  • 图形点(gray=255)在其3x3邻域,只要有若干个背景点,则该点设为背景点(0)。

数字图像处理入门(c++实现)_第11张图片
代码实现:

void CMFCApplication1View::erosion(BYTE* image, int w, int h, BYTE* outImg)
{
	int rept;
	//腐蚀
	memcpy(outImg, image, sizeof(BYTE) * width * height);
	int i, j;
	int m, n;
	BYTE flag;
	for (rept = 0; rept < 3; rept++)//多次腐蚀
	{
		for (i = 1; i < h - 1; i++)
		{
			for (j = 1; j < w - 1; j++)
			{
				if (image[i * w + j] == 255)//找到一个图形点
				{
					flag = 0;
					for (m = -1; m < 2; m++)
					{
						for (n = -1; n < 2; n++)
						{
							if (image[(i + m) * w + j + n] == 0)
							{
								flag++;//3x3邻域包含多少个背景点
								break;
							}
						}
					}
					if (flag > 2)
						outImg[i * w + j] = 0;//该图形点设为背景点
				}
			}
		}
	}
	memcpy(image, outImg, sizeof(BYTE) * width * height);
}

腐蚀:
数字图像处理入门(c++实现)_第12张图片

膨胀

将与物体接触所有背景点合并到该物体中,使边界向外部扩张的过程,可以用来填补物体中的空洞

数字图像处理入门(c++实现)_第13张图片
代码实现:

void CMFCApplication1View::dilation(BYTE* image, int w, int h, BYTE* outImg)
{
	int rept;
	//膨胀
	memcpy(outImg, image, sizeof(BYTE) * width * height);
	int i, j;
	int m, n;
	BYTE flag;
	for (rept = 0; rept < 3; rept++)//多次膨胀
	{
		for (i = 1; i < h - 1; i++)
		{
			for (j = 1; j < w - 1; j++)
			{
				if (image[i * w + j] == 0)//找到一个背景点(gray=0)
				{
					flag = 0;
					for (m = -1; m < 2; m++)
					{
						for (n = -1; n < 2; n++)
						{
							if (image[(i + m) * w + j + n] == 255)
							{
								flag++;//3x3邻域包含多少个图形点
							}
						}
					}
					if (flag > 1)
						outImg[i * w + j] = 255;//该图形点设为图形点
				}
			}
		}
	}
	memcpy(image, outImg, sizeof(BYTE) * width * height);
}

膨胀:
数字图像处理入门(c++实现)_第14张图片

开运算

先腐蚀后膨胀,能够消除图像区域外的小白点(噪声)

数字图像处理入门(c++实现)_第15张图片

闭运算

先膨胀后腐蚀,能够消除图像区域内的小黑点(噪声)

数字图像处理入门(c++实现)_第16张图片
开闭运算可以保持物体原有大小,一个是消除物体外部噪声(开运算)的,另一个是增强物体之间连接点(闭运算)的

总结

数字图像处理入门(c++实现)_第17张图片

  • c++的项目属实猛,一个文件是完不成这么多任务的,和算法那种高思维量不同,项目是一种结构组织上的美
  • 数字图像处理需要认真的分析,本文涉及的算法都很简单,而且自己动手调参就可以看到变化,也易于解释(比如在腐蚀运算中,把邻域背景点判断范围从大于2放大为大于1)

资料

【北交】图像处理与机器学习课件和代码地址:

传送门

我这个项目可以在百度网盘下载:

传送门

提取码:

cccc

你可能感兴趣的:(图像识别,c++,计算机视觉,opencv)