2015-12-29 11:21:24 u013088062 阅读数 30196

  最近有人问我图像处理怎么研究,怎么入门,怎么应用,我竟一时语塞。仔细想想,自己也搞了两年图像方面的研究,做个两个创新项目,发过两篇论文,也算是有点心得,于是总结总结和大家分享,希望能对大家有所帮助。在写这篇教程之前我本想多弄点插图,让文章看起来花哨一点,后来我觉得没必要这样做,大家花时间沉下心来读读文字没什么不好,况且学术和技术本身也不是多么花哨的东西。

  一、图像处理的应用

  这个其实没什么好说的,一种技术的应用价值不是靠嘴上说,而是要看有多少人去搞,很简单的道理。其实我觉得判断一项技术有没有价值、有多大价值的最简单最有效的方法就是看有多少人在研究它。如果大家都在研究,那必然说明它很火,至少目前很火,以后的几年里依然还会火。因此,如果你不确定图像处理是不是有价值,那就查查全国图像处理工程师的数量就行了。

当然这里还是简单提一下。如果你真的只想问“图像处理有什么用?”,相信百度会给出比我更专业的答案。不过作为图像处理的行内人,我还是从几个基本的点来具体说一下。

  1、身份认证

  21世纪是刷脸的时代,这一点无可厚非。首先是银行,据说重庆的银行已经使用了人脸识别的验证系统来进行辅助的认证。其次是门禁系统,以前是指纹,虹膜,现在就是人脸。指纹、虹膜的识别虽然准确,但是有侵犯性,采集的过程中有侵犯性,验证的过程中也有侵犯性,反正让谁天天录指纹(采集指纹信息),用眼睛瞪摄像头(采集虹膜信息),谁都会觉得不舒服的,况且手还会脱皮。相比之下,人脸的识别就方便多了,拍张照片(采集人脸信息)谁都不会介意。最后是监控,一个摄像头所拍的监控能从不同的角度记录成百上千的人(比如车站等密集场所的监控),让警察去辨认将是一个浩大的工程,要是系统能够自动判别人员信息,无疑会给办案带来极大方便。

  2、监控安防

  安防监控可以说是图像处理领域最有潜力的应用领域。如今各个城市都在疯狂的安装监控摄像头,全国时刻都有无数的摄像头在录监控,但是安防监控的后端处理却没跟上。什么是后端处理,简单的说就是监控录像的视频处理。注意这里的视频处理可就不止包含人脸识别了,还有行人检测、异常检测、显著性检测、协同跟踪等。人脸识别之前说了,这里简单说说行人异常检测。图像处理中的行人异常检测在外行人眼中是一个非常有魔力的东西。毕竟让摄像头通过监控视频就能判断出当前画面中谁是好人谁是坏人(当然直接分为好人和坏人还是太武断了),在一般思维中貌似是不可能的。但是请不要忽略这样一个事实,就是目前大部分监控视频的分析处理都是由人工来完成的,警察破案时经常动不动就调出最近几天的监控视频,然后从头看到尾,其工程量之大可想而知。也正是这样才催生了人们对智能监控方面的研究,因为有这方面的实际需求。当然我们的视频分析程序不会直接给出诸如“好人or坏人”这样的武断而片面的判断结果。就当前的技术水平而言,能够统计当下监控画面中的人数(行人检测)、定位他们的人脸(人脸检测)、识别他们的身份(人脸识别)、判别他们的表情(表情识别)、检测他们的动作(异常检测),这就已经够了。这样以后人们就不会再面对长达几十甚至上百个小时的监控视频发呆,而是直接分析计算机给出的数据,当前画面中有多少人、都是谁、谁的动作可疑等。总之,接下来智能监控发展会很迅速,因为需求很迫切。

  3、深度学习(Deep Learning)

  通俗的说一句,“图像处理是深度学习应用的天堂”。深度学习这个概念可能有人不太熟悉,大家可以自行百度,我这里给出一个相对通俗的解释:“如果你不知道什么叫深度学习,就想想《终结者》中的T-800”。当然这句话不是我说的,是出自业界的一位大牛之口。当然这可能有点小片面,不过深度学习确实是公认的新一代人工智能的基础。

  这里举两个例子。一是谷歌的人工大脑项目。谷歌公司可以说是深度学习方面的牵头企业了,其在2012年公布的谷歌大脑项目,动用了1.6万个计算节点,训练数周,得到的人工智能模型能够自主识别猫脸图像,为新一代人工智能开辟了道路,之后微软深度学习研究院、百度深度学习研究院等机构都开始大量投入,各个高校也搞得风声水起,原因很简单,大家都知道它会火。

  第二就是图像识别方面的竞赛。最有权威的就是ImageNet竞赛。大家在一个拥有上千万张,上千类别的图像数据库上训练和测试自己的算法,比拼识别率。近几年来,摘得桂冠的一直都是深度学习模型,确切的说是卷积神经网络。更多有关ImageNet历年的竞赛信息大家可以自行百度。

  说道深度学习在图像处理的应用,不得不提中国的汤晓鸥教授,说他是国内深度学习的领头羊也不为过。他提出的DeepID人脸识别算法(一共分为三代),在一些大规模人脸数据库上的正确率(若LFW库)已经达到了99.75%,单纯从数字上讲的话可以说已经超越了人类的识别率,为此汤教授还开办了公司,开发FaceSDK(虽然还没有公布)。不过拿计算机和人脑相比本身就是不合理的,各有所长嘛。不过可见DeepLearning在图像识别领域的强大威力。至于深度学习与图像处理的关系这里就不用多说了,谷歌大脑识别的是图像,深度学习竞赛用的是图像,DeepID识别的还是图像人脸,虽然深度学习在其他方面诸如语音识别等也有应用,在图像处理依然是其主要的应用领域。

  二、图像处理研究工具

  图像处理的研究分为算法研究和应用两个部分。用到的主要编程语言有Matlab、C/C++、Python等,原因很简单,它们都有很多相应的第三方库,不用我们从零开始编程。

  1、Matlab

  MathWork公司的Matlab软件可以说是算法研究的利器,它的强大之处在于其方便快捷的矩阵运算能力和图形仿真能力,单从简洁性和封装性来说,确实完爆其他语言。但高度封装必然会相应的损失一部分灵活性,况且Matlab严格的讲更像是一个工具,而非一门编程语言。顺便提一句,它在2015年编程语言排行榜中位于第20名,仅次于IOS开发的Objective-C。

  对于算法研究人员(尤其是高校的硕士博士),首选工具自然是matlab,因为它简便快捷,封装性好,更重要的是全世界几乎所有的算法大牛、精英教授都会首先公布对应的Matlab源码,然后在逐步改写成其他语言进行实际应用。所以,如果你想做图像处理方面的研究,Matlab是必须掌握的,而且是熟练掌握。当你有一些想法需要验证时,最好明智的先用matlab编写出来测试。如果你上来就用看似高大上的C++来实验,不仅错误BUG一大堆,到头来可能效果还不佳,就算效果好,时间也会耽搁不少,毕竟算法开发还是要快的,这样才能赶在别人之前发论文。总之,只要是接触图像算法,终究逃不过Matlab,就算你是软件开发的,不研发算法,但总得能看懂别人的Matlab算法吧。

  对于之前没怎么接触过Matlab与图像处理的人,在这里推荐一本相关的书籍《MATLAB图像处理实例详解(附光盘)》。这本书对于Matlab图像处理入门还是很有帮助的。记得我当时刚上研究生时就靠两本书入门的,一是冈萨雷斯的《数字图像处理》,二是这本《MATLAB图像处理实例详解》。不过这里友情提示,在看这类教程(不仅仅是Matlab)时千万不要试图去记忆所有的工具函数,这种做法是十分愚蠢的。正确的做法是根据自己的情况快速翻阅这类工具书,可以找出里面的有实际意义的源码来敲一敲练练手感,至于具体的工具函数,只需要知道Matlab提供了这方面的功能就行了,以后用到了再回来查,或者谷歌百度。我觉得在入门阶段,最重要的不是看了多少书,听了多少课,而是尽快自己敲出一段代码,运行出结果,来建立自信和成就感,这才是支持我们走下去的最实在的动力。记得我当时看了没多久就自己敲了一个蹩脚的车牌检测的Matlab程序,现在看来真是漏洞百出,不过当时我真的很兴奋,很有成就感,觉得自己能干这行,对于初学者来说,这种感受弥足珍贵。

  2、OpenCv

  Opencv是Intel公司开发的C++图像处理工具包,形象的理解为就是C++版的Matlab。当初Intel公司开发这个工具包的初衷也是方便大家共享,希望大家能够在一个共同架构的基础上共同建造摩天大楼,而不是各自在自己的地基上盖平房。与Matlab不同,Opencv是面向开发的,稳定性好,异常处理机制周全,但有一点需要注意,由于Opencv是开源的,那么如果你在项目中直接调用了它的API,那就意味着你的项目也必须开源。因此在真正的产品开发过程中,往往需要从Opencv库里面挖代码,而不是直接调用,幸好Intel公司允许我们看源码,自己编译一把就可以了。

  说道C++和Opencv,有一个问题不得不提,那就是深度学习领域大名鼎鼎的Caffe框架。这是一个典型的基于C++和OpenCv的深度学习框架,由谷歌深度学习团队、“谷歌大脑”负责人之一贾扬清学者编写,并公布了源码。如今各个深度学习机构都在大量使用这个框架进行研究。

  这里同样对推荐两本关于Opencv方面的教程。一本是CSDN博客大牛毛星云写的《OpenCV3编程入门》,这是它根据自己多年的博客整理成的书,很详细,很典型的一本教程,介绍了OpenCv中相对前沿的知识。我翻看过这本教程,中规中矩,里面的代码通俗易懂,尤其适合初学者。当然大家同样要注意不要犯了死读书的毛病,只看它的功能,敲代码练手感即可,不要试图记忆API函数。重要的工具用多了自然会记住,不重要的工具记住了也没用。

  这里推荐的第二本书是《图像识别与项目实践――VC++、MATLAB技术实现》,这本书是一本偏向于工程应用的书,我之所以推荐它是因为它给出了很多有新意、能运行的代码。其中里面有一个项目让我印象很深,是一个车牌检测的实例。简单描述一下:由于车牌中的字符数是固定的,因此它通过判断横向区域笔画的跳变数以及笔画宽度来定位车牌区域。这个想法让人耳目一新,并且它还给出了详细代码,我也亲身试验过,效果还不错。

  这里同样再强调一下,就是一定要尽早入手写程序,建立自信和成就感。我当时学OpenCv正好用它开发了一个人脸性别识别的系统,是一个本科大学生创新计划的需求,效果还可以。

  3、Python

  Python在今年12月份的编程语言排行榜中名列第5,增长迅速。可以说Python已经逐渐成为当下脚本语言的新标准。Python在图像处理算法方面除了其自身简洁的编程优势外,还得益于两个重要的Python类库——Numpy和Theano。

  Numpy是Python的线性代数库,对于矩阵运算能提供很好的支持,并且能够在此基础上进行很多机器学习相关算法的开发仿真,这里推荐一本受到大家广泛认可的书《机器学习实战》,我最近也正在看这本书,里面对好多机器学习领域的经典算法,小到KNN,大到SVM,都给出了详细的介绍以及代码实现(Python版)。Theano是Python的机器学习库,能够方便的实现深度学习(例如卷积神经网络CNN)算法,网上很多对于DeepID算法的复现都是用的这个库。

  人觉得单从图像处理的角度评价的话,Python并没有前面两个工具(Matlab和OpenCv)应用广泛,不过作为通用的脚本语言,我觉得每个程序员都应该去了解了解它,毕竟俗话说没有烂的编程语言,只有烂程序员。我在学Python时第一个自己写的程序就是微信打飞机的小程序,在我的博客中有详细的教程,虽然是参照小甲鱼的《零基础入门学习Python》视频教程写的,但还是蛮有成就感的。

  三、图像处理研究方法

  我觉得,图像处理研究主要可以分为三个部分:基础概念、基本思想、算法研究。

  1、基础概念

  所谓基础概念,就是图像处理里最基本的知识,比如什么是图像?什么是像素?什么是彩色图像等等。没有一个明确的界限来划定什么是基础概念什么是高级知识,因人而异。了解图像处理的基础知识,有一本书是必读的,就是冈萨雷斯编写的、阮秋琦翻译的《数字图像处理》。这本书已经作为图像处理领域的经典教材使用了三十多年,我自己也把这本书看了好几遍,每一遍都会有新的体会。我觉得每一个搞图像的都应该熟读这本书。书中除了有几章内容在讲小波变换、模式识别等相对抽象的内容外,其他内容相对都是很基础的,本科生水平就能看懂。而且我建议要尽早看这本书,如果是研究生尽量在进入课题之前就看一遍,因为这样一本经典的书在进入课题之后可能就没时间看了,以后也顶多是查阅而已。我当初就是在大四的寒假看完了这本书,以后在图像入门的过程中就显得轻松很多。看完这本书,哪怕是只看前几章,明白了什么是图像(二维或者三维矩阵)、什么是像素、彩色图和灰度图、颜色空间、图像滤波、图像噪声、图像频域变换等概念,将来在进行更深一步的研究的话就会方便很多了。

  2、基本思想

  刚开始想把这部分内容命名为“基本算法”,意在介绍图像处理中的一些基本算法,后来仔细想想决定不这么写,因为图像处理是一个非常大的概念,图像处理不等于人脸识别,也不等于模式识别,直接介绍诸如图像处理基本算法之类的内容很容易写成空话,没有什么实际意义。读者有兴趣的话可以直接谷歌百度“图像处理十大经典算法”,上面有我想说的内容。

  万变不离其宗,算法是死的,重在思想。举个例子,我个人是主攻模式识别方向,在这个方向判断一个学生是否入门有一个非常简单的方法,就是“如果你能把图像很自然的想象成高维空间中的一个点”,那就说明在模式识别方面入门了,可以对图像进行分类了。当然标准不是唯一,在其他领域如目标检测也会有其他的判断标准,总之我们要对图像进行处理,那么图像就不再只是图像,它可能会演变成各种不同形式的概念,可能是点,可能是面,还可能是一个坐标空间。在目标跟踪的经典算法粒子滤波中,将一个个的小图像块看做一个个粒子;在子空间理论中,将一系列图像放在一起构建一个成分主空间(例如主成分分析PCA算法等等。,我不会详细介绍这些算法,说多了就显得抽象老套,但我要说的是我们一定要把图像本身理解好,它是一个图像,是一个矩阵,是一个信息的容器,是一种数据的表现形式,图像不一定都必须在视觉上有意义(比如频域的图像)。

  总之图像处理的基本思想还是要立足于图像本身,要深度到图像内部结构中,思维要灵活。我当时做本科毕设时,怎么也不知道图像和高维空间中的点之间有什么对应关系,后来总算有一天,突然就明白了,这也就是所谓的量变产生质变。总之一定要多想,多总结,主动去钻研,才能够真正领悟一些东西。最基本的东西往往蕴藏着深奥的道理,无论你现在多牛多厉害,都不能放掉最本源的东西。多想想图像是什么,有什么本质属性,你可能无法得到准确的答案,但肯定能得到一些有用的感悟(有点像哲学问题了)。

  3、算法研究

  算法研究应该是图像处理的核心工作,尤其是各大高校的博士硕士。这里我并不想谈那些高大上的算法,我更想说的是一些算法研究的一些基础的东西,比如说一些基础课程,比如说矩阵运算。

  研究图像处理的算法,离不开数学。在这里我建议图像处理方面的硕士一定要上两门课:《泛函分析》以及《最优化算法》,有的学校已经将这两门课列为了研究生阶段的必修课程。这两门可可以说是图像处理(至少是模式识别)的基础。我当初没上过最优化算法,但后来也自己补上了,不然真的是寸步难行。至于泛函我当时听课的时候也不是很懂,但是在之后的研究过程中发现很多图像处理的基本知识基本理论都和泛函分析中枯燥的定理如出一辙,没办法,有的东西本身就是枯燥的干货,学着费力,缺它不行。

  其次我想说的是矩阵运算。图像就是矩阵,图像处理就是矩阵运算。大家为什么都喜欢用Matlab,就是因为它的矩阵运算能力实在是太强大,在Matlab的世界中任何变量都是矩阵。同样OpenCv之所以能流行,不仅仅是因为它良好的封装性,也是因为它的矩阵格式,它定义了Mat基础类,允许你对矩阵进行各种操作。Python也不例外,它的Numpy就是一个专门的线性代数库。

  真正在图像编程过程中,那些看着高大上的API函数归根到底都是工具,查查手册就能找到,真正核心还是在算法,算法是由公式编写的,公式的单元是变量,而图像届的变量就是矩阵。所以,熟练去操作矩阵,求秩、求逆、最小二乘,求协方差,都是家常便饭。所以,如果你有幸能上《矩阵分析》这门课,一定要把它看懂,那里面都是干货。

  四、小结

  总之,图像处理就是一个典型的门槛低、厅堂深的领域。不需要太多基础,学过线性代数,会一点编程就够了;但是那些算法却深不可测,是个消耗功夫的活儿。在写这篇教程时我说的很直白,就像和大家对话一样,想到什么说什么。在最后我想说两句题外话,就是不仅仅针对图像处理,对于其他新技术的入门学习也是一样,尽快迈出第一步,尽快去建立自信和成就感,让自己有勇气走下去,然后缺什么补什么就行了。我觉得真正让人望而却步的往往不是技术本身,而是我们对自身的不自信。唯有果断开工,才能战胜心魔。


如果觉得这篇文章对您有所启发,欢迎关注我的公众号,我会尽可能积极和大家交流,谢谢。


2010-09-20 11:05:00 superdont 阅读数 3122

说明:

该系列读书笔记为《C#数字图像处理算法典型事例》(赵春江 编著,人民邮电出版社,2009)读书笔记。

详细内容,请参考原始图书。

================================================

 

代码如下:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

namespace Demo1

{

public partial class Form1 : Form

{

private string curFileName;

private System.Drawing.Bitmap curBitmap;

public Form1()

{

InitializeComponent();

}

private void Form1_Load(object sender, EventArgs e)

{

}

private void open_Click(object sender, EventArgs e)

{

OpenFileDialog opndlg = new OpenFileDialog();

opndlg.Filter = "所有文件|*.bmp;*.pcx;*.png;*.jpg;*.gif;" +

"*.tif;*.ico;*.dcx;*.cgm;*.cdr;*.wmf;*.eps;*.emf;|" +

"位图(*.bmp;*.jpg;*.png;...)|*.bmp;*.pcx;*.png;*.jpg;*.gif;*.tif;*.ico|" +

"矢量图(*.wmf;*.eps;*.emf;...)|*.dcf;*.cgm;*.cdr;*.wmf;*.eps;*.emf";

opndlg.Title = "打开图形文件";

opndlg.ShowHelp = true;

if (opndlg.ShowDialog() == DialogResult.OK)

{

curFileName = opndlg.FileName;

try

{

curBitmap = (Bitmap)Image.FromFile(curFileName);

}

catch (Exception exp)

{

MessageBox.Show(exp.Message);

}

}

Invalidate();

}

private void save_Click(object sender, EventArgs e)

{

if (curBitmap == null)

return;

SaveFileDialog saveDlg = new SaveFileDialog();

saveDlg.Title = "保存为";

saveDlg.OverwritePrompt = true;

saveDlg.Filter = "BMP文件(*.bmp)|*.bmp|" + "Gif文件(*.gif)|*.gif|" +

"JPEG文件(*.jpg)|*.jpg|" + "PNG文件(*.png)|*.png";

saveDlg.ShowHelp = true;

if (saveDlg.ShowDialog() == DialogResult.OK)

{

string fileName = saveDlg.FileName;

string strFilExtn = fileName.Remove(0, fileName.Length - 3);

switch (strFilExtn)

{

case "bmp":

curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Bmp);

break;

case "jpg":

curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg);

break;

case "gif":

curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Gif);

break;

case "tif":

curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Tiff);

break;

case "png":

curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);

break;

default:

break;

}

