基于一维级联快速膨胀与腐蚀算法
一:基本原理
膨胀与腐蚀是图像形态学两个基本操作之一,传统的代码实现都是基于二维窗口卷积模式,对于正常的3x3窗口要八次与运算,而基于一维级联方式先X方向后Y方向只需要4次与运算即可。对于结构元素比较大的矩形来说,我们还可以通过连续的3x3的级联腐蚀或者膨胀来替代,假设对于11x11窗口大小腐蚀来说,正常的计算需要120次的与操作,而通过一维级联腐蚀只需要在X方向10次与操作,Y方向10次与操作,总计2x10=20次与操作即可实现。这样就极大的提高了二值图像腐蚀与膨胀的计算效率。图示如下:
二:代码实现
快速版本
package com.gloomyfish.ii.demo; public class FastErode extends AbstractByteProcessor { private byte[] data; private int radius; // must be odd public FastErode() { this.radius = 25; } public void setRadius(int radius) { this.radius = radius; if(radius % 2 == 0) { throw new RuntimeException("invalid parameters"); } } public void setData(byte[] data) { this.data = data; } @Override public void process(int width, int height) { int size = width*height; byte[] output = new byte[size]; System.arraycopy(data, 0, output, 0, size); // X Direction int xr = radius/2; byte c = (byte)0; int offset = 0; for(int row=0; row<height; row++) { for(int col=0; col<width; col++) { c = data[row*width+col]; if((c&0xff) == 0)continue; for(int x=-xr; x<=xr; x++) { if(x==0)continue; offset = x + col; if(offset < 0) { offset = 0; } if(offset >= width) { offset = width - 1; } c &=data[row*width+offset]; } if(c == 0){ output[row*width+col] = (byte)0; } } } System.arraycopy(output, 0, data, 0, size); // Y Direction int yr = radius/2; c = 0; offset = 0; for(int col=0; col<width; col++) { for(int row=0; row<height; row++) { c = data[row*width+col]; if((c&0xff) == 0)continue; for(int y=-yr; y<=yr; y++) { if(y == 0)continue; offset = y + row; if(offset < 0) { offset = 0; } if(offset >= height) { offset = height - 1; } c &=data[offset*width+col]; } if(c == 0){ output[row*width+col] = (byte)0; } } } System.arraycopy(output, 0, data, 0, size); } }
传统版本
@Override public void process(int width, int height) { int size = width*height; byte[] output = new byte[size]; IntIntegralImage grayii = new IntIntegralImage(); grayii.setImage(data); grayii.process(width, height); int yr = radius/2; int xr = radius/2; System.arraycopy(data, 0, output, 0, size); byte c = 0; int nx=0, ny=0; for(int row=0; row<height; row++) { for(int col=0; col<width; col++) { c = data[row*width+col]; if(c == 0)continue; for(int y=-yr; y<=yr; y++) { ny = y + row; if(ny < 0 || ny >= height){ ny = 0; } for(int x=-xr; x<=xr; x++) { nx = x+col; if(nx < 0 || nx >= width) { nx = 0; } c &= data[ny*width+nx]&0xff; } } if(c == 0) { output[row*width+col] = (byte)0; } } } System.arraycopy(output, 0, data, 0, size); }
三:耗时比较
对一张大小为381x244大小二值图像一维快速与传统腐蚀操作耗时比较结果如下(Win64,CPU i5, JDK8 64位):
无论是卷积还是高斯模糊,还是形态学操作,理论上都是卷积计算,但是在实际编码过程中基于对计算耗时考虑都是进行了各种有效变换从而提高计算速度与减少执行时间,所以对于任何看似简单的图像操作,所以理论一定要联系实践!不然长期如此的结果就是眼高手低! 愿与各位共勉!祝各位五一劳动节快乐!