Recognition.cs 12.8 KB
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace BLL
{
    /// <summary>
    /// Optical Character Recognition
    /// </summary>
    public class OCR
    {
        private PictureBox _pic;
        private bool moveImage;  //true 移动图像    false 矩形选择
        private CodeSplice.BarCode _code;
        private Tesseract.TesseractEngine eng;
        private Point oldPoint = new Point();
        private PointF codeCenter = new PointF();
        private int index;

        private Bitmap ocrRotate;                     //旋转后的图片
        private Rectangle ocrTemp;                    //临时
        private List<Rectangle> ocrRect;              //ocr红框的位置
        private List<string> ocrText;                 //ocr文本
        private bool ocrDraw = false;                 //ocr画框
        private Point ocrOffset = new Point();        //偏移

        private readonly Pen PEN_SELECT = new Pen(Color.Red, 2);
        private readonly Pen PEN_RECT = new Pen(Color.PaleVioletRed, 1);
        private readonly Pen PEN_DRAW = new Pen(Color.Black, 2);
        private readonly Font FONT = new Font("宋体", 12f);

        /// <summary>
        /// ocr识别
        /// </summary>
        /// <param name="pic"></param>
        public OCR(PictureBox pic)
        {
            try
            {
                eng = new Tesseract.TesseractEngine("./tessdata", "eng", Tesseract.EngineMode.TesseractAndCube);
            }
            catch (Exception ex)
            {
                eng = null;
                CodeSplice.Common.Log.OutError(ex.ToString());
            }

            index = -1;
            ocrRect = new List<Rectangle>();
            ocrText = new List<string>();
            _pic = pic;
            pic.MouseMove += Pic_MouseMove;
            pic.MouseDown += Pic_MouseDown;
            pic.MouseUp += Pic_MouseUp;
            pic.Paint += Pic_Paint;
            pic.Resize += Pic_Resize;
        }

        public Bitmap Image { set; get; }

        public void SetCode(CodeSplice.BarCode code)
        {
            _code = code;
            ocrOffset = new Point();
            //ocrRect.Clear();
            index = -1;
            CalcImage();
            _pic.Refresh();
        }

        public void SelectMode()
        {
            moveImage = false;
            _pic.Cursor = Cursors.Cross;
        }

        public void MoveMode()
        {
            moveImage = true;
            _pic.Cursor = Cursors.SizeAll;
        }

        public void DelSelect()
        {
            if (index > -1)
            {
                ocrRect.RemoveAt(index);
                ocrText.RemoveAt(index);
                index = -1;
                _pic.Refresh();
            }
        }

        public void DelAll()
        {
            ocrRect.Clear();
            ocrText.Clear();
            index = -1;
            _pic.Refresh();
        }

        public Rectangle[] GetRect()
        {
            Rectangle[] rect = new Rectangle[ocrRect.Count];
            for (int i = 0; i < rect.Length; i++)
            {
                rect[i] = new Rectangle(Convert.ToInt32(ocrRect[i].X - codeCenter.X), Convert.ToInt32(ocrRect[i].Y - codeCenter.Y), ocrRect[i].Width, ocrRect[i].Height);
            }
            return rect;
        }

        public void SetRect(Rectangle[] rect)
        {
            ocrRect.Clear();
            ocrText.Clear();
            for (int i = 0; i < rect.Length; i++)
            {
                rect[i].X = Convert.ToInt32(rect[i].X + codeCenter.X);
                rect[i].Y = Convert.ToInt32(rect[i].Y + codeCenter.Y);

                Bitmap bmp = new Bitmap(rect[i].Width, rect[i].Height);
                Graphics g = Graphics.FromImage(bmp);
                g.DrawImage(ocrRotate, new Rectangle(0, 0, bmp.Width, bmp.Height), rect[i], GraphicsUnit.Pixel);
                g.Save();
                g.Dispose();

                if (eng == null)
                {
                    ocrText.Add("");
                }
                else
                {
                    Tesseract.Page page = eng.Process(bmp);
                    string s = page.GetText();
                    page.Dispose();
                    ocrText.Add(s.Trim('\n'));
                }
            }
           
            ocrRect.AddRange(rect);
            _pic.Refresh();
        }






        private void CalcImage()
        {
            PointF pt = _code.Center;
            double aa = Math.Atan2(pt.Y, pt.X);
            aa = aa * 180 / Math.PI;  //转角度
            double cc = Math.Sqrt(pt.X * pt.X + pt.Y * pt.Y);
            aa += _code.Angle;
            aa = aa * Math.PI / 180;  //转弧度
            double x1 = Math.Cos(aa) * cc;
            double y1 = Math.Sin(aa) * cc;

            int w = _pic.ClientSize.Width;
            int h = _pic.ClientSize.Height;
            ocrRotate = new Bitmap(w, h);
            Graphics g = Graphics.FromImage(ocrRotate);
            codeCenter.X = w / 2f + ocrOffset.X;
            codeCenter.Y = h / 2f + ocrOffset.Y;
            float dx = Convert.ToSingle(x1 - codeCenter.X);
            float dy = Convert.ToSingle(y1 - codeCenter.Y);
            g.TranslateTransform(-dx, -dy);
            g.RotateTransform(_code.Angle);

            RectangleF src = new RectangleF(0, 0, Image.Width, Image.Height);
            g.DrawImage(Image, src, src, GraphicsUnit.Pixel);
            g.ResetTransform();
            g.DrawLine(PEN_SELECT, codeCenter.X - 10, codeCenter.Y - 10, codeCenter.X + 10, codeCenter.Y + 10);
            g.DrawLine(PEN_SELECT, codeCenter.X - 10, codeCenter.Y + 10, codeCenter.X + 10, codeCenter.Y - 10);
            g.Save();
            g.Dispose();
        }

        private void Pic_Resize(object sender, EventArgs e)
        {
        }

        private void Pic_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (moveImage)
                {
                    ocrOffset.X += e.X - oldPoint.X;
                    ocrOffset.Y += e.Y - oldPoint.Y;

                    for (int i = 0; i < ocrRect.Count; i++)
                    {
                        ocrRect[i] = new Rectangle(ocrRect[i].X + e.X - oldPoint.X, ocrRect[i].Y + e.Y - oldPoint.Y, ocrRect[i].Width, ocrRect[i].Height);
                    }
                    oldPoint = e.Location;
                    CalcImage();
                }
                else
                {
                    if (index > -1)
                    {
                        ocrRect[index] = new Rectangle(ocrRect[index].X + e.X - oldPoint.X, ocrRect[index].Y + e.Y - oldPoint.Y, ocrRect[index].Width, ocrRect[index].Height);
                        oldPoint = e.Location;
                    }
                    else
                    {
                        if (e.Location.X > oldPoint.X)
                        {
                            ocrTemp.X = oldPoint.X;
                            ocrTemp.Width = e.Location.X - oldPoint.X;
                        }
                        else
                        {
                            ocrTemp.X = e.Location.X;
                            ocrTemp.Width = oldPoint.X - e.Location.X;
                        }
                        if (e.Location.Y > oldPoint.Y)
                        {
                            ocrTemp.Y = oldPoint.Y;
                            ocrTemp.Height = e.Location.Y - oldPoint.Y;
                        }
                        else
                        {
                            ocrTemp.Y = e.Location.Y;
                            ocrTemp.Height = oldPoint.Y - e.Location.Y;
                        }
                        ocrDraw = true;
                    }
                }
                _pic.Refresh();
            }
            //else
            //{
            //    if (!moveImage)
            //    {
            //        bool find = false;
            //        for (int i = 0; i < ocrRect.Count; i++)
            //        {
            //            if (ocrRect[i].Contains(e.Location))
            //            {
            //                find = true;
            //                if (index != i)
            //                {
            //                    ocrInside = true;
            //                    index = i;
            //                    _pic.Cursor = Cursors.Hand;
            //                    _pic.Refresh();
            //                    break;
            //                }
            //            }
            //        }
            //        if (!find)
            //        {
            //            if (ocrInside)
            //            {
            //                ocrInside = false;
            //                index = -1;
            //                _pic.Cursor = Cursors.Cross;
            //                _pic.Refresh();
            //            }
            //        }
            //    }
            //}
        }

        private void Pic_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                oldPoint = e.Location;
                ocrTemp = new Rectangle(e.X, e.Y, 0, 0);

                if (!moveImage)
                {
                    bool find = false;
                    for (int i = 0; i < ocrRect.Count; i++)
                    {
                        if (ocrRect[i].Contains(e.Location))
                        {
                            find = true;
                            if (index != i)
                            {
                                index = i;
                                _pic.Cursor = Cursors.Hand;
                                _pic.Refresh();
                                break;
                            }
                        }
                    }
                    if (!find)
                    {
                        if (index > -1)
                        {
                            index = -1;
                            _pic.Cursor = Cursors.Cross;
                            _pic.Refresh();
                        }
                    }
                }
            }
        }

        private void Pic_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (ocrDraw)
                {
                    //ocr识别
                    if (ocrTemp.Width == 0 || ocrTemp.Height == 0) return;
                    ocrRect.Add(ocrTemp);
                    index = ocrRect.Count - 1;
                    ocrDraw = false;

                    Bitmap bmp = new Bitmap(ocrTemp.Width, ocrTemp.Height);
                    Graphics g = Graphics.FromImage(bmp);
                    g.DrawImage(ocrRotate, new Rectangle(0, 0, bmp.Width, bmp.Height), ocrTemp, GraphicsUnit.Pixel);
                    g.Save();
                    g.Dispose();

                    if (eng == null)
                    {
                        ocrText.Add("");
                    }
                    else
                    {
                        Tesseract.Page page = eng.Process(bmp);
                        string s = page.GetText();
                        page.Dispose();
                        ocrText.Add(s.Trim('\n'));
                    }
                }
                else if (index > -1)
                {
                    Bitmap bmp = new Bitmap(ocrRect[index].Width, ocrRect[index].Height);
                    Graphics g = Graphics.FromImage(bmp);
                    g.DrawImage(ocrRotate, new Rectangle(0, 0, bmp.Width, bmp.Height), ocrRect[index], GraphicsUnit.Pixel);
                    g.Save();
                    g.Dispose();

                    if (eng == null)
                    {
                        ocrText[index] = "";
                    }
                    else
                    {
                        Tesseract.Page page = eng.Process(bmp);
                        string s = page.GetText();
                        page.Dispose();
                        ocrText[index] = s.Trim('\n');
                    }
                }
                _pic.Refresh();
            }
        }

        private void Pic_Paint(object sender, PaintEventArgs e)
        {
            if (ocrRotate == null) return;
            e.Graphics.DrawImage(ocrRotate, 0, 0);

            for (int i = 0; i < ocrRect.Count; i++)
            {
                e.Graphics.DrawRectangle(i == index ? PEN_SELECT : PEN_RECT, ocrRect[i]);
                SizeF sf = e.Graphics.MeasureString(ocrText[i], FONT);
                e.Graphics.FillRectangle(Brushes.White, ocrRect[i].X, ocrRect[i].Bottom, sf.Width, sf.Height);     //白色背景
                e.Graphics.DrawString(ocrText[i], FONT, Brushes.Red, ocrRect[i].X, ocrRect[i].Bottom);             //红色文本
            }

            if (ocrDraw)
                e.Graphics.DrawRectangle(PEN_DRAW, ocrTemp);

        }

    }
}