//设定文件格式,Ctrl+E,D

}

}

private void close_Click(object sender, EventArgs e)

{

this.Close();

}

private void Form1_Paint(object sender, PaintEventArgs e)

{

Graphics g = e.Graphics;

if (curBitmap != null)

{

g.DrawImage(curBitmap, 160, 20, curBitmap.Width, curBitmap.Height);

}

}

}

}

结果如图:

clip_image002

需要注意的问题:

在写好paint事件后,需要在窗体的事件中进行关联,开始没有关联,所以总是不能显示。

如下:

clip_image004

2018-10-27 16:17:06 phthon1997 阅读数 448

有关中医舌像的简单分析
黑白图的应用十分广泛,它是深度学习图像处理的基础,是图像分割、图像拼接、图像纹理分析等等技术的组成部分,较常见的应用在于X线图片、CT图片、MRI图片、B超图片、电镜图片等医学领域。
在传统医学的“望闻问切”四诊中,望诊作为疾病视觉信息的诊察手段被誉为“四诊之首”,舌诊又作为望诊的重要部分,机器视觉显得尤为重要。
裂纹舌是一种典型的特殊舌面纹理,在图像表现上形态各异、变化多端,在识别中纯在一定的难度,在裂纹特征的分析方面,我们主要针对裂纹自身图像特征点进行分析和处理。通过对大量裂纹舌的观察发现,典型的裂纹主要是灰度特征异常。

