public FormDetectForDatabase(DetectMode mode)
 {
     this.mode = mode;
     InitializeComponent();
     switch (mode)
     {
         case DetectMode.SNAPS:
             {
                 this.Text = Program.ResourceManager.GetString("Title_DetectSnapshots");
                 textBox_extensions.Text = ".jpg;.png;.bmp;.gif;.jpeg;.tiff;.tif;.tga;.ico";
                 if (Program.Settings.Database_FoldersSnapshots == null)
                     Program.Settings.Database_FoldersSnapshots = new System.Collections.Specialized.StringCollection();
                 foreach (string folder in Program.Settings.Database_FoldersSnapshots)
                 {
                     if (Directory.Exists(folder))
                         listView1.Items.Add(folder, 0);
                 }
                 break;
             }
         case DetectMode.COVERS:
             {
                 this.Text = Program.ResourceManager.GetString("Title_DetectCovers");
                 textBox_extensions.Text = ".jpg;.png;.bmp;.gif;.jpeg;.tiff;.tif;.tga;.ico";
                 if (Program.Settings.Database_FoldersCovers == null)
                     Program.Settings.Database_FoldersCovers = new System.Collections.Specialized.StringCollection();
                 foreach (string folder in Program.Settings.Database_FoldersCovers)
                 {
                     if (Directory.Exists(folder))
                         listView1.Items.Add(folder, 0);
                 }
                 break;
             }
         case DetectMode.INFOS:
             {
                 this.Text = Program.ResourceManager.GetString("Title_DetectInfoFiles");
                 textBox_extensions.Text = ".txt;.doc;.rtf";
                 if (Program.Settings.Database_FoldersInfos == null)
                     Program.Settings.Database_FoldersInfos = new System.Collections.Specialized.StringCollection();
                 foreach (string folder in Program.Settings.Database_FoldersInfos)
                 {
                     if (Directory.Exists(folder))
                         listView1.Items.Add(folder, 0);
                 }
                 break;
             }
         case DetectMode.MANUALS:
             {
                 this.Text = Program.ResourceManager.GetString("Title_DetectManuals");
                 textBox_extensions.Text = ".pdf";
                 if (Program.Settings.Database_FoldersManuals == null)
                     Program.Settings.Database_FoldersManuals = new System.Collections.Specialized.StringCollection();
                 foreach (string folder in Program.Settings.Database_FoldersManuals)
                 {
                     if (Directory.Exists(folder))
                         listView1.Items.Add(folder, 0);
                 }
                 break;
             }
     }
 }
