/// <summary>
        ///
        /// </summary>
        /// <param name="input_img">original image</param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List <Image <Gray, byte> > find_all_possible_plates(Image <Gray, byte> input_img, Plate_feature.type_of_plate type)
        {
            Image <Gray, byte> blur     = Image_utils.gaussian_blur(input_img);
            Image <Gray, byte> sobelx   = Image_utils.sobel_X(blur).Convert <Gray, byte>();
            Image <Gray, byte> adaptive = Image_utils.adaptive_threshold(sobelx);
            Image <Gray, byte> morp     = Image_utils.morphology_ex(adaptive, Plate_feature.type_of_plate.RECT_PLATE);

            VectorOfVectorOfPoint contours = Image_utils.find_all_contours(morp);

            List <Image <Gray, byte> > approved_plates = new List <Image <Gray, byte> >();

            for (int i = 0; i < contours.Size; i++)
            {
                double area = CvInvoke.ContourArea(contours[i]);

                Rectangle   r  = CvInvoke.BoundingRectangle(contours[i]);
                RotatedRect rr = CvInvoke.MinAreaRect(contours[i]);

                Image <Gray, byte> suspected_plate = input_img.Copy(r);


                Tuple <Image <Gray, byte>, Rectangle>     after_clean_plate_tuple;
                Tuple <bool, List <Image <Gray, byte> > > after_check_plate_has_characters_tuple;

                if (!Plate_feature.ratio_check(type, area, r.Width, r.Height))
                {
                    continue;
                }
                else
                {
                    if (!Plate_feature.validate_rotation_and_ratio(type, rr))
                    {
                        continue;
                    }
                    else
                    {
                        after_clean_plate_tuple = clean_plate(suspected_plate, type);
                        after_check_plate_has_characters_tuple = check_plate_has_character(after_clean_plate_tuple.Item1, type);

                        if (!after_check_plate_has_characters_tuple.Item1)
                        {
                            continue;
                        }
                        else
                        {
                            approved_plates = after_check_plate_has_characters_tuple.Item2;
                        }
                    }
                }
            }
            return(approved_plates);
        }
        /// <summary>
        /// clean the input suspected plate image and decide if that is a possible plate or not by checking ratio condition.
        /// </summary>
        /// <param name="suspected_plate"></param>
        /// <param name="type"></param>
        /// <returns>a tupple that contains:
        /// 1: image of the plate,
        /// 2: the (x,y,w,h) of the actual plate in the image
        /// </returns>
        public static Tuple <Image <Gray, byte>, Rectangle> clean_plate(Image <Gray, byte> suspected_plate, Plate_feature.type_of_plate type)
        {
            //Image<Gray, byte> threshold_plate = Image_utils.adaptive_threshold(suspected_plate);
            Image <Gray, byte>    threshold_plate = suspected_plate.ThresholdBinary(new Gray(100), new Gray(255));
            VectorOfVectorOfPoint contours        = Image_utils.find_all_contours(threshold_plate);

            Rectangle r = new Rectangle();

            Tuple <Image <Gray, byte>, Rectangle> output = new Tuple <Image <Gray, byte>, Rectangle>(suspected_plate, r);

            if (contours != null)
            {
                double        max_area    = 0;
                VectorOfPoint max_contour = new VectorOfPoint();

                for (int i = 0; i < contours.Size; i++)
                {
                    double temp = CvInvoke.ContourArea(contours[i]);
                    if (temp > max_area)
                    {
                        max_area    = temp;
                        max_contour = contours[i];
                    }
                }

                VectorOfVectorOfPoint c = new VectorOfVectorOfPoint(max_contour);
                CvInvoke.DrawContours(threshold_plate, c, 0, new MCvScalar(0), 2);

                r = CvInvoke.BoundingRectangle(max_contour);

                RotatedRect        plate_feature = CvInvoke.MinAreaRect(max_contour);
                Image <Gray, byte> rotated_plate = crop_and_rotated_plate(suspected_plate, plate_feature);

                output = new Tuple <Image <Gray, byte>, Rectangle>(rotated_plate, r);

                return(output);
            }
            else
            {
                return(output);
            }
        }
        /// <summary>
        /// check whether the possible plate after clean func is a plate or not by finding the characters in it.
        /// </summary>
        /// <param name="suspected_plate"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static Tuple <bool, List <Image <Gray, byte> > > check_plate_has_character(Image <Gray, byte> suspected_plate, Plate_feature.type_of_plate type)
        {
            List <Image <Gray, byte> > characters_found_on_plate = Plate_segmentation.segment_characters_from_plate(suspected_plate);
            Tuple <bool, List <Image <Gray, byte> > > output     = new Tuple <bool, List <Image <Gray, byte> > >(false, characters_found_on_plate);

            if (characters_found_on_plate.Count > 5)
            {
                output = new Tuple <bool, List <Image <Gray, byte> > >(true, characters_found_on_plate);
                return(output);
            }
            else
            {
                return(output);
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="input_image"></param>
        /// <returns></returns>
        public static Image <Gray, byte> morphology_ex(Image <Gray, byte> input_image, Plate_feature.type_of_plate type)
        {
            Mat structure = new Mat();

            if (type == Plate_feature.type_of_plate.RECT_PLATE)
            {
                structure = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, new Size(22, 3), new Point(-1, -1));
            }
            else if (type == Plate_feature.type_of_plate.SQUARE_PLATE)
            {
                structure = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, new Size(26, 5), new Point(-1, -1));
            }

            Image <Gray, byte> output_image = input_image.MorphologyEx(MorphOp.Close, structure, new Point(-1, -1), 1, BorderType.Default, new MCvScalar(0));

            return(output_image);
        }