Bitmap的读写和几个小儿科的滤镜效果~
闲来玩玩图像处理,拿破仑说过:“不想自己实现滤镜的美工不是好程序员~~#@!*^...#&!@......” 因为在学校做过很多美工的工作,而且从小就喜欢画画所以对图像相关的东西都还比较感兴趣,而且PS提供了强大的功能,那就是自己写的滤镜程序可以以适当的形式嵌入作为滤镜库里的一种效果而存在,要是能自己能写常用的滤镜效果以后用起来就方便多了。从最简单的bitmap开始,bitmap是Windows系统下的标准图像格式。由于位图不采用任何压缩方法,所以大小一般都比较大。图像的结构可以表示如下:
1.首先是位图文件头
两字节的位图文件类型用于指示位图,其值必须为0x4d42,即"BM",接着是4个字节存储的位图大小,之后的4个字节保用不用,最后是记录位图数据距离位图文件头的偏移量。
2.位图信息头
内容太多就不一一介绍了。
如果是24位位图,是指一个像素的颜色由24bit来决定,24bit中R、G、B三原色各占8bit,当然也有32bit位图,就是多了一个α分量,这个分量对于调节颜色的透明度很重要。24位的位图在位图信息头后面紧接着的就是位图数据,而对于8位、16位的位图,位图信息头后还有一个颜色块,用于说明各个颜色分量的亮度。固然我们可以使用MFC或者其他一些类库提供的编程接口来完成位图解析与处理的工作,但不从头实现一遍总会觉得失去了什么,而且别人的实现方式你怎么知道?现以C语言方式实现位图的读写与几个小滤镜效果。
首先在bitmap.h中定义需要的数据结构:
#pragma pack(1) typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef long LONG; typedef struct bitmap_filehead{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffset;
}BITMAPFILEHEADER; typedef struct bitmap_infohead{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biclrUsed;
DWORD biclrImportant;
}BITMAPINFOHEADER; typedef struct rgb_quad{
BYTE rgb_red;
BYTE rgb_green;
BYTE rgb_blue;
BYTE rgb_Reserved;
}RGBQUAD;
bitmap.h
在位图处理的时候需要注意一些问题,比如说每行的字节数必须是整数,所以下面用到的lineByte的计算方式应该是这样:
int lineByte = (bmpWidth*biBitCount/+)/*;
//每行的字节数必须为4个倍数,bmpWidth为宽度,biBitCount为每个像素所占位数
lineByte
下面来看第一个滤镜:灰度效果。所谓灰度,无非是所有像素颜色介于黑白之间。因为纯黑色的表示是RGB(0,0,0),而纯白色则是RGB(255,255,255),所以要保证颜色从黑到白变化(0-255)就只能让RGB三个分量一致,所以灰度滤镜的公式为X=(R+G+B)/3,然后只需要将原图像的24位颜色数据全部赋值成X就行了。代码如下,pBmpBuf是用于存放位图数据的缓冲区。
//灰度处理
bool imageGray(unsigned char *pBmpBuf,int lineByte)
{
if(pBmpBuf==NULL)
return false; for(int i=;i<lineByte*bmpHeight/;i++)
{
pBmpBuf[*i] = (pBmpBuf[*i]+pBmpBuf[*i+]+pBmpBuf[*i+])/;
pBmpBuf[*i+] = pBmpBuf[*i];
pBmpBuf[*i+] = pBmpBuf[*i];
}
return true;
}
灰度滤镜
貌似博客园不能上传bmp格式的图片,所以我把图片转成png格式的了,来看一下效果:
第二个滤镜:黑白效果。顾名思义也就是图像只能有黑白两种颜色,而这个滤镜有点特殊,那就是根据什么来判断一个像素点到底应该是黑还是白,感性的认识是原来较深的地方应该用黑色,较浅的地方应该用白色。那么深和浅又怎么区分呢?这个就要按照你需要达到的效果来定义了,也就是说这个阈值是自定义的,甚至都可以做成一个滑动条来改变。我在这里是将原像素颜色计算得到的灰度值与100进行比较,如果大于等于100则为白色,反之则为黑色,代码如下:
bool imageBlackWhite(unsigned char *pBmpBuf,int lineByte)
{
if(pBmpBuf==NULL)
return false; unsigned char temp;
for(int i=;i<lineByte*bmpHeight/;i++)
{
temp = (pBmpBuf[*i]+pBmpBuf[*i+]+pBmpBuf[*i+])/;
if(temp>=)
{
pBmpBuf[*i] = ;
pBmpBuf[*i+] = ;
pBmpBuf[*i+] = ;
}
else
{
pBmpBuf[*i] = ;
pBmpBuf[*i+] = ;
pBmpBuf[*i+] = ;
}
}
return true;
}
黑白滤镜
效果如下:
边缘查找其实是一个很复杂的效果,往深里做可以涉及到滤波器设计等,在这里从简,就按照最简单的想法,用像素的原始颜色数据减去柔化处理后的数据,得到的就是边缘,柔化的方法见底部。
bool imageEdge(unsigned char *pBmpBuf,int lineByte,unsigned long totalbytes)
{
if(pBmpBuf==NULL)
return false; tempbuf = (unsigned char *)malloc(totalbytes); memcpy(tempbuf,pBmpBuf,totalbytes); for(int j=;j<=bmpHeight-;j++)
{
for(int i=;i<=bmpWidth-;i++)
{
pBmpBuf[j*lineByte+*i] =( pBmpBuf[(j-)*lineByte+*(i-)]/ + pBmpBuf[(j-)*lineByte+*i]/ + pBmpBuf[(j-)*lineByte+*(i+)]/+ \
pBmpBuf[j*lineByte+*(i-)]/ + pBmpBuf[j*lineByte+*(i+)]/ + pBmpBuf[(j+)*lineByte+*(i-)]/ + \
pBmpBuf[(j+)*lineByte+*i]/ + pBmpBuf[(j+)*lineByte+*(i+)]/); pBmpBuf[j*lineByte+*i+] =( pBmpBuf[(j-)*lineByte+*(i-)+]/ + pBmpBuf[(j-)*lineByte+*i+]/ + pBmpBuf[(j-)*lineByte+*(i+)+]/+ \
pBmpBuf[j*lineByte+*(i-)+]/ + pBmpBuf[j*lineByte+*(i+)+]/ + pBmpBuf[(j+)*lineByte+*(i-)+]/ + \
pBmpBuf[(j+)*lineByte+*i+]/ + pBmpBuf[(j+)*lineByte+*(i+)+]/); pBmpBuf[j*lineByte+*i+] =( pBmpBuf[(j-)*lineByte+*(i-)+]/ + pBmpBuf[(j-)*lineByte+*i+]/ + pBmpBuf[(j-)*lineByte+*(i+)+]/+ \
pBmpBuf[j*lineByte+*(i-)+]/ + pBmpBuf[j*lineByte+*(i+)+]/ + pBmpBuf[(j+)*lineByte+*(i-)+]/ + \
pBmpBuf[(j+)*lineByte+*i+]/ + pBmpBuf[(j+)*lineByte+*(i+)+]/);
}
} for(int k=;k<lineByte*bmpHeight/;k++)
{
pBmpBuf[*k] = tempbuf[*k] - pBmpBuf[*k];
pBmpBuf[*k+] = tempbuf[*k+] - pBmpBuf[*k+];
pBmpBuf[*k+] = tempbuf[*k+] - pBmpBuf[*k+];
}
return true;
}
边缘查找
效果如下,由于只是很简单的边缘查找算法,所以效果不是太好,但人物轮廓还是很明显的:
反相效果就是底片效果,没什么好说的,对于像素的各个颜色分量对255求补,即R = 255-R,G = 255-G,B = 255-B。
bool imageReverse(unsigned char *pBmpBuf,int lineByte)
{
if(pBmpBuf==NULL)
return false; for(int i=;i<lineByte*bmpHeight/;i++)
{
pBmpBuf[*i] = -pBmpBuf[*i];
pBmpBuf[*i+] = -pBmpBuf[*i+];
pBmpBuf[*i+] = -pBmpBuf[*i+];
}
return true;
}
反相
效果如下:
柔化效果,这里采用取自身和周围8个像素点的颜色平均值来取代原像素的值,这样能够比较粗略的消除一些噪点,使得图像能够更加平滑,对于噪点比较多的图像效果就是图像更柔和了,而对于已经比较清晰的图像,相应给人的感觉就是清晰度变低了。
bool imageSoft(unsigned char *pBmpBuf,int lineByte)
{
if(pBmpBuf==NULL)
return false; //不用正确的数据结构存储,数据处理起来就是这么费劲
for(int j=;j<=bmpHeight-;j++)
{
for(int i=;i<=bmpWidth-;i++)
{
pBmpBuf[j*lineByte+*i] =( pBmpBuf[(j-)*lineByte+*(i-)]/ + pBmpBuf[(j-)*lineByte+*i]/ + pBmpBuf[(j-)*lineByte+*(i+)]/+ \
pBmpBuf[j*lineByte+*(i-)]/ + pBmpBuf[j*lineByte+*i]/ + pBmpBuf[j*lineByte+*(i+)]/ + pBmpBuf[(j+)*lineByte+*(i-)]/ + \
pBmpBuf[(j+)*lineByte+*i]/ + pBmpBuf[(j+)*lineByte+*(i+)]/); pBmpBuf[j*lineByte+*i+] =( pBmpBuf[(j-)*lineByte+*(i-)+]/ + pBmpBuf[(j-)*lineByte+*i+]/ + pBmpBuf[(j-)*lineByte+*(i+)+]/+ \
pBmpBuf[j*lineByte+*(i-)+]/ + pBmpBuf[j*lineByte+*i+]/ + pBmpBuf[j*lineByte+*(i+)+]/ + pBmpBuf[(j+)*lineByte+*(i-)+]/ + \
pBmpBuf[(j+)*lineByte+*i+]/ + pBmpBuf[(j+)*lineByte+*(i+)+]/); pBmpBuf[j*lineByte+*i+] =( pBmpBuf[(j-)*lineByte+*(i-)+]/ + pBmpBuf[(j-)*lineByte+*i+]/ + pBmpBuf[(j-)*lineByte+*(i+)+]/+ \
pBmpBuf[j*lineByte+*(i-)+]/ + pBmpBuf[j*lineByte+*i+]/ + pBmpBuf[j*lineByte+*(i+)+]/ + pBmpBuf[(j+)*lineByte+*(i-)+]/ + \
pBmpBuf[(j+)*lineByte+*i+]/ + pBmpBuf[(j+)*lineByte+*(i+)+]/);
}
}
return true;
}
柔化
效果如下,注意左边是原图、右边是结果,仔细看还是能看出有差别的,右边模糊一些:
完整实例程序猛击这里。
(注:程序仅处理24位的位图,所以没有颜色块,需要指明需要处理图片的完整路径,或者将所需处理图片放在工程中。结果另存为了copy-yourbitmap.bmp)
Bitmap的读写和几个小儿科的滤镜效果~的更多相关文章
- Bitmap的读写
Bitmap的读写和几个小儿科的滤镜效果~ 闲来玩玩图像处理,拿破仑说过:“不想自己实现滤镜的美工不是好程序员~~#@!*^...#&!@......” 因为在学校做过很多美工的工作,而且从 ...
- android 内部缓存器(手机自带的存储空间中的当前包文件的路径)
关于Context中: 1. getCacheDir()方法用于获取/data/data/<application package>/cache目录 2. getFilesDir()方法用 ...
- ACache【轻量级的开源缓存框架】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 官方介绍 ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架.轻量到只有一个java文件(由十几个类精简 ...
- 缓存之 ACache
1.android缓存的介绍 Android开发本质上就是手机和互联网中的webserver之间进行通信,就必定须要从服务端获取数据.而重复通过网络获取数据是比較耗时的.特别是訪问比較多的时候.会极大 ...
- Android轻量级的开源缓存框架ASimpleCache
点击查看原文 先上方法调用,写最经常使用的.其它不一一写 保存数据: ACache mACache=ACache.get(this); mACache.put("数据名称", js ...
- C#读写BitMap及颜色相乘
C#读写BitMap及颜色相乘 private Bitmap ReadBitMapAndMultipy(Bitmap bitmap0) { int x1width = bitmap0.Width; i ...
- VB6 GDI+ 入门教程[9] Bitmap魔法(2):数据读写
本文转自 http://vistaswx.com/blog/article/category/tutorial/page/2 VB6 GDI+ 入门教程[9] Bitmap魔法(2):数据读写 200 ...
- Bitmap 图片格式并用 C++ 读写 Bitmap
转自 Bitmap 图片格式并用 C++ 读写 Bitmap 1.Bitmap 图片格式 每部分的具体内容就不展开了.要说的有两点: (1)调色板不是必须的,可有可无,有没有调色板可以通过位图文件头的 ...
- PPM图片格式及其C读写代码
PPM图像格式介绍 PPM图像格式是由Jef Poskanzer 大叔,在我出生那一年,也就是1991年所创造的,碰巧的是PPM也是天蝎座. PPM(Portable Pixmap Format)还有 ...
随机推荐
- Android中SQLite数据库操作(2)——使用SQLiteDatabase提供的方法操作数据库
如果开发者对SQL语法不熟,甚至以前从未使用过任何数据库,Android的SQLiteDatabase提供了insert.update.delete或query语句来操作数据库. 一.insert方法 ...
- cocos2d-x 调色
在游戏开发.我们须要实现闪光的灯.照明弹效果等等,我么你能够採用混合模式来实现. 假设学习过OpenGL(ES),就知道里面使用glBlendFunc函数实现的.在cocos2d-x里肯定也有,对于精 ...
- PAT 1041-1050 题解
浏览全部代码:请戳 本文谨代表个人思路,欢迎讨论;) 1041. Be Unique (20) 题意 给出 N (<=105)个数(数值范围为 [1, 104]),找到其中不重复的第一个数字.比 ...
- error: expected declaration or statement at end of input----solved
error: expected declaration or statement at end of input 解决方法: 1.程序缺少一个括号相应地 2.而不添加头文件 版权声明:本文博主原创文章 ...
- Xbin-Store(分布式商城)项目所用Linux服务系列 FastDFS安装(五)
系列 Xbin-Store(分布式商城)项目所用Linux服务系列 MySQL安装(一) Xbin-Store(分布式商城)项目所用Linux服务系列 Redis集群安装(二) Xbin-Store( ...
- win10系统应用打不开
可能有一些用户升级Win10之后遇到了应用商店.应用打不开或闪退的问题,此时可尝试通过下面的一些方法来解决. 1.点击任务栏的搜索(Cortana小娜)图标,输入Powershell,在搜索结果中右键 ...
- 编译wxWidgets —— windows、vc71、bcc32、MinGW与命令行
编译wxWidgets —— windows.vc71.bcc32.MinGW与命令行 http://www.diybl.com/course/3_program/vc/vc_js/20071226/ ...
- 张汝京:CIDM模式进可攻、退可守,建议尝试
飞象网讯(路金娣/文)大约30多年前一些美国.日本和欧洲的IDM半导体工厂把多余的产能出来做代工服务,因为代工的公司不会与客户竞争,所以专业代工的模式成为半导体市场的新宠.那么,究竟国内半导体行业更加 ...
- bigdata_ Kafka集群模式部署
环境:kafka 0.8.1.1 基本概念 Kafka维护按类区分的消息,称为主题(topic) 生产者(producer)向kafka的主题发布消息 消费者(consumer)向主题注册,并且接收发 ...
- 一台虚拟机配置nginx反向代理+3个apache虚拟主机
三个虚拟主机通过一张网卡添加三个IP来实现 一.安装nginx 1.解决依赖 [root@xuegod1 ~]# yum groupinstall "Development Tools&qu ...