Exemple #2
0
        /// <summary>
        /// Detect basic elements (such as circlr, line, rectangle and triangle)
        /// </summary>
        /// <param name="argPath"></param>
        /// <param name="argMode"></param>
        /// <returns></returns>
        public static DetectBasicEleementResult DetectBasicElement(string argPath, DetectMode argMode)
        {
            //Load the image from file and resize it for display
            Image <Rgb, byte> img = new Image <Rgb, byte>(argPath).Resize(400, 400, Emgu.CV.CvEnum.Inter.Linear, true);

            return(DetectBasicElement(img, argMode));
        }
        public FormDetectForDatabase(DetectMode mode)
        {
            this.mode = mode;
            InitializeComponent();
            switch (mode)
            {
            case DetectMode.SNAPS:
            {
                this.Text = Program.ResourceManager.GetString("Title_DetectSnapshots");
                textBox_extensions.Text = ".jpg;.png;.bmp;.gif;.jpeg;.tiff;.tif;.tga;.ico";
                if (Program.Settings.Database_FoldersSnapshots == null)
                {
                    Program.Settings.Database_FoldersSnapshots = new System.Collections.Specialized.StringCollection();
                }
                foreach (string folder in Program.Settings.Database_FoldersSnapshots)
                {
                    if (Directory.Exists(folder))
                    {
                        listView1.Items.Add(folder, 0);
                    }
                }
                break;
            }

            case DetectMode.COVERS:
            {
                this.Text = Program.ResourceManager.GetString("Title_DetectCovers");
                textBox_extensions.Text = ".jpg;.png;.bmp;.gif;.jpeg;.tiff;.tif;.tga;.ico";
                if (Program.Settings.Database_FoldersCovers == null)
                {
                    Program.Settings.Database_FoldersCovers = new System.Collections.Specialized.StringCollection();
                }
                foreach (string folder in Program.Settings.Database_FoldersCovers)
                {
                    if (Directory.Exists(folder))
                    {
                        listView1.Items.Add(folder, 0);
                    }
                }
                break;
            }

            case DetectMode.INFOS:
            {
                this.Text = Program.ResourceManager.GetString("Title_DetectInfoFiles");
                textBox_extensions.Text = ".txt;.doc;.rtf";
                if (Program.Settings.Database_FoldersInfos == null)
                {
                    Program.Settings.Database_FoldersInfos = new System.Collections.Specialized.StringCollection();
                }
                foreach (string folder in Program.Settings.Database_FoldersInfos)
                {
                    if (Directory.Exists(folder))
                    {
                        listView1.Items.Add(folder, 0);
                    }
                }
                break;
            }

            case DetectMode.MANUALS:
            {
                this.Text = Program.ResourceManager.GetString("Title_DetectManuals");
                textBox_extensions.Text = ".pdf";
                if (Program.Settings.Database_FoldersManuals == null)
                {
                    Program.Settings.Database_FoldersManuals = new System.Collections.Specialized.StringCollection();
                }
                foreach (string folder in Program.Settings.Database_FoldersManuals)
                {
                    if (Directory.Exists(folder))
                    {
                        listView1.Items.Add(folder, 0);
                    }
                }
                break;
            }
            }
        }