有关图像二极化的提取,裂纹分析代码如下:

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img=np.array(Image.open('C:\\Users\\Administrator\\Desktop\\图像处理文件\\QQ截图.png').convert('L'))
#打开图像数字矩阵
rows,cols=img.shape
for i in range(rows):
    for j in range(cols):
        if(img[i,j]<=128):
            img[i,j]=0
            else:
            img[i,j]=1
plt.figure('dog_blackandwhite')
plt.imshow(img,cmap='gray')
plt.axis('off')
plt.show()
        

代码运行效果:
典型裂纹舌彩色图像和灰度图像1:
在这里插入图片描述
在这里插入图片描述

2012-10-06 07:15:57 luoweifu 阅读数 6419

       大家都知道,人类所获取的信息中,大部分都来自视觉,人类用自己的双眼观察世界,发现世界。图像是对客观存在的物体、场景的一种相似性的生动描述。现在在计算机、网络及电子产品看到的图像都属于数字图像。在讲解图像处理之前需要必备一些关于图像处理的基本知识,下面就对一些常用的关于图像处理的基本知识进行讲解。

像素

        像素是基本原色素及其灰度的基本编码。我们看到的数字图片是有一个二维的像素矩阵组成。像素在计算机中通常用3个字节24位保存,如16-23 位表示红色(R)分量,8-15 位表示绿色(G)分量,0-7 位表示蓝色(B)分量;详细信息见下面“计算机颜色模型机RGB”中颜色的表示。

