private void RunOCR(Bitmap sourceImage)
        {
            this.sourceImagePV.Image = sourceImage;

            Bitmap bw = ImageUtil.ToBlackAndWhite(sourceImage);

            this.bwImagePV.Image = bw;
            Bitmap rotBw = ImageUtil.RotateCounterClockwise(bw);

            this.rotBwImagePV.Image = rotBw;

            var horizOptions = RecognitionOptions.HorizontalOptions();

            horizOptions.imageWidth  = bw.Width;
            horizOptions.imageHeight = bw.Height;

            var vertOptions = RecognitionOptions.VerticalOptions();

            vertOptions.imageWidth  = rotBw.Width;
            vertOptions.imageHeight = rotBw.Height;

            List <Point> horizEdgePoints = EdgePointExtraction.ExtractEdgePoints(bw);

            this.edgePointsPV.Image = EdgePointExtraction.DrawPoints(bw, horizEdgePoints);
            int[,] horizHough       = PseudoHoughTransform.HoughTransform(horizEdgePoints, horizOptions);
            List <Point>   horizHoughPeaks      = PseudoHoughTransform.FindHoughPeaks(horizHough, horizOptions);
            Bitmap         horizHoughPlainImage = PseudoHoughTransform.HoughTransformImage(horizHough);
            Bitmap         horizHoughImage      = PseudoHoughTransform.HoughTransformImageWithPeaks(horizHough, horizHoughPeaks);
            List <RawLine> horizRawLines        = PseudoHoughTransform.ExtractRawLines(horizHoughPeaks, horizOptions);
            List <Line>    horizLines           = LineFilter.FilterLines(horizEdgePoints, horizRawLines, horizOptions);

            List <Point> vertEdgePoints = EdgePointExtraction.ExtractEdgePoints(rotBw);

            this.rotEdgePointsPV.Image = EdgePointExtraction.DrawPoints(rotBw, vertEdgePoints);
            int[,] vertHough           = PseudoHoughTransform.HoughTransform(vertEdgePoints, vertOptions);
            List <Point>   vertHoughPeaks      = PseudoHoughTransform.FindHoughPeaks(vertHough, vertOptions);
            Bitmap         vertHoughPlainImage = PseudoHoughTransform.HoughTransformImage(vertHough);
            Bitmap         vertHoughImage      = PseudoHoughTransform.HoughTransformImageWithPeaks(vertHough, vertHoughPeaks);
            List <RawLine> vertRawLines        = PseudoHoughTransform.ExtractRawLines(vertHoughPeaks, vertOptions);

            this.cyclicPatternsPV.Image = CyclicPatternDetector.CyclicPatternsInLines(vertEdgePoints, vertRawLines, vertOptions);

            RecognitionOptions vertNoFilterOptions = vertOptions;

            vertNoFilterOptions.detectCyclicPatterns = false;
            List <Line> vertUnfilteredLines = LineFilter.FilterLines(vertEdgePoints, vertRawLines, vertNoFilterOptions);
            List <Line> vertLines           = LineFilter.FilterLines(vertEdgePoints, vertRawLines, vertOptions);

            Bitmap rawLinesImage      = DrawLines(bw, horizLines, vertUnfilteredLines, 2);
            Bitmap filteredLinesImage = DrawLines(bw, horizLines, vertLines, 4);

            this.filteredLinesPV.Image = filteredLinesImage;

            this.houghPV.Image = ImageUtil.VerticalConcat(new List <Bitmap> {
                ImageUtil.HorizontalConcat(new List <Bitmap> {
                    rawLinesImage, horizHoughImage, horizHoughPlainImage
                }),
                ImageUtil.RotateClockwise(vertHoughImage),
                ImageUtil.RotateClockwise(vertHoughPlainImage)
            });

            var    lnorm = new LineNormalization(horizLines, vertLines, sourceImage);
            Bitmap normalizedLinesImage = DrawLines(bw, lnorm.normHorizLines, lnorm.normVertLines, 2);

            this.normalizedLinesPV.Image = normalizedLinesImage;
            var    tb = TableBuilder.NewBuilder(lnorm, new None <List <double> >());
            Bitmap tableRecognitionImage = tb.DebugImage(bw);

            this.tableRecognitionPV.Image = tableRecognitionImage;
            Option <Table> recognizedTable = tb.table;

            recognizedTable.ForEach(table => {
                Bitmap recognizedTableImage = new Bitmap(bw);
                Graphics g = Graphics.FromImage(recognizedTableImage);
                table.DrawTable(g, new Pen(Color.Red, 2));
                g.Dispose();
                this.recognizedTablePV.Image = recognizedTableImage;
            });
            if (recognizedTable.IsEmpty())
            {
                Console.WriteLine("no table was recognized");
            }

            this.recognizedTablePV.AddDoubleClickListener((pt, e) => {
                recognizedTable.ForEach(table => {
                    table.GetCellAtPoint(pt.X, pt.Y).ForEach(cell => {
                        table.GetCellImage(bw, cell.X, cell.Y).ForEach(cellImage => {
                            new GradeRecognitionDebugView(cellImage, "<gen>").ShowDialog();
                        });
                    });
                });
            });
        }