图像处理开操作和比操作

2018-07-27 20:05:06 weixin_41929524 阅读数 9858

1. 回顾

简单的图像处理——1. 图像的形态学操作:膨胀与腐蚀 中,我们介绍了图像基本的形态学操作——膨胀腐蚀,同时也利用了Python进行了实现。在这里我们将接着上次的内容,接着描述其它的一些图像形态学操作方法,以及相应的Python实现。

下面我们同样以这只小鸟为例,来看看图像其它的形态学算法。
这里写图片描述


2. 图像的开运算

开运算的具体实现:通过先进行腐蚀操作,再进行膨胀操作得到。我们在移除小的对象时候很有用(假设物品是亮色,前景色是黑色),被用来去除噪声

我们先以二值图为例,其如下所示。左侧是原始图像,右侧是应用开运算之后的图像。我们可以看到左侧图像小的黑色空间被填充消失,所以开运算可以进行白色的孔洞填补。因为可以想象,我们先将黑色区域变大,然后填充部分白色区域,白色小区域这时就会被抹去,然后膨胀再将黑色区域变回,但是抹去的部分会消失,则会达到下面的效果。


而对于彩色图而言,则是将一些小的偏白色孔洞或者区域用周围的颜色进行填补,整体的图像也会模糊化,宛如一幅水彩画。

下面分别是卷积核为10与50像素开运算处理后的效果,可以发现眼部与羽毛中的白色部分均被填充,地面上的气泡也接近模糊消失了。

这里写图片描述
这里写图片描述


3. 图像的闭运算

闭运算是开运算的一个相反的操作,具体是先进行膨胀然后进行腐蚀操作。通常是被用来填充前景物体中的小洞,或者抹去前景物体上的小黑点。因为可以想象,其就是先将白色部分变大,把小的黑色部分挤掉,然后再将一些大的黑色的部分还原回来,整体得到的效果就是:抹去前景物体上的小黑点了。

二值图进行闭运算则会是如下的效果,左侧是原图,右侧是进行闭运算之后的图。


下面分别是卷积核为10与50像素闭运算处理后的效果,可以发现左眼的黑色部分变小了,以及双腿在大卷积核进行处理时,直接会消失,这是由于因为腿比较细。然后图像整体会变白一些。

这里写图片描述
这里写图片描述

而开闭运算直接的抹除小区域的体现如下:
这里写图片描述

后面我们会继续介绍图像的形态学梯度以及顶帽变换与底帽变换。

2018-04-21 15:45:00 learning_tortosie 阅读数 14198

实验目的

1.理解并掌握形态学图像处理中的开操作和闭操作
2.熟悉并掌握MATLAB软件的使用

实验环境

操作系统:Windows 10
软件:MATLAB R2014a

相关知识

1.定义

开操作:使图像的轮廓变得光滑,断开较窄的狭颈和消除细的突出物。
使结构元B对集合A进行开操作,定义为:

AB=(AB)B

含义:先用B对A进行腐蚀,然后用B对结果进行膨胀。
闭操作:同样使图像的轮廓变得光滑,但与开操作相反,它能弥合狭窄的间断和细长的沟壑,消除小的孔洞,并填补轮廓线中的裂痕。
使用结构元B对集合A进行闭操作,定义为:

AB=(AB)B

含义:先用B对A进行膨胀,然后用B对结果进行腐蚀。

2.几何解释

(1)开操作的何解释
A○B的边界由B中的点建立
当B在A的边界内侧滚动时,B所能到达的A的边界的最远点。


(2)闭操作的几何解释
A•B的边界由B中的点建立
B在A的边界外侧滚动
满足〖(B)〗_z⋂A≠”Ø” 的所有点的集合

3.相关函数说明