现实世界是三维的,但是我们从现实世界拍摄的图像是二维信息。一张图片可以定义为一个二维函数f(x,y)(x,y)是二维空间中的点坐标,f(x,y)是对应于该点的坐标值,即像素。


        当图片尺寸以像素为单位时,每一厘米等于28像素,比如15*15厘米长度的图片,等于420*420像素的长度。 

一个像素所能表达的不同颜色数取决于比特每像素(BPP)。如8bpp[2^8=256色, 灰度图像]16bpp[2^16=65536色,称为高彩色]24bpps[2^24=16777216色,称为真彩色]

分辨率

       图像总像素的多少,称为图像分辨率。由于图像通常用矩阵表示,所以分辨率常用,m*n表示,其中n表示行数(即一列包含的像素)m表示列数(即一行包含的像素)。如640*480,表示图像的长和宽分别为640480,总像素为640*480=307200(相机中所说的30万分辨率),800*600,表示图像的长和宽分别为800600,总像素为800*600=480000(相机中所说的50万分辨率)。

计算机颜色模型机RGB

       颜色模型,是将颜色表示成数字形式的模型,或者说是一种记录图像颜色的方式。有RGB模型、CMYK模型、HSL模型、Lab颜色模型等,其中最常用的是RGB模型。

RGB

       大家都知道,几乎世界上的所有颜色都可以用红(Red)、绿(Green)、蓝(Blue)三种颜色的不同比例组合形成,红绿蓝被称为三原色。

