图像处理之六边形网格分割效果

一:原理

根据输入参数blockSize的大小,将图像分块,决定每块的中心通过该像素块内所有

像素之和的均值与该块内部每个像素比较,RGB值之间几何距离最小为新的中心,迭

代更新运算,直到达到输入参数声明的最大循环次数为止,然后输出结果图像即可。

二:程序实现

类MyCluster,存储每个像素块中心的信息,计算中心位置。

类SuperPixelsFilter, 滤镜实现,完成六边形网格分割的主要功能,其中距离计算,基

于欧几里德距离公式。

三:效果

原图:


效果:


四:完全源代码

package com.gloomyfish.image.cluster.effect;

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.gloomyfish.filter.study.AbstractBufferedImageOp;

public class SuperPixelsFilter extends AbstractBufferedImageOp {

	private double[] distances;
	private int[] labels; 
	private MyCluster[] clusters;
	private int maxClusteringLoops = 50;
	
	private double blockSize;
	private double modifier;
	
	public SuperPixelsFilter()
	{
		blockSize = 16;
		modifier = 130;
	}
	
	public double getBlockSize() {
		return blockSize;
	}

	public void setBlockSize(double blockSize) {
		this.blockSize = blockSize;
	}

	public double getModifier() {
		return modifier;
	}

	public void setModifier(double modifier) {
		this.modifier = modifier;
	}
    
	@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];
        getRGB( src, 0, 0, width, height, inPixels );
        int index = 0;
        // initialization
        distances = new double[width*height];
        labels = new int[width*height];
        Arrays.fill(distances, Integer.MAX_VALUE);
        Arrays.fill(labels, -1);
        initClusters(width, height, inPixels, blockSize, modifier);
        // loop to get all block/cells, image segmentation
        int loops = 0;
        boolean pixelChangedCluster = true;
        while (pixelChangedCluster&&loops<maxClusteringLoops) { 
            pixelChangedCluster = false;
            loops++;
            // for each cluster center C  
            for (int i=0;i<clusters.length;i++) { 
            	MyCluster c = clusters[i];
                // for each pixel i in 2S region around 
                // cluster center 
                int xs = Math.max((int)(c.avg_x-blockSize),0);
                int ys = Math.max((int)(c.avg_y-blockSize),0);
                int xe = Math.min((int)(c.avg_x+blockSize),width);
                int ye = Math.min((int)(c.avg_y+blockSize),height);
                for (int y=ys;y<ye;y++) { 
                    for (int x=xs;x<xe;x++) { 
                        int pos = x+width*y;
                        int tr = (inPixels[pos] >> 16) & 0xff;
                        int tg = (inPixels[pos] >> 8) & 0xff;
                        int tb = inPixels[pos] & 0xff;
                        double D = c.distance(x, y, tr, 
                                                    tg, 
                                                    tb, 
                                                    blockSize, modifier, width, height);
                        if ((D<distances[pos])&&(labels[pos]!=c.id)) { 
                            distances[pos]         = D;
                            labels[pos]            = c.id;
                            pixelChangedCluster = true;
                        } 
                    } // end for x 
                } // end for y 
            } // end for clusters 
            // reset clusters 
            for (index=0;index<clusters.length;index++) { 
                clusters[index].reset();
            } 
            // add every pixel to cluster based on label 
            for (int y=0;y<height;y++) { 
                for (int x=0;x<width;x++) { 
                    int pos = x+y*width;
                    int tr = (inPixels[pos] >> 16) & 0xff;
                    int tg = (inPixels[pos] >> 8) & 0xff;
                    int tb = inPixels[pos] & 0xff;
                    clusters[labels[pos]].addPixel(x, y, 
                            tr, tg, tb);
                } 
            } 
            
            // calculate centers 
            for (index=0;index<clusters.length;index++) { 
                clusters[index].calculateCenter();
            } 
        } 
        
        // Create output image with pixel edges  
        for (int y=1;y<height-1;y++) { 
            for (int x=1;x<width-1;x++) { 
                int id1 = labels[x+y*width];
                int id2 = labels[(x+1)+y*width];
                int id3 = labels[x+(y+1)*width];
                if (id1!=id2||id1!=id3) { 
                	int pos = x+y*width;
                	inPixels[pos] = (255 << 24) | (0 << 16) | (0 << 8) | 0; 
                } 
            } 
        } 

        setRGB( dest, 0, 0, width, height, inPixels );
        return dest;
	}
	
	public void initClusters(int width, int height, int[] input, 
            double S, double m) { 
		List<MyCluster> temp = new ArrayList<MyCluster>();
		boolean even = false;
		double xstart = 0;
		int id = 0;
		for (double y = S / 2; y < height; y += S) {
			// 创建六边形网格
			if (even) {
				xstart = S / 2.0;
				even = false;
			} else {
				xstart = S;
				even = true;
			}
			for (double x = xstart; x < width; x += S) {
				int index = (int) (x + y * width);
                int tr = (input[index] >> 16) & 0xff;
                int tg = (input[index] >> 8) & 0xff;
                int tb = input[index] & 0xff;
				MyCluster c = new MyCluster(id, tr, tg, tb,
						(int) x, (int) y, S, m);
				temp.add(c);
				id++;
			}
		}
		clusters = new MyCluster[temp.size()];
		for (int i = 0; i < temp.size(); i++) {
			clusters[i] = temp.get(i);
		} 
} 

}