(1)strel
功能:形态学结构元素。
用法:
SE = STREL('arbitrary',NHOOD,HEIGHT) 创建一个指定领域的非平面结构化元素。HEIGHT是一个矩阵,大小和NHOOD相同,他指定了NHOOD中任何非零元素的高度值。
SE = STREL('ball',R,H,N) 创建一个空间椭球状的结构元素,其X-Y平面半径为R,高度为H。R必须为非负整数,H是一个实数。N必须为一个非负偶数。当N>0时此球形结构元素由一系列空间线段结构元素来近似。
SE = STREL('diamond',R) 创建一个指定大小R平面钻石形状的结构化元素。R是从结构化元素原点到其点的距离,必须为非负整数。
SE = STREL('disk',R,N) 创建一个指定半径R的平面圆盘形的结构元素。这里R必须是非负整数. N须是0, 4, 6, 8.当N大于0时,圆盘形结构元素由一组N(或N+2)个周期线结构元素来近似。当N等于0时,不使用近似,即结构元素的所有像素是由到中心像素距离小于等于R的像素组成。N可以被忽略,此时缺省值是4。注: 形态学操作在N>0情况下要快于N=0的情形。
如:se1 = strel('square',11) % 11乘以11的正方形
(2)imeroad
腐蚀图像
用法:IM2 = imerode(IM,SE)
腐蚀灰度、二进制或压缩二进制图像 IM ,返回腐蚀图像 IM2 。参数 SE 是函数 strel 返回的一个结构元素体或是结构元素体阵列。
(3)imdilate
膨胀图像
用法:IM2 = imdilate(IM, SE)
膨胀灰度图像、二值图像、或者打包的二值图像IM,返回膨胀图像M2。变量SE是一个结构元素或者一个结构元素的数组,其是通过strel函数返回的。

实验内容

先开操作再闭操作,组成形态学滤波器。
a 图是受噪声污染的指纹的二值图像,噪声为黑色背景上的亮元素和亮指纹部分的暗元素
b图是使用的结构元
c图是使用结构元素对图a腐蚀的结果:背景噪声消除了,指纹中的噪声尺寸增加
d图是使用结构元素对图c膨胀的结果:包含于指纹中的噪声分量的尺寸被减小或被完全消除,带来的问题是:在指纹纹路间产生了新的间断
e图是对图d膨胀的结果,图d的大部分间断被恢复,但指纹的线路变粗了
f图是对图e腐蚀的结果,即对图d中开操作的闭操作。最后结果消除了噪声斑点
缺点:指纹线路还是有断点,可以通过加入限制性条件解决。

实验结果

总结

通过本次实验,我基本掌握了开操作和闭操作的理论知识和matlab实现方法,同时体会到了数字图像处理的强大功能,在我们生活的方方面面都有着广泛的应用。学习理论知识第一步,还需要用编程软件去实现,再进一步是应用到现实生活中,再进阶一步就是提出新的理论。
总之,这次实践让我收获颇多,最后衷心感谢老师的细致讲解,她严谨的学风和认真的态度给我打开了数字图像处理领域的大门。

附录

matlab程序

A=imread('Fig0911(a)(noisy_fingerprint).tif'); %注意图片的路径要设置正确
subplot(2,3,1);
imshow(A)
title('噪声图像')
se=strel('square',3);
A2=imerode(A,se);
subplot(2,3,2);
imshow(A2)
title('腐蚀后的图像')
A3=imopen(A,se);
subplot(2,3,3);
imshow(A3)
title('A的开操作')
A4=imdilate(A3,se);
subplot(2,3,4);
imshow(A4)
title('开操作的膨胀')
A5=imclose(A3,se);
subplot(2,3,5);
imshow(A5)
title('开操作的闭操作')
2015-10-12 19:47:54 zxc024000 阅读数 85752

写在前头:说到数字图像处理,不得不提起MATLAB。这是一款非常方便的仿真软件,绝大多数的图像处理可以用MATLAB完成。
  有人问,处理图片,用PS岂不是更好。两者各有优点,如果需要将10000幅图片转换成灰度图像并保存呢?MATLAB只需要一段很短的程序运行几秒就可以完成这个工作。
本文基于MatlabR2012a,将由浅入深写下去。

MATLAB中图像的基本操作

1、读取、显示图片

MATLAB中提供了immread()与imshow()函数读取和显示图片。其中读取函数imread()原型:

imread:
A = imread(filename, fmt)

A是结构体名,用来存储读入的图像数据。filename是读取的文件名,文件名要用”括起来。fmt是读取文件的类型如:jpg、png等等,这个参数可以不输入,由MATLAB自动判断。
显示函数imshow()原型:

    imshow:
    imshow(I)

I为读取后保存在MATLAB中的结构体名。
程序实例:  

A=imread('1.jpg');%读取名为1.jpg的图片
     imshow(A)%显示图片

这里写图片描述