然而在计算机上他是怎样表示的呢?

在计算机中,RGB三种颜色分别被量化成0255256个等级。这样彩色图像就有256*256*256=16777216种彩色,这种图像被称为全彩色图像(full-color nimage)或真彩色图像(true-color image)。

在图像中每一个像素保存一个颜色值,而每种颜色有RGB三种颜色组合而成。所以颜色可以用R、G、B三种颜色的三维坐标表示,如下图:


       根据以上图像颜色的组成原理,可以把一个图像分解成RGG三种基颜色的灰度图像。如下图:

        

原图1                                                                            1_red

        

1_green                                                                            1_blue

算法代码实现(java):见下面附录1

特别说明:当一张图片各个像素的RGB三种颜色的分量都相同时就是一个无彩色灰度图像。如下图:


1_gray

算法代码实现(java):见下面附录2

附录


附录1:将图片分解成R、G、B三种灰度图片的算法

/**
	 * 将图片分解成R、G、B三种灰度图片
	 */
	public static void analyseRGB() {
		OutputStream output = null;
		try {
			// read image
			BufferedImage img = ImageIO.read(new File("F:\\image processing\\图1.jpg"));
			int imageType = img.getType();
			int w = img.getWidth();
			int h = img.getHeight();
			int startX = 0;
			int startY = 0;
			int offset = 0;
			int scansize = w;
			int dd = w-startX;
			int hh = h - startY;
			int x0 = w / 2;
			int y0 = h / 2;
			//System.out.println("dd:" + dd + "  hh:" + hh);
			// rgb的数组,保存像素,用一维数组表示二位图像像素数组
			int[] rgbArray = new int[offset + hh * scansize
					+ dd];
			//newArray 保存处理后的像素
			int[] newArray = new int[offset + hh * scansize
			     					+ dd];
			img.getRGB(startX, startY, w, h, rgbArray, offset, scansize);
			
			int rgb = rgbArray[offset + (y0 - startY) * scansize
					+ (x0 - startX)];
			Color c = new Color(rgb);
			//System.out.println("中间像素点的rgb:" + c);
			for(int i=0; i<h-startY; i++) {
				for(int j=0; j<w-startX; j++) {
					c = new Color(rgbArray[i*dd + j]);
					//newArray[i*dd + j] = new Color(c.getRed(), 0, 0).getRGB() ;	//红色灰度图像
					//newArray[i*dd + j] = new Color(0, c.getGreen(), 0).getRGB();	//绿色灰度图像
					newArray[i*dd + j] = new Color(0, 0, c.getBlue()).getRGB();	//蓝色灰度图像
				}
			}
			
			// create and save to bmp
			//File out = new File("F:\\image processing\\图1_red.jpg");
			//File out = new File("F:\\image processing\\图1_green.jpg");
			File out = new File("F:\\image processing\\图1_blue.jpg");
			if (!out.exists())
				out.createNewFile();
			output = new FileOutputStream(out);
			BufferedImage imgOut = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
			imgOut.setRGB(startX, startY, w, h, newArray, offset, scansize);
			ImageIO.write(imgOut, "jpg", output);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (output != null)
				try {
					output.close();
				} catch (IOException e) {
				}
		}
	}


