点击上方“小白学视觉”,选择加"星标"或“置顶”
重磅干货,第一时间送达
初学图像处理,在常用算法方面,二白实在是有些头疼。就在昨天,亲爱的小白师兄,对迷茫的二白伸出了援手,为二白送来了一大份干货——图像处理常用算法总结。二白仔细阅读了这些干货,并将其中的代码跑了几遍,觉得受益匪浅。在这里,二白将干货分享给大家。
1.二值化:
图1 二值化(阈值:140)处理效果
所谓二值化简单一点讲,就是将图像划分成黑和白,通过设定一个标准如果大于这个标准就设为白,如果小于这个标准,就设为黑,而这个标准,就叫做阈值。
具体定义如下所示:
下面给出实现的代码:
//二值化
//函数的参数iTR为阈值
void CBMPSampleDlg::ThresholdProcess(int iTR)
{
//读取BMP文件
m_Dib.AttachMapFile("1.bmp", TRUE);
m_Dib.CopyToMapFile("二值化.bmp");
//将像素指针定位到图像数据的开始
RGBTRIPLE *rgbtri = (RGBTRIPLE *)m_Dib.m_lpImage;
//获得图像的大小
int iSize = m_Dib.GetSizeImage();
//BMP文件头指针
BITMAPINFOHEADER * pBmiHeader = (BITMAPINFOHEADER *)m_Dib.m_lpBMIH;
//遍历每一个像素,并判断每一个像素的分量(RGB),将其与阈值比较,然后进行赋值
for(int i = 0; i < iSize/( pBmiHeader->biBitCount / 8); i++)
{
if ( (rgbtri[i].rgbtRed < iTR )| (rgbtri[i].rgbtGreen < iTR) | (rgbtri[i].rgbtBlue < iTR) )
{
rgbtri[i].rgbtRed = (BYTE) 0;
rgbtri[i].rgbtGreen = (BYTE) 0;
rgbtri[i].rgbtBlue = (BYTE) 0;
}
else
{
rgbtri[i].rgbtRed = (BYTE) 255;
rgbtri[i].rgbtGreen = (BYTE) 255;
rgbtri[i].rgbtBlue = (BYTE) 255;
}
}
//显示图像
DrawPic();
}
在读取图像之后,会将指针定位到图像像素数据的开始位置,然后获得图像的大小,然后通过BMP文件头获得图像的一个像素所占据的二进制的位数,这样就知道一个像素由几个字节组成的了,需要注意的是,一个像素不一定是由三个字节组成的,比如是灰度图像其只需要一个字节来存储一个像素究竟是灰到什么程度其范围在0-255 之间,而彩色图像却是由三种颜色组成的也就是所说的三原色RGB分别为Red、Green、Blue三种颜色组成,这三种颜色每个分量各占一个字节,所以这里需要三个字节,另外在BMP图像中还一个结构为RGBQUAD的结构体,这里一个像素占据的是4个字节,其实,这里就涉及到了8位图像24位图像以及32位图像的问题了,所谓的8位图像其实,每一个像素占一个字节,24位图像,每一个像素占据3个字节、而32位图像每一个像素占据4个字节就是这么来的。代码中,首先会读取原始图像文件,文件的格式为BMP的,关于BMP图像的存储结构,在接下来的文章中会讲到。
2.海报化
图2 海报化处理效果
所谓的海报化其实就是将每一个像素的分量与224进行与运算,而244的16进制表示可以表示成0xe0,前面介绍了一个像素的分量的范围在0-255范围内,所以只需要将这两个数值的二进制位相与即可完成海报化的处理效果。
下面为实现的具体代码:
//海报化
void CBMPSampleDlg::Posterize()
{
m_Dib.AttachMapFile("1.bmp", TRUE);
m_Dib.CopyToMapFile("海报化.bmp");
RGBTRIPLE *rgbtri = (RGBTRIPLE *)m_Dib.m_lpImage;
int iSize = m_Dib.GetSizeImage();
BITMAPINFOHEADER * pBmiHeader = (BITMAPINFOHEADER *)m_Dib.m_lpBMIH;
for(int i = 0; i < iSize/( pBmiHeader->biBitCount / 8); i++)
{
rgbtri[i].rgbtRed = (BYTE) (rgbtri[i].rgbtRed & 0xe0);
rgbtri[i].rgbtGreen = (BYTE) (rgbtri[i].rgbtGreen & 0xe0);
rgbtri[i].rgbtBlue = (BYTE) (rgbtri[i].rgbtBlue & 0xe0);
}
DrawPic();
}
上面的这段代码是参考DirectShow里面的ezrgb24滤镜这个例子改写的,另外下面的灰度化也是采用里面的改写的。
3.灰度化
图3 灰度化处理效果
灰度化有很多种处理方法,有分量法、最大值法、平均值法以及加权平均值法。
1)分量法
将彩色图像中的三分量的亮度作为三个灰度图像的灰度值,可根据应用需要选取一种灰度图像。
f1(i,j)=R(i,j) f2(i,j)=G(i,j)f3(i,j)=B(i,j)
其中fk(i,j)(k=1,2,3)为转换后的灰度图像在(i,j)处的灰度值。
2)最大值法
将彩色图像中的三分量亮度的最大值作为灰度图的灰度值。
f(i,j)=max(R(i,j),G(i,j),B(i,j))
3) 平均值法
将彩色图像中的三分量亮度求平均得到一个灰度图。
f(i,j)=(R(i,j)+G(i,j)+B(i,j)) /3
4) 加权平均法
根据重要性及其它指标,将三个分量以不同的权值进行加权平均。由于人眼对绿色的敏感最高,对蓝色敏感最低,因此,按下式对RGB三分量进行加权平均能得到较合理的灰度图像。
f(i,j)=0.30R(i,j)+0.59G(i,j)+0.11B(i,j))
在我们的程序中,我们采用的是加权平均法进行灰度化。
下面为实现的代码:
//灰度化
void CBMPSampleDlg::ConvertToGray()
{
m_Dib.AttachMapFile("1.bmp", TRUE);
m_Dib.CopyToMapFile("灰度化.bmp");
RGBTRIPLE *rgbtri = (RGBTRIPLE *)m_Dib.m_lpImage;
int iSize = m_Dib.GetSizeImage();
BITMAPINFOHEADER * pBmiHeader = (BITMAPINFOHEADER *)m_Dib.m_lpBMIH;
int iGrayvalue = 0;
//遍历每一个像素
for(int i = 0; i < iSize/( pBmiHeader->biBitCount / 8); i++)
{
iGrayvalue = int( rgbtri[i].rgbtBlue * 0.11 + rgbtri[i].rgbtGreen * 0.59 + rgbtri[i].rgbtRed * 0.3 );
rgbtri[i].rgbtRed = (BYTE) iGrayvalue;
rgbtri[i].rgbtGreen = (BYTE) iGrayvalue;
rgbtri[i].rgbtBlue = (BYTE) iGrayvalue;
}
DrawPic();
}
在上述代码中,通过遍历每一个像素,然后计算该像素的三个分量的加权平均值,将三个分量设置成同一个值,这样就实现了对图像的灰度化处理。
4.模糊化
图4 模糊化处理效果
其实所谓的模糊化,就是将各个像素的相邻的像素的各个分量的值相加,然后除以2就可以实现对图像的模糊处理。
下面给出代码:
//模糊化
void CBMPSampleDlg::Blur()
{
m_Dib.AttachMapFile("1.bmp", TRUE);
m_Dib.CopyToMapFile("模糊化.bmp");
RGBTRIPLE *rgbtri = (RGBTRIPLE *)m_Dib.m_lpImage;
int iSize = m_Dib.GetSizeImage();
BITMAPINFOHEADER * pBmiHeader = (BITMAPINFOHEADER *)m_Dib.m_lpBMIH;
LONG lHeight = pBmiHeader->biHeight;
LONG lWidth = pBmiHeader->biWidth;
for (int y = 0 ; y < lHeight; y++) {
for (int x = 2 ; x < lWidth; x++, rgbtri ++) {
rgbtri->rgbtRed = (BYTE) ((rgbtri->rgbtRed + rgbtri[2].rgbtRed) >> 1);
rgbtri->rgbtGreen = (BYTE) ((rgbtri->rgbtGreen + rgbtri[2].rgbtGreen) >> 1);
rgbtri->rgbtBlue = (BYTE) ((rgbtri->rgbtBlue + rgbtri[2].rgbtBlue) >> 1);
}
rgbtri +=2;
}
DrawPic();
}
上面的代码同样是遍历每一个像素将前一个像素和后一个像素相加,然后将获得的值右移一位,这样就能实现除以2的效果,之所以做位运算,是因为位运算的速度比除法运算要快很多。
希望大家跟二白一起,学习图像处理,有大家的陪伴,二白再也不用担心被小白师兄批评啦。
本文转载自xizero00博客,并进行修改,仅用作学习交流,如有侵权,请联系后台删除
https://blog.csdn.net/xizero00/article/details/6631209
下载1:OpenCV-Contrib扩展模块中文版教程
在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。
下载2:Python视觉实战项目52讲
在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。
下载3:OpenCV实战项目20讲
在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。
交流群
欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~