private void OnWorkerProgressChanged(object sender, ProgressChangedEventArgs args)
        {
            EMWorker worker = sender as EMWorker;

            if (worker == null)
            {
                return;
            }

            lock (currentWorkersProgress)
            {
                currentWorkersProgress[currentWorkers.IndexOf(worker)] = args.ProgressPercentage;
                int combinedProgress = 0;
                combinedProgress = currentWorkersProgress.Sum() / currentWorkersProgress.Count;


                if (currentProgress != combinedProgress)
                {
                    currentProgress = combinedProgress;
                    if (this.ProgressChanged != null)
                    {
                        this.ProgressChanged(this, new ProgressChangedEventArgs(currentProgress, null));
                    }
                }
            }
        }
        private void OnWorkerProgressCompleted(object sender, RunWorkerCompletedEventArgs args)
        {
            EMWorker worker = sender as EMWorker;

            if (worker == null)
            {
                return;  // TODO: Handle Error
            }

            if (args.Error != null)
            {
                // TODO: Handle Error
                throw new EMWorkNotCompletedException("An error occurred in an EM Worker", args.Error);
            }

            this.currentWorkersCompleted[currentWorkers.IndexOf(worker)] = true;

            if (!this.currentWorkersCompleted.Contains(false))
            {
                this.Mixtures = new Dictionary <EMPatch, GaussianMixtureModel>();
                foreach (EMWorker w in this.currentWorkers)
                {
                    foreach (Tuple <EMPatch, GaussianMixtureModel> t in w.Mixtures)
                    {
                        this.Mixtures.Add(t.Item1, t.Item2);
                    }
                }

                this.workCompleted = true;

                if (this.ProgressCompleted != null)
                {
                    this.ProgressCompleted(this, new RunWorkerCompletedEventArgs(null, null, false));
                }
            }
        }
        public void Run()
        {
            // Create thread workers
            currentWorkers          = new List <EMWorker>();
            currentWorkersCompleted = new List <bool>();
            currentWorkersProgress  = new List <int>();
            currentProgress         = 0;
            for (int worker = 0; worker < ThreadCount; worker++)
            {
                EMWorker thread = new EMWorker();
                thread.ProgressChanged    += new ProgressChangedEventHandler(OnWorkerProgressChanged);
                thread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnWorkerProgressCompleted);
                currentWorkers.Add(thread);
                currentWorkersCompleted.Add(false);
                currentWorkersProgress.Add(0);
            }

            // Create data objects for workers
            List <List <EMPatch> > workerPatches = new List <List <EMPatch> >();

            for (int t = 0; t < ThreadCount; t++)
            {
                workerPatches.Add(new List <EMPatch>());
            }

            // Patch size
            int patchArrayWidth  = (int)Math.Ceiling(Width / (double)Configuration.PatchSize);
            int patchArrayHeight = (int)Math.Ceiling(Height / (double)Configuration.PatchSize);

            int currentThreadIndex = 0;

            for (int patchX = 0; patchX < patchArrayWidth; patchX++)
            {
                for (int patchY = 0; patchY < patchArrayHeight; patchY++)
                {
                    // Calculate bounding box of the patch
                    int left   = patchX * Configuration.PatchSize;
                    int top    = patchY * Configuration.PatchSize;
                    int right  = Math.Min(left + Configuration.PatchSize, Width);
                    int bottom = Math.Min(top + Configuration.PatchSize, Height);

                    // Create a new EMPatch
                    EMPatch patch = new EMPatch(patchX, patchY, left, right, top, bottom);

                    // Assign patch to a worker thread
                    workerPatches[currentThreadIndex].Add(patch);
                    currentThreadIndex = (currentThreadIndex + 1) % ThreadCount;
                }
            }

            // Launch workers
            for (int worker = 0; worker < currentWorkers.Count; worker++)
            {
                currentWorkers[worker].IntensityBuffer = IntensityBuffer;
                currentWorkers[worker].Patches         = workerPatches[worker];
                currentWorkers[worker].Width           = this.Width;
                currentWorkers[worker].Height          = this.Height;
                currentWorkers[worker].Configuration   = this.Configuration;
                currentWorkers[worker].RunWorkerAsync();
            }
        }