MyCluster类代码:

package com.gloomyfish.image.cluster.effect;

public class MyCluster {

	int id;
	double inv = 0; // inv variable for optimization
	double pixelCount; // pixels in this cluster
	double avg_red; // average red value
	double avg_green; // average green value
	double avg_blue; // average blue value
	double sum_red; // sum red values
	double sum_green; // sum green values
	double sum_blue; // sum blue values
	double sum_x; // sum x
	double sum_y; // sum y
	double avg_x; // average x
	double avg_y; // average y

	public MyCluster(int id, int in_red, int in_green, int in_blue, int x,
			int y, double S, double m) {
		// inverse for distance calculation
		this.inv = 1.0 / ((S / m) * (S / m));
		this.id = id;
		addPixel(x, y, in_red, in_green, in_blue);
		// calculate center with initial one pixel
		calculateCenter();
	}

	public void reset() {
		avg_red = 0;
		avg_green = 0;
		avg_blue = 0;
		sum_red = 0;
		sum_green = 0;
		sum_blue = 0;
		pixelCount = 0;
		avg_x = 0;
		avg_y = 0;
		sum_x = 0;
		sum_y = 0;
	}

	/*
	 * Add pixel color values to sum of previously added color values.
	 */
	void addPixel(int x, int y, int in_red, int in_green, int in_blue) {
		sum_x += x;
		sum_y += y;
		sum_red += in_red;
		sum_green += in_green;
		sum_blue += in_blue;
		pixelCount++;
	}

	public void calculateCenter() {
		// Optimization: using "inverse"
		// to change divide to multiply
		double inv = 1 / pixelCount;
		avg_red = sum_red * inv;
		avg_green = sum_green * inv;
		avg_blue = sum_blue * inv;
		avg_x = sum_x * inv;
		avg_y = sum_y * inv;
	}

	double distance(int x, int y, int red, int green, int blue, double S,
			double m, int w, int h) {
		// power of color difference between
		// given pixel and cluster center
		double dx_color = (avg_red - red) * (avg_red - red)
				+ (avg_green - green) * (avg_green - green) + (avg_blue - blue)
				* (avg_blue - blue);
		// power of spatial difference between
		// given pixel and cluster center
		double dx_spatial = (avg_x - x) * (avg_x - x) + (avg_y - y)
				* (avg_y - y);
		// Calculate approximate distance D
		// double D = dx_color+dx_spatial*inv;
		// Calculate squares to get more accurate results
		double D = Math.sqrt(dx_color) + Math.sqrt(dx_spatial * inv);
		return D;
	}
}
五:参考这里

该滤镜是SuperPixel算法的简单应用,多数时候,我们可能更熟悉

K-Means等图像分割算法,其实SuperPixel是图像分割算法之一。

告示一下:

博客从这个月恢复更新,请大家继续关注,之前消失了一年,完

了本人的第一本关于图像处理的书初稿写作,谢谢大家厚爱

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值