public string Apply(string input_dir, string output_dir, string fn, int k, int tn)
        {
            try
            {
                string fn_only = Path.GetFileNameWithoutExtension(fn);

                //MeanShift
                Log.WriteLine("Meanshift in progress...");
                MeanShiftMultiThreads mt = new MeanShiftMultiThreads();
                string ms_path = output_dir + fn_only + "_ms.png";
                mt.ApplyYIQMT(input_dir + fn, tn, 3, 3, ms_path);
                mt = null;
                GC.Collect();
                Log.WriteLine("Meanshift finished");

                // Median Cut
                Log.WriteLine("Median Cut in progress...");
                int mc_colors = 256;
                string mc_path = output_dir + fn_only + "_mc" + mc_colors.ToString() + ".png";

                using (Bitmap msimg = new Bitmap(output_dir + fn_only + "_ms.png"))
                {
                    WuQuantizer wq = new WuQuantizer();
                    wq.QuantizeImage(msimg).Save(mc_path, ImageFormat.Png);
                }
                Log.WriteLine("Median Cut finished");

                // KMeans
                Log.WriteLine("KMeans in progress...");
                MyKMeans kmeans = new MyKMeans();
                string kmeans_path = output_dir + fn_only + "_mc" + mc_colors + "_k" + k + ".png";
                kmeans.Apply(k, mc_path, kmeans_path);
                kmeans = null;
                GC.Collect();
                Log.WriteLine("KMeans finished");
                return kmeans_path;
            }
            catch (Exception e)
            {
                Log.WriteLine("ColorSegmentationWorker: " + e.Message);
                Log.WriteLine(e.Source);
                Log.WriteLine(e.StackTrace);
                throw;
            }
        }
        //#region Ramtin Code
        //[Obsolete("Ramtin version")]
        //public int Apply(String fullFilePath, int fromK, int toK, bool doExtraction)
        //{
        //    PreProcessing pp = new PreProcessing();
        //    fullFilePath = pp.doPerProccessing(fullFilePath);
        //    Dictionary<int, double> report = new Dictionary<int, double>();
        //    int uc = PreProcessing.countUniqueColorNumber(fullFilePath);
        //    if ( uc < toK)
        //    {
        //        System.Console.WriteLine(String.Format(" number of unique colors less than {0} so do only  {1}-mean", toK,uc));
        //        fromK = uc;
        //        toK = uc;
        //    }
        //    for (int i = fromK; i <= toK; i++)
        //    {
        //        System.Console.WriteLine(String.Format("k-mean {0} ... from {1}", i, toK));
        //        //K-mean
        //        string kfullFilePath = doKmean(fullFilePath, i, ref report);
        //        //Color extraction
        //        if (doExtraction)
        //        {
        //            String[] pathList = doColorExctraction(kfullFilePath);
        //            /*
        //            foreach (String s in pathList)
        //            {
        //                Connected Components
        //                doConnectedComponent(s);
        //            }*/
        //            CompareImageLayers cp = new CompareImageLayers();
        //            String fileFormat = System.IO.Path.GetFileNameWithoutExtension(fullFilePath) + "_k" + i + "_l{0}" + System.IO.Path.GetExtension(fullFilePath);
        //            List<List<double>> normalizedSpatialList = cp.analysisSpatialSimilarityOfLayers(i, System.IO.Path.GetDirectoryName(fullFilePath) + "\\", fileFormat);
        //            List<List<double>> normalizedColorList = cp.analysisColorSimilarityOfLayers(i, System.IO.Path.GetDirectoryName(fullFilePath) + "\\", fileFormat);
        //            //save Output
        //            StringBuilder sbTxt = new StringBuilder();
        //            for (int m = 0; m < normalizedColorList.Count; m++)
        //            {
        //                sbTxt.Append(string.Format("l{0},", m));
        //            }
        //            sbTxt = sbTxt.Remove(sbTxt.Length - 1, 1);
        //            sbTxt.Append(Environment.NewLine);
        //            //merge Color and Spatial half half
        //            List<List<double>> colorSpatialList = new List<List<double>>();
        //            for (int m = 0; m < normalizedColorList.Count; m++)
        //            {
        //                List<double> ls = new List<double>();
        //                for (int n = 0; n < normalizedColorList[0].Count; n++)
        //                {
        //                   //double d = normalizedSpatialList[m][n] + normalizedColorList[m][n];
        //                    double d =  normalizedColorList[m][n];
        //                    ls.Add(d);
        //                    sbTxt.Append(d + ",");
        //                }
        //                sbTxt = sbTxt.Remove(sbTxt.Length - 1, 1);
        //                sbTxt.Append(Environment.NewLine);
        //                colorSpatialList.Add(ls);
        //            }
        //            //Save the output
        //            System.IO.File.WriteAllText(System.IO.Path.GetDirectoryName(fullFilePath) + "\\" + "layersColorSpatialComparison_" + normalizedColorList.Count + ".txt", sbTxt.ToString());
        //        }
        //    }
        //    int bestK = 0;
        //    if (!doExtraction)
        //    {
        //        bestK = new KDetector().findBestK(report);
        //    }
        //    return bestK;
        //}
        //private String doKmean(String fullFilePath, int k,ref Dictionary<int, double> report)
        //{
        //    KMeans kmean = new KMeans();
        //    String latestFullFilePath = kmean.Apply(Path.GetDirectoryName(fullFilePath) + "\\", Path.GetFileName(fullFilePath), changeFileName("_k" + k, fullFilePath), k, ref report);
        //    KMeans.kdetector = null;
        //    kmean = null;
        //    return latestFullFilePath;
        //}
        //private String[] doColorExctraction(String fullFilePath)
        //{
        //    ColorExtraction ce = new ColorExtraction();
        //    Dictionary<int, Color> tbl = ce.ApplyFast(fullFilePath, changeFileName("_l{0}", fullFilePath));
        //    String[] returnPath = new String[tbl.Count];
        //    for (int i = 0; i < tbl.Count; i++)
        //    {
        //        returnPath[i] = changeFileName("_l" + i, fullFilePath);
        //    }
        //    return returnPath;
        //}
        //private String doConnectedComponent(String fullFilePath)
        //{
        //    String path = changeFileName("_cc", fullFilePath);
        //    ConnectedComponent cc = new ConnectedComponent();
        //    int ccCount = cc.apply(fullFilePath, path);
        //    return path;
        //}
        //private string changeFileName(String postFix, String fullFilePath)
        //{
        //    return fullFilePath.Insert(fullFilePath.LastIndexOf('.'), postFix);
        //}
        //#endregion
        public string[] Apply(string input_dir, string output_dir, string fn)
        {
            List<String> outImagePaths = new List<string>();
            try
            {
                string fn_only = Path.GetFileNameWithoutExtension(fn);

                //MeanShift
                MeanShiftMultiThreads mt = new MeanShiftMultiThreads();
                outImagePaths.Add(mt.ApplyYIQMT(input_dir + fn, 8, 3, 15, output_dir + fn_only + "_ms.png"));
                mt = null;
                GC.Collect();

                // Median Cut
                MedianCutMultiThreads mcq = new MedianCutMultiThreads();
                List<int> qnum_list = new List<int>();
                qnum_list.Add(1024);
                mcq.GenerateColorPalette(output_dir + fn_only + "_ms.png", qnum_list);
                string[] mcqImagePaths = mcq.quantizeImageMT(8, output_dir, output_dir, fn_only + "_mc");
                mcq = null;
                GC.Collect();

                /* Parin
                List<int> qnum_list = new List<int>();
                qnum_list.Add(1024);
                for (int i = 0; i < qnum_list.Count; i++)
                {
                    Console.WriteLine(dir + fn_only + "_ms.png");

                    Image<Bgr, Byte> inpImage = new Image<Bgr, Byte>(dir + fn_only + "_ms.png");

                    Image<Rgb, Byte> dst = new Image<Rgb, Byte>(inpImage.Size);
                    CvInvoke.cvSmooth(inpImage.Ptr, dst.Ptr, Emgu.CV.CvEnum.SMOOTH_TYPE.CV_MEDIAN, 31, 31, 1.5, 1);
                    dst.ToBitmap().Save(dir + fn_only + "_mc" + qnum_list[i] + ".png", ImageFormat.Png);
                }
                */
                for (int i = 0; i < mcqImagePaths.Length; i++)
                    outImagePaths.Add(mcqImagePaths[i]);

                // KMeans
                for (int i = 0; i < qnum_list.Count; i++)
                {
                    int km = 128;//qnum_list[i];
                    for (int k = 0; k < 10; k++)
                    {
                        MyKMeans kmeans = new MyKMeans();
                        km /= 2;
                        if (km < 4) break;
                        Console.WriteLine(km);
                        string kmeansInputFN= output_dir + fn_only + "_mc" + qnum_list[i] + ".png";

                        string kmeansOutputFN = output_dir + fn_only + "_mc" + qnum_list[i] + "_k" + km + ".png";
                             kmeans.Apply(km,kmeansInputFN, kmeansOutputFN);
                            outImagePaths.Add(kmeansOutputFN);
                        kmeans = null;
                        GC.Collect();
                    }
                }
            }
            catch (Exception e)
            {
                //Console.WriteLine(e.ToString());
            }

            return outImagePaths.ToArray();
        }