2、将灰度图片变成负片

  对图像进行操作,实际上是将图像看成许多个像素点,对每个像素点进行操作。在计算机系统中,灰度图片被看成是许多个由值在[0~255]之间的像素点组成的图像,255表示白色,0表示黑色,黑白之间存在256个灰度级。
这里写图片描述
  负片是指将原灰度图白色的地方变成黑色,黑色的地方变成白色。也就是将0变成255,255变成0。MALTAB的imadjust()函数提供了该功能。其函数原型:  

imadjust:
  J = imadjust(I,[low_in; high_in],[low_out; high_out])

  其中,I为原灰度图像,low_in,high_in为输入图像的低和高灰度级,设置为[0,1]表示从0~255的归一化,low_out,high_out为输出图像的低高灰度级。
  若是想将图片转换为负片,那么将[low_in; high_in]设置为[0,1],将[low_out; high_out]设置为[1,0]。即原来输入为0的地方变成1输出,输入为1的地方变成0输出。
  实例: 

 A=imread('1.jpg');
imshow(A)%显示原图
A1=imadjust(A,[0,1],[1,0]);%将灰度级对调
figure,imshow(A1)%显示负片

  这里写图片描述
  

3、彩色图片转换成灰度图片

  我们在计算机中看到的大多数彩色图片是基于RBG三通道的图片,红绿蓝三种颜色,每一种取值均为[0~255]。通过255*255*255,可以构成庞大的颜色群。而灰度图像只有256个灰度级。通过以下公式可以将RGB转换成灰度
  GRAY=0.2989 R + 0.5870 * G + 0.1140 * B*
  MATLAB中提供的函数rgb2gray为我们提供了将彩色图片转换成灰度图片的功能。函数原型: 

I = rgb2gray(RGB)

实例:

 A=imread('001.png');%原彩色图片
imshow(A)
A_gray=rgb2gray(A);%转换成灰度图片
figure,imshow(A_gray)

这里写图片描述
  

2012-07-01 19:11:14 jia20003 阅读数 11379

开操作概述:

图像处理中的开闭运算是两个非常重要的数学形态学操作,它们同时都继承自基本的腐蚀与

膨胀操作,这些操作一般都会应用在二值图像的分析与处理上。开操作有点像腐蚀操作,主

要是会remove前景像素边缘,但是不会像腐蚀操作remove那么多边缘像素。开操作主要

是用来保留某种结构操作,remove其他不符合结构元素的前景区域像素。

 

开操作原理:

一个开操作是一个腐蚀操作再接着一个膨胀操作使用相同的结构元素。开操作需要两个输入

数据一个是要开操作的像素数据,一个是开操作的结构元素,根据开操作的要求不同,结构

元素可以是圆形,正方形,矩形等。关于腐蚀与膨胀操作见博客文章:

二值图像膨胀操作 - http://blog.csdn.net/jia20003/article/details/7574214

二值图像腐蚀操作 - http://blog.csdn.net/jia20003/article/details/7582666


程序效果:- 原图


通过开操作,我们可以除去干扰线(竖线与斜线),通过过开操作也可以只保留竖线

唯一的秘诀就在于输入开操作的结构元素的形状决定,效果如下图:


开操作源代码:

package com.gloomyfish.morphology;

import java.awt.Color;
import java.awt.image.BufferedImage;

public class OpeningFilter extends BinaryFilter {
	private int[][] structure_element;
	private Color bgColor;
	private Color fgColor;
	
	public OpeningFilter() {
		structure_element = new int[3][10];
		// structure_element = new int[20][1];
		bgColor = Color.BLACK;
		fgColor = Color.WHITE;
	}
	
	public void setBackGroundColor(Color c) {
		this.bgColor = c;
	}
	
	public void setForeGroundColor(Color c) {
		this.fgColor = c;
	}
	
	public void setElement(int[][] element) {
		this.structure_element = element;
	}

