private void btnGMMImage_Click(object sender, EventArgs e)
        {
            pic1.Load("Tennis Ball 620.jpg");
            bmp           = new Bitmap("Tennis Ball 620.jpg");
            imageDataList = new List <ImagePoints>(bmp.Width * bmp.Height);

            int k   = int.Parse(txtNumClusters.Text);
            int dim = 3;

            imageDataList = InitializeImageData(bmp, k);
            Matrix imgMatrix = new Matrix(bmp.Width * bmp.Height, dim);

            for (int i = 0; i < (bmp.Width * bmp.Height); i++)
            {
                imgMatrix[i, 0] = imageDataList[i].red;
                imgMatrix[i, 1] = imageDataList[i].green;
                imgMatrix[i, 2] = imageDataList[i].blue;
            }

            GMM_NDim gmmnd = new GMM_NDim(k, dim, imgMatrix, bmp.Width * bmp.Height);

            gmmnd.ComputeGMM_ND();

            // determine class membership i.e., which point belongs to which cluster
            imageDataList = new List <ImagePoints>();
            for (int i = 0; i < imgMatrix.Rows; i++)
            {
                // Gamma matrix has the probabilities for a data point for its membership in each cluster
                double[] probabs   = new double[k];
                int      cnum      = 0;
                double   maxprobab = gmmnd.Gamma[i, 0];
                for (int m = 0; m < k; m++)
                {
                    if (gmmnd.Gamma[i, m] > maxprobab)
                    {
                        cnum      = m; // data i belongs to cluster m
                        maxprobab = gmmnd.Gamma[i, m];
                    }
                }
                ImagePoints imgpt = new ImagePoints {
                    clusterID = cnum, red = gmmnd.X[i, 0], green = gmmnd.X[i, 1], blue = gmmnd.X[i, 2]
                };

                imageDataList.Add(imgpt);
            }
            //MyImageProc.DrawClusters(pic1, imageDataList, 1, k);
            //redraw image from rgb values
            MessageBox.Show("img list len = " + imageDataList.Count.ToString() + " img width = " + bmp.Width.ToString() + " img height = " + bmp.Height.ToString());

            //MessageBox.Show("new image done");
        }
        List <ImagePoints> InitializeImageData(Bitmap bmp, int numClusters)
        {
            System.Diagnostics.Debug.WriteLine("in intialise");
            List <ImagePoints> PList = new List <ImagePoints>();

            PList.Clear();
            Random rand       = new Random();
            int    dataLength = bmp.Width * bmp.Height; // number of data points

            // create numCLuster distributions with different means and std devs
            double[] meanX       = new double[numClusters];
            double[] meanY       = new double[numClusters];
            double[] meanZ       = new double[numClusters];
            double   meanSampleX = 0;
            double   meanSampleY = 0;
            double   meanSampleZ = 0;

            double[] stdDevX       = new double[numClusters];
            double[] stdDevY       = new double[numClusters];
            double[] stdDevZ       = new double[numClusters];
            double   stdDevSampleX = 0;
            double   stdDevSampleY = 0;
            double   stdDevSampleZ = 0;

            //initialise datapoints to RGB values from image
            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    ImagePoints imgpt = new ImagePoints();
                    imgpt.red   = (double)bmp.GetPixel(i, j).R;
                    imgpt.green = (double)bmp.GetPixel(i, j).G;
                    imgpt.blue  = (double)bmp.GetPixel(i, j).B;
                    PList.Add(imgpt);
                }
            }

            //selecting means i.e. random pts from the dataset.
            //for (int i = 0; i < numClusters; i++)
            //{
            //    meanX[i] = PList[rand.Next(0, dataLength)].red;
            //    meanY[i] = PList[rand.Next(0, dataLength)].green;
            //    meanZ[i] = PList[rand.Next(0, dataLength)].blue;
            //}

            ////calculate sample mean
            //for(int i = 0; i < dataLength; i++)
            //{
            //    meanSampleX += PList[i].red;
            //    meanSampleY += PList[i].green;
            //    meanSampleZ += PList[i].blue;
            //}
            //meanSampleX /= dataLength;
            //meanSampleY /= dataLength;
            //meanSampleZ /= dataLength;

            ////calculate sample variance
            //for(int i = 0; i < dataLength; i++)
            //{
            //    stdDevSampleX += ((PList[i].red - meanSampleX) * (PList[i].red - meanSampleX));
            //    stdDevSampleY += ((PList[i].green - meanSampleY) * (PList[i].green - meanSampleY));
            //    stdDevSampleZ += ((PList[i].blue - meanSampleZ) * (PList[i].blue - meanSampleY));
            //}
            //stdDevSampleX /= dataLength;
            //stdDevSampleY /= dataLength;
            //stdDevSampleZ /= dataLength;

            ////set component variances to sample variance
            //for (int i = 0; i < numClusters; i++)
            //{
            //    stdDevX[i] = Math.Sqrt(stdDevSampleX);
            //    stdDevY[i] = Math.Sqrt(stdDevSampleY);
            //    stdDevZ[i] = Math.Sqrt(stdDevSampleZ);
            //}

            return(PList);
        }