Exemple #4
0
        static void Main(string[] args)
        {
            const int       NoiseSilencerEffect = 10;
            ChannelType     channelType         = ChannelType.Null;
            AudioFileReader audioStream         = null;
            long            currentBaseOffset   = 0;

            float[]             buffer = null;
            int                 bufferPointer = 0;
            long                peakCount = 0;
            TextWriter          outRawWriter = null;
            string              outputDirectory = null;
            float               upperPeak, lowerPeak;
            Tuple <float, long> peak           = new Tuple <float, long>(0, 0);
            long                lastPeakOffset = 0;
            bool                upper          = true;
            Speeds              speed          = Speeds.s600bps;
            int                 OnePeaks;
            int                 ZeroPeaks;
            int                 ThresholdPeakCount;
            int                 TypicalOneCount;
            int                 TypicalZeroCount;
            int                 peakCount1 = 0;
            int                 peakCount0 = 0;

            bool?[]    shiftRegister   = new bool?[11];
            DetectMode currentMode     = DetectMode.WaitHeader;
            int        valueCounter    = 0;
            string     currentFileName = "";

            byte[] currentFileImage     = new byte[32767];
            int    currentFileImageSize = 0;
            bool   bitsInPeakLog        = true;
            int    tryingBits           = 0;

#if DEBUG
            var waveRecorder   = new List <Tuple <float, long> >();
            var peakRecorder   = new List <Tuple <float, long> >();
            var waveLogEnabled = false;
#endif

            if (args.Length == 0)
            {
                Console.Error.WriteLine("Soft CMT Interface by autumn");
                Console.Error.WriteLine("usage: softcmtif INPUT_FILE_NAME [--verbose] [--300|--600|--1200] [--right|--left|--average|--maximum] [--peaklog FILE_NAME] [--bitsinpeaklog] [--outraw FILE_NAME] [--outdir PATH]");
                return;
            }
            bool bVerbose       = false;
            bool peaklogWaiting = false;
            bool outRawWaiting  = false;
            bool outDirWaiting  = false;
            foreach (var item in args.Skip(1))
            {
                if (peaklogWaiting)
                {
                    peaklogWriter  = File.CreateText(item);
                    peaklogWaiting = false;
                }
                else if (outRawWaiting)
                {
                    outRawWriter  = File.CreateText(item);
                    outRawWaiting = false;
                }
                else if (outDirWaiting)
                {
                    outputDirectory = item;
                    outDirWaiting   = false;
                }
                else if (item == "--verbose")
                {
                    bVerbose = true;
                }
                else if (item == "--right")
                {
                    channelType = ChannelType.Right;
                }
                else if (item == "--left")
                {
                    channelType = ChannelType.Left;
                }
                else if (item == "--average")
                {
                    channelType = ChannelType.Average;
                }
                else if (item == "--maximum")
                {
                    channelType = ChannelType.Maximum;
                }
                else if (item == "--bitsinpeaklog")
                {
                    bitsInPeakLog = true;
                }
                else if (item == "--peaklog")
                {
                    peaklogWaiting = true;
                }
                else if (item == "--outraw")
                {
                    outRawWaiting = true;
                }
                else if (item == "--outdir")
                {
                    outDirWaiting = true;
                }
                else if (item == "--300")
                {
                    speed = Speeds.s300bps;
                }
                else if (item == "--600")
                {
                    speed = Speeds.s600bps;
                }
                else if (item == "--1200")
                {
                    speed = Speeds.s1200bps;
                }
                else
                {
                    Console.WriteLine($"Unknwon option {item}");
                    return;
                }
            }
            if (bVerbose)
            {
                Console.WriteLine($"File Length: {new FileInfo(args[0]).Length}");
            }
            using (audioStream = new AudioFileReader(args[0]))
            {
                audioStream.Position = 0;
                setSpeed();
                clearShiftRegister();
                if (bVerbose)
                {
                    Console.WriteLine($"Audio Stream Length: {audioStream.Length}");
                    Console.WriteLine($"BlockAlign: {audioStream.BlockAlign}");
                    Console.WriteLine($"Channels: {audioStream.WaveFormat.Channels}");
                    Console.WriteLine($"BitsPerSample: {audioStream.WaveFormat.BitsPerSample}");
                    Console.WriteLine($"Encoding: {audioStream.WaveFormat.Encoding}");
                    Console.WriteLine($"ExtraSize: {audioStream.WaveFormat.ExtraSize}");
                    Console.WriteLine($"SampleRate: {audioStream.WaveFormat.SampleRate}");
                }
                if (audioStream.WaveFormat.Channels == 1)
                {
                    if (channelType != ChannelType.Null)
                    {
                        Console.WriteLine("Mono file not support --right|--left|--average");
                        return;
                    }
                }
                else if (audioStream.WaveFormat.Channels == 2)
                {
                    if (channelType == ChannelType.Null)
                    {
                        channelType = ChannelType.Maximum;
                    }
                }
                else
                {
                    Console.WriteLine($"Not supported channels {audioStream.WaveFormat.Channels}");
                    return;
                }
                if (bVerbose)
                {
                    Console.WriteLine($"Channel selected: ChannelType:{channelType}");
                }

                // detect upper peak and lower peak
                audioStream.Position = 0;
                upperAndLowerPeak();

                // detect wave peaks
                audioStream.Position = 0;
                peakCount1           = 0;
                peakCount0           = 0;
                currentBaseOffset    = 0;
#if DEBUG
                waveLogEnabled = true;
#endif
                for (; ;)
                {
                    var d = readUnit();
                    if (d == null)
                    {
                        break;
                    }

                    //if (peaklogWriter != null) peaklogWriter.WriteLine($"[{d.Item1} {d.Item2}]");
                    if (upper)
                    {
                        if (d.Item1 > peak.Item1)
                        {
                            peak = d;
                        }
                        else if (d.Item1 < 0.0f)
                        {
                            setPeak(d, false);
                        }
                    }
                    else
                    {
                        if (d.Item1 < peak.Item1)
                        {
                            peak = d;
                        }
                        else if (d.Item1 > 0.0f)
                        {
                            setPeak(d, true);
                        }
                    }
                }

                //float[] samples = new float[audioStream.Length / audioStream.BlockAlign * audioStream.WaveFormat.Channels];
                //audioStream.Read(samples, 0, samples.Length);



                // playback
                //var outputDevice = new WaveOutEvent();
                //outputDevice.Init(audioStream);
                //outputDevice.Play();
                //await Task.Delay(10000);

                if (bVerbose)
                {
                    Console.WriteLine($"Detected: {peakCount} peaks.");
                }
            }
            if (peaklogWriter != null)
            {
                peaklogWriter.Close();
            }
            if (outRawWriter != null)
            {
                outRawWriter.Close();
            }
            Console.WriteLine("Done");

#if DEBUG
            void waveLogSaver()
            {
                //Console.WriteLine($"waveRecorder.Count()=={waveRecorder.Count()}");
                //Console.WriteLine($"waveRecorder[0].Item2=={waveRecorder[0].Item2}");
                //Console.WriteLine($"waveRecorder[1].Item2=={waveRecorder[1].Item2}");
                using (var w = File.CreateText("wavelog1.csv"))
                {
                    //var waves = waveRecorder.TakeLast(300);
                    var waves = waveRecorder;
                    foreach (var item in waves)
                    {
                        w.WriteLine($"{item.Item2},{item.Item1}");
                    }
                }
                using (var w = File.CreateText("peaklog1.csv"))
                {
                    foreach (var item in peakRecorder.TakeLast(100))
                    {
                        w.WriteLine($"{item.Item2},{item.Item1}");
                    }
                }
                Console.WriteLine("Fatal Exit");
                if (peaklogWriter != null)
                {
                    peaklogWriter.Close();
                }
                if (outRawWriter != null)
                {
                    outRawWriter.Close();
                }
                Environment.Exit(0);
            }
#endif

            void saveFile()
            {
                if (outputDirectory == null)
                {
                    Console.WriteLine("If you want to save this file, use --outdir option");
                    return;
                }
                var fullpath = Path.Combine(outputDirectory, DateTime.Now.ToString("yyyyMMddHHmmss") + " " + currentFileName + ".bin");

                using (var stream = File.Create(fullpath))
                {
                    stream.Write(currentFileImage, 0, currentFileImageSize - 9 + 2);
                }
                Console.WriteLine($"{fullpath} saved");
            }

            void fileDetector(int value)
            {
                if (currentMode == DetectMode.WaitHeader)
                {
                    if (value == 0xd3)
                    {
                        valueCounter++;
                        if (valueCounter >= 10)
                        {
                            valueCounter    = 0;
                            currentFileName = "";
                            currentMode     = DetectMode.GettingFileName;
                        }
                    }
                    else
                    {
                        valueCounter = 0;
                    }
                }
                else if (currentMode == DetectMode.GettingFileName)
                {
                    if (value != 0)
                    {
                        currentFileName += (char)value;
                    }
                    valueCounter++;
                    if (valueCounter >= 6)
                    {
                        Console.WriteLine($"Found: {currentFileName} (N-BASIC Binary Image)");
                        valueCounter         = 0;
                        currentMode          = DetectMode.GettingBody;
                        currentFileImageSize = 0;
                        goToCarrierDetectMode();
                    }
                }
                else if (currentMode == DetectMode.GettingBody)
                {
                    currentFileImage[currentFileImageSize++] = (byte)value;
                    if (value == 0)
                    {
                        valueCounter++;
                        if (valueCounter == 12)
                        {
                            saveFile();
                            valueCounter = 0;
                            currentMode  = DetectMode.WaitHeader;
                            goToCarrierDetectMode();
                        }
                    }
                    else
                    {
                        valueCounter = 0;
                    }
                }
            }

            void notifyByte(int value)
            {
                if (peaklogWriter != null)
                {
                    peaklogWriter.WriteLine($"BYTE {value:X2}");
                }
                if (outRawWriter != null)
                {
                    outRawWriter.Write((char)value);
                }

                fileDetector(value);

                // TBW
            }

            void clearShiftRegister()
            {
                for (int i = 0; i < shiftRegister.Length; i++)
                {
                    shiftRegister[i] = true;
                }
            }

            void tapeReadError()
            {
                Console.WriteLine($"Tape Read Error [offset:{currentBaseOffset + bufferPointer}]");
                //Environment.Exit(0);
                waveLogSaver();
            }

            void notifyBit(bool?bit)
            {
                tryingBits++;
                if (bitsInPeakLog && peaklogWriter != null)
                {
                    peaklogWriter.WriteLine($"[{bit} {peakCount0} {peakCount1}]");
                }
                for (int i = 0; i < shiftRegister.Length - 1; i++)
                {
                    shiftRegister[i] = shiftRegister[i + 1];
                }
                shiftRegister[shiftRegister.Length - 1] = bit;
                // check start bit and two stop bit
                if (shiftRegister[0] == false && shiftRegister[9] == true && shiftRegister[10] == true)
                {
                    // found frame
                    var val = 0;
                    for (int j = 0; j < 8; j++)
                    {
                        val >>= 1;
                        if (shiftRegister[j + 1] == true)
                        {
                            val |= 0x80;
                        }
                        else if (shiftRegister[j + 1] == null)
                        {
                            if (carrierDetectMode == CDMode.TryingFirstByte)
                            {
                                carrierDetectMode = CDMode.TransferMode;
                                return;
                            }
                            tapeReadError();
                            return;
                        }
                    }
                    notifyByte(val);
                    if (carrierDetectMode == CDMode.TryingFirstByte)
                    {
                        carrierDetectMode = CDMode.TransferMode;
                    }
                    clearShiftRegister();
                }
                else if (tryingBits == 10)
                {
                    if (carrierDetectMode == CDMode.TryingFirstByte)
                    {
                        carrierDetectMode = CDMode.CarrierDetecting;
                    }
                }
            }

            void setPeak(Tuple <float, long> d, bool upperValue)
            {
#if DEBUG
                if (waveLogEnabled)
                {
                    peakRecorder.Add(d);
                }
#endif
                var timeOffset = (peak.Item2 - lastPeakOffset) / audioStream.WaveFormat.Channels;
                notifyPeak(timeOffset);
                //if (peaklogWriter != null) peaklogWriter.WriteLine($"PEAK {timeOffset} {peak.Item2}");
                lastPeakOffset = peak.Item2;
                peak           = d;
                upper          = upperValue;
            }

            void goToCarrierDetectMode()
            {
                carrierDetectMode = CDMode.CarrierDetecting;
            }

            void notifyPeak(long timeOffset)
            {
                peakCount++;
                //if (bVerbose && peakCount < 20) Console.Write($"{timeOffset},");
                var b = timeOffset < ThresholdPeakCount;

                //if (peaklogWriter != null) peaklogWriter.WriteLine($"[{(b ? 1 : 0)}]");

                if (carrierDetectMode == CDMode.CarrierDetecting)
                {
                    if (b == false)
                    {
                        return;
                    }
                    carrierDetectMode = CDMode.CarrierDetected;
                    return;
                }
                else if (carrierDetectMode == CDMode.CarrierDetected)
                {
                    if (b == true)
                    {
                        return;
                    }
                    carrierDetectMode = CDMode.TryingFirstByte;
                    clearShiftRegister();
                    tryingBits = 0;
                    peakCount1 = 0;
                    peakCount0 = 1;
                    return;
                }

                if (b)
                {
                    peakCount1++;
                }
                else
                {
                    peakCount0++;
                }
                if (peakCount1 == OnePeaks && peakCount0 == 0)
                {
                    notifyBit(true);
                    peakCount1 = 0;
                    peakCount0 = 0;
                }
                else if (peakCount1 == 0 && peakCount0 == ZeroPeaks)
                {
                    notifyBit(false);
                    peakCount1 = 0;
                    peakCount0 = 0;
                }
                else if (peakCount1 + peakCount0 * 2 >= OnePeaks)
                {
#if DEBUG
                    if (bufferPointer + currentBaseOffset == 5380)
                    {
                        waveLogSaver();
                    }
#endif
                    notifyBit(null);
                    peakCount1 = 0;
                    peakCount0 = 0;
                    if (carrierDetectMode == CDMode.TryingFirstByte)
                    {
                        carrierDetectMode = CDMode.CarrierDetecting;
                    }
                }
            }

            float[] readBlock()
            {
                var buf   = new float[256];
                var bytes = audioStream.Read(buf, 0, buf.Length);

                if (bytes == 0)
                {
                    return(null);
                }
                return(buf);
            }

            Tuple <float, long> readRawUnit()
            {
                if (buffer == null || bufferPointer >= buffer.Length)
                {
                    buffer = readBlock();
                    if (buffer == null)
                    {
                        return(null);
                    }
                    //currentBaseOffset = audioStream.Position;
                    currentBaseOffset += bufferPointer;
                    bufferPointer      = 0;
                }
                var v = buffer[bufferPointer];

#if NOISE_SILENCER_ENABLE
                // noise silencer
                if (v > 0 && v < upperPeak / NoiseSilencerEffect)
                {
                    v = 0;
                    //if (peaklogWriter != null) peaklogWriter.WriteLine("Detect upper cancel");
                }
                if (v < 0 && v > lowerPeak / NoiseSilencerEffect)
                {
                    v = 0;
                    //if (peaklogWriter != null) peaklogWriter.WriteLine("Detect lower cancel");
                }
#endif

                var r = new Tuple <float, long>(v, bufferPointer + currentBaseOffset);
                bufferPointer++;
                return(r);
            }

            Tuple <float, long> readUnit()
            {
                Tuple <float, long> t = null;
                var l = readRawUnit();

                if (l == null)
                {
                    return(null);
                }
                if (audioStream.WaveFormat.Channels == 1)
                {
                    t = l;
                }
                else
                {
                    var r = readRawUnit();
                    if (r == null)
                    {
                        return(null);
                    }
                    switch (channelType)
                    {
                    case ChannelType.Left:
                        t = l;
                        break;

                    case ChannelType.Right:
                        t = r;
                        break;

                    case ChannelType.Maximum:
                        if (r.Item1 >= 0 && l.Item1 >= 0)
                        {
                            t = new Tuple <float, long>(Math.Max(r.Item1, l.Item1), l.Item2);
                        }
                        else
                        {
                            t = new Tuple <float, long>(Math.Min(r.Item1, l.Item1), l.Item2);
                        }
                        break;

                    default:
                        t = new Tuple <float, long>((r.Item1 + l.Item1) / 2, l.Item2);
                        break;
                    }
                }
#if DEBUG
                if (waveLogEnabled)
                {
                    waveRecorder.Add(t);
                }
#endif
                return(t);
            }

            void setSpeed()
            {
                TypicalZeroCount   = (int)(1.0 / 1200 / 2 * audioStream.WaveFormat.SampleRate);
                TypicalOneCount    = (int)(1.0 / 2400 / 2 * audioStream.WaveFormat.SampleRate);
                ThresholdPeakCount = (TypicalZeroCount + TypicalOneCount) / 2;
                if (bVerbose)
                {
                    Console.WriteLine($"TypicalZeroCount:{TypicalZeroCount} TypicalOneCount:{TypicalOneCount} ThresholdPeakCount:{ThresholdPeakCount}");
                }

                switch (speed)
                {
                case Speeds.s300bps:
                    OnePeaks  = 8 * 2;
                    ZeroPeaks = 4 * 2;
                    break;

                case Speeds.s600bps:
                    OnePeaks  = 4 * 2;
                    ZeroPeaks = 2 * 2;
                    break;

                default:
                    OnePeaks  = 2 * 2;
                    ZeroPeaks = 1 * 2;
                    break;
                }
            }

            void upperAndLowerPeak()
            {
                upperPeak = 0.0f;
                lowerPeak = 0.0f;
                for (; ;)
                {
                    var pair = readUnit();
                    if (pair == null)
                    {
                        break;
                    }
                    if (upperPeak < pair.Item1)
                    {
                        upperPeak = pair.Item1;
                    }
                    if (lowerPeak > pair.Item1)
                    {
                        lowerPeak = pair.Item1;
                    }
                }
                if (bVerbose)
                {
                    Console.WriteLine($"Detect upperPeak/lowerPeak: {upperPeak}/{lowerPeak}");
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// Detect basic elements (such as circlr, line, rectangle and triangle)
        /// </summary>
        /// <param name="argPath"></param>
        /// <param name="argtMode"></param>
        /// <returns></returns>
        public static DetectBasicEleementResult DetectBasicElement(string argPath, DetectMode argtMode)
        {
            StringBuilder msgBuilder = new StringBuilder("Performance: ");

            //Load the image from file and resize it for display
            Image <Bgr, byte> img = new Image <Bgr, byte>(argPath).Resize(400, 400, Emgu.CV.CvEnum.Inter.Linear, true);

            //Convert the image to grayscale and filter out the noise
            UMat uimage = new UMat();

            CvInvoke.CvtColor(img, uimage, ColorConversion.Bgr2Gray);

            //use image pyr to remove noise
            UMat pyrDown = new UMat();

            CvInvoke.PyrDown(uimage, pyrDown);
            CvInvoke.PyrUp(pyrDown, uimage);

            //Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp();

            #region circle detection

            CircleF[] circles        = null;
            Stopwatch watch          = new Stopwatch();
            double    cannyThreshold = 180.0;
            if (argtMode == DetectMode.IncludeCircle)
            {
                watch = Stopwatch.StartNew();
                double circleAccumulatorThreshold = 120;
                circles = CvInvoke.HoughCircles(uimage, HoughType.Gradient, 2.0, 20.0, cannyThreshold, circleAccumulatorThreshold, 5);

                watch.Stop();
                msgBuilder.Append(String.Format("Hough circles - {0} ms; ", watch.ElapsedMilliseconds));
            }
            #endregion

            #region Canny and edge detection
            watch.Reset(); watch.Start();
            double cannyThresholdLinking = 120.0;
            UMat   cannyEdges            = new UMat();
            CvInvoke.Canny(uimage, cannyEdges, cannyThreshold, cannyThresholdLinking);

            LineSegment2D[] lines = CvInvoke.HoughLinesP(cannyEdges,
                                                         1,              //Distance resolution in pixel-related units
                                                         Math.PI / 45.0, //Angle resolution measured in radians.
                                                         20,             //threshold
                                                         30,             //min Line width
                                                         10);            //gap between lines

            watch.Stop();
            msgBuilder.Append(String.Format("Canny & Hough lines - {0} ms; ", watch.ElapsedMilliseconds));
            #endregion

            #region Find triangles and rectangles
            watch.Reset(); watch.Start();
            List <Triangle2DF> triangleList = new List <Triangle2DF>();
            List <RotatedRect> boxList      = new List <RotatedRect>();      //a box is a rotated rectangle

            using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
            {
                CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
                int count = contours.Size;
                for (int i = 0; i < count; i++)
                {
                    using (VectorOfPoint contour = contours[i])
                        using (VectorOfPoint approxContour = new VectorOfPoint())
                        {
                            CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true);
                            if (CvInvoke.ContourArea(approxContour, false) > 250)    //only consider contours with area greater than 250
                            {
                                if (approxContour.Size == 3)                         //The contour has 3 vertices, it is a triangle
                                {
                                    Point[] pts = approxContour.ToArray();
                                    triangleList.Add(new Triangle2DF(pts[0], pts[1], pts[2]));
                                }
                                else if (approxContour.Size == 4)                         //The contour has 4 vertices.
                                {
                                    #region determine if all the angles in the contour are within [80, 100] degree
                                    bool            isRectangle = true;
                                    Point[]         pts         = approxContour.ToArray();
                                    LineSegment2D[] edges       = PointCollection.PolyLine(pts, true);

                                    for (int j = 0; j < edges.Length; j++)
                                    {
                                        double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j]));
                                        if (angle < 80 || angle > 100)
                                        {
                                            isRectangle = false;
                                            break;
                                        }
                                    }
                                    #endregion

                                    if (isRectangle)
                                    {
                                        boxList.Add(CvInvoke.MinAreaRect(approxContour));
                                    }
                                }
                            }
                        }
                }
            }

            watch.Stop();
            msgBuilder.Append(String.Format("Triangles & Rectangles - {0} ms; ", watch.ElapsedMilliseconds));
            #endregion

            return(new DetectBasicEleementResult(img, triangleList, boxList, circles, lines, msgBuilder.ToString()));
        }