	@Override
	public BufferedImage filter(BufferedImage src, BufferedImage dest) {
		int width = src.getWidth();
        int height = src.getHeight();

        if ( dest == null )
        	dest = createCompatibleDestImage( src, null );

        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        src = super.filter(src, null);
        getRGB( src, 0, 0, width, height, inPixels );
        int index = 0;
        int subrow = structure_element.length/2;
        int subcol = structure_element[0].length/2;
        int rowoffset = 0, coloffset = 0;
        int index2 = 0;
        for(int row=0; row<height; row++) {
        	int ta = 0, tr = 0, tg = 0, tb = 0;
        	for(int col=0; col<width; col++) {
        		index = row * width + col;
        		ta = (inPixels[index] >> 24) & 0xff;
                tr = (inPixels[index] >> 16) & 0xff;
                tg = (inPixels[index] >> 8) & 0xff;
                tb = inPixels[index] & 0xff;
                int ta2 = 0, tr2 = 0, tg2= 0, tb2 = 0;
                boolean isfound = false;
                for(int i=-subrow; i<=subrow; i++) {
                	for(int j=-subcol; j<=subcol; j++) {
                		rowoffset = row + i;
                		coloffset = col + j;
                		if(rowoffset >=0 && rowoffset < height) {
                			rowoffset = row + i;
                		} else {
                			rowoffset = 0;
                		}
                		
                		if(coloffset >= 0 && coloffset < width) {
                			coloffset = col + j;
                		} else {
                			coloffset = 0;
                		}
                		index2 = rowoffset * width + coloffset;
                		ta2 = (inPixels[index2] >> 24) & 0xff;
                        tr2 = (inPixels[index2] >> 16) & 0xff;
                        tg2 = (inPixels[index2] >> 8) & 0xff;
                        tb2 = inPixels[index2] & 0xff;
                        if(tr2 == bgColor.getRed() && tg2 == bgColor.getGreen()) {
                        	isfound = true;
                        	break;
                        }
                	}
                	if(isfound) break;
                }
                rowoffset = 0;
                coloffset = 0;
                if(isfound) {
                	tr = bgColor.getRed();
                	tg = bgColor.getGreen();
                	tb = bgColor.getBlue();
                	outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
                } else {
                	outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
                }
                
        	}
        }
        
        // copy the Erosion result pixels to input pixels data 
        // and ready to Dilation operation
        System.arraycopy(outPixels, 0, inPixels, 0, width*height);
        
        // start to dilate the pixels data...
        for(int row=0; row<height; row++) {
        	int ta = 0, tr = 0, tg = 0, tb = 0;
        	for(int col=0; col<width; col++) {
        		index = row * width + col;
        		ta = (inPixels[index] >> 24) & 0xff;
                tr = (inPixels[index] >> 16) & 0xff;
                tg = (inPixels[index] >> 8) & 0xff;
                tb = inPixels[index] & 0xff;
                int ta2 = 0, tr2 = 0, tg2= 0, tb2 = 0;
                boolean isfound = false;
                for(int i=-subrow; i<=subrow; i++) {
                	for(int j=-subcol; j<=subcol; j++) {
                		rowoffset = row + i;
                		coloffset = col + j;
                		if(rowoffset >=0 && rowoffset < height) {
                			rowoffset = row + i;
                		} else {
                			rowoffset = 0;
                		}
                		
                		if(coloffset >= 0 && coloffset < width) {
                			coloffset = col + j;
                		} else {
                			coloffset = 0;
                		}
                		index2 = rowoffset * width + coloffset;
                		ta2 = (inPixels[index2] >> 24) & 0xff;
                        tr2 = (inPixels[index2] >> 16) & 0xff;
                        tg2 = (inPixels[index2] >> 8) & 0xff;
                        tb2 = inPixels[index2] & 0xff;
                        if(tr2 == fgColor.getRed() && tg2 == fgColor.getGreen()) {
                        	isfound = true;
                        	break;
                        }
                	}
                	if(isfound) break;
                }
                rowoffset = 0;
                coloffset = 0;
                if(isfound) {
                	tr = fgColor.getRed();
                	tg = fgColor.getGreen();
                	tb = fgColor.getBlue();
                	outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
                } else {
                	outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
                }
                
        	}
        }
        
        setRGB( dest, 0, 0, width, height, outPixels );
        return dest;
	}
}
转载请注明出处


2018-07-01 15:11:10 chen134225 阅读数 6001
在图像处理技术中,有一些的操作会对图像的形态发生改变,这些操作一般称之为形态学操作(phology)。数学形态学是基于集合论的图像处理方法,最早出现在生物学的形态与结构中,图像处理中的形态学操作用于图像与处理操作(去噪,形状简化)图像增强(骨架提取,细化,凸包及物体标记)、物体背景分割及物体形态量化等场景中,形态学操作的对象是二值化图像。
有名的形态学操作中包括腐蚀,膨胀,开操作,闭操作等。其中腐蚀,膨胀是许多形态学操作的基础。
  
