Esempio n. 1
0
        private void ProcessSegmentationMethod(object sender, RoutedEventArgs e)
        {
            string       strSermenterName = (sender as Control).Tag.ToString();
            ISegmentLine segmenter        = ComponentCreator.MakeComponent <ISegmentLine>(strSermenterName);

            if (segmenter == null || currBookLine == null)
            {
                return;
            }

            // приведем к чернобелому
            Bytearray image = currBookLine.ImageBytearray;

            //IBinarize binarizer = new BinarizeByOtsu();
            //binarizer.Binarize(image, image);
            OcrRoutine.binarize_simple(image, image);
            // сегментация
            Intarray charseg = new Intarray();

            segmenter.Charseg(ref charseg, image);
            // фон равен 0
            SegmRoutine.make_line_segmentation_black(charseg);
            // удалим маленькие сегменты
            SegmRoutine.remove_small_components(charseg, 3, 3);
            ImgLabels.renumber_labels(charseg, 1);

            currBookLine.CharsegIntarray = charseg;
            CurrSegmentsCount            = NarrayUtil.Max(charseg);
            // Show segmented image
            ShowCharsegImage(charseg,
                             (currBookLine.HaveTranscript && CurrSegmentsCount == currBookLine.Transcript.Length) ?
                             currBookLine.Transcript : "");
            // to enable save button
            EnableCharsegCmdButtons();
        }
Esempio n. 2
0
        public static void remove_small_components(Intarray segmentation, int w = 5, int h = 4)
        {
            if (NarrayUtil.Max(segmentation) > 100000)
            {
                throw new Exception("remove_small_components: to many segments");
            }
            Narray <Rect> bboxes = new Narray <Rect>();

            ImgLabels.bounding_boxes(ref bboxes, segmentation);
            for (int i = 1; i < bboxes.Length(); i++)
            {
                Rect b = bboxes[i];
                if (b.Width() < w && b.Height() < h)
                {
                    for (int x = b.x0; x < b.x1; x++)
                    {
                        for (int y = b.y0; y < b.y1; y++)
                        {
                            if (segmentation[x, y] == i)
                            {
                                segmentation[x, y] = 0;
                            }
                        }
                    }
                }
            }
        }
Esempio n. 3
0
        public static void threshold_frac(Bytearray thresholded, Floatarray input, float frac)
        {
            float minofinput = NarrayUtil.Min(input);
            float theta      = frac * (NarrayUtil.Max(input) - minofinput) + minofinput;

            binarize_with_threshold(thresholded, input, theta);
        }
Esempio n. 4
0
        public override void SetSegmentationAndGt(Intarray segmentation, Intarray cseg, ref string text)
        {
            // first, set the segmentation as usual
            SetSegmentation(segmentation);

            // Maybe fix up the transcript (remove spaces).
            gttranscript = text;
            string s = text;

            fixup_transcript(ref s, false);
            int  max_cseg  = NarrayUtil.Max(cseg);
            bool old_csegs = (s.Length != max_cseg);

            fixup_transcript(ref gttranscript, old_csegs);

            // Complain if it doesn't match.
            if (gttranscript.Length != max_cseg)
            {
                Logger.Default.Format("transcript = '{0}'\n", gttranscript);
                throw new Exception(String.Format("transcript doesn't agree with cseg (transcript {0}, cseg {1})",
                                                  gttranscript.Length, max_cseg));
            }

            // Now compute the correspondences between the character segmentation
            // and the raw segmentation.
            GrouperRoutine.segmentation_correspondences(gtsegments, segmentation, cseg);
        }
