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

一:原理

根据输入参数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是图像分割算法之一。

告示一下:

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

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

时间: 2024-10-31 08:22:02

图像处理之六边形网格分割效果的相关文章

Atitit 图像处理之仿油画效果&#160;Oilpaint油画滤镜 水彩画 漫画滤镜&#160;v2

Atitit 图像处理之仿油画效果 Oilpaint油画滤镜 水彩画 漫画滤镜 v2 1.1. 具体源码参考1 2. ,油画 水彩画具有几个比较明显的特点如下:1 2.1. 明暗层次(灰度)较少  也就5级别够用了1 2.2. 颜色泛用   使用的颜色比较单一,一般不会超过7种颜色,不像真实照片那样,具有丰富的颜色种类:2 3. 水彩画滤镜算法如下:2 3.1. 这个其实就是灰度层次降低维度的过程.3 3.2. 模板半径Radius用来调节水彩画的水彩程度.即是颜色的降低维度的过程3 3.3.

图像处理之图像梯度效果(转载)

转载自:http://blog.csdn.net/jia20003/article/details/7664777 图像处理之图像梯度效果 基本思想: 利用X方向与Y方向分别实现一阶微分,求取振幅,实现图像梯度效果.关于如何计算图像 一阶微分参见这里:http://blog.csdn.net/jia20003/article/details/7562092 使用的两种微分算子分别为Prewitt与Sobel,其中Soble在X, Y两个方向算子分别为: Prewitt在X, Y方向上梯度算子分别

android图像处理,实现变暗效果

图像处理主要是图像的颜色矩阵和坐标矩阵进行处理,要实现变暗效果只需要对颜色矩阵中的RGB偏移减小即可,具体代码如下: int brightness = -80; //RGB偏移量,变暗为负数 ColorMatrix matrix = new ColorMatrix(); matrix.set(new float[]{1, 0, 0, 0, brightness, 0, 1, 0, 0, brightness, 0, 0, 1, 0, brightness, 0, 0, 0, 1, 0}); Co

数字图像处理特效中彩色墨水效果的设计与实现

先来看两张对比图,首先是原图. 下面是处理后的效果,其实下图看起来已经不再像是一张拍摄的照片了,更像是手工绘制的. 其实除了对于边缘的描绘外,显然对色彩也需要进行适当处理. 应该还可以有改进的空间,但是毕竟算法的实现方式非常的简单,而且毕竟体现了处理此类问题所应该考虑的基本思想. 下面是我基于MAGICHOUSE平台用C++实现的代码. 函数调用部分 SeaFun::InkSketch(our_image_buffer,temp_imageBuffer,X_image,Y_image); for

Html --用简单的&lt;hr&gt;实现多样化分割效果

最基本的:<hr width=300 size=1 color=#5151A2 align=center noshade>. <!--其中 width 规定线条的长度,还可以是百分比:color 表示颜色,size 表示厚度:align 规定线条位置,有left.right.center:noshade 表示是否有立体效果--> 两头渐变透明: <hr width=80% size=3 color=#5151A2 style="FILTER: alpha(opaci

图像处理之简单数字水印 - 文字轧花效果

http://blog.csdn.net/jia20003/article/details/7338614 图像处理之文字轧花效果- 简单数字水印 @ gloomyfish 首先看一下效果,左边是一张黑白的文字图像,右边是混合之后的数字水印效果 实现原理 主要是利用位图块迁移算法,首先提取文字骨架,宽度为一个像素.然后将提取的骨架,按 照一定的像素值填充到目标图像中即可.关于位图块迁移算法说明请看这里: http://en.wikipedia.org/wiki/Bit_blit 程序思路: 1.

python数字图像处理(11):图像自动阈值分割

图像阈值分割是一种广泛应用的分割技术,利用图像中要提取的目标区域与其背景在灰度特性上的差异,把图像看作具有不同灰度级的两类区域(目标区域和背景区域)的组合,选取一个比较合理的阈值,以确定图像中每个像素点应该属于目标区域还是背景区域,从而产生相应的二值图像. 在skimage库中,阈值分割的功能是放在filters模块中. 我们可以手动指定一个阈值,从而来实现分割.也可以让系统自动生成一个阈值,下面几种方法就是用来自动生成阈值. 1.threshold_otsu 基于Otsu的阈值分割方法,函数调

【数字图像处理】帧差法与Kirsch边缘检测实现运动目标识别与分割

本文链接:https://blog.csdn.net/qq_18234121/article/details/82763385 作者:冻人的蓝鲸梁思成 视频分割算法可以从时域和空域两个角度考虑.时域分割算法利用视频流时域连续性,通过 相邻帧的时域变化来检测运动目标.在摄像头静止的情况下,常用的方法有帧差法和减背景法. 帧差法比较直观实用,对光照的变化干扰不敏感,但是 对目标的检测不准确,对于缓慢运动的目标甚至可 能无法提取出目标边界,对于快速运动的目标提取 出的目标区域又过大.减背景法容易得到目

图像处理基本算法 形状特征

形状特征 (一)特点:各种基于形状特征的检索方法都可以比较有效地利用图像中感兴趣的目标来进行检索,但它们也有一些共同的问题,包括:①目前基于形状的检索方法还缺乏比较完善的数学模型:②如果目标有变形时检索结果往往不太可靠:③许多形状特征仅描述了目标局部的性质,要全面描述目标常对计算时间和存储量有较高的要求:④许多形状特征所反映的目标形状信息与人的直观感觉不完全一致,或者说,特征空间的相似性与人视觉系统感受到的相似性有差别.另外,从 2-D 图像中表现的 3-D 物体实际上只是物体在空间某一平面的投