FrmCodeOCR.cs 14.6 KB
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using Model;
using System.Windows.Forms;
using Newtonsoft.Json;
using BLL;
using System.Drawing.Imaging;

namespace SmartScan
{
    public partial class FrmCodeOCR : Asa.FaceControl.FaceFormFixed
    {
        public readonly List<MaterialCodeOCR> codeOcr = null;
        public readonly List<MaterialCodeMatch> codeMatch = null;

        private readonly MaterialCode mateCode = null;
        private readonly Bitmap codeImage = null;
        private PointF codeCenter = new();
        private Bitmap ocrRotate;                     //旋转后的图片
        private Point ocrOffset = new();        //偏移
        private readonly List<Rectangle> ocrRect = new();              //ocr红框的位置
        //private readonly List<string> ocrText = new();                 //ocr文本
        //private readonly List<string> ocrMode = new();
        //private readonly List<int> ocrIndex = new();
        private Point oldPoint = new();
        private bool moveImage;  //true 移动图像    false 矩形选择
        private bool ocrDraw = false;                 //ocr画框
        private Rectangle ocrTemp;                    //临时
        private int ocrRectIndex = -1;

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

        public FrmCodeOCR()
        {
            InitializeComponent();
            PicImage.Paint += PicImage_Paint;
            PicImage.MouseUp += PicImage_MouseUp;
            PicImage.MouseDown += PicImage_MouseDown;
            PicImage.MouseMove += PicImage_MouseMove;
        }

        string ocrStr = "";
        public FrmCodeOCR(MaterialCode code, List<MaterialCodeOCR> ocr, List<MaterialCodeMatch> matchAll, Bitmap bmp) : this()
        {
            mateCode = code;
            codeOcr = new();
            for (int i = 0; i < ocr.Count; i++)
                codeOcr.Add(ocr[i].Clone());
            codeMatch = new();
            for (int i = 0; i < matchAll.Count; i++)
            {
                if (codeOcr.FindIndex(s => s.ID == matchAll[i].CodeID) > -1)
                    codeMatch.Add(matchAll[i].Clone());
            }

            codeImage = bmp;
            ocrOffset = new Point();
            ocrRect.Clear();
            ocrRectIndex = -1;
            CalcImage();
            PicImage.Refresh();
            //codeImage?.Save("ocrt.jpg",ImageFormat.Jpeg);
            //ocrStr = getOcrString();
            for (int i = 0; i < codeOcr.Count; i++)
            {
                MaterialCodeOCR ocrTemp = codeOcr[i];
                int x = Convert.ToInt32(ocrTemp.OffsetX + codeCenter.X);
                int y = Convert.ToInt32(ocrTemp.OffsetY + codeCenter.Y);
                ocrRect.Add(new Rectangle(x, y, ocrTemp.Width, ocrTemp.Height));
                codeOcr[i].Text = GetOcrString(ocrRect[i]);
            }

            PicImage.Refresh();
        }


        private string GetOcrString(Rectangle rect)
        {
            Bitmap bmpTemp = new(rect.Width, rect.Height);
            Graphics g = Graphics.FromImage(bmpTemp);
            Rectangle destRect = new(new Point(), rect.Size);
            g.DrawImage(ocrRotate, destRect, rect, GraphicsUnit.Pixel);
            g.Save();
            g.Dispose();
            bmpTemp.Save("ocrt.jpg");
            bmpTemp.Dispose();
            string codeOcr = getOcrString();

            return codeOcr;
        }

        private string FormatCode(int index)
        {
            if (codeOcr.Count <= index) return "";
            string text = codeOcr[index].Text;
            List<string> arr = new();
            for (int i = 0; i < codeMatch.Count; i++)
            {
                if (codeOcr[index].ID == codeMatch[i].CodeID)
                    arr.Add(codeMatch[i].Keyword);
            }
            if (arr.Count > 0)
                text += " [" + string.Join(",", arr) + "]";
            return text;
        }

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

            int w = PicImage.ClientSize.Width;
            int h = PicImage.ClientSize.Height;
            ocrRotate = new(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(mateCode.Angle);

            RectangleF src = new(0, 0, codeImage.Width, codeImage.Height);
            g.DrawImage(codeImage, src, src, GraphicsUnit.Pixel);
            g.ResetTransform();
            codeCenter.X -= mateCode.Width / 2;
            //codeCenter.Y += mateCode.Height / 4;

            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 PicImage_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 == ocrRectIndex ? PEN_SELECT : PEN_RECT, ocrRect[i]);