腐蚀操作:
  顾名思义,是将物体的边缘加以腐蚀。具体的操作方法是拿一个宽m,高n的矩形作为模板,对图像中的每一个像素x做如下处理:像素x至于模板的中心,根据模版的大小,遍历所有被模板覆盖的其他像素,修改像素x的值为所有像素中最小的值。这样操作的结果是会将图像外围的突出点加以腐蚀。如下图的操作过程:

                                                                             图5 腐蚀操作原理

上图演示的过程是背景为黑色,物体为白色的情况。腐蚀将白色物体的表面加以“腐蚀”。在opencv的官方教程中,是以如下的图示说明腐蚀过程的,与我上面图的区别在于:背景是白色,而物体为黑色(这个不太符合一般的情况,所以我没有拿这张图作为通用的例子)。读者只需要了解背景为不同颜色时腐蚀也是不同的效果就可以了。


                                                        图6 腐蚀操作原理2

简单来说在背景为白(1),情景为黑的图像(0)中,核与其覆盖的图像部分做“与”操作,如果全为1,则该像素点为1,否则为0;也就是0容易得到,图像更多的地方变黑了,白色部分被腐蚀了。


膨胀操作:

  膨胀操作与腐蚀操作相反,是将图像的轮廓加以膨胀。操作方法与腐蚀操作类似,也是拿一个矩形模板,对图像的每个像素做遍历处理。不同之处在于修改像素的值不是所有像素中最小的值,而是最大的值。这样操作的结果会将图像外围的突出点连接并向外延伸。如下图的操作过程:


                                                                           图7 膨胀操作原理

下面是在opencv的官方教程中,膨胀过程的图示:


                                                       图8 膨胀操作原理2

简单来说在背景为白(1),前景为黑(0)的图像中,核与其覆盖的图像部分做“与”操作,如果全为0,则该像素点为0,否则为1;也就是1容易得到,图像更多的地方变白了,白色部分膨胀了。


开操作:

作用:放大裂缝和低密度区域,消除小物体,在平滑较大物体的边界时,不改变其面积。消除物体表面的突起。

开操作就是对图像先腐蚀,再膨胀。其中腐蚀与膨胀使用的模板是一样大小的。为了说明开操作的效果,请看下图的操作过程:


                                                                          图9 开操作原理

由于开操作是先腐蚀,再膨胀。因此可以结合图5和图7得出图9,其中图5的输出是图7的输入,所以开操作的结果也就是图7的结果。


闭操作:

作用:排除小型黑洞,突触了比原图轮廓区域更暗的区域,将两个区域连接起来,形成连通域。

  闭操作就是对图像先膨胀,再腐蚀。闭操作的结果一般是可以将许多靠近的图块相连称为一个无突起的连通域。在我们的图像定位中,使用了闭操作去连接所有的字符小图块,然后形成一个车牌的大致轮廓。闭操作的过程我会讲的细致一点。为了说明字符图块连接的过程。在这里选取的原图跟上面三个操作的原图不大一样,是一个由两个分开的图块组成的图。原图首先经过膨胀操作,将两个分开的图块结合起来(注意我用偏白的灰色图块表示由于膨胀操作而产生的新的白色)。接着通过腐蚀操作,将连通域的边缘和突起进行削平(注意我用偏黑的灰色图块表示由于腐蚀被侵蚀成黑色图块)。最后得到的是一个无突起的连通域(纯白的部分)。


                                                                         图10 闭操作原理

4.代码

  在opencv中,调用闭操作的方法是首先建立矩形模板,矩形的大小是可以设置的,由于矩形是用来覆盖以中心像素的所有其他像素,因此矩形的宽和高最好是奇数。

  通过以下代码设置矩形的宽和高。

Mat element = getStructuringElement(MORPH_RECT, Size(m_MorphSizeWidth, m_MorphSizeHeight) );
在这里,我们使用了类成员变量,这两个类成员变量在构造函数中被赋予了初始值。宽是17,高是3.
  设置完矩形的宽和高以后,就可以调用形态学操作了。opencv中所有形态学操作有一个统一的函数,通过参数来区分不同的具体操作。例如MOP_CLOSE代表闭操作,MOP_OPEN代表开操作。
morphologyEx(img_threshold, img_threshold, MORPH_CLOSE, element);