附录2:将图片分解成黑白图片的算法

/**
	 * 将图片分解成黑白图片
	 */
	public static void grayImage() {
		OutputStream output = null;
		try {
			// read image
			BufferedImage img = ImageIO.read(new File("F:\\image processing\\baboom.jpg"));
			int imageType = img.getType();
			int w = img.getWidth();
			int h = img.getHeight();
			int startX = 0;
			int startY = 0;
			int offset = 0;
			int scansize = w;
			int dd = w-startX;
			int hh = h - startY;
			int x0 = w / 2;
			int y0 = h / 2;
			System.out.println("dd:" + dd + "  hh:" + hh);
			// rgb的数组,保存像素,用一维数组表示二位图像像素数组
			int[] rgbArray = new int[offset + hh * scansize
					+ dd];
			//newArray 保存处理后的像素
			int[] newArray = new int[offset + hh * scansize
			     					+ dd];
			img.getRGB(startX, startY, w, h, rgbArray, offset, scansize);
			
			int rgb = rgbArray[offset + (y0 - startY) * scansize
					+ (x0 - startX)];
			Color c = new Color(rgb);
			System.out.println("中间像素点的rgb:" +c+" "+c.getRGB());
			for(int i=0; i<h-startY; i++) {
				for(int j=0; j<w-startX; j++) {
					c = new Color(rgbArray[i*dd + j]);
					//彩色图像转换成无彩色的灰度图像Y=0.299*R + 0.578*G + 0.114*B
					int gray = (int)(0.299*c.getRed() + 0.578*c.getGreen() + 0.114*c.getBlue());
					newArray[i*dd + j] = new Color(gray, gray, gray).getRGB();	//蓝色灰度图像
				}
			}
			
			// create and save to bmp
			File out = new File("F:\\image processing\\baboom_gray.jpg");
			if (!out.exists())
				out.createNewFile();
			output = new FileOutputStream(out);
			BufferedImage imgOut = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
			imgOut.setRGB(startX, startY, w, h, newArray, offset, scansize);
			ImageIO.write(imgOut, "jpg", output);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (output != null)
				try {
					output.close();
				} catch (IOException e) {
				}
		}
	}