                string s = FormatCode(i);
                //if (ocrMode[i].Length > 0)
                //    s += string.Format(" [{0}]", ocrMode[i]);
                SizeF sf = e.Graphics.MeasureString(s, FONT);
                e.Graphics.FillRectangle(Brushes.White, ocrRect[i].X, ocrRect[i].Bottom, sf.Width, sf.Height);     //白色背景
                e.Graphics.DrawString(s, FONT, Brushes.Red, ocrRect[i].X, ocrRect[i].Bottom);             //红色文本
            }

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

        }

        private void PicImage_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (ocrDraw)  //画框后识别
                {
                    //ocr识别
                    if (ocrTemp.Width == 0 || ocrTemp.Height == 0) return;
                    ocrRect.Add(ocrTemp);
                    ocrRectIndex = ocrRect.Count - 1;
                    ocrDraw = false;
                    string s = GetOcrString(ocrTemp);
                    PicImage.Cursor = Cursors.Cross;

                    MaterialCodeOCR ocr = new()
                    {
                        CodeID = mateCode.ID,
                        ID = ++Common.mateMaxCodeID,
                        Text = s.Replace(";", "\r\n")
                    };
                    ocr.OffsetX = ocrTemp.X - codeCenter.X;
                    ocr.OffsetY = ocrTemp.Y - codeCenter.Y;
                    ocr.Width = ocrTemp.Width;
                    ocr.Height = ocrTemp.Height;
                    codeOcr.Add(ocr);

                }
                else if (ocrRectIndex > -1 && !moveImage)
                {
                    Bitmap bmp = new(ocrRect[ocrRectIndex].Width, ocrRect[ocrRectIndex].Height);
                    Graphics g = Graphics.FromImage(bmp);
                    g.DrawImage(ocrRotate, new Rectangle(0, 0, bmp.Width, bmp.Height), ocrRect[ocrRectIndex], GraphicsUnit.Pixel);
                    g.Save();
                    g.Dispose();
                    bmp.Save("ocrt.jpg");
                    bmp.Dispose();

                    string codeOcrs = getOcrString();

                    codeOcr[ocrRectIndex].Text = codeOcrs;
                    codeOcr[ocrRectIndex].OffsetX = ocrRect[ocrRectIndex].X - codeCenter.X;
                    codeOcr[ocrRectIndex].OffsetY = ocrRect[ocrRectIndex].Y - codeCenter.Y;
                    PicImage.Cursor = Cursors.Cross;
                    //_ocr[ocrIndex[codeOcrIndex]].Offset = new Point(Convert.ToInt32(ocrRect[codeOcrIndex].X - codeCenter.X), Convert.ToInt32(ocrRect[codeOcrIndex].Y - codeCenter.Y));
                }

                PicImage.Refresh();
            }
        }
        string getOcrString()
        {
            string codeOcrs = "";
           // if (Config.UsePaddleOCR)
            {
                codeOcrs = PaddleOCRHelper.StartTest("..\\ocrt.jpg");
            }
            //else
            //{
            //    var resp = Common.mateEdit.namedPipeClient.Request("..\\ocrt.jpg");
            //    var lp = JsonConvert.DeserializeObject<List<TextBlock>>(resp);
            //    double maxbox = 0;
            //    foreach (var l in lp)
            //    {
            //        var boxa = l.CalculateArea(l.BoxPoints);
            //        if (boxa > maxbox)
            //        {
            //            maxbox = boxa;
            //            codeOcrs = l.Text;
            //        }
            //    }
            //}
            return codeOcrs;
        }
        private void PicImage_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 (ocrRectIndex != i)
                            {
                                ocrRectIndex = i;
                                PicImage.Cursor = Cursors.Hand;
                                PicImage.Refresh();
                                break;
                            }
                        }
                    }
                    if (!find)
                    {
                        if (ocrRectIndex > -1)
                        {
                            ocrRectIndex = -1;
                            PicImage.Cursor = Cursors.Cross;
                            PicImage.Refresh();
                        }
                    }
                }
            }
        }

        private void PicImage_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;

            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 (ocrRectIndex > -1)
                {
                    ocrRect[ocrRectIndex] = new Rectangle(ocrRect[ocrRectIndex].X + e.X - oldPoint.X, ocrRect[ocrRectIndex].Y + e.Y - oldPoint.Y, ocrRect[ocrRectIndex].Width, ocrRect[ocrRectIndex].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;
                }
            }
            PicImage.Refresh();

        }

        private void BtnSelect_Click(object sender, EventArgs e)
        {
            moveImage = false;
            BtnSelect.HoldPress = true;
            BtnMove.HoldPress = false;
            PicImage.Cursor = Cursors.Cross;
        }

        private void BtnMove_Click(object sender, EventArgs e)
        {
            moveImage = true;
            BtnSelect.HoldPress = false;
            BtnMove.HoldPress = true;
            PicImage.Cursor = Cursors.SizeAll;
        }

        private void BtnDel_Click(object sender, EventArgs e)
        {
            if (ocrRectIndex > -1)
            {
                codeOcr.RemoveAt(ocrRectIndex);
                ocrRect.RemoveAt(ocrRectIndex);
                //ocrText.RemoveAt(ocrRectIndex);
                //ocrMode.RemoveAt(ocrRectIndex);
                //ocrIndex.RemoveAt(ocrRectIndex);
                ocrRectIndex = -1;
                PicImage.Refresh();

                //string ss = AnalyzeCode(LstCode.SelectedIndex, newMate.LabelRect[labelIndex].Code[codeIndex], labelIndex);
                //LstCode.Items(LstCode.SelectedIndex, ss);
            }
        }

        private void BtnKey_Click(object sender, EventArgs e)
        {
            if (ocrRectIndex == -1) return;
            List<MaterialCodeMatch> match = codeMatch.FindAll(s => s.CodeID == codeOcr[ocrRectIndex].ID);
            FrmCodeExtract frm = new(codeOcr[ocrRectIndex].Text, codeOcr[ocrRectIndex].ID, "OCR", match);//codeOcr[ocrRectIndex].Text
            DialogResult dr = frm.ShowDialog();
            if (dr == DialogResult.OK)
            {
                codeMatch.RemoveAll(s => s.CodeID == codeOcr[ocrRectIndex].ID);
                codeMatch.AddRange(frm.CodeMatch);
                Refresh();
            }
        }

        private void BtnOK_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.OK;
        }

        private void BtnCancel_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
        }
    }
}