• 图像处理算法优质博客整理 图像分割 K-means实现图像分割 图像叠加 图像叠加 特征: 分水岭算法 线性滤波与卷积 图像信息隐藏 相似图片搜索: 哈希法 直方图法 图像处理Java代码基础部分 ...

    图像处理算法优质博客整理

    图像分割

    K-means实现图像分割

    图像叠加

    图像叠加

    特征:

    分水岭算法
    线性滤波与卷积
    图像信息隐藏

    相似图片搜索:

    哈希法
    直方图法

    图像处理Java代码基础部分

    展开全文
  • Java图像处理

    2019-03-30 21:15:02
    在开发应用程序时,为了使程序界面美观...跟图形的操作类似,在图像处理中我们也是通过重写JComponent类的paint()方法来实现对图像的各种操作的。下面是用到的一些方法的定义 public abstract boolean drawImage(Im...

    在开发应用程序时,为了使程序界面美观,可以为应用程序窗口添加背景图片,方法是通过Java的绘图技术在控件上绘制图像,并将带有图片的控件添加到窗体上,运行程序,就可以看到在窗体显示的图片。跟图形的操作类似,在图像处理中我们也是通过重写JComponent类的paint()方法来实现对图像的各种操作的。下面是用到的一些方法的定义

    public abstract boolean drawImage(Image img,int x,int y,ImageObserver observer);//绘制图像
    //参数img是需要绘制的图像对象,x、y是绘制顶点的坐标,observer是图像的观察者,一般是绘制图像的控件
    
    public abstract boolean drawImage(Image img,int x,int y,int width,int height,ImageObserver observer);//按给定大小绘制图像
    //比上一个方法多出的width和height分别是图像的宽和高,通过这两个参数,可以实现对图像的缩放操作
    
    public abstract boolean drawImage(Image img,int dx1,int dy1,int dx2,int dy2,int sx1,int sy1,int sx2,int sy2,ImageObserver observer);//翻转图像
    //参数dx1、dy1、dx2、dy2分别是目标矩形的第1、2个角的坐标;sx1、sy1、sx2、sy2是源矩形第1、2个角的坐标
    //通过互换drawImage()方法中源矩形第1个角和第2个角的x坐标,可以实现图像的水平翻转;通过互换drawImage()方法中源矩形第1个角和第2个角的y坐标,可以实现图像的垂直翻转;
    
    
    
    //以下方法是Graphics2D类的方法,即在重写paint()方法时要将Graphics参数g转换为Graphics2D再进行调用
    public abstract void rotate(double theta);//旋转图像
    //theta是旋转的角度,以弧度为单位
    
    public abstract void shear(double shx,double shy);//倾斜图像
    //shx、shy是正x、y轴方向移动坐标的乘数,它可以作为其y、x坐标的函数
    
    public BufferedImage createScreenCapture(Rectangle screenRect);//裁剪图片
    //screenRect是屏幕上被截取的矩形区域,返回值即是从屏幕上截取的缓冲图像对象
    
    public final BufferedImage filter(BufferedImage src,BufferedImage dst);//调整图片的亮度
    //src是要过滤的源BufferedImage对象;dst是目标BufferedImage对象,或null
    
    public ColorConvertOp(ColorSpace srcCspace,ColorSpace dstCspace,RenderingHints hints);//转换彩色图片为灰度图片
    //srcCspace是原颜色空间对象;dstCspace是目标颜色空间对象;hints是用于控制颜色转换的RenderingHints对象,或null
    
    public Image createImage(ImageProducer producer);//使用像素值生成图像
    //producer是图像生成器,返回值是该方法执行成功返回一个Image对象
    

    下面是使用上述方法的一些例子

    class DrawImagePanel extends JPanel{	//绘制图像
    		public void paint(Graphics g){
    				g.drawImage(img,0,0,this);	//绘制图像
    		}
    }
    
    class ZoomImagePanel extends JPanel{		//绘制指定大小的图片
    		public void paint(Graphics g){
    			g.clearRect(0,0,this.getWidth(),this.getHeight());
    			imgWidth = img.getWidth(this);
    			imgHeight = img.getHeight(this);		//获取图片的宽高
    			float value = slider.getValue();		//滑块组件的取值
    			newW = (int)(imgWidth*value/100);
    			newH = (int)(imgHeight*value/100);				//计算图片缩放后的宽高
    			g.drawImage(img,0,0,newW,newH,this);		//绘制制定大小的图片
    	}
    }
    
    class PartImagePanel extends JPanel{	//翻转图像
    		public void paint(Graphics g){
    			g.clearRect(0,0,this.getWidth(),this.getHeight());
    			g.drawImage(img,dx1,dy1,dx2,dy2,dx2,dy1,dx1,dy2,this);	//水平翻转
    		}
    }
    
    class RotatePanel extends JPanel { //旋转图片
    	public void paint(Graphics g){
    		Graphics2D g2 = (Graphics2D)g;
    		g2.drawImage(img,80,10,260,150,this);
    		g2.rotate(Math.toRadians(10));
    		g2.drawImage(img,80,10,260,150,this);
    		g2.rotate(Math.toRadians(10));
    		g2.drawImage(img,80,10,260,150,this);
    	}
    }
    
    class ShearImagePanel extends JPanel {	//倾斜图片
    	public void paint(Graphics g){
    		Graphics2D g2 = (Graphics2D)g;
    		g2.shear(0.5,0);
    		g2.drawImage(img,10,20,220,160,this);
    	}
    }
    
    class CutImagePanel extends JPanel {		//裁剪图片
    	public void paint (Graphics g){
    		Graphics2D g2 = (Graphics2D)g;
    		g2.drawImage(img,0,0,this.getWidth(),this.getHeight(),this);
    		g2.setColor(Color.WHITE);
    		if(flag){
    			float[] arr = {5.0f};
    			BasicStroke stroke = new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL,1.0f,arr,0);
    			g2.setStroke(stroke);
    			g.clearRect(0,0,this.getWidth(),this.getHeight());
    			g.drawImage(createScreenCapture(g2.drawRect(pressPanelX,pressPanelY,releaseX-pressX,releaseY-pressY);),0,0,releaseX-pressX,releaseY-pressY,this);
    		}
    	}
    }
    
    class CreateImagePanel extends JPanel{ //使用像素值生成图像
    	public void paint(Graphic g){
    		int w=300,h=220;
    		int pix[]=new int[w*h];
    		int index = 0;
    		for(int y=0;y<h;y++){
    			int red=(y*255)/(h-1);
    			for(int x =0;x<w;x++){
    				int blue=(x*255)/(w-1);
    				pix[index++]=(255<<24)|(red<<16)blue;
    			}
    		}
    		ImageProducer imageProducer = new MemoryImageSource(w,h,pix,0,w);
    		Image img=createImage(imageProducer);
    		g.drawImage(img,0,0,getWidth(),getHeight(),this);
    	}
    }
    		
    
    展开全文
  • Java 图像处理

    2015-11-06 09:56:22
    终于写完数字图像分割这部分内容了,由于内容比较多,因此一个小的内容提要,有利于更有调理的阅读,如下: 1.数字图像分割方法概要 2.基于边界分割 2.1边缘检测 2.2边界提取(简单连接,启发式搜索...

    终于写完数字图像分割这部分内容了,由于内容比较多,因此做一个小的内容提要,有利于更有调理的阅读,如下:

    1.数字图像分割方法概要
    2.基于边界分割

    2.1边缘检测

    2.2边界提取(简单连接,启发式搜索,曲线拟合)

    3.基于区域分割

    3.1阀值分割(直方图双峰,迭代法,Ostu(大律)法,基于熵的二值方法)

    3.2区域生长

    3.3区域分裂与合并
    4.总结与实验实现(Java语言)

    提供最佳阀值分割迭代算法,Otsu阀值分割算法,基于熵的二值方法的实现

    最后,还是雨生的歌声,真的很不错…… 2012年9月3日2:54,更新与3:38

     

    §1 数字图像分割处理根据不同特征,分为两类:基于边界分割和基于区域分割,主要方法有:

    灰度阀值分割

    边界分割法

    基于纹理的分割

    区域生长法

    §2 基于边界分割

    §2.1 边缘检测

    基于边界分割其实就是点,线和边缘检测,边缘检测我在之前的一篇博文(http://dsqiu.iteye.com/blog/1638589)有介绍,可以前往查看。下面附上不同检测算子的对比:

     

    §2.2 边界获取

    使用边缘检测算子检测处理的都是孤立的一些点,需要进行边界获取将孤立点连接成线。

    边缘检测的结果得到许多梯度大的点,还必须进一步处理:

    原因:物体边界一般是线,而非孤立的点。必须把边缘点连接成边缘链,形成直线、曲线、各种轮廓线等,直到能表示图像中物体的边界。边界表示可以使图像的表示简洁,可以用来完成一定的文字识别任务或高层次的理解创造前提。边缘 形成线特征包括二个过程:抽取可能的边缘点;将虑出的边缘连接成直线、曲线、轮廓线,或用一定的直线、曲线去拟合它们。

    困难:

    梯度大的点、不一定真正是边缘点。

    边缘点的梯度也有可能小于周围其它点。

    分岔和缺损。

    对于一阶算子,需要对得到的边缘图进行细化,理想情况时,细化成单象素宽的闭合连通边界图。非理想情况下,边缘图像会有间隙存在,需要加以填充。对于二阶算子,过零点一般是单线,不需要细化,仍然需要补充间隙点。

    细化算法见数学形态学。

     

     

     

    边界跟踪

    连点成线

    例如,一个简单的算法:e(x,y)边缘强度,ф(x,y)边缘方向,两边缘点满足以下条件时可以连接:

    |e(xi,yi)-e(xj,yj)|<T1

    |ф(xi,yi)-ф(xj,yj)|mod 2π<T2

    |e(xi,yi)|>T, |e(xj,yj)|>T

    条件3 使小的干扰避免被误认为边缘。

    从满足|e(xA,yA)|>T 的A 点出发,如果找不到满足以上条件的相邻点,算法停止。如果有多个满足条件的邻点,选边缘强度差和角度差小的点。再不断从新的起始点出发继续搜索。

    启发式搜索

    人工智能中的概念,是一种从多种可能的路径中选优的方法。搜索需要有评价函数,为每一条路径打分,以便于选择路径。边缘质量评价函数可以包括各点的边缘强度,也可以利用边缘的方向信息。

    当有多条可能路径时,可以用全搜索(穷举法),找到评价指标最优的路径作为结果。然而,全搜索运算太大,组合爆炸。启发式搜索是在搜索的过程中设定一些启发性规则,当规则满足时就认为某一段路经合理,不再比较其它候选路经。例如:如果边缘方向上出现大的边缘点,则认为方向正确。边界的点稀疏或有长缺口时可以采用此方法。该技术对相对简单的图像效果很好,启发式搜索比全搜索减少了运算量,但不一定能找到两端点间连接的全局最优路径。

    图:启发性规则的例子,只有满足图中形式的连接被认为可能。

    曲线拟合

    如果边缘点很稀疏,可以用分段线性或高阶样条曲线来拟合这些点,从而形成边界。

     

    图:多边形拟合

    我们都学过最小二乘法作直线拟合,更复杂的二次曲线,高斯拟合等也不难实现。数学上是某种准则下的最优参数估计问题。所用准则多为均方误差最小准则,所估计的参数是曲线方程中的未知参数。具体的拟合方法参考各种参考书。

    其它边界抽取方法

    Hough 变换

    图搜索

    动态规划

    使用阀值进行图像分割

    阈值分割法是一种简单的基于区域的分割技术,是一种广泛使用的图像分割技术,它利用图像中要提取的目标和背景在灰度特性上的差异,把图像视为具有不同灰度级的两类区域的组合,选取一个合适的阈值,以确定图像中每个像素点是属于目标还是属于背景。它不仅可以极大的压缩数据量,而且也大大简化了图像信息的分析和处理步骤。阈值法是首先确定一个处于图像灰度级范围内的灰度阈值T,然后将图像中每个像素的灰度值都与这个阈值T比较,根据它是否超过阈值T而将该像素归于两类中的一类。常用的方法就是设定某一阈值T,用T将图像分割成大于阈值T的像素群(目标)和小于阈值T(背景)的像素群两部分。这两类像素一般属于图像中的两类区域,所以对像素根据阈值分类达到了区域分割的目的。输入图像是F(x,y),输出图像是B(x,y),则:

                                                  

    §3.1 阈值化分割方法

    根据图像本身的特点,可分为单阈值分割方法(全局)和多阈值分割方法(局部);也可分为基于像素值的阈值分割方法、基于区域性质的阈值分割方法和基于坐标位置的阈值分割方法。若根据分割算法所具有的特征或准则,还可以分为直方图峰谷法、最大类空间方差法、最大墒法、模糊集法、特征空间聚类法、基于过渡区的阈值选取法等。

     

     §3.1.1直方图阈值的双峰法

    该阈值化方法的依据是图像的直方图,通过对直方图进行各种分析来实现对图像的分割。图像的直方图可以看作是像素灰度值概率分布密度函数的一个近似,设一幅图像仅包含目标和背景,那么它的直方图所代表的像素灰度值概率密度分布函数实际上就是对应目标和背景的两个单峰分布密度函数的和。图像二值化过程就是在直方图上寻找两个峰、一个谷来对一个图像进行分割,也可以通过用两级函数来近似直方图。

    若灰度图像的直方图,其灰度级范围为i=0,1,…,L-1,当灰度级为k时的像素数为 ,则一幅图像的总像素数N为:

                                                   
     灰度级 i出现的概率为:

                                                   

     

    当灰度图像中画面比较简单且对象物的灰度分布比较有规律时,背景和对物象在图像的灰度值方图上各自形成一个波峰,由于每两个波峰间形成一个低谷,因而选择双峰间低谷处所对应的灰度值为阈值,可将两个区域分离。

    把这种通过选取直方图阈值来分割目标和背景的方法称为直方图阈值双峰法。如下图所示,在灰度级t1和t2两处有明显的波峰,而在t处是一个谷点

    具体实现的方法先做出图像f(x,y)的灰度直方图,若出现背景目标物两区域部分所对应的直方图呈双峰且有明显的谷底,则可以将谷底点所对应的灰度值作为阈值t,然后根据阈值进行分割就可以将目标从图像中分割出来。这种方法适用于适用于目标和对景的灰度差较大,直方图有明显谷底的情况。

    将原始图像和阈值分割后的图像比较,可以发现有些前景图像和背景图像的灰度值太接近,导致有些前景图像没有从背景中分离出来,图像失真了。双峰法比较简单,在可能情况下常常作为首选的阈值确定方法,但是图像的灰度直方图的形状随着对象、图像输入系统,输入环境等因素的不同而千差万别,当出现波峰间的波谷平坦、各区域直方图的波形重叠等情况时,用直方图阈值难以确定阈值,必须寻求其他方法来选择适宜的阈值。

     

    §3.1.2迭代法(最佳阀值分割迭代法)

    迭代法也是聚类方法中的 K-means算法,当然下面演示的K=2的情况。

    迭代式阈值选取的基本思路是:首先根据图像中物体的灰度分布情况,选取一个近似阈值作为初始阈值,一个较好的方法就是将图像的灰度均值作为初始阈值;然后通过分割图像和修改阈值的迭代过程获得认可的最佳阈值。迭代式阈值选取过程可描述如下。

    (1)选取一个初始阈值T。

    (2)利用阈值T把给定图像分割成两组图像,记为 和 。

    (3)计算 和  均值 和  。

    (4)选取新的阈值T,且

     

    (5)重复第(2)~(4)步,直至 和 均值 和  不再变化为止。

    具体实现时,首先根据初始开关函数将输入图逐个图像分为前景和背景,在第一遍对图像扫描结束后,平均两个积分器的值以确定一个阈值。用这个阈值控制开关再次将输入图分为前景和背景,并用做新的开关函数。如此反复迭带直到开关函数不在发生变化,此时得到的前景和背景即为最终分割结果。迭代所得的阈值分割的图像效果良好。基于迭代的阈值能区分出图像的前景和背景的主要区域所在,但在图像的细微处还没有很好的区分度。对某些特定图像,微小数据的变化却会引起分割效果的巨大改变,两者的数据只是稍有变化,但分割效果却反差极大。对于直方图双峰明显,谷底较深的图像,迭代方法可以较快地获得满意结果,但是对于直方图双峰不明显,或图像目标和背景比例差异悬殊,迭代法所选取的阈值不如其它方法。基于迭代的阈值能区分出图像的前景的主要区域所在,但在图像的细微处还没有很好的区分度。总的来说迭代法比双峰法分割的效果有很大的提高。

     

    §3.1.3大律法(Otsu阀值分割算法)

    图像记t为前景与背景的分割阈值,前景点数占图像比例为 ,平均灰度为 ;背景点数占图像比例为 ,平均灰度为 ,则图像的总平均灰度为:

                                                                                            

    从最小灰度值到最大灰度值遍历t,当t使得值

          

    最大时的t即为分割的最佳阈值。

    大津法可作如下理解:该式实际上就是类间方差值,阈值t 分割出的前景和背景两部分构成了整幅图像,而前景取值 ,概率为 ,背景取值,概率为 ,总均值为u,根据方差的定义即得该式。因方差是灰度分布均匀性的一种度量,方差值越大,说明构成图像的两部分差别越大,当部分目标错分为背景或部分背景错分为目标都会导致两部分差别变小,因此使类间方差最大的分割意味着错分概率最小。直接应用大津法计算量较大,因此在实现时采用了等价的公式

                                                                               

    在测试中发现,大津法选取出来的阈值非常理想,表现较为良好。虽然它在很多情况下都不是最佳的分割,但分割质量通常都有一定的保障,可以说是最稳定的分割。

     

    §3.1.4 类内方差最小方差法

    对Otsu阀值分割做下变形,就可以得到类内最小方差法。对于每个可能的阈值,分成两类,分别计算类内方差:

    使类内方差最小。

     

    §3.1.5 最小错误概率分类法

    已知前景和背景的概率分布的情况下:

           

    例如:假设背景与前景的灰度都是正态分布,分布参数已知时可以推导出最小错误概率的门限值。假设图像上前景点的灰度值概率分布是  ,背景点是,选取阈值T 作为分割点。

    则背景判为前景的错误:

    则前景判为背景的错误:

    总错误:

    总错误最小,则对T 导数为零。得到:

    如果前景背景都是正态分布:

    是前景与背景点数量的比例,如果方差相同,比例也相同

    则:

     

    §3.1.6 基于熵的二值化方法

    假设以阀值T分割图像,图像中低于阀值T的灰度的像素点构成目标物体(O),高于阀值T的像素点构成背景(B),则各个灰度级在本区的分布概率如下:

    O区: 

    B区:
    其中,L是图像灰度级总数,并且


     
    目标和背景区域的熵分别为



     对图像每个灰度级分别计算

    选取使w最大的灰度级作为分割图像的阀值T。

    局部自适应

    当照明或透射不均匀时,整幅图像分割将没有合适 的单一门限。这时,可对图像分块,对每一块分别选一门限进行分割,如果某块内有目标和背景,则直方图呈双峰。如果块内只有目标或背景,则直方图没有双峰,可根据邻居诸块得到的参数通过内插进行分割。

     

     

    §3.2 基于区域的图像分割

     

    基于边缘的图像分割:寻找区域之间的边界

    基于区域的图像分割:直接创建区域

    基于边缘的方法得到的结果通常不会与区域生长方法得到的分割完全一致。

    二种方法结合,会是一个好办法。区域生长的方法在噪声干扰、边缘不易提取的情况下,效果更好。区域内部的一致性描述是区域生长法的基本准则。一般是其灰度,也可以考虑颜色、纹理、形状等。基于阈值的方法:基于单个点的特点。基于区域的方法考虑到相邻点的一致性。

     

    §3.2.1 区域生长和区域合并

    区域生长的原理和步骤

    区域生长的基本思想是将具有相似性质的像素集合起来构成区域。具体先对每个需要分割的区域找一个种子像素作为生长的起点,然后将种子像素周围邻域中与种子像素有相同或相似性质的像素(根据某种事先确定的生长或相似准则来判定)合并到种子像素所在的区域中。将这些新像素当作新的种子像素继续进行上面的过程,直到再没有满足条件的像素可被包括进来。这样一个区域就长成了。

    思路:从一些种子点生长,直到充满整个图像。种子点有监督选取。每个目标区域中至少有一个点。

    需要确定:

    如何选择一组能正确代表所需要区域的种子像素,如果计算结果可以看出聚类的情况,那么可以选择聚类中心作为种子像素。

    生长的方法

    和每次生长后的一致性准则,如灰度差小于阈值。

    简单的生长方法,区域的所有8 邻域点。

    如果该点加入后满足一致性准则,则加入。两个区域满足一定准则,可以合并,该准则可以考虑两个区域分别的均值和方差。如果没有预先确定的种子点,可采用一般步骤

    1. 用某种方法把图像分割成许多小区域。

    2. 定义合并相邻区域的准则。

    3. 按照合并准则合并所有相邻的区域,如果没有再能够合并的块后停止。

    采用不同的初始分割方法和合并准则,可以得到适应不同情况的算法。另外,区域合并得结果通常还依赖于区域合并的顺序。

    相邻区域的特征值之间的差异是计算边界强度的一个尺度。如果给定边界两侧的特征值差异明显,那么这个边界很强,反之则弱。强边界允许继续存在,而弱边界被消除,相邻区域被合并。计算是一个迭代过程,每一步重新计算被扩大的区

    域成员隶属关系,并消除弱边界。没有弱边界可消除时,合并过程结束。

    过程看起来象一个物体内部区域不断增长,直到到达边界为止的过程。

    该方法计算开销大,但能够同时利用图像的若干种性质(多种描述),对自然景物分割方面效果相对最优。

     

    生长准则和过程

    区域生长的一个关键是选择合适的生长或相似准则,大部分区域生长准则使用图像的局部性质。生长准则可根据不同原则制定,而使用不同的生长准则会影响区域生长的过程。下面介绍3种基本的生长准则和方法。

    (1) 灰度差准则

    区域生长方法将图像的像素为基本单位来进行操作,基本的区域灰度差方法主要有如下步骤:

    ①对图像进行逐步扫描,找出尚没有归属的像素;

    ②以该像素为中心检查它的邻域像素,将邻域中的像素逐个与它比较,如果灰度差小于预先确定的值,将它们合并;

    ③以新合并的像素为中心,返回到步骤②,检查新像素的邻域,直到区域能进一步扩张;

    ④返回到步骤①,继续扫描直到不能发现没有归属的像素,则结束整个生长过程。

    采用上述方法得到的结果对区域生长起点的选择有较大依赖性。为克服这个问题可采用下面的改进方法:

    ①设灰度差的阈值为零,用上述方法进行区域扩张,使灰度相同像素合并;

    ②求出所有邻接区域之间的平均灰度差,并合并具有最小灰度差的邻接区域;

    ③设定终止准则,通过反复进行上述步骤②中的操作将区域依次合并直到终止准则满足为止。

    另外,当图像中存在缓慢变化的区域时,上述方法有能会将不同区域逐步合并而产生错误。为克服这个问题,可不用新像素的灰度值去与邻域像素灰度值比较,而用新像素所在区域的平均灰度值去与各邻域像素的灰度值进行比较。

    对一个含N个像素的图像区域R,其均值为: 

    对像素是否合并的比较测试表示为:

     

    其中T为给定的阈值。

    区域生长的过程中,要求图像的同一区域的灰度值变化尽可能小,而不同的区域之间,灰度差尽可能大。下面分两种情况进行讨论:

    1)设区域为均匀的,各像素灰度值为m与一个零均值高斯噪音的叠加。当测试某个像素是否合并时,条件不成立的概率为:

    这就是误差概率函数,当T取3倍的方差时,误判概率为1-99.7%。这表明,当考虑灰度均值时,区域内的灰度变化应尽量小。

    2)设区域为非均匀,且由两部分不同目标的图像像素构成。这两部分像素在R中所占比例分别为 ,灰度值分别为 ,则区域均值为 。对灰度值为m的像素,它与区域均值的差为: 

    可知正确的判决概率为:

    这表明,当考虑灰度均值时,不同部分像素间的灰度差距应尽量大。

    (2) 灰度分布统计准则

    这里考虑以灰度分布相似性作为生长准则来决定区域的合并,具体步骤为:

    ①把图像分成互不重叠的小区域;

    ②比较邻接区域的累积灰度直方图根据灰度分布的相似性进行区域合并;

    ③设定终止准则,通过反复进行步骤②中的操作将各个区域依次合并直到终止准则满足。

    这里对灰度分布的相似性常用两种方法检测(设分别为两邻接区域的累积灰度直方图):

    Kolmogorov-Smirnov检测:

    Smoothed-Difference检测:

    如果检测结果小于给定的阈值,即将两区域合并。

    采用灰度分布相似合并法生成区域的效果与微区域的大小和阈值的选取关系密切,一般说来微区域太大,会造成因过渡合并而漏分区域:反之,则因合并不足而割断区域。而且,图像的复杂程度,原图像生成状况的不同,对上述参数的选择有很大影响。通常,微区域大小q和阈值T由特定条件下的区域生成效果确定。

    (3) 区域形状准则

    在决定对区域的合并时也可以利用对目标形状的检测结果,常用的方法有两种:

    ①把图像分割成灰度固定的区域,设两邻区域的周长分别为p1和p2 ,把两区域共同边界线两侧灰度差小于给定值的那部分长度设为L,如果(t1,为预定阈值): 

    则合并两区域;

    ②把图像分割成灰度固定的区域,设两邻接区域的共同边界长度为B,把两区域共同边界线两侧灰度差小于给定值的那部分长度设为L,如果(为预定阈值)

    则合并两区域。

    上述两种方法的区别是:第一种方法是合并两邻区域的共同边界中对比度较低部分占整个区域边界份额较大的区域,而第二种方法则是合并两邻接区域的共同边界中对比度较低部分比较多的区域。

     

    §3.2.2 区域分裂

    区域分裂是与区域合并相反的过程。

    先假设整个图像是一个对象。

    不满足一致性准则,则分裂,(一般是分裂成4 个子图像)。

    分裂过程反复进行,直到所有分开的区域满足一致性准则。

    如果图像是大小为N×N 的正方形,N 是2 的整数次幂,即N=2n,则分裂得到的所有区域都是2 的整数次幂的正方形。逐层得到的一种图像的表示方法,叫做四叉树(quadtree)。每个节点有4 个子节点。

    四叉树是一种很方便的区域描述方法。

    分裂的结果,可能有相邻且满足一致性准则,但分到了不同的块中。解决方法―增加合并过程。

    进一步:分裂/合并综合的方法。

     

    §3.2.3 分裂和合并法

    如果用树表示一幅图像,树根代表整个图像,树叶代表每个象素。

    分裂的方法是从树根开始处理;合并的方法是从树叶开始处理。

    如果中间层次开始处理,按照一致性准则,该合并的合并,该分裂的分裂,无疑是更好的选择。

    减少计算量的同时,具有分裂和合并法的优点。

    方法的要素:输入图像、一致性准则、初始的区域

    划分

    以四叉树的某一层节点作初始区域划分。

    1. 合并具有一致属性的共根四个节点块。

    2. 分开不满足一致性要求的块,上一步没有合并得块,如果它的四个子块不满足一致性,则将其分解成4 个子块。分出的子块如不满足一致性,还可以继续分解。

    3. 对相邻的具有一致属性的块合并,即使不在同一层或者没有共同的父节点。将四叉树变为邻接图表示。

    4. 如果没有进一步的合并或分解,算法终止。

     

    §3.4 边缘与区域相结合的分割

    边缘与区域组合分割的主要思想是结合二者的优点,通过边缘点的限制,避免区域的过分割;同时,通过区域分割补充漏检的边缘,使轮廓更加完整。例如:先进行边缘检测与连接,再比较相邻区域的特征(灰度均值、方差等),若相近则合并;对原始图像分别进行边缘检测和区域生长,获得边缘图和区域片段图后,再按一定的准则融合,得到最终分割结果。

     

    连通区域标记

    图像分割一般得到的多个区域,通常需要通过标记每个象素分别属于哪个区域,分别把每个区域提取出来。

    在有多个对象需要处理的情况下,这一步骤是必不可少的。

    基于边缘的方法已经得到闭合边界,可以采用边界跟踪和内部填充的方法。见platt 书P581。

    基于区域的方法一般采用连通性分析方法,按照一定的顺序把连通的像素用相同的序号标注。

    算法:

    1. 把所有像素点放到待处理点集合A 中

    2. 如果 A 空则结束。否则从A 中任意移出一点,作为连通域a(用集合表示)的初始点。

    3. 在 A 中寻找所有与a 连通的点,并移到a 中。如果没有找到,转到2,寻找下一个连通域

    4. 转到 3,迭代寻找新的连同点。算法逻辑简单,速度慢。快速算法:每点只需要遍历一次。

     图像分割的评价

    找到某种方式来评价图像分割方法的好坏对选择和研究算法有非常有用。

    Haralick 和Shapiro 建立了下列定性的指导:

    对于某些特征(如灰度、纹理),同一个区域的图像应该一致和均匀

    区域内部应该简单,没有很多空洞

    相邻的区域在满足区域内部一致性的特征上应该有显著的区别

    每个区域的边界应该简单而不粗糙,并且空间位置准确

    目前仍没有定量的度量标准。

     

    §4.1图像分割总结

    算法的其他的分类方式:

    本文以使用特征的物理意义不同来区分,有利于掌握本质特点。

    章毓晋书按照计算过程分:串行、并行。并行算法所有判断可以独立同时做出,串行算法后一步要利用前一步的结果。

    总结

    1. 图像分割是图像描述的重要基础。

    2. 怎样获得分割呢?

    可以设想分割后的区域对某种或某些图像特性具有可靠的一致或平稳;相邻区域之间的边界应该完整、不破碎又是能精确定位的。

    3. 基于边界或区域的方法都是基于基本假设,假设不成立时就会遇到困难。基于边界的方法,物体内部边缘,光照等原因物体间边缘差别小或平滑过渡。人可以在理解的基础上判别,需要更上层知识的指导。基于区域的方法,区域内部特征不一定那么均匀。

    4. 虽然图像处理一开始就研究分割的问题,也取得了相当进展,但尚无一种适合于所有图像的通用分割算法。

    5. 人们至今仍然在努力发展新的、更有潜力的方法,期待更通用、更完美的分割结果。

    6. 本章介绍了一些典型的基本的分割算法,实际上,现有的方法通常是针对具体问题。为了得到好的性能,要根据实际问题选择或设计算法。众多方法的关键是模型和条件,不同的模型和条件决定了不同的方法。根据具体任务找到或设计匹配的模型,根据条件求解。

    7. 在研究新方法的同时,分割参数的自动选择,利用统计理论作决策,适用于快速处理的数据结构,较为通用的分割结果质量评价标准都是研究者关心的内容。如果区域内部灰度有剧烈的变化,则需要用纹理分析来分割。

     

    §4.2 程序实现

    一维最大熵分割算法

     

    Java代码  收藏代码
    1. //一维最大熵分割算法  
    2.     public int segment(int[] pix, int w, int h)  
    3.     {  
    4.         int i, j, t;  
    5.         double a1, a2, max, pt;  
    6.         double[] p = new double[256];  
    7.         double[] num = new double[256];       
    8.              
    9.         int[][] im = new int[w][h];  
    10.           
    11.         for(j = 0; j < h; j++)  
    12.             for(i = 0; i < w; i++)             
    13.                 im[i][j] = pix[i+j*w]&0xff;  
    14.           
    15.         for (i = 0; i < 256; i++)  
    16.             p[i] = 0;  
    17.           
    18.         //统计各灰度级出现的次数  
    19.         for (j = 0; j < h; j++)  
    20.             for (i = 0; i < w; i++)              
    21.                 p[im[i][j]]++;  
    22.           
    23.         /** 
    24.          *关于计算各灰度级出现的概率 
    25.          *1.因为(p[j]/(w*h)) / (pt/(w*h)) = p[j] / pt 
    26.          *  所以计算p[j] / pt不必计算概率 
    27.          *2.当p[j]=0时,计算Math.log(p[j] / pt)将出现无穷大.但 
    28.          *  此时p[j] / pt) * Math.log(p[j] / pt)=0 
    29.          *  所以在计算a1时,不必计算这一项        
    30.          */  
    31.         int hw =  h*w;                 
    32.         for (i = 0; i < 256; i++)  
    33.         {  
    34.             a1 = a2 = 0.0;  
    35.             pt = 0.0;  
    36.             for (j = 0; j <= i; j++)  
    37.                 pt += p[j];  
    38.               
    39.             for (j = 0; j <= i; j++)  
    40.               
    41.                 if(p[j]>0)  
    42.                     a1 += (p[j]/pt) * Math.log(pt/p[j]);  
    43.                           
    44.             for (j = i+1; j <256; j++)  
    45.                 if(p[j]>0)  
    46.                     a2 += (p[j] /(hw-pt))* Math.log((hw - pt)/p[j]);  
    47.               
    48.             num[i] = a1 + a2;  
    49.         }  
    50.           
    51.         max = 0.0; t = 0;  
    52.         for (i = 0; i < 256; i++)  
    53.         {  
    54.             if (max < num[i])  
    55.             {  
    56.                 max = num[i];  
    57.                 t = i;  
    58.             }  
    59.         }          
    60.         return t;  
    61.     }  

    二维最大熵分割算法, 使用递推算法 

     

    Java代码  收藏代码
    1.   public int segment2(int[] pix, int w, int h)  
    2. {  
    3.     int i, j, u, v, t;  
    4.        double a1, a2, max, pa, pb, pa2, pb2, sum;  
    5.        double[][] p = new double[256][256];  
    6.        double[][] num = new double[256][256];  
    7.       
    8.     int[][] im = new int[w][h];  
    9.       
    10.     for(j = 0; j < h; j++)  
    11.         for(i = 0; i < w; i++)             
    12.             im[i][j] = pix[i+j*w]&0xff;  
    13.               
    14.        for(i = 0; i < 256; i++)  
    15.            for(j = 0; j < 256; j++)  
    16.                p[i][j] = 0;  
    17.          
    18.        //统计2维直方图p[i][j]  
    19.        for(j = 1; j < h-1; j++)  
    20.        {  
    21.            for(i = 1; i < w-1; i++)  
    22.            {  
    23.             t = (int)((im[i-1][j]+im[i+1][j]+im[i][j-1]  
    24.               +im[i][j+1]+im[i][j])/5);//4-邻域均值  
    25.                p[im[i][j]][t]++;  
    26.            }  
    27.        }  
    28.          
    29.        pa = 0.0; pb = 0.0; max = 0.0; t = 0;  
    30.        for(i = 49; i < 200; i=i+2)  
    31.        {     
    32.            System.out.println((int)(i*100/199)+" %");  
    33.            for(j = 0; j < 256; j++)  
    34.         {  
    35.             a1 = 0.0; a2 = 0.0;                   
    36.             pb = 0.0;  
    37.               
    38.             //递推算法计算pa  
    39.             if(j != 0)  
    40.             {  
    41.                 for(u = 0; u <= i; u++)   
    42.                     pa += p[u][j];  
    43.             }  
    44.             else  
    45.             {     
    46.                 pa = 0.0;  
    47.                 for( u = 0; u <= i; u++)  
    48.                     pa += p[u][0];  
    49.             }  
    50.                               
    51.             //递推算法计算pb  
    52.             if(j != 0)          
    53.             {  
    54.                 for(u = i+1;u < 256;u++)  
    55.                     pb -= p[u][j];  
    56.             }  
    57.             else  
    58.             {  
    59.                 pb = 0;  
    60.                 for(u = i+1;u < 256;u++)  
    61.                     for(v = j+1; v < 256; v++)  
    62.                         pb += p[u][v];  
    63.             }  
    64.              
    65.             for(u = 0; u <= i; u++)  
    66.                 for(v = 0; v <= j; v++)  
    67.                     if(p[u][v] > 0)  
    68.                         a1 += (double)(-p[u][v]/pa)* Math.log(p[u][v]/pa);  
    69.              
    70.             for(u = i+1; u < 256; u++)  
    71.                 for(v = j+1; v < 256; v++)  
    72.                     if(p[u][v] > 0)  
    73.                         a2 += (double)(-p[u][v]/pb)* Math.log(p[u][v]/pb);    
    74.              
    75.             num[i][j] = a1 + a2;                              
    76.            }  
    77.        }  
    78.          
    79.        max = 0.0; t = 0;  
    80.        for (i = 0; i < 256; i++)  
    81.        {  
    82.         for(j = 0; j < 256; j++)  
    83.         {  
    84.                if (max < num[i][j])  
    85.                {  
    86.                    max = num[i][j];  
    87.                    t = i;   
    88.                }  
    89.            }  
    90.        }      
    91.        return t;  
    92. }  

     最佳阈值分割

    Java代码  收藏代码
    1. public int bestThresh(int[] pix, int w, int h)  
    2. {  
    3.     int i, j, t,  
    4.         thresh,   
    5.         newthresh,  
    6.         gmax, gmin;         //最大,最小灰度值  
    7.        double a1, a2, max, pt;  
    8.        double[] p = new double[256];  
    9.        long[] num = new long[256];  
    10.   
    11.     int[][] im = new int[w][h];  
    12.       
    13.     for(j = 0; j < h; j++)  
    14.         for(i = 0; i < w; i++)             
    15.             im[i][j] = pix[i+j*w]&0xff;  
    16.               
    17.        for (i = 0; i < 256; i++)  
    18.            p[i] = 0;  
    19.          
    20.        //1.统计各灰度级出现的次数、灰度最大和最小值  
    21.        gmax = 0;  
    22.        gmin =255;  
    23.        for (j = 0; j < h; j++)  
    24.        {  
    25.            for (i = 0; i < w; i++)  
    26.            {  
    27.             int g = im[i][j];  
    28.                p[g]++;  
    29.                if(g > gmax) gmax = g;  
    30.                if(g < gmin) gmin = g;  
    31.            }  
    32.        }  
    33.          
    34.        thresh = 0;  
    35.        newthresh = (gmax+gmin)/2;  
    36.          
    37.        int meangray1,meangray2;  
    38.        long p1, p2, s1, s2;  
    39.        for(i = 0; (thresh!=newthresh)&&(i<100);i++)  
    40.        {  
    41.         thresh = newthresh;  
    42.         p1 = 0; p2 = 0; s1 = 0; s2 = 0;  
    43.           
    44.         //2. 求两个区域的灰度平均值  
    45.         for(j = gmin; j < thresh;j++)  
    46.         {  
    47.             p1 += p[j]*j;  
    48.             s1 += p[j];               
    49.         }  
    50.         meangray1 = (int)(p1/s1);  
    51.           
    52.         for(j = thresh+1; j < gmax; j++)  
    53.         {  
    54.             p2 += p[j]*j;  
    55.             s2 += p[j];               
    56.         }  
    57.         meangray2 = (int)(p2/s2);  
    58.         //3. 计算新阈值  
    59.         newthresh = (meangray1+meangray2)/2;      
    60.        }  
    61.        return newthresh;  
    62. }  

     Otsu阈值分割

    Java代码  收藏代码
    1. public int otsuThresh(int[] pix, int iw, int ih)  
    2. {  
    3.     ColorModel cm = ColorModel.getRGBdefault();  
    4.        int wh = iw * ih;  
    5.        int[][] inIm = new int[iw][ih];   
    6.   
    7.        int i, j, t;  
    8.        int L = 256;  
    9.        double[] p = new double[L];  
    10.                          
    11.        for (j = 0; j < ih; j++)  
    12.            for (i = 0; i < iw; i++)  
    13.                inIm[i][j] = pix[i+j*iw]&0xff;                 
    14.   
    15.        for (i = 0; i < L; i++)  
    16.            p[i] = 0;  
    17.   
    18.        //计算各灰度出现次数  
    19.        for (j = 0; j < ih; j++)  
    20.            for (i = 0; i < iw; i++)  
    21.                p[inIm[i][j]]++;  
    22.   
    23.        //计算各灰度级出现概率  
    24.        for (int m = 0; m < L; m++)  
    25.            p[m] = p[m] / wh;  
    26.   
    27.        double[] sigma = new double[L];  
    28.        for (t = 0; t < L; t++)  
    29.        {  
    30.            double w0 = 0;  
    31.            for (int m = 0; m < t+1; m++)  
    32.                w0 += p[m];  
    33.            double w1 = 1 - w0;  
    34.   
    35.            double u0 = 0;  
    36.            for (int m = 0; m < t + 1; m++)  
    37.                u0 += m * p[m] / w0;  
    38.   
    39.            double u1 = 0;  
    40.            for (int m = t; m < L; m++)  
    41.                u1 += m * p[m] / w1;  
    42.   
    43.            sigma[t] = w0*w1*(u0-u1)*(u0-u1);  
    44.        }  
    45.        double max = 0.0;  
    46.        int T = 0;  
    47.        for (i = 0; i < L-1; i++)  
    48.        {  
    49.            if (max < sigma[i])  
    50.            {  
    51.                max = sigma[i];  
    52.                T = i;  
    53.            }  
    54.        }          
    55.        return T;                  
    56. }  

     

    上述算法函数返回值都是图像分割的阀值,然后进一步对图像进行阀值灰度处理。

     

    Java代码  收藏代码
    1. //图像序列pix阈值分割     
    2. public int[] thSegment(int[] pix, int iw, int ih, int th)  
    3. {                         
    4.     int[] im = new int[iw*ih];  
    5.     int t;  
    6.     for(int i = 0; i < iw*ih; i++)     
    7.     {  
    8.         t = pix[i]&0xff;  
    9.                               
    10.         if(t > th)   
    11.             im[i] = (255<<24)|(255<<16)|(255<<8)|255;//背景色  
    12.         else  
    13.             im[i] = (255<<24)|(0<<16)|(0<<8)|0;      //前景色为         
    14.     }  
    15.     return im;  
    16. }  

     

    最后附上几张实验效果图:

     




     

     

     转载地址 http://dsqiu.iteye.com/blog/1669891

     

    展开全文
  • Java图像处理(1)

    2019-08-21 15:21:19
    图像处理 首先是原图的绘制 一、获取图像文件 获取文件所用到的方法是文件选择方法即JFileChooser JFileChooser jc = new JFileChooser("默认路径"); jc.showOpenDialog(null); File file = jc.getSelectedFile(); ...

    图像处理

    首先是原图的绘制

    一、获取图像文件

    获取文件所用到的方法是文件选择方法即JFileChooser

    JFileChooser jc = new JFileChooser("默认路径");
    jc.showOpenDialog(null);
    File file = jc.getSelectedFile();
    

    上面代码即使用JFileChooser类来选择并得到一个文件。

    二、将图像文件存至数组

    在这里需要用到BufferedImage这个类,并使用ImageIO来读取上面选择的图像文件的图像信息,并赋给buffer。然后创建与图像分辨率相应大小的数组,并将buffer中图像各像素点的ARBG颜色数据相应的赋给数组。代码如下:

    BufferedImage buffer = new BufferedImage();
    buffer = ImageIO.read(file);		
    imgdata = new int[buffer.getHeight()][buffer.getWidth()];
    for (int n=0; n<buffer.getHeight(); n++){
    	for (int m=0; m<buffer.getWidth();m++){
    		imgdata[n][m] = buffer.getRGB(m, n);
    	}
    }
    

    三、提取ARGB颜色数据

    上面所得到的像素点颜色数据包括A(透明度)、R(红色)、G(绿色)、B(蓝色) 四种数据。我们需要使用位运算将这四种数据从单个像素点数据中分离出来。

    位运算

    或运算:^
    与运算:&
    >>n:转换成二进制并向右移动n位,空位补零
    <<n:转换成二进制并向左移动n位,空位补零
    以上均是针对二进制的运算

    int rgb = imgdata[n][m];
    a = rgb>>24&0xff;
    r = rgb>>16&0xff;
    g = rgb>>8&0xff;
    b = rgb&0xff;
    

    画出原图

    上面我们已经得到了每个像素点的A、R、G、B的数据,下面只需要创建一个Color类型,然后将数据输入进去,再将从buffer获取的画笔设置颜色为此颜色,就可以在buffer中画出原图了。

    Graphics grb = buffer.getGraphics();
    for (int n=0; n<imgdata.length; n++){
    	for (int m=0; m<imgdata[n].length; m++){
    		int rgb = imgdata[n][m];
    		a = rgb>>24&0xff;
    		r = rgb>>16&0xff;
    		g = rgb>>8&0xff;
    		b = rgb&0xff;
    		c = new Color(r, g, b, a);
    		grb.setColor(c);
    		grb.drawLine(m, n, m, n);
    	}
    }
    

    最后再在画图板中将buffer画出来。(gr 为画图板的画笔)

    gr.drawImage(buffer, xo, yo, null);
    

    四、简单黑白和反色处理

    上面已经得到图像每个像素的argb数据并储存在数组里,所以直接数组中的像素数据提取出A、R、G、B处理,然后画出来即可。

    黑白处理

    只需设定一个中间值avg,R、G、B值在avg之下的赋0,在avg以上的赋255,即可实现黑白化。

    for (int n=0; n<imgdata.length; n++){
    	for (int m=0; m<imgdata[n].length; m++){
    		int rgb = imgdata[n][m];
    		a = rgb>>24&0xff;
    		r = rgb>>16&0xff;
    		g = rgb>>8&0xff;
    		b = rgb&0xff;
    		if(r>125 || g>125 || b>125){
    			r = 255;
    			g = 255;
    			b = 255;
    		}
    		else{
    			r = 0;
    			g = 0;
    			b = 0;
    		}
    		c = new Color(r, g, b, a);
    		grb.setColor(c);
    		grb.drawLine(m, n, m, n);
    	}
    }
    

    反色

    同上只需将像素的R、G、B值处理即可

    a = rgb>>24&0xff;
    r = 255-rgb>>16&0xff;
    g = 255-rgb>>8&0xff;
    b = 255-rgb&0xff;
    
    展开全文
  • 此文件包含了基于java图像处理源代码,具体有图像灰度变换、阈值变换、线性变换、伪彩色处理、图像融合、图像合成、内置变换、仿射变换、图像插值、边缘检测、图像分割、hough变换、图像编码、分形演示等等等等,...
  • 本文就JAVA图像处理中一些基本应用进行了介绍。希望通过能够对大家在以后的图像处理中有些帮助。 一、对一个现有的图片进行文字和图标的合成 我们先从下面的这段简单的代码开始   im...

    引言

    相信大家平时碰到过一些在JAVA中对图像进行处理的需求,比如需要对上传的图片加上自己的签名或图标,或者生成和解析动态的GIF图片,以及处理PSD文件图像信息。本文就JAVA在图像处理中一些基本应用进行了介绍。希望通过能够对大家在以后的图像处理中有些帮助。

    一、对一个现有的图片进行文字和图标的合成
                          
    我们先从下面的这段简单的代码开始

     

    import java.awt.*;
    import javax.imageio.ImageIO;
    import com.sun.image.codec.jpeg.*;
    /**
     * @author Anders.Hu
     * 2005-01-12
     */
     public class Test {
     public static void main(String[] args) {
      try {
        //读取模板图片内容
        BufferedImage image = ImageIO.read(new FileInputStream("c:\\1.jpg"));
        Graphics2D g = image.createGraphics();//得到图形上下文
        g.setColor(Color.BLACK); //设置画笔颜色
        //设置字体
        g.setFont(new Font("宋体", Font.LAYOUT_LEFT_TO_RIGHT, 15));//写入签名
        g.drawString("很好吃诶,要不要也来一口?",43, image.getHeight() - 10);
        g.dispose();
        FileOutputStream out = new FileOutputStream("c:\\2.jpg");
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(image);
        out.close();
        } catch(Exception e) {
         e.printStackTrace();
        }
     }
    }

    相信大家看到这里已经知道了大致的操作过程,我想我还是在这里把基本的原理简单说明一下便于对后续内容的阐述:首先我们通过javax.imageio.ImageIO的read方法读取图像在BufferedImage中,然后我们可以通过BufferedImage的createGraphics方法取得图像的上下文便于对图像的处理,如加上自己喜爱的文字或图片等,最后调用JPEGCodec的encode方法进行JPEG编码,然后就是保存到文件中了。

    这就是我运行上面代码的结果

    需要提出的是JPEGCodec是非标准类,如果程序是运行JDK1.4以上版本的话,可以采取以下代码进行JPEG编码ImageIO.write(image, "JPEG", out);

    可能在你的实际需求还要加入一些图标的修饰,要做到这一步,我们只需要在上面的代码中利用Graphics2D的drawImage方法做到。下面是加入图标的代码

     

    public static void main(String[] args) {
      try {
         BufferedImage image = ImageIO.read(new FileInputStream("c:\\1.jpg"));
         //读取图标
         BufferedImage image_biao = ImageIO.read(new FileInputStream("c:\\i.jpg"));
         Graphics2D g = image.createGraphics();
         g.setColor(Color.YELLOW);
         g.setFont(new Font("宋体", Font.LAYOUT_LEFT_TO_RIGHT, 25));
         g.drawString("很好吃诶,要不要也来一口?",43, image.getHeight() - 80);
         //写入图标
         g.drawImage(image_biao, 20,image.getHeight() - 80, image_biao.getWidth(null),
           image_biao.getHeight(null), null);
         g.dispose();
         FileOutputStream out = new FileOutputStream("c:\\3.jpg");
         JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
         encoder.encode(image);
         out.close();
        } catch(Exception e) {
         e.printStackTrace();
        }
     }

    代码运行的结果如下

    二、生成和解析动态的GIF图片

    有了以上对图象的基本处理之后,我们再来看看对动态GIF图片的处理。
    GIF是一种由CompuServe创建的压缩和传送图像文件的格式。

    GIF图像是基于颜色列表的(存储的数据是该点的颜色对应于颜色列表的索引值),最多只支持8位(256色)。GIF文件内部分成许多存储块,用来存储多幅图像(Frame)或者是决定图像表现行为的控制块,用以实现动画和交互式应用。因此我们要生成和分析GIF图像的话,就需要对GIF文件格式进行分析,这里我们采用网上的一个开源代码进行处理。

    先在http://www.fmsware.com/stuff/gif.zip 下载处理GIF图片的代码,解压之后可以发现有AnimatedGifEncoder.java, GifDecoder.java, LZWEncoder.java,NeuQuant.java这4个JAVA文件,在这些文件的开头都已经有了简单的说明。其中AnimatedGifEncoder.是用来生成GIF文件的类,而GifDecoder则是用来解析GIF动态图像Frame信息的类。LZWEncoder是LZW压缩算法类,NeuQuant是用来生成颜色列表的类。

    把它们加入到我们的项目文件中,然后我们就来利用AnimatedGifEncoder来写一段合成动态GIF文件的代码。

     

    import java.io.FileInputStream;
    import javax.imageio.ImageIO;
    import open.AnimatedGifEncoder;
    /**
     * @author Anders.Hu
     * 2005-01-13
     */
    public class TestMakeGIF {
     public static void main(String[] args) {
      try {
       //指定Frame的文件
       String imgFileName[] = new String[]{"c:\\1.jpg","c:\\2.jpg", "c:\\3.jpg"};
       String outputFileName = "c:\\test.gif";
       AnimatedGifEncoder e = new AnimatedGifEncoder();
       e.start(outputFileName);//开始处理
       e.setDelay(500); //设置延迟时间
       for (int i = 0; i < imgFileName.length; i++) {
        e.addFrame(ImageIO.read(new FileInputStream(imgFileName[i])));//加入Frame
       }
       e.finish();
      } catch (Exception e) {
       e.printStackTrace();
     }
    }

    代码运行的结果如下

    是不是觉得有了这个AnimatedGifEncoder类,合成GIF文件挺方便的,现在我们再来看看GifDecoder的使用。

     

    public class TestGifDecoder {
     public static void main(String[] args) {
      try {
       String inputFileName = "c:\\test.gif";
       GifDecoder decoder = new GifDecoder();
       decoder.read(inputFileName);
       int n = decoder.getFrameCount();//得到frame的个数
       for (int i = 0; i < n; i++) {
        BufferedImage frame = decoder.getFrame(i); //得到frame
        int delay = decoder.getDelay(i);//得到延迟时间
        //生成JPG文件
        String outFilePath = "c:\\test_"+i+".jpg";
        FileOutputStream out = new FileOutputStream(outFilePath);
        ImageIO.write(frame,"jpeg",out);
       }
      } catch (Exception e) {
       e.printStackTrace();
      }
     }
    }

    代码运行完毕之后,就可以生成了相应的4个jpg文件。

    对于以上的代码有下面几点需要补充:

    1. 我测试过使用BMP文件的情况,但是没有通过代码的测试,可能是在把BMP图像转为256色图像时出现了错误。所以在使用之前还需要用其他工具把BMP文件转为JPG格式。

    2. 在合成GIF文件的AnimatedGifEncoder类中有下面几个值得关注的函数

    2.1:setFrameRate(float)每秒种播放的帧数
    2.2:setQuality(int quality) 设置在GIF规范中转换为256位图像时的质量参数这个值设置的越小,质量越高,但速度越慢,反之依然,不过超过20以后,速度不会有明显的提升,默认为10。
    2.3:setSize(int x,int y) 设置GIF图像的大小,默认值为第一个加入的帧的图像的大小。

    三、对PSD图像文件的分析

     我们先用PS对模板图片加上一串字符,保存为TestPsd.psd,注意保存时不要合并图层。然后从http://www.fmsware.com/stuff/PSDReader.java 下载一个分析PSD代码的JAVA文件,并加入到我们的项目中。并运行下面的代码

     

    import java.awt.Point;
    import java.awt.image.BufferedImage;
    import java.io.FileOutputStream;
    import open.PSDReader;
    import com.sun.image.codec.jpeg.*;
    /**
     * @author Ander.Hu
     * 2005-10-13
     */
    public class TestPsd {
      public static void main(String[] args) {
       try {
       PSDReader r = new PSDReader();
           r.read("c:\\testPsd.psd");
            int n = r.getFrameCount();
            for (int i = 0; i < n; i++) {
               BufferedImage image = r.getLayer(i);
               Point offset = r.getLayerOffset(i);
               //生成JPG文件
         String outFilePath = "c:\\testPsd_"+i+".jpg";
         FileOutputStream out = new FileOutputStream(outFilePath);
         JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
         encoder.encode(image);
            }
      } catch(Exception e) {
       e.printStackTrace();
      }
     }
    }

    此时我们便可以发现3个解析后的JPG文件,因为包括背景图层在内有3个图层,故有3个JPG文件。 目前PSDReader 类只支持没有压缩过的或者使用RLE压缩的RGB文件,并且也不支持PS3.0以上的特殊功能。

    总结

    在JAVA对图像的处理过程中,通常基本步骤是通过读取图像信息到图像缓冲中->同时取得图形上下文->对图像进行相应的处理->生成图像文件。

    展开全文
  • 版权声明:转载时请务必保留以下作者信息和链接作者:陈维(chenweionline@hotmail.com)作者的网站:http://www.chenwei.mobi图像编码输出的方法,提供编码进度监听,向图像文件中添加缩略图和设置编码...Java SE 6
  • Java图像处理技巧四则

    2004-07-30 23:04:00
    下面代码中用到的sourceImage是一个已经存在的Image对象 图像剪切 对于一个已经存在的Image对象,要得到它的一个局部图像,可以使用下面的步骤: //import java.awt.*; //import java.awt.image.*; Image ...
  • OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授...
  • 公司一个图像识别的项目,要我用java做BMP图片的底层识别处理,我了基本上一个月但是程序始终不稳定,最后没办法让别人转用C语言来,我真的很不明白,java适合做图像处理么,现在这些处理图片得到的数据...
  • 写了很多篇关于图像处理的文章,没有一篇介绍Java 2D的图像处理API,文章讨论和提及的 API都是基于JDK6的,首先来看Java中如何组织一个图像对象BufferedImage的,如图: 一个BufferedImage的像素数据储存在Raster...
  • 数字图像处理是计算机视觉,视频语义分析的基础知识。要对数字图像进行处理,比如调整灰度级,图像增强,图像模糊等等操作,首先要对图像进行读写操作。用Java对数字图像进行读写比较简单,ImageIO.read读,...
  • Java图像处理类库 Java Image Filters Java Image Filters 是由 Jhlabs 开发的一组用来处理 Java 图像的类库,提供各种常用的图像处理效果,例如反转色、扭曲、水波纹、凹凸、黑白效果等等数十种效果,如...
  • 图像取反相当于取底片,对于每个像素点的RGB来讲,就是: R′=255−RR'=255-RG′=255−GG'=255-GB′=...那么处理后的图像就是这样的: 代码实现如下:import java.io.File; import java.io.IOException; import java
  • 水平镜像变换,也就是把图像的像素点按照垂直中线调换。代码实现也很简单:import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException;public class ...
  • Java图像处理类库Java Image Filters Java Image Filters 是由 Jhlabs 开发的一组用来处理 Java 图像的类库,提供各种常用的图像处理效果,例如反转色、扭曲、水波纹、凹凸、黑白效果等等数十种效果,如...
  • Java图像处理框架比较少,目前比较流行的有Jmagick以及Marvin,但Jmagick只能处理图像(上篇Java清除图片中的恶意信息(利用Jmagick)中对Jmagick已过简略介绍),而Marvin不但可以处理图像,而且可以集成各种插件...
  • 首先不多说上代码 public int[][] getImagePixel(String image) { //读取图片文件 File file = new File(image); BufferedImage bi = null; try {
  • 关于《Java数字图像处理-编程技巧与应用实践》一书 源代码
  • JAVA处理图像例如图片等时会用到一些接口,类或者方法。如果对于从未接触到的人来说可能会很陌生。所以在这里整理一下,以备需要。 1.抽象类 Image 是表示图形图像的所有类的超类。必须以特定于平台的方式获取图像。...
1 2 3 4 5 ... 20
收藏数 113,071
精华内容 45,228