2013-06-10 17:01:54 insaneguy 阅读数 1163

滤波

滤波是将信号中特定波段频率滤除的操作,是从含有干扰的接收信号中提取有用信号的一种技术。


均值滤波

均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,该模板包括了其周围的临近像素(如3×3模板:以目标象素为中心的周围8个象素,构成一个滤波模板,即去掉目标象素本身),再用模板中的全体像素的平均值来代替原来像素值。


效果

平滑线性滤波处理降低了图像的“尖锐”变化。由于典型的随机噪声由灰度级的急剧变化组成,因此常见的平滑处理的应用就是降低噪声。均值滤波器的主要应用是去除图像中的不相关细节,其中“不相关”是指与滤波器模板尺寸相比较小的像素区域。然而,由于图像的边缘也是由图像灰度的尖锐变化带来的特性,所以均值滤波处理还是存在着边缘模糊的负面效应。


实验

使用OpenCV进行实验的部分代码:

	IplImage *pImgTmp = cvCloneImage(m_pImg);

	// 第二种边界处理:对边界特殊处理
	for (i = 0; i < m_pImg->width; i++)
	{
		for (j = 0; j < m_pImg->height; j++)
		{
			CvScalar color;
			CvScalar colorTmp;
			int m, n, cnt = 0;
			color.val[0] = color.val[1] = color.val[2] = 0;		
			for (m = i - nKernelSize/2; m <= i+nKernelSize/2; m++)
			{
				for (n = j-nKernelSize/2; n <= j+nKernelSize/2; n++)
				{
					// 处理边界和中心像素
					if ( (m == i && n == j) || m < 0 || m >= m_pImg->width 
						|| n < 0 || n >= m_pImg->height )
						continue;
					
					cvGetPixel(pImgTmp, n, m, colorTmp);
					color.val[0] += colorTmp.val[0];
					color.val[1] += colorTmp.val[1];
					color.val[2] += colorTmp.val[2];
					cnt++;
				}
			}
			// 取邻域中像素的平均值
			color.val[0] /= cnt;
			color.val[1] /= cnt;
			color.val[2] /= cnt;
			cvSetPixel(m_pImg, j, i, color);
		}
	}
	cvReleaseImage(&pImgTmp);



其中cvGetPixel和cvSetPixel的定义为:

void  cvGetPixel(const IplImage* pIplImg, int row, int col, CvScalar &color)
{
	if (col >= pIplImg->width || col < 0 ||
		row >= pIplImg->height || row < 0 )
		return;
	
	uchar *p = ((uchar*)(pIplImg->imageData + pIplImg->widthStep * row + col * 3));
	color = cvScalar(p[0], p[1], p[2]);
}

void  cvSetPixel(IplImage* pIplImg, int row, int col, CvScalar color)
{
	if (col >= pIplImg->width || col < 0 ||
		row >= pIplImg->height || row < 0 )
		return;
	
	uchar *p = ((uchar*)(pIplImg->imageData + pIplImg->widthStep * row + col * 3));
	p[2] = color.val[2];
	p[1] = color.val[1];
	p[0] = color.val[0];
}


测试图原图:



3×3模板结果:



5×5模板结果:



21×21模板结果:



参考

http://baike.baidu.com/view/1220844.htm

http://page.renren.com/601107605/note/803745240


没有更多推荐了,返回首页