图像处理------Fuzzy C Means的聚合算法
Fuzzy C-Means聚合算法在图像分割(segmentation)和图像视觉处理中常常被用到聚合算法之
一本文是完全基于JAVA语言实现Fuzzy C-Means聚合算法,并可以运用到图像处理中实现简
单的对象提取。
一:数学原理
在解释数学原理之前,请先看看这个链接算是热身吧
看不懂没关系。我的解释足够详细,小学毕业都可以学会,本人就是小学毕业。
Fuzzy C-means算法主要是比较RGB空间的每个像素值与Cluster中的每个中心点值,最终给
每个像素指派一个值(0~1之间)说明该像素更接近于哪里Cluster的中心点,模糊规则是该像
素对所有cluster的值之和为1。简单的举例:假设图像中有三个聚类cluster1,cluster2,cluster3,
像素A对三个聚类的值分别为a1, a2, a3, 根据模糊规则a1 + a2 + a3 = 1。更进一步,如果a1
最大,则该像素比较接近于Cluster1。计算总的对象值J:
二:算法流程
初始输入参数:
a. 指定的聚类个数numberOfClusters,
b. 指定的最大循环次数maxIteration
c. 指定的最小终止循环差值deltaValue
大致流程如下:
1. 初始化所有像素点值与随机选取每个Cluster的中心点,初始化每个像素点P[i]对应
Cluster的模糊值p[i][k]并计算cluster index。
2. 计算对象值J
3. 计算每个Cluster的颜色值,产生新的图像像素
4. 计算每个像素的对应每个cluster的模糊值,更新每个像素的Cluster Index
5. 再次计算对象值J,并与第二步的对象值相减,如果差值小于deltaValue或者达到最大
循环数,停止计算输出结果图像,否则继续2 ~ 4
三:关键代码解析
欧几里德距离计算方法如下:
- private double calculateEuclideanDistance(ClusterPoint p, ClusterCentroid c)
- {
- // int pa = (p.getPixelColor() >> 24) & 0xff;
- int pr = (p.getPixelColor() >> 16) & 0xff;
- int pg = (p.getPixelColor() >> 8) & 0xff;
- int pb = p.getPixelColor() & 0xff;
- // int ca = (c.getPixelColor() >> 24) & 0xff;
- int cr = (c.getPixelColor() >> 16) & 0xff;
- int cg = (c.getPixelColor() >> 8) & 0xff;
- int cb = c.getPixelColor() & 0xff;
- return Math.sqrt(Math.pow((pr - cr), 2.0) + Math.pow((pg - cg), 2.0) + Math.pow((pb - cb), 2.0));
- }
计算每个像素与每个Cluster的Fuzzy数值的代码如下:
- public void stepFuzzy()
- {
- for (int c = 0; c < this.clusters.size(); c++)
- {
- for (int h = 0; h < this.points.size(); h++)
- {
- double top;
- top = calculateEuclideanDistance(this.points.get(h), this.clusters.get(c));
- if (top < 1.0) top = Eps;
- // sumTerms is the sum of distances from this data point to all clusters.
- double sumTerms = 0.0;
- for (int ck = 0; ck < this.clusters.size(); ck++)
- {
- sumTerms += top / calculateEuclideanDistance(this.points.get(h), this.clusters.get(ck));
- }
- // Then the membership value can be calculated as...
- fuzzyForPixels[h][c] = (double)(1.0 / Math.pow(sumTerms, (2 / (this.fuzzy - 1))));
- }
- };
- this.recalculateClusterMembershipValues();
- }
计算并更新每个像素的Cluster index的代码如下:
- private void recalculateClusterMembershipValues()
- {
- for (int i = 0; i < this.points.size(); i++)
- {
- double max = 0.0;
- double min = 0.0;
- double sum = 0.0;
- double newmax = 0;
- ClusterPoint p = this.points.get(i);
- //Normalize the entries
- for (int j = 0; j < this.clusters.size(); j++)
- {
- max = fuzzyForPixels[i][j] > max ? fuzzyForPixels[i][j] : max;
- min = fuzzyForPixels[i][j] < min ? fuzzyForPixels[i][j] : min;
- }
- //Sets the values to the normalized values between 0 and 1
- for (int j = 0; j < this.clusters.size(); j++)
- {
- fuzzyForPixels[i][j] = (fuzzyForPixels[i][j] - min) / (max - min);
- sum += fuzzyForPixels[i][j];
- }
- //Makes it so that the sum of all values is 1
- for (int j = 0; j < this.clusters.size(); j++)
- {
- fuzzyForPixels[i][j] = fuzzyForPixels[i][j] / sum;
- if (Double.isNaN(fuzzyForPixels[i][j]))
- {
- fuzzyForPixels[i][j] = 0.0;
- }
- newmax = fuzzyForPixels[i][j] > newmax ? fuzzyForPixels[i][j] : newmax;
- }
- // ClusterIndex is used to store the strongest membership value to a cluster, used for defuzzification
- p.setClusterIndex(newmax);
- };
- }
四:运行效果
五:算法源代码
FuzzyCMeansProcessor - 算法类
- package com.gloomyfish.segmentation.fuzzycmeans;
- import java.awt.image.BufferedImage;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Random;
- import com.gloomyfish.filter.study.AbstractBufferedImageOp;
- public class FuzzyCMeansProcessor extends AbstractBufferedImageOp {
- private List<ClusterPoint> points;
- private List<ClusterCentroid> clusters;
- private BufferedImage originalImage;
- private BufferedImage processedImage;
- private double Eps = Math.pow(10, -5);
- private double[][] fuzzyForPixels;
- // Gets or sets objective function
- private double numObj;
- public void setObj(double j) {
- this.numObj = j;
- }
- public double getObj() {
- return this.numObj;
- }
- private float fuzzy; // default is 2
- private int numCluster; // number of clusters in image
- public BufferedImage getResultImage()
- {
- return this.processedImage;
- }
- public FuzzyCMeansProcessor(/*List<ClusterPoint> points, List<ClusterCentroid> clusters, */float fuzzy, BufferedImage myImage, int numCluster)
- {
- points = new ArrayList<ClusterPoint>();
- int width = myImage.getWidth();
- int height = myImage.getHeight();
- int index = 0;
- int[] inPixels = new int[width*height];
- myImage.getRGB( 0, 0, width, height, inPixels, 0, width );
- for (int row = 0; row < myImage.getHeight(); ++row)
- {
- for (int col = 0; col < myImage.getWidth(); ++col)
- {
- index = row * width + col;
- int color = inPixels[index];
- points.add(new ClusterPoint(row, col, color));
- }
- }
- clusters = new ArrayList<ClusterCentroid>();
- //Create random points to use a the cluster centroids
- Random random = new Random();
- for (int i = 0; i < numCluster; i++)
- {
- int randomNumber1 = random.nextInt(width);
- int randomNumber2 = random.nextInt(height);
- index = randomNumber2 * width + randomNumber1;
- clusters.add(new ClusterCentroid(randomNumber1, randomNumber2, inPixels[index]));
- }
- this.originalImage = myImage;
- this.fuzzy = fuzzy;
- this.numCluster = numCluster;
- double diff;
- // Iterate through all points to create initial U matrix
- fuzzyForPixels = new double[this.points.size()][this.clusters.size()];
- for (int i = 0; i < this.points.size(); i++)
- {
- ClusterPoint p = points.get(i);
- double sum = 0.0;
- for (int j = 0; j < this.clusters.size(); j++)
- {
- ClusterCentroid c = this.clusters.get(j);
- diff = Math.sqrt(Math.pow(calculateEuclideanDistance(p, c), 2.0));
- fuzzyForPixels[i][j] = (diff == 0) ? Eps : diff;
- sum += fuzzyForPixels[i][j];
- }
- }
- // re-calculate the membership value for one point of all clusters, and make suer it's sum of value is 1
- recalculateClusterMembershipValues();
- }
- public void calculateClusterCentroids()
- {
- for (int j = 0; j < this.clusters.size(); j++)
- {
- ClusterCentroid clusterCentroid = this.clusters.get(j);
- double l = 0.0;
- clusterCentroid.setRedSum(0);
- clusterCentroid.setBlueSum(0);
- clusterCentroid.setGreenSum(0);
- clusterCentroid.setMemberShipSum(0);
- double redSum = 0;
- double greenSum = 0;
- double blueSum = 0;
- double memebershipSum = 0;
- double pixelCount = 1;
- for (int i = 0; i < this.points.size(); i++)
- {
- ClusterPoint p = this.points.get(i);
- l = Math.pow(fuzzyForPixels[i][j], this.fuzzy);
- int ta = (p.getPixelColor() >> 24) & 0xff;
- int tr = (p.getPixelColor() >> 16) & 0xff;
- int tg = (p.getPixelColor() >> 8) & 0xff;
- int tb = p.getPixelColor() & 0xff;
- redSum += l * tr;
- greenSum += l * tg;
- blueSum += l * tb;
- memebershipSum += l;
- if (fuzzyForPixels[i][j] == p.getClusterIndex())
- {
- pixelCount += 1;
- }
- }
- int clusterColor = (255 << 24) | ((int)(redSum / memebershipSum) << 16) | ((int)(greenSum / memebershipSum) << 8) | (int)(blueSum / memebershipSum);
- clusterCentroid.setPixelColor(clusterColor);
- }
- //update the original image
- // Bitmap tempImage = new Bitmap(myImageWidth, myImageHeight, PixelFormat.Format32bppRgb);
- BufferedImage tempImage = createCompatibleDestImage( originalImage, null );
- int width = tempImage.getWidth();
- int height = tempImage.getHeight();
- int index = 0;
- int[] outPixels = new int[width*height];
- for (int j = 0; j < this.points.size(); j++)
- {
- for (int i = 0; i < this.clusters.size(); i++)
- {
- ClusterPoint p = this.points.get(j);
- if (fuzzyForPixels[j][i] == p.getClusterIndex())
- {
- int row = (int)p.getX(); // row
- int col = (int)p.getY(); // column
- index = row * width + col;
- outPixels[index] = this.clusters.get(i).getPixelColor();
- }
- }
- }
- // fill the pixel data
- setRGB( tempImage, 0, 0, width, height, outPixels );
- processedImage = tempImage;
- }
- /// <summary>
- /// Perform one step of the algorithm
- /// </summary>
- public void stepFuzzy()
- {
- for (int c = 0; c < this.clusters.size(); c++)
- {
- for (int h = 0; h < this.points.size(); h++)
- {
- double top;
- top = calculateEuclideanDistance(this.points.get(h), this.clusters.get(c));
- if (top < 1.0) top = Eps;
- // sumTerms is the sum of distances from this data point to all clusters.
- double sumTerms = 0.0;
- for (int ck = 0; ck < this.clusters.size(); ck++)
- {
- sumTerms += top / calculateEuclideanDistance(this.points.get(h), this.clusters.get(ck));
- }
- // Then the membership value can be calculated as...
- fuzzyForPixels[h][c] = (double)(1.0 / Math.pow(sumTerms, (2 / (this.fuzzy - 1))));
- }
- };
- this.recalculateClusterMembershipValues();
- }
- public double calculateObjectiveFunction()
- {
- double Jk = 0.0;
- for (int i = 0; i < this.points.size();i++)
- {
- for (int j = 0; j < this.clusters.size(); j++)
- {
- Jk += Math.pow(fuzzyForPixels[i][j], this.fuzzy) * Math.pow(this.calculateEuclideanDistance(points.get(i), clusters.get(j)), 2);
- }
- }
- return Jk;
- }
- private void recalculateClusterMembershipValues()
- {
- for (int i = 0; i < this.points.size(); i++)
- {
- double max = 0.0;
- double min = 0.0;
- double sum = 0.0;
- double newmax = 0;
- ClusterPoint p = this.points.get(i);
- //Normalize the entries
- for (int j = 0; j < this.clusters.size(); j++)
- {
- max = fuzzyForPixels[i][j] > max ? fuzzyForPixels[i][j] : max;
- min = fuzzyForPixels[i][j] < min ? fuzzyForPixels[i][j] : min;
- }
- //Sets the values to the normalized values between 0 and 1
- for (int j = 0; j < this.clusters.size(); j++)
- {
- fuzzyForPixels[i][j] = (fuzzyForPixels[i][j] - min) / (max - min);
- sum += fuzzyForPixels[i][j];
- }
- //Makes it so that the sum of all values is 1
- for (int j = 0; j < this.clusters.size(); j++)
- {
- fuzzyForPixels[i][j] = fuzzyForPixels[i][j] / sum;
- if (Double.isNaN(fuzzyForPixels[i][j]))
- {
- fuzzyForPixels[i][j] = 0.0;
- }
- newmax = fuzzyForPixels[i][j] > newmax ? fuzzyForPixels[i][j] : newmax;
- }
- // ClusterIndex is used to store the strongest membership value to a cluster, used for defuzzification
- p.setClusterIndex(newmax);
- };
- }
- private double calculateEuclideanDistance(ClusterPoint p, ClusterCentroid c)
- {
- // int pa = (p.getPixelColor() >> 24) & 0xff;
- int pr = (p.getPixelColor() >> 16) & 0xff;
- int pg = (p.getPixelColor() >> 8) & 0xff;
- int pb = p.getPixelColor() & 0xff;
- // int ca = (c.getPixelColor() >> 24) & 0xff;
- int cr = (c.getPixelColor() >> 16) & 0xff;
- int cg = (c.getPixelColor() >> 8) & 0xff;
- int cb = c.getPixelColor() & 0xff;
- return Math.sqrt(Math.pow((pr - cr), 2.0) + Math.pow((pg - cg), 2.0) + Math.pow((pb - cb), 2.0));
- }
- @Override
- public BufferedImage filter(BufferedImage src, BufferedImage dest) {
- return processedImage;
- }
- }
;
; // (int)numericUpDown2.Value;
六:Fuzzy C-means不足之处
需要提供额外的参数,不能自动识别Cluster,运行时间比较长。
图像处理------Fuzzy C Means的聚合算法的更多相关文章
- Fuzzy C Means 算法及其 Python 实现——写得很清楚,见原文
Fuzzy C Means 算法及其 Python 实现 转自:http://note4code.com/2015/04/14/fuzzy-c-means-%E7%AE%97%E6%B3%95%E5% ...
- Win8 Metro(C#)数字图像处理--2.75灰度图像的形态学算法
原文:Win8 Metro(C#)数字图像处理--2.75灰度图像的形态学算法 前面章节中介绍了二值图像的形态学算法,这里讲一下灰度图的形态学算法,主要是公式,代码略. 1,膨胀算法 2,腐蚀算法 3 ...
- 图像处理之基础---彩色转灰度算法优化rgb to yuv
File: StudyRGB2Gray.txtName: 彩色转灰度算法彻底学习Author: zyl910Version: V1.0Updata: 2006-5- ...
- Win8 Metro(C#)数字图像处理--2.64图像高斯滤波算法
原文:Win8 Metro(C#)数字图像处理--2.64图像高斯滤波算法 [函数名称] 高斯平滑滤波器 GaussFilter(WriteableBitmap src,int r ...
- Win8 Metro(C#)数字图像处理--2.60部分彩色保留算法
原文:Win8 Metro(C#)数字图像处理--2.60部分彩色保留算法 [函数名称] 部分彩色保留函数 WriteableBitmap PartialcolorProcess ...
- Win8 Metro(C#)数字图像处理--2.44图像油画效果算法
原文:Win8 Metro(C#)数字图像处理--2.44图像油画效果算法 [函数名称] 图像油画效果 OilpaintingProcess(WriteableBitmap src ...
- Win8 Metro(C#)数字图像处理--2.47人脸红眼去除算法
原文:Win8 Metro(C#)数字图像处理--2.47人脸红眼去除算法 [函数名称] 红眼去除 RedeyeRemoveProcess(WriteableBitmap src) ...
- Win8 Metro(C#)数字图像处理--2.40二值图像轮廓提取算法
原文:Win8 Metro(C#)数字图像处理--2.40二值图像轮廓提取算法 [函数名称] 二值图像轮廓提取 ContourExtraction(WriteableBitm ...
- Win8 Metro(C#)数字图像处理--2.43图像马赛克效果算法
原文:Win8 Metro(C#)数字图像处理--2.43图像马赛克效果算法 [函数名称] 图像马赛克效果 MosaicProcess(WriteableBitmap src, i ...
随机推荐
- KBEngine游戏服务器(一)——引擎环境配置
系统:Win10 版本:Visual Studio 2013(也就是vs120) kbengine:v1.0.0 MySQL:5.7 MySQL Workbench :6.3 一.下载kbengine ...
- phpstorm中配置真正的远程调试(xdebug)
这里说的是真正的远程调试,不是本地,本地不需要安装任何php程序!!! 这里略去xdebug的安装,安装很简单可以下载源码包,动态编译进去! 环境: Dev 服务器(IP:192.168.2.100) ...
- 纯静态界面中(html)中通过js调用dll中的方法从数据库中读取数据
最近接到一个离职员工的任务,一个搭好框架的ERP系统,看了两天,说一下看到的东西,整个项目目录中我没发现一个.aspx后缀的文件,全是静态HTML文件,之后发现他用的jquery简直看的头疼,不过大概 ...
- XBIM 基于 WexBIM 文件在 WebGL 浏览和加载
目录 xBIM 应用与学习 (一) xBIM 应用与学习 (二) xBIM 基本的模型操作 xBIM 日志操作 XBIM 3D 墙壁案例 xBIM 格式之间转换 xBIM 使用Linq 来优化查询 x ...
- java线程池原理及实现方式
线程池的定义 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程 为什么要使用线程池 1.减少在创建和销毁线程上所花的时间以及系统资源的开 ...
- UOJ Round #15 [构造 | 计数 | 异或哈希 kmp]
UOJ Round #15 大部分题目没有AC,我只是水一下部分分的题解... 225[UR #15]奥林匹克五子棋 题意:在n*m的棋盘上构造k子棋的平局 题解: 玩一下发现k=1, k=2无解,然 ...
- CF 570D. Tree Requests [dsu on tree]
传送门 题意: 一棵树,询问某棵子树指定深度的点能否构成回文 当然不用dsu on tree也可以做 dsu on tree的话,维护当前每一个深度每种字母出现次数和字母数,我直接用了二进制.... ...
- 用 k8s 运行一次性任务 - 每天5分钟玩转 Docker 容器技术(132)
容器按照持续运行的时间可分为两类:服务类容器和工作类容器. 服务类容器通常持续提供服务,需要一直运行,比如 http server,daemon 等.工作类容器则是一次性任务,比如批处理程序,完成后容 ...
- vue调试工具之 vue-devtools的安装
这里介绍一下vue-devtools的安装方法之一: chrome浏览器的应用商店不能直接访问(需要跨域),所以直接应用商店安装的方法就行不通了. 1.到github主页去下载安装: git clon ...
- LeetCode - 492. Construct the Rectangle
For a web developer, it is very important to know how to design a web page's size. So, given a speci ...