• 图像处理------Fuzzy C Means的聚合算法 分类: 视频图像处理 2015-07-24 15:00 56人阅读 评论(0) 收藏


    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

    三:关键代码解析

    欧几里德距离计算方法如下:

    1. private double calculateEuclideanDistance(ClusterPoint p, ClusterCentroid c)   
    2. {  
    3.     // int pa = (p.getPixelColor() >> 24) & 0xff;  
    4.     int pr = (p.getPixelColor() >> 16) & 0xff;  
    5.     int pg = (p.getPixelColor() >> 8) & 0xff;  
    6.     int pb = p.getPixelColor() & 0xff;  
    7.     // int ca = (c.getPixelColor() >> 24) & 0xff;  
    8.     int cr = (c.getPixelColor() >> 16) & 0xff;  
    9.     int cg = (c.getPixelColor() >> 8) & 0xff;  
    10.     int cb = c.getPixelColor() & 0xff;  
    11.       
    12.     return Math.sqrt(Math.pow((pr - cr), 2.0) + Math.pow((pg - cg), 2.0) + Math.pow((pb - cb), 2.0));  
    13. }  

    计算每个像素与每个Cluster的Fuzzy数值的代码如下:

    1. public void stepFuzzy()  
    2. {  
    3.     for (int c = 0; c < this.clusters.size(); c++)  
    4.     {  
    5.         for (int h = 0; h < this.points.size(); h++)  
    6.         {  
    7.   
    8.             double top;  
    9.             top = calculateEuclideanDistance(this.points.get(h), this.clusters.get(c));  
    10.             if (top < 1.0) top = Eps;  
    11.   
    12.             // sumTerms is the sum of distances from this data point to all clusters.  
    13.             double sumTerms = 0.0;  
    14.   
    15.             for (int ck = 0; ck < this.clusters.size(); ck++)  
    16.             {  
    17.                 sumTerms += top / calculateEuclideanDistance(this.points.get(h), this.clusters.get(ck));  
    18.   
    19.             }  
    20.             // Then the membership value can be calculated as...  
    21.             fuzzyForPixels[h][c] = (double)(1.0 / Math.pow(sumTerms, (2 / (this.fuzzy - 1))));   
    22.         }  
    23.     };  
    24.   
    25.   
    26.     this.recalculateClusterMembershipValues();  
    27. }  

    计算并更新每个像素的Cluster index的代码如下:

    1. private void recalculateClusterMembershipValues()   
    2. {  
    3.   
    4.     for (int i = 0; i < this.points.size(); i++)  
    5.    {  
    6.        double max = 0.0;  
    7.        double min = 0.0;  
    8.        double sum = 0.0;  
    9.        double newmax = 0;  
    10.        ClusterPoint p = this.points.get(i);  
    11.        //Normalize the entries  
    12.        for (int j = 0; j < this.clusters.size(); j++)  
    13.        {  
    14.            max = fuzzyForPixels[i][j] > max ? fuzzyForPixels[i][j] : max;  
    15.            min = fuzzyForPixels[i][j] < min ? fuzzyForPixels[i][j] : min;  
    16.        }  
    17.        //Sets the values to the normalized values between 0 and 1  
    18.        for (int j = 0; j < this.clusters.size(); j++)  
    19.        {  
    20.            fuzzyForPixels[i][j] = (fuzzyForPixels[i][j] - min) / (max - min);  
    21.            sum += fuzzyForPixels[i][j];  
    22.        }  
    23.        //Makes it so that the sum of all values is 1   
    24.        for (int j = 0; j < this.clusters.size(); j++)  
    25.        {  
    26.            fuzzyForPixels[i][j] = fuzzyForPixels[i][j] / sum;  
    27.            if (Double.isNaN(fuzzyForPixels[i][j]))  
    28.            {  
    29.                fuzzyForPixels[i][j] = 0.0;  
    30.            }  
    31.            newmax = fuzzyForPixels[i][j] > newmax ? fuzzyForPixels[i][j] : newmax;  
    32.        }  
    33.        // ClusterIndex is used to store the strongest membership value to a cluster, used for defuzzification  
    34.         p.setClusterIndex(newmax);  
    35.      };  
    36. }  

    四:运行效果


    五:算法源代码

    FuzzyCMeansProcessor - 算法类

    1. package com.gloomyfish.segmentation.fuzzycmeans;  
    2.   
    3. import java.awt.image.BufferedImage;  
    4. import java.util.ArrayList;  
    5. import java.util.List;  
    6. import java.util.Random;  
    7.   
    8. import com.gloomyfish.filter.study.AbstractBufferedImageOp;  
    9.   
    10. public class FuzzyCMeansProcessor extends AbstractBufferedImageOp {  
    11.       
    12.     private List<ClusterPoint> points;  
    13.     private List<ClusterCentroid> clusters;  
    14.     private BufferedImage originalImage;  
    15.     private BufferedImage processedImage;  
    16.     private double Eps = Math.pow(10, -5);  
    17.   
    18.     private double[][] fuzzyForPixels;  
    19.       
    20.     // Gets or sets objective function  
    21.     private double numObj;  
    22.       
    23.     public void setObj(double j) {  
    24.         this.numObj = j;  
    25.     }  
    26.       
    27.     public double getObj() {  
    28.         return this.numObj;  
    29.     }  
    30.       
    31.     private float fuzzy; // default is 2  
    32.     private int numCluster; // number of clusters in image  
    33.       
    34.     public BufferedImage getResultImage()  
    35.     {  
    36.         return this.processedImage;  
    37.     }  
    38.       
    39.     public FuzzyCMeansProcessor(/*List<ClusterPoint> points, List<ClusterCentroid> clusters, */float fuzzy, BufferedImage myImage, int numCluster)  
    40.     {  
    41.         points = new ArrayList<ClusterPoint>();  
    42.   
    43.         int width = myImage.getWidth();  
    44.         int height = myImage.getHeight();  
    45.         int index = 0;  
    46.         int[] inPixels = new int[width*height];  
    47.         myImage.getRGB( 00, width, height, inPixels, 0, width );  
    48.         for (int row = 0; row < myImage.getHeight(); ++row)  
    49.         {  
    50.             for (int col = 0; col < myImage.getWidth(); ++col)  
    51.             {  
    52.                 index = row * width + col;  
    53.                 int color = inPixels[index];  
    54.                 points.add(new ClusterPoint(row, col, color));  
    55.   
    56.             }  
    57.         }  
    58.   
    59.   
    60.   
    61.         clusters = new ArrayList<ClusterCentroid>();  
    62.          
    63.         //Create random points to use a the cluster centroids  
    64.         Random random = new Random();  
    65.         for (int i = 0; i < numCluster; i++)  
    66.         {  
    67.             int randomNumber1 = random.nextInt(width);  
    68.             int randomNumber2 = random.nextInt(height);  
    69.             index = randomNumber2 * width + randomNumber1;  
    70.             clusters.add(new ClusterCentroid(randomNumber1, randomNumber2, inPixels[index]));   
    71.         }  
    72.           
    73.         this.originalImage = myImage;  
    74.         this.fuzzy = fuzzy;  
    75.         this.numCluster = numCluster;  
    76.           
    77.         double diff;  
    78.   
    79.         // Iterate through all points to create initial U matrix  
    80.         fuzzyForPixels = new double[this.points.size()][this.clusters.size()];  
    81.         for (int i = 0; i < this.points.size(); i++)  
    82.         {  
    83.             ClusterPoint p = points.get(i);  
    84.             double sum = 0.0;  
    85.   
    86.             for (int j = 0; j < this.clusters.size(); j++)  
    87.             {  
    88.                 ClusterCentroid c = this.clusters.get(j);  
    89.                 diff = Math.sqrt(Math.pow(calculateEuclideanDistance(p, c), 2.0));  
    90.                 fuzzyForPixels[i][j] = (diff == 0) ? Eps : diff;  
    91.                 sum += fuzzyForPixels[i][j];  
    92.             }  
    93.          }  
    94.           
    95.         // re-calculate the membership value for one point of all clusters, and make suer it's sum of value is 1  
    96.         recalculateClusterMembershipValues();  
    97.           
    98.     }  
    99.       
    100.     public void calculateClusterCentroids()  
    101.     {  
    102.         for (int j = 0; j < this.clusters.size(); j++)  
    103.         {  
    104.             ClusterCentroid clusterCentroid = this.clusters.get(j);  
    105.               
    106.             double l = 0.0;  
    107.             clusterCentroid.setRedSum(0);  
    108.             clusterCentroid.setBlueSum(0);  
    109.             clusterCentroid.setGreenSum(0);  
    110.             clusterCentroid.setMemberShipSum(0);  
    111.             double redSum = 0;  
    112.             double greenSum = 0;  
    113.             double blueSum = 0;  
    114.             double memebershipSum = 0;  
    115.             double pixelCount = 1;  
    116.   
    117.             for (int i = 0; i < this.points.size(); i++)  
    118.             {  
    119.               
    120.                 ClusterPoint p = this.points.get(i);  
    121.                 l = Math.pow(fuzzyForPixels[i][j], this.fuzzy);  
    122.                 int ta = (p.getPixelColor() >> 24) & 0xff;  
    123.                 int tr = (p.getPixelColor() >> 16) & 0xff;  
    124.                 int tg = (p.getPixelColor() >> 8) & 0xff;  
    125.                 int tb = p.getPixelColor() & 0xff;  
    126.                 redSum += l * tr;  
    127.                 greenSum += l * tg;  
    128.                 blueSum += l * tb;  
    129.                 memebershipSum += l;  
    130.   
    131.                 if (fuzzyForPixels[i][j] == p.getClusterIndex())  
    132.                 {  
    133.                     pixelCount += 1;  
    134.                 }  
    135.             }  
    136.               
    137.             int clusterColor = (255 << 24) | ((int)(redSum / memebershipSum) << 16) | ((int)(greenSum / memebershipSum) << 8) | (int)(blueSum / memebershipSum);  
    138.             clusterCentroid.setPixelColor(clusterColor);  
    139.          }  
    140.   
    141.         //update the original image  
    142.         // Bitmap tempImage = new Bitmap(myImageWidth, myImageHeight, PixelFormat.Format32bppRgb);  
    143.         BufferedImage tempImage = createCompatibleDestImage( originalImage, null );  
    144.         int width = tempImage.getWidth();  
    145.         int height = tempImage.getHeight();  
    146.         int index = 0;  
    147.         int[] outPixels = new int[width*height];  
    148.           
    149.         for (int j = 0; j < this.points.size(); j++)  
    150.         {  
    151.             for (int i = 0; i < this.clusters.size(); i++)  
    152.             {  
    153.                 ClusterPoint p = this.points.get(j);  
    154.                 if (fuzzyForPixels[j][i] == p.getClusterIndex())  
    155.                 {  
    156.                     int row = (int)p.getX(); // row  
    157.                     int col = (int)p.getY(); // column  
    158.                     index = row * width + col;  
    159.                     outPixels[index] = this.clusters.get(i).getPixelColor();  
    160.                 }  
    161.             }  
    162.         }  
    163.           
    164.         // fill the pixel data  
    165.         setRGB( tempImage, 00, width, height, outPixels );  
    166.         processedImage = tempImage;  
    167.     }  
    168.       
    169.     /// <summary>  
    170.     /// Perform one step of the algorithm  
    171.     /// </summary>  
    172.     public void stepFuzzy()  
    173.     {  
    174.         for (int c = 0; c < this.clusters.size(); c++)  
    175.         {  
    176.             for (int h = 0; h < this.points.size(); h++)  
    177.             {  
    178.   
    179.                 double top;  
    180.                 top = calculateEuclideanDistance(this.points.get(h), this.clusters.get(c));  
    181.                 if (top < 1.0) top = Eps;  
    182.   
    183.                 // sumTerms is the sum of distances from this data point to all clusters.  
    184.                 double sumTerms = 0.0;  
    185.   
    186.                 for (int ck = 0; ck < this.clusters.size(); ck++)  
    187.                 {  
    188.                     sumTerms += top / calculateEuclideanDistance(this.points.get(h), this.clusters.get(ck));  
    189.   
    190.                 }  
    191.                 // Then the membership value can be calculated as...  
    192.                 fuzzyForPixels[h][c] = (double)(1.0 / Math.pow(sumTerms, (2 / (this.fuzzy - 1))));   
    193.             }  
    194.         };  
    195.   
    196.   
    197.         this.recalculateClusterMembershipValues();  
    198.     }  
    199.       
    200.     public double calculateObjectiveFunction()  
    201.     {  
    202.         double Jk = 0.0;  
    203.   
    204.         for (int i = 0; i < this.points.size();i++)  
    205.         {  
    206.             for (int j = 0; j < this.clusters.size(); j++)  
    207.             {  
    208.                 Jk += Math.pow(fuzzyForPixels[i][j], this.fuzzy) * Math.pow(this.calculateEuclideanDistance(points.get(i), clusters.get(j)), 2);  
    209.             }  
    210.         }  
    211.         return Jk;  
    212.     }  
    213.       
    214.       
    215.     private void recalculateClusterMembershipValues()   
    216.     {  
    217.       
    218.         for (int i = 0; i < this.points.size(); i++)  
    219.        {  
    220.            double max = 0.0;  
    221.            double min = 0.0;  
    222.            double sum = 0.0;  
    223.            double newmax = 0;  
    224.            ClusterPoint p = this.points.get(i);  
    225.            //Normalize the entries  
    226.            for (int j = 0; j < this.clusters.size(); j++)  
    227.            {  
    228.                max = fuzzyForPixels[i][j] > max ? fuzzyForPixels[i][j] : max;  
    229.                min = fuzzyForPixels[i][j] < min ? fuzzyForPixels[i][j] : min;  
    230.            }  
    231.            //Sets the values to the normalized values between 0 and 1  
    232.            for (int j = 0; j < this.clusters.size(); j++)  
    233.            {  
    234.                fuzzyForPixels[i][j] = (fuzzyForPixels[i][j] - min) / (max - min);  
    235.                sum += fuzzyForPixels[i][j];  
    236.            }  
    237.            //Makes it so that the sum of all values is 1   
    238.            for (int j = 0; j < this.clusters.size(); j++)  
    239.            {  
    240.                fuzzyForPixels[i][j] = fuzzyForPixels[i][j] / sum;  
    241.                if (Double.isNaN(fuzzyForPixels[i][j]))  
    242.                {  
    243.                    fuzzyForPixels[i][j] = 0.0;  
    244.                }  
    245.                newmax = fuzzyForPixels[i][j] > newmax ? fuzzyForPixels[i][j] : newmax;  
    246.            }  
    247.            // ClusterIndex is used to store the strongest membership value to a cluster, used for defuzzification  
    248.             p.setClusterIndex(newmax);  
    249.          };  
    250.     }  
    251.   
    252.     private double calculateEuclideanDistance(ClusterPoint p, ClusterCentroid c)   
    253.     {  
    254.         // int pa = (p.getPixelColor() >> 24) & 0xff;  
    255.         int pr = (p.getPixelColor() >> 16) & 0xff;  
    256.         int pg = (p.getPixelColor() >> 8) & 0xff;  
    257.         int pb = p.getPixelColor() & 0xff;  
    258.         // int ca = (c.getPixelColor() >> 24) & 0xff;  
    259.         int cr = (c.getPixelColor() >> 16) & 0xff;  
    260.         int cg = (c.getPixelColor() >> 8) & 0xff;  
    261.         int cb = c.getPixelColor() & 0xff;  
    262.           
    263.         return Math.sqrt(Math.pow((pr - cr), 2.0) + Math.pow((pg - cg), 2.0) + Math.pow((pb - cb), 2.0));  
    264.     }  
    265.   
    266.     @Override  
    267.     public BufferedImage filter(BufferedImage src, BufferedImage dest) {  
    268.         return processedImage;  
    269.     }  
    270.   
    271. }  
    ClusterPoint- 存储图像像素点对象

    1. package com.gloomyfish.segmentation.fuzzycmeans;  
    2.   
    3. public class ClusterPoint {  
    4.     private double x;  
    5.     private double y;  
    6.     private int pixelColor;  
    7.     private int originalPixelColor;  
    8.     private double clusterIndex;  
    9.       
    10.     public ClusterPoint(double x, double y, int col)  
    11.     {  
    12.         this.x = x;  
    13.         this.y = y;  
    14.         this.pixelColor = col;  
    15.         this.originalPixelColor = col;  
    16.         this.clusterIndex = -1;  
    17.     }  
    18.       
    19.     public double getX() {  
    20.         return x;  
    21.     }  
    22.   
    23.     public void setX(double x) {  
    24.         this.x = x;  
    25.     }  
    26.   
    27.     public double getY() {  
    28.         return y;  
    29.     }  
    30.   
    31.     public void setY(double y) {  
    32.         this.y = y;  
    33.     }  
    34.   
    35.     public int getPixelColor() {  
    36.         return pixelColor;  
    37.     }  
    38.   
    39.     public void setPixelColor(int pixelColor) {  
    40.         this.pixelColor = pixelColor;  
    41.     }  
    42.   
    43.     public int getOriginalPixelColor() {  
    44.         return originalPixelColor;  
    45.     }  
    46.   
    47.     public void setOriginalPixelColor(int originalPixelColor) {  
    48.         this.originalPixelColor = originalPixelColor;  
    49.     }  
    50.   
    51.     public double getClusterIndex() {  
    52.         return clusterIndex;  
    53.     }  
    54.   
    55.     public void setClusterIndex(double clusterIndex) {  
    56.         this.clusterIndex = clusterIndex;  
    57.     }  
    58.   
    59. }  
    ClusterCentroid - 存储Cluster信息对象

    1. package com.gloomyfish.segmentation.fuzzycmeans;  
    2.   
    3. public class ClusterCentroid {  
    4.   
    5.     private double x;  
    6.     private double y;  
    7.     private int pixelColor;  
    8.     private double redSum;  
    9.     private double greenSum;  
    10.     private double blueSum;  
    11.     private double memberShipSum;  
    12.     private int originalPixelColor;  
    13.       
    14.     public ClusterCentroid(double x, double y, int color)  
    15.     {  
    16.         this.x = x;  
    17.         this.y = y;  
    18.         this.originalPixelColor = color;  
    19.         this.pixelColor = color;  
    20.     }  
    21.       
    22.     public double getX() {  
    23.         return x;  
    24.     }  
    25.   
    26.     public void setX(double x) {  
    27.         this.x = x;  
    28.     }  
    29.   
    30.     public double getY() {  
    31.         return y;  
    32.     }  
    33.   
    34.     public void setY(double y) {  
    35.         this.y = y;  
    36.     }  
    37.   
    38.     public int getPixelColor() {  
    39.         return pixelColor;  
    40.     }  
    41.   
    42.     public void setPixelColor(int pixelColor) {  
    43.         this.pixelColor = pixelColor;  
    44.     }  
    45.   
    46.     public double getRedSum() {  
    47.         return redSum;  
    48.     }  
    49.   
    50.     public void setRedSum(double redSum) {  
    51.         this.redSum = redSum;  
    52.     }  
    53.   
    54.     public double getGreenSum() {  
    55.         return greenSum;  
    56.     }  
    57.   
    58.     public void setGreenSum(double greenSum) {  
    59.         this.greenSum = greenSum;  
    60.     }  
    61.   
    62.     public double getBlueSum() {  
    63.         return blueSum;  
    64.     }  
    65.   
    66.     public void setBlueSum(double blueSum) {  
    67.         this.blueSum = blueSum;  
    68.     }  
    69.   
    70.     public double getMemberShipSum() {  
    71.         return memberShipSum;  
    72.     }  
    73.   
    74.     public void setMemberShipSum(double memberShipSum) {  
    75.         this.memberShipSum = memberShipSum;  
    76.     }  
    77.   
    78.     public int getOriginalPixelColor() {  
    79.         return originalPixelColor;  
    80.     }  
    81.   
    82.     public void setOriginalPixelColor(int originalPixelColor) {  
    83.         this.originalPixelColor = originalPixelColor;  
    84.     }  
    85.   
    86. }  

    算法调用:

    1.   int numClusters = 2// (int)numericUpDown2.Value;  
    2.   int maxIterations = 20//(int)numericUpDown3.Value;  
    3.   double accuracy = 0.00001// (double)numericUpDown4.Value;  
    4.   FuzzyCMeansProcessor alg = new FuzzyCMeansProcessor(numClusters, sourceImage, numClusters);  
    5.   int k = 0;  
    6.   do  
    7.   {  
    8.       k++;  
    9.       alg.setObj(alg.calculateObjectiveFunction());  
    10.       alg.calculateClusterCentroids();  
    11.       alg.stepFuzzy();  
    12.       double Jnew = alg.calculateObjectiveFunction();  
    13.       System.out.println("Run method accuracy of delta value = " + Math.abs(alg.getObj() - Jnew));  
    14.       if (Math.abs(alg.getObj() - Jnew) < accuracy) break;  
    15.   }  
    16.   while (maxIterations > k);  
    17.   resultImage = alg.getResultImage();  
    18.   this.repaint();  
    19. }  

    六:Fuzzy C-means不足之处

    需要提供额外的参数,不能自动识别Cluster,运行时间比较长。

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    spring framework体系结构及模块jar依赖关系
    Spring的核心jar包
    Spring AOP的理解和使用
    Spring特点与工作原理
    接口和抽象类的区别
    Java重载和重写的区别
    Jdk1.8中的HashMap实现原理
    Java集合中List,Set以及Map等集合体系详解
    Spring面试题整理
    ActiveMQ入门操作示例
  • 原文地址:https://www.cnblogs.com/mao0504/p/4705505.html
Copyright © 2020-2023  润新知