Esempio n. 5
0
        public static void rseg_to_cseg(Intarray cseg, Intarray rseg, Intarray ids)
        {
            Intarray map = new Intarray(NarrayUtil.Max(rseg) + 1);

            map.Fill(0);
            int color = 0;

            for (int i = 0; i < ids.Length(); i++)
            {
                if (ids[i] == 0)
                {
                    continue;
                }
                color++;
                int start = ids[i] >> 16;
                int end   = ids[i] & 0xFFFF;
                if (start > end)
                {
                    throw new Exception("segmentation encoded in IDs looks seriously broken!");
                }
                if (start >= map.Length() || end >= map.Length())
                {
                    throw new Exception("segmentation encoded in IDs doesn't fit!");
                }
                for (int j = start; j <= end; j++)
                {
                    map[j] = color;
                }
            }
            cseg.MakeLike(rseg);
            for (int i = 0; i < cseg.Length1d(); i++)
            {
                cseg.Put1d(i, map[rseg.At1d(i)]);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Merge segments from start to end.
        /// </summary>
        /// <param name="cseg">Output</param>
        /// <param name="rseg">Input</param>
        /// <param name="start">start merge position</param>
        /// <param name="end">end merge position</param>
        public static void rseg_to_cseg(Intarray cseg, Intarray rseg, int start, int end)
        {
            int maxSegNum = NarrayUtil.Max(rseg);

            if (start > end)
            {
                throw new Exception("segmentation encoded in IDs looks seriously broken!");
            }
            if (start > maxSegNum || end > maxSegNum)
            {
                throw new Exception("segmentation encoded in IDs doesn't fit!");
            }
            Intarray map = new Intarray(maxSegNum + 1);

            map.Fill(0);

            int color = 1;

            for (int i = 1; i <= maxSegNum; i++)
            {
                map[i] = color;
                if (i < start || i >= end)
                {
                    color++;
                }
            }
            cseg.MakeLike(rseg);
            for (int i = 0; i < cseg.Length1d(); i++)
            {
                cseg.Put1d(i, map[rseg.At1d(i)]);
            }
        }
Esempio n. 7
0
 protected void Recompute()
 {
     nc = NarrayUtil.Max(classes) + 1;
     nf = data[0].Dim(0);
     CHECK_ARG(DataMin(data) >= 0 && DataMax(data) < 256, "min(data) >= 0 && max(data) < 256");
     CHECK_ARG(NarrayUtil.Min(classes) >= -1 && NarrayUtil.Max(classes) < 10000,
               "min(classes)>=-1 && max(classes)<10000");
     CHECK_ARG(nc > 0, "nc > 0");
     CHECK_ARG(nf > 0, "nf > 0");
 }
Esempio n. 8
0
 protected void Recompute()
 {
     nc = NarrayUtil.Max(classes) + 1;
     nf = data.Dim(1);
     CHECK_ARG(Min(data) > -100 && Max(data) < 100, "min(data) > -100 && max(data) < 100");
     CHECK_ARG(NarrayUtil.Min(classes) >= -1 && NarrayUtil.Max(classes) < 10000,
               "min(classes)>=-1 && max(classes)<10000");
     CHECK_ARG(nc > 0, "nc > 0");
     CHECK_ARG(nf > 0, "nf > 0");
 }
Esempio n. 9
0
        public static void combine_segmentations(ref Intarray dst, Intarray src)
        {
            dst.SameDims(src);
            int n = NarrayUtil.Max(dst) + 1;

            for (int i = 0; i < dst.Length1d(); i++)
            {
                dst.Put1d(i, (dst.At1d(i) + src.At1d(i) * n));
            }
            ImgLabels.renumber_labels(dst, 1);
        }
Esempio n. 10
0
        /// <summary>
        /// Изменился текущий BookLine
        /// </summary>
        private void BookLine_CurrentChanged(object sender, EventArgs e)
        {
            if (listingDataView.View.CurrentItem == null)
            {
                return;
            }

            // сбросим кэш предыдущего елемента
            if (currBookLine != null)
            {
                currBookLine.Image           = null;
                currBookLine.ImageBytearray  = null;
                currBookLine.CharsegIntarray = null;
            }
            // текущий елемент
            BookLine bline = listingDataView.View.CurrentItem as BookLine;

            currBookLine = bline;
            // сбросим некоторые признаки
            isCurrDeletedSegment = false;

            // показать Charseg
            if (bline != null && bline.HaveCharseg)
            {
                // загрузим с файла
                Intarray charseg = bline.CharsegIntarray;
                // занесем в кэш
                bline.CharsegIntarray = charseg;
                // номер максимального сегмента
                CurrSegmentsCount = NarrayUtil.Max(charseg);
                // отобразим картинку
                ShowCharsegImage(charseg, bline.Transcript);
                // активируем кнопки действий
                EnableCharsegCmdButtons();
            }
            else
            {
                imgCharSeg.Source = null;
                DisableCharsegCmdButtons();
            }

            // показать Transcript
            if (bline != null && bline.HaveTranscript)
            {
                ShowTranscript(bline.Transcript);
            }
            else
            {
                ShowTranscript("");
            }
            // сбросим к началу номер начальног осегмента
            numUpDnStart.Value = 1;
            numUpDnEnd.Value   = 2;
        }
Esempio n. 11
0
        public static int binarize_simple(Bytearray result, Bytearray image)
        {
            int threshold = (NarrayUtil.Max(image) /* + NarrayUtil.Min(image)*/) / 2;

            result.MakeLike(image);
            for (int i = 0; i < image.Length1d(); i++)
            {
                result.Put1d(i, image.At1d(i) < threshold ? (byte)0 : (byte)255);
            }
            return(threshold);
        }
Esempio n. 12
0
        public static void binsmooth(Bytearray binary, Floatarray input, float sigma)
        {
            Floatarray smoothed = new Floatarray();

            smoothed.Copy(input);
            smoothed -= NarrayUtil.Min(smoothed);
            smoothed /= NarrayUtil.Max(smoothed);
            if (sigma > 0)
            {
                Gauss.Gauss2d(smoothed, sigma, sigma);
            }
            binarize_with_threshold(binary, smoothed, 0.5f);
        }
Esempio n. 13
0
        /// <summary>
        /// Get spacing to the next component.
        /// </summary>
        public override int PixelSpace(int i)
        {
            int end = NarrayUtil.Max(segments.At1d(i));

            if (end >= rboxes.Length() - 1)
            {
                return(-1);
            }
            int x0 = rboxes.At1d(end).x1;
            int x1 = rboxes.At1d(end + 1).x0;

            return(x1 - x0);
        }
Esempio n. 14
0
        public static Bitmap read_image_binary(Bytearray image, string path)
        {
            Bitmap bitmap = LoadBitmapFromFile(path);

            image.Resize(bitmap.Width, bitmap.Height);
            ImgRoutine.NarrayFromBitmap(image, bitmap);
            double threshold = (NarrayUtil.Min(image) + NarrayUtil.Max(image)) / 2.0;

            for (int i = 0; i < image.Length1d(); i++)
            {
                image.Put1d(i, (byte)((image.At1d(i) < threshold) ? 0 : 255));
            }
            return(bitmap);
        }
Esempio n. 15
0
 public override void Add(Floatarray v, int c)
 {
     CHECK_ARG(NarrayUtil.Min(v) > -1.2f && NarrayUtil.Max(v) < 1.2f, "float8: value out of range (-1.2..1.2)");
     CHECK_ARG(c >= -1, "c>=-1");
     if (c >= nc)
     {
         nc = c + 1;
     }
     if (nf < 0)
     {
         nf = v.Length();
     }
     RowPush(data, v);
     classes.Push(c);
 }
Esempio n. 16
0
        /// <summary>
        /// Remove segments from start to end.
        /// </summary>
        /// <param name="cseg">Output</param>
        /// <param name="rseg">Input</param>
        /// <param name="start">start remove position</param>
        /// <param name="end">end remove position</param>
        public static void rseg_to_cseg_remove(Intarray cseg, Intarray rseg,
                                               Bytearray outimg, Bytearray img, int start, int end)
        {
            int maxSegNum = NarrayUtil.Max(rseg);

            if (start > end)
            {
                throw new Exception("segmentation encoded in IDs looks seriously broken!");
            }
            if (start > maxSegNum || end > maxSegNum)
            {
                throw new Exception("segmentation encoded in IDs doesn't fit!");
            }
            if (rseg.Length1d() != img.Length1d())
            {
                throw new Exception("rseg and img must have same a dimension!");
            }
            Intarray map = new Intarray(maxSegNum + 1);

            map.Fill(0);

            int color = 1;

            for (int i = 1; i <= maxSegNum; i++)
            {
                map[i] = color;
                if (i < start || i > end)
                {
                    color++;
                }
                else
                {
                    map[i] = 0;
                }
            }
            cseg.MakeLike(rseg);
            outimg.Copy(img);
            for (int i = 0; i < cseg.Length1d(); i++)
            {
                int val = rseg.At1d(i);
                cseg.Put1d(i, map[val]);
                if (val > 0 && map[val] == 0)
                {
                    outimg.Put1d(i, 255);
                }
            }
        }
Esempio n. 17
0
        private void ProcessMergeSegments(object sender, RoutedEventArgs e)
        {
            int start = numUpDnStart.Value ?? 1;
            int end   = numUpDnEnd.Value ?? 1;

            start = Math.Min(start, CurrSegmentsCount);
            end   = Math.Min(end, CurrSegmentsCount);

            SegmRoutine.rseg_to_cseg(currBookLine.CharsegIntarray, currBookLine.CharsegIntarray, start, end);

            // пересчитаем число сегментов
            CurrSegmentsCount = NarrayUtil.Max(currBookLine.CharsegIntarray);
            // Show segmented image
            ShowCharsegImage(currBookLine.CharsegIntarray,
                             (currBookLine.HaveTranscript && CurrSegmentsCount == currBookLine.Transcript.Length) ?
                             currBookLine.Transcript : "");
        }
Esempio n. 18
0
        public static void line_segmentation_sort_x(Intarray segmentation)
        {
            if (NarrayUtil.Max(segmentation) > 100000)
            {
                throw new Exception("line_segmentation_merge_small_components: to many segments");
            }
            Narray <Rect> bboxes = new Narray <Rect>();

            ImgLabels.bounding_boxes(ref bboxes, segmentation);
            Floatarray x0s = new Floatarray();

            unchecked
            {
                x0s.Push((float)-999999);
            }
            for (int i = 1; i < bboxes.Length(); i++)
            {
                if (bboxes[i].Empty())
                {
                    x0s.Push(999999);
                }
                else
                {
                    x0s.Push(bboxes[i].x0);
                }
            }
            // dprint(x0s,1000); printf("\n");
            Narray <int> permutation  = new Intarray();
            Narray <int> rpermutation = new Intarray();

            NarrayUtil.Quicksort(permutation, x0s);
            rpermutation.Resize(permutation.Length());
            for (int i = 0; i < permutation.Length(); i++)
            {
                rpermutation[permutation[i]] = i;
            }
            // dprint(rpermutation,1000); printf("\n");
            for (int i = 0; i < segmentation.Length1d(); i++)
            {
                if (segmentation.At1d(i) == 0)
                {
                    continue;
                }
                segmentation.Put1d(i, rpermutation[segmentation.At1d(i)]);
            }
        }
Esempio n. 19
0
        public override void Info()
        {
            bool bak = Logger.Default.verbose;

            Logger.Default.verbose = true;
            Logger.Default.WriteLine("MLP");
            PPrint();
            Logger.Default.WriteLine(String.Format("nInput {0} nHidden {1} nOutput {2}",
                                                   w1.Dim(1), w1.Dim(0), w2.Dim(0)));
            if (w1.Length() > 0 && w2.Length() > 0)
            {
                Logger.Default.WriteLine(String.Format("w1 [{0},{1}] b1 [{2},{3}]",
                                                       NarrayUtil.Min(w1), NarrayUtil.Max(w1), NarrayUtil.Min(b1), NarrayUtil.Max(b1)));
                Logger.Default.WriteLine(String.Format("w2 [{0},{1}] b2 [{2},{3}]",
                                                       NarrayUtil.Min(w2), NarrayUtil.Max(w2), NarrayUtil.Min(b2), NarrayUtil.Max(b2)));
            }
            Logger.Default.verbose = bak;
        }
Esempio n. 20
0
        public static void weighted_sample(Intarray samples, Floatarray weights, int n)
        {
            Floatarray cs = new Floatarray();

            cs.Copy(weights);
            for (int i = 1; i < cs.Length(); i++)
            {
                cs[i] += cs[i - 1];
            }
            cs /= NarrayUtil.Max(cs);
            samples.Clear();
            for (int i = 0; i < n; i++)
            {
                float value = (float)DRandomizer.Default.drand();
                int where = Binsearch(cs, value);
                samples.Push(where);
            }
        }
Esempio n. 21
0
 public Dataset8(Narray <sbyte> data, Intarray classes)
     : this()
 {
     data.Copy(data);
     classes.Copy(classes);
     if (classes.Length() > 0)
     {
         nc = NarrayUtil.Max(classes) + 1;
         nf = data.Dim(1);
         //CHECK_ARG(NarrayUtil.Min(data) > -100 && NarrayUtil.Max(data) < 100, "min(data)>-100 && max(data)<100");
         CHECK_ARG(NarrayUtil.Min(classes) >= -1 && NarrayUtil.Max(classes) < 10000, "min(classes)>=-1 && max(classes)<10000");
     }
     else
     {
         nc = 0;
         nf = -1;
     }
 }
Esempio n. 22
0
        /// <summary>
        /// Compute a classmap that maps a set of possibly sparse classes onto a dense
        /// list of new classes and vice versa
        /// </summary>
        public static void ClassMap(Intarray out_class_to_index, Intarray out_index_to_class, Intarray classes)
        {
            int      nclasses = NarrayUtil.Max(classes) + 1;
            Intarray hist     = new Intarray(nclasses);

            hist.Fill(0);
            for (int i = 0; i < classes.Length(); i++)
            {
                if (classes[i] == -1)
                {
                    continue;
                }
                hist[classes[i]]++;
            }
            int count = 0;

            for (int i = 0; i < hist.Length(); i++)
            {
                if (hist[i] > 0)
                {
                    count++;
                }
            }
            out_class_to_index.Resize(nclasses);
            out_class_to_index.Fill(-1);
            out_index_to_class.Resize(count);
            out_index_to_class.Fill(-1);
            int index = 0;

            for (int i = 0; i < hist.Length(); i++)
            {
                if (hist[i] > 0)
                {
                    out_class_to_index[i]     = index;
                    out_index_to_class[index] = i;
                    index++;
                }
            }
            CHECK_ARG(out_class_to_index.Length() == nclasses, "class_to_index.Length() == nclasses");
            CHECK_ARG(out_index_to_class.Length() == NarrayUtil.Max(out_class_to_index) + 1,
                      "index_to_class.Length() == Max(class_to_index)+1");
            CHECK_ARG(out_index_to_class.Length() <= out_class_to_index.Length(),
                      "index_to_class.Length() <= class_to_index.Length()");
        }
Esempio n. 23
0
        public static void binarize_by_range(Bytearray outa, Floatarray ina, float fraction)
        {
            float imin   = NarrayUtil.Min(ina);
            float imax   = NarrayUtil.Max(ina);
            float thresh = (int)(imin + (imax - imin) * fraction);

            outa.MakeLike(ina);
            for (int i = 0; i < ina.Length1d(); i++)
            {
                if (ina.At1d(i) > thresh)
                {
                    outa.Put1d(i, 255);
                }
                else
                {
                    outa.Put1d(i, 0);
                }
            }
        }
Esempio n. 24
0
        public override void Add(Floatarray v, int c)
        {
            CHECK_ARG(NarrayUtil.Min(v) >= 0.0f && NarrayUtil.Max(v) <= 1.0f, "float8: value out of range (0..1)");
            CHECK_ARG(c >= -1, "c>=-1");
            if (c >= nc)
            {
                nc = c + 1;
            }
            if (nf < 0)
            {
                nf = v.Length();
            }
            Narray <byte> newDataItem = data.Push(new Narray <byte>());

            Copy(newDataItem, v);
            classes.Push(c);
            CHECK_ARG(nc > 0, "nc>0");
            CHECK_ARG(nf > 0, "nf>0");
        }
Esempio n. 25
0
        public static void erase_small_components(Floatarray input, float mins = 0.2f, float thresh = 0.25f)
        {
            // compute a thresholded image for component labeling
            float    threshold  = thresh * NarrayUtil.Max(input);
            Intarray components = new Intarray();

            components.MakeLike(input);
            components.Fill(0);
            for (int i = 0; i < components.Length(); i++)
            {
                components[i] = (input[i] > threshold ? 1 : 0);
            }

            // compute the number of pixels in each component
            int      n      = ImgLabels.label_components(ref components);
            Intarray totals = new Intarray(n + 1);

            totals.Fill(0);
            for (int i = 0; i < components.Length(); i++)
            {
                totals[components[i]] = totals[components[i]] + 1;
            }
            totals[0] = 0;
            int biggest = NarrayUtil.ArgMax(totals);

            // erase small components
            float     minsize    = mins * totals[biggest];
            Bytearray keep       = new Bytearray(n + 1);
            float     background = NarrayUtil.Min(input);

            for (int i = 0; i < keep.Length(); i++)
            {
                keep[i] = (byte)(totals[i] > minsize ? 1 : 0);
            }
            for (int i = 0; i < input.Length(); i++)
            {
                if (keep[components[i]] == 0)
                {
                    input[i] = background;
                }
            }
        }
Esempio n. 26
0
        public static void segmentation_correspondences(Narray <Intarray> outsegments, Intarray seg, Intarray cseg)
        {
            if (NarrayUtil.Max(seg) >= 10000)
            {
                throw new Exception("CHECK_ARG: (max(seg)<10000)");
            }
            if (NarrayUtil.Max(cseg) >= 10000)
            {
                throw new Exception("CHECK_ARG: (max(cseg)<10000)");
            }

            int      nseg     = NarrayUtil.Max(seg) + 1;
            int      ncseg    = NarrayUtil.Max(cseg) + 1;
            Intarray overlaps = new Intarray(nseg, ncseg);

            overlaps.Fill(0);
            if (seg.Length() != cseg.Length())
            {
                throw new Exception("CHECK_ARG: (seg.Length()==cseg.Length())");
            }
            for (int i = 0; i < seg.Length(); i++)
            {
                overlaps[seg.At1d(i), cseg.At1d(i)]++;
            }
            outsegments.Clear();
            outsegments.Resize(ncseg);
            for (int i = 0; i < nseg; i++)
            {
                int j = NarrayRowUtil.RowArgMax(overlaps, i);
                if (!(j >= 0 && j < ncseg))
                {
                    throw new Exception("ASSERT: (j>=0 && j<ncseg)");
                }
                if (outsegments[j] == null)
                {
                    outsegments[j] = new Intarray();
                }
                outsegments[j].Push(i);
            }
        }
Esempio n. 27
0
        /// <summary>
        /// Compute the bounding boxes for the pixels in the image.
        /// </summary>
        public static void bounding_boxes(ref Narray <Rect> result, Intarray image)
        {
            result.Clear();
            int n = NarrayUtil.Max(image);

            if (n < 1)
            {
                return;
            }
            result.Resize(n + 1);
            result.Fill(Rect.CreateEmpty());
            for (int i = 0; i < image.Dim(0); i++)
            {
                for (int j = 0; j < image.Dim(1); j++)
                {
                    int  value = image[i, j];
                    Rect r     = result[value];
                    r.Include(i, j);
                    result[value] = r;
                    //original: result(value).include(i, j);
                }
            }
        }
Esempio n. 28
0
        private void ProcessDeleteSegment(object sender, RoutedEventArgs e)
        {
            int start = numUpDnStart.Value ?? 1;

            start = Math.Min(start, CurrSegmentsCount);

            Bytearray outgray = new Bytearray();

            SegmRoutine.rseg_to_cseg_remove(
                currBookLine.CharsegIntarray, currBookLine.CharsegIntarray,
                outgray, currBookLine.ImageBytearray, start, start);

            // пересчитаем число сегментов
            CurrSegmentsCount = NarrayUtil.Max(currBookLine.CharsegIntarray);
            // Show segmented image
            ShowCharsegImage(currBookLine.CharsegIntarray,
                             (currBookLine.HaveTranscript && CurrSegmentsCount == currBookLine.Transcript.Length) ?
                             currBookLine.Transcript : "");

            currBookLine.ImageBytearray = outgray;
            currBookLine.Image          = ImgRoutine.NarrayToRgbBitmap(outgray);
            isCurrDeletedSegment        = true;
        }
Esempio n. 29
0
 public override int nClasses()
 {
     return(NarrayUtil.Max(_classes) + 1);
 }
Esempio n. 30
0
        protected void rescale(Floatarray v, Floatarray input)
        {
            if (input.Rank() != 2)
            {
                throw new Exception("CHECK_ARG: sub.Rank()==2");
            }

            Floatarray sub = new Floatarray();
            // find the largest connected component
            // and crop to its bounding box
            // (use a binary version of the character
            // to compute the bounding box)
            Intarray components = new Intarray();
            float    threshold  = PGetf("threshold") * NarrayUtil.Max(input);

            Global.Debugf("biggestcc", "threshold {0}", threshold);
            components.MakeLike(input);
            components.Fill(0);
            for (int i = 0; i < components.Length(); i++)
            {
                components[i] = (input[i] > threshold ? 1 : 0);
            }
            int      n      = ImgLabels.label_components(ref components);
            Intarray totals = new Intarray(n + 1);

            totals.Fill(0);
            for (int i = 0; i < components.Length(); i++)
            {
                totals[components[i]]++;
            }
            totals[0] = 0;
            Narray <Rect> boxes = new Narray <Rect>();

            ImgLabels.bounding_boxes(ref boxes, components);
            int  biggest = NarrayUtil.ArgMax(totals);
            Rect r       = boxes[biggest];
            int  pad     = (int)(PGetf("pad") + 0.5f);

            r.PadBy(pad, pad);
            Global.Debugf("biggestcc", "({0}) {1}[{2}] :: {3} {4} {5} {6}",
                          n, biggest, totals[biggest],
                          r.x0, r.y0, r.x1, r.y1);

            // now perform normal feature extraction
            // (use the original grayscale input)
            sub = input;
            ImgMisc.Crop(sub, r);
            int   csize = PGeti("csize");
            float s     = Math.Max(sub.Dim(0), sub.Dim(1)) / (float)csize;

            if (PGetf("noupscale") > 0 && s < 1.0f)
            {
                s = 1.0f;
            }
            float sig = s * PGetf("aa");
            float dx  = (csize * s - sub.Dim(0)) / 2f;
            float dy  = (csize * s - sub.Dim(1)) / 2f;

            if (sig > 1e-3f)
            {
                Gauss.Gauss2d(sub, sig, sig);
            }
            v.Resize(csize, csize);
            v.Fill(0f);
            for (int i = 0; i < csize; i++)
            {
                for (int j = 0; j < csize; j++)
                {
                    float x = i * s - dx;
                    float y = j * s - dy;
                    if (x < 0 || x >= sub.Dim(0))
                    {
                        continue;
                    }
                    if (y < 0 || y >= sub.Dim(1))
                    {
                        continue;
                    }
                    float value = ImgOps.bilin(sub, x, y);
                    v[i, j] = value;
                }
            }

            /*Global.Debugf("biggestcc", "{0} {1} ({2}) -> {3} {4} ({5})",
             *     sub.Dim(0), sub.Dim(1), NarrayUtil.Max(sub),
             *     v.Dim(0), v.Dim(1), NarrayUtil.Max(v));*/
        }