简单的图像特效(上)

喜你入骨 提交于 2020-01-13 01:12:19

简单介绍

博主是某工大的学生,最近在做各科的课设,然后其中一个是C++图像处理的课程设计。做这种东西没啥技术含量,但是加上写报告又得浪费个一两天的时间。
为了节约各位大佬们的时间(为了打发无聊),我在这里简单总结一下之前查到的各种简单的图像处理特效实现方法,尽量帮到想要想要学习图像处理特效的大家。
在评论里我会贴上一个完整的实现链接。帮到下个学期想要直接用到这个的小伙伴们~老师还没出成绩,我担心老师对照网上突然发现我的代码查重率100%,所以出成绩后我再贴上地址蛤。

正文

首先,博主使用的是老师发下的CDIB类和VS的MFC框架来实现。上网查的时候发现不同人写的CDIB类区别还挺大的,所以我要先对这个类做一下介绍,方便只是想学方法的同学能够理解之后的部分核心代码的意思。
以下是CDIB类的头文件。其中:
ShowDIB使用是把对应的三维按照BGR的格式打印到屏幕上。
m_pDIBData是彩色图片信息(自带补零位)。
m_pDIBDumpData是原始图片的的信息(自带补零位)。
m_pdata是图片的灰度信息(无补零位)。
知道这些信息,然后再和你们自己设计的cdib类对应起来,就会方便很多。
tips:关于补零位,这是bmp格式文件的特色,为了加快运行速度而设计的,想要仔细了解的同学可以在该博客详细了解一下。

class CDIB :
	public CObject
{
public:
	int m_nImType;
	void close();
	void UpdateData();
	void InvalidateData();
	BYTE* m_pdata;
	BYTE* m_pR, * m_pG, * m_pB;
	void ShowDIB(CDC*, int, int, int, int, BYTE*, BITMAPINFO*);
	bool m_bLoaded;
	CDIB();
	virtual ~CDIB();
	BITMAPINFO* m_pBMI;               //BITMAPINFO pointer
	BYTE* m_pDIBData;                 //DIB data pointer
	BYTE* m_pDumpDIBData;
	BITMAPFILEHEADER bfh;
	BITMAPINFOHEADER bih;
	CPalette* m_pPalette;


	DWORD dataBytes;
	bool SaveFile(LPCTSTR lpszFileName);
	virtual bool LoadFromFile(LPCTSTR lpszFileName);

	int GetDIBWidth()
	{
		return m_pBMI->bmiHeader.biWidth;
	}

	int GetDIBHeight()
	{
		return m_pBMI->bmiHeader.biHeight;
	}
};

灰度变换

彩色图片输入输入转为灰度图的视觉效果一般是通过改变色彩结构实现的,对彩色图片的每个通道使用以下变换公式就可以得到灰度图了:

Gray = R*0.299 + G*0.587 + B*0.114

但是这里运算都是浮点数运算,速度较慢。为了加快速度,可以使用以下公式:

Gray = (R*299 + G*587 + B*114 + 500)/1000

该公式里面所有运算都是整数运算,所以可以显著提高运算效率,因为是除于1000,所以加500以实现四舍五入。
运行效果:
在这里插入图片描述
值得一提的是:一般像素都是用八位像素保存的,一定要先进行溢出判断再赋值,不然你永远也不会发现它溢出了,别问我咋知道的。。。

马赛克

我们日常生活中经常见到马赛克,实际上马赛克的实现代码方法也是非常简单的。我在这里提供一个马赛克的实现思路:

  1. 按照固定的间隔对目标图像区域进行遍历
  2. 对于两个间隔之间的像素求统计平均(或者中位数啥的也行,但是统计平均可以保持图片能量不变,而且实现也比较简单)
  3. 使用计算结果替换掉像个像素区域中的值

以上是一个比较简单的正方形马赛克的思路,但是偶尔我们可能希望做得虽然简单,但是老师给的分也高,这个时候我们也可以来一个⚪形状的马赛克,在具体实现的时候,最主要变化的就是每个马赛克区间的范围,这个对于遍历的参数进行修改就可以实现了。
贴上一个马赛克的结果:
对8起bilibili妹,都变糊了

浮雕

实现浮雕的是要模仿光从某一个方向射入,产生亮边和阴影的赶脚,总的来说浮雕还是很好实现的。
这里提供一个简单的实现方法(网上还有更加复杂的,不过我都试过,貌似效果并没有啥差异,简单的效果貌似更加出色的鸭子),使用该公式进行计算:

img(x,y) = img(x, y) - img(x+1, y+1) + background

background浮雕背景的颜色,根据喜爱调整,值得注意的是需要进行溢出判定。如果不想进行溢出判定可以使用以下公式:

img(x,y) = (img(x, y) - img(x+1, y+1) + 255)/2

这条公式不需要进行溢出判定,但是也有个缺点,就是浮雕的效果没有第一个明显。
结果展示:
石雕的放电妹

油画

油画效果也是一个比较简单的方法,主要是通过把图片中的像素转为某一区域最常见的像素的均值,以做到油画的图片的效果。
但是如果直接对于某个区域的所有所有像素都进行这个操作,就变陈均值滤波了,而且一些极端情况下会明显地改变图片地色彩结构。所以,为了防止图片的色彩结构被改变,又要实现这个效果,就把灰度分为许多个等级,选择灰度等级众数中彩色像素的平均值。给一个实现方法:

  1. 把灰度分为几个等级:比如说平均分为四个等级
  2. 对图片进行遍历,取图片a^2-1的领域,a为某一个像素进行油画处理的运算范围。
  3. 计算该范围内的灰度等级的众数。
  4. 求灰度等级为众数的像素的BGR通道的平均值
  5. 该值赋给遍历中的点
    实现效果如图所示:
    又是一个糊了的放电妹

全局均衡化

灰度均衡化的原理就8说啦,要做这个课设的人肯定都已经学过啦。彩色均衡化一般有两种实现方法:
一种是对于BGR每个通道进行直方图均衡化得到均衡化结果,另外一个是转为HSI图片格式,然后对于I通道进行直方图均衡化,得到均衡化结果之后转回RGB通道。
其中第一个可能会改变色彩结构,从理论上来说效果必须是第二个好的,但是奈何进行HSI的转换非常麻烦,计算速度也很慢,所以我只使用了第一种方法。有一篇对于转hsi的公式说得非常详细,有兴趣可以去看一下:https://blog.csdn.net/chaolei3/article/details/79408380/

这里只给出了灰度的步骤,彩色的话按照感兴趣的方法做吧:

  1. 求通道的灰度直方图
  2. 对灰度直方图进行归一化
  3. 对均衡化的通道可取的所有值进行遍历(RGB中是0-255)。使用以下公式计算像素的映射关系:
    pixelnew(x)=(L1)r=1xpixelorign(r)pixel_{new}(x) = (L-1)\sum_{r=1}^xpixel_{orign}(r)
    在实际实现的时候要注意舍入问题。
  4. 使用映射关系把通道中的像素映射到新像素中
    运行结果:
    在这里插入图片描述

EMMM

溜去恰饭了,那就干脆分为上下两部分吧,代码链接也在下一并提供~

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!