PaddleSharpAPI.cs 11.3 KB
using log4net;
using log4net.Util;
using PaddleOCRSharp;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace paddleOCR
{
    internal class PaddleSharpAPI
    {
        static PaddleOCREngine engine;
        static string baseDir = ".\\LabelOut\\";

        public static void Init()
        {
            //自带轻量版中英文模型V3模型
            OCRModelConfig config = null;

            //服务器中英文模型
            //OCRModelConfig config = new OCRModelConfig();
            //string root = System.IO.Path.GetDirectoryName(typeof(OCRModelConfig).Assembly.Location);
            //string modelPathroot = root + @"\inferenceserver";
            //config.det_infer = modelPathroot + @"\ch_ppocr_server_v2.0_det_infer";
            //config.cls_infer = modelPathroot + @"\ch_ppocr_mobile_v2.0_cls_infer";
            //config.rec_infer = modelPathroot + @"\ch_ppocr_server_v2.0_rec_infer";
            //config.keys = modelPathroot + @"\ppocr_keys.txt";

            //英文和数字模型V3
            //OCRModelConfig config = new OCRModelConfig();
            //string root = System.IO.Path.GetDirectoryName(typeof(OCRModelConfig).Assembly.Location);
            //string modelPathroot = root + @"\en_v3";
            //config.det_infer = modelPathroot + @"\en_PP-OCRv3_det_infer";
            //config.cls_infer = modelPathroot + @"\ch_ppocr_mobile_v2.0_cls_infer";
            //config.rec_infer = modelPathroot + @"\en_PP-OCRv3_rec_infer";
            //config.keys = modelPathroot + @"\en_dict.txt";


            //OCR参数
            OCRParameter oCRParameter = new OCRParameter();
            oCRParameter.numThread = 6;//预测并发线程数
            oCRParameter.Enable_mkldnn = true;//web部署该值建议设置为0,否则出错,内存如果使用很大,建议该值也设置为0.
            oCRParameter.cls = false; //是否执行文字方向分类;默认false
            oCRParameter.det = true;//是否开启方向检测,用于检测识别180旋转
            oCRParameter.use_angle_cls = true;//是否开启方向检测,用于检测识别180旋转
            oCRParameter.det_db_score_mode = true;//是否使用多段线,即文字区域是用多段线还是用矩形,
            oCRParameter.UnClipRatio = 1.6f;
            oCRParameter.MaxSideLen = 960;
            //初始化OCR引擎
            engine = new PaddleOCREngine(config, oCRParameter);

        }
        static ILog log = VisionAPI.log;
        static System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        public static bool OCRHandle(string imgPath, out string result)
        {
            result = "";
            sw.Restart();
            if (string.IsNullOrEmpty(imgPath))
            {
                return false;
            }
            if (Directory.Exists(baseDir))
            {
                Directory.Delete(baseDir, true);
            }
            Directory.CreateDirectory(baseDir);


            EyemImage image = new EyemImage();
            EyemImage tpDstImg = new EyemImage();
            int flag;
            log.Info($"准备读取图像:{imgPath}");
            flag = VisionAPI.eyemImageRead(imgPath, -1, out image);
            log.Info($"读取图像:{imgPath},rtnCode={flag}");
            ///实例分割
            ///
            {
                RotateBox container = new RotateBox();
                flag = VisionAPI.eyemNNInstanceSegment(image, 0.15f, ref container, out tpDstImg);
                log.Info($"标签分割完成,rtncode={flag}");
                Bitmap b = VisionAPI.eyemCvtToBitmap(tpDstImg);
                log.Info($"转换为Bitmap");
                b?.Save($"labelSplit.jpg", ImageFormat.Jpeg);
                log.Info($"保存分割结果图:labelSplit.jpg");
                VisionAPI.eyemImageFree(ref tpDstImg);
                for (int i = 0; i < 25; i++)
                {

                    EyemImage tpDstImg1 = new EyemImage();
                    if (i < container.p1.Length && container.p1[i].iX != 0)
                    {
                        flag = VisionAPI.eyemAchvRotateImage(image, container.p1[i], container.p2[i], container.p3[i], container.p4[i], out tpDstImg1);
                        //if (flag == 0)
                        {
                            if (!Directory.Exists($"{baseDir}label{i}"))
                                Directory.CreateDirectory($"{baseDir}label{i}");
                            Bitmap lbl = VisionAPI.eyemCvtToBitmap(tpDstImg1);
                            lbl?.Save($"{baseDir}label{i}\\1.jpg", ImageFormat.Jpeg);
                            lbl?.RotateFlip(RotateFlipType.Rotate180FlipNone);
                            lbl?.Save($"{baseDir}label{i}\\2.jpg", ImageFormat.Jpeg);
                            log.Info($"获取标签图像并保存:{baseDir}label{i}");
                        }
                        VisionAPI.eyemImageFree(ref tpDstImg1);
                    }

                }
                VisionAPI.eyemImageFree(ref image);
            }
            log.Info($"分隔标签耗时:{sw.ElapsedMilliseconds}ms");
            sw.Restart();
            DirectoryInfo directoryInfo = new DirectoryInfo(baseDir);
            var files = directoryInfo.GetDirectories();
            if (files != null && files.Length == 0)
            {
                if (!Directory.Exists($"{baseDir}label"))
                    Directory.CreateDirectory($"{baseDir}label");
                log.Info($"无分割的标签,将原图传入名为label.jpg");
                byte[] bytes;
                using (FileStream fs = new FileStream(imgPath, FileMode.Open))
                {
                    bytes = new byte[fs.Length];
                    fs.Read(bytes, 0, bytes.Length);
                }
                MemoryStream memoryStream = new MemoryStream(bytes);
                Bitmap bitmap = new Bitmap(memoryStream);
                bitmap.Save($"{baseDir}label\\label.jpg");
            }
            log.Info($"开始OCR识别");
            StringBuilder stringBuilder = new StringBuilder();
            foreach (var dir in directoryInfo.GetDirectories())
            {
                float maxScore = 0f;
                List<TextBlock> list = new List<TextBlock>();
                foreach (var item in dir.GetFiles())
                {
                    float score = 0f;
                    var imagebyte = File.ReadAllBytes(item.FullName);
                    var res = engine.DetectText(imagebyte);
                    StringBuilder sb = new StringBuilder();
                    res.TextBlocks.ForEach(s => { score += s.Score; sb.AppendLine(s.Text); });
                    log.Info($"【{item.FullName}】识别结果:【{score}】【{sb.ToString().Replace("\r", "").Replace("\n", ";")}】");
                    if (score > maxScore)
                    {
                        maxScore = score;
                        list = res.TextBlocks;
                    }
                }
                log.Info($"使用识别分数【{maxScore}】");
                Dictionary<int, List<TextBlock>> lines = new Dictionary<int, List<TextBlock>>();
                int line = 0, idx = 0, i = 1;
                while (idx < list.Count)
                {
                    while (i < list.Count)
                    {
                        if (IsInSameLine(list[idx], list[i]))
                        {
                            if (lines.ContainsKey(line))
                            {
                                lines[line].Add(list[i]);
                            }
                            else
                            {
                                lines.Add(line, new List<TextBlock> { list[i] });
                            }
                            i++;
                        }
                        else
                        {
                            if (lines.ContainsKey(line))
                            {
                                lines[line].Add(list[idx]);
                            }
                            else
                            {
                                lines[line] = new List<TextBlock> { list[idx] };
                            }
                            line++;
                            idx = i;
                            i++;
                        }
                    }
                    if (i >= list.Count)
                    {
                        if (lines.ContainsKey(line))
                        {
                            lines[line].Add(list[idx]);
                        }
                        else
                        {
                            lines[line] = new List<TextBlock> { list[idx] };
                        }
                        break;
                    }


                }
                foreach (var lineTxt in lines)
                {
                    lineTxt.Value.Sort(delegate (TextBlock x1, TextBlock x2) { if (x1.BoxPoints[0].X > x2.BoxPoints[0].X) return 1; else return -1; });
                    foreach (var text in lineTxt.Value)
                    {
                        log.Info($"行{lineTxt.Key}【{text.BoxPoints[0]}】【{text.BoxPoints[3]}】【{text.Text}】");
                        stringBuilder.Append(text.Text);
                    }
                    stringBuilder.AppendLine();
                }
            }
            log.Info($"OCR识别完成");
            sw.Stop();
            log.Info("识别耗时:" + sw.ElapsedMilliseconds.ToString() + "ms");
            string[] strs = stringBuilder.ToString().Replace(":\r", ":").Replace("\r", "").Split('\n');
            foreach (string str in strs)
            {
                if (string.IsNullOrEmpty(str)) continue;
                result += str + ";";
            }
            if (result.EndsWith(";"))
            {
                result = result.Substring(0, result.Length - 1);
            }
            log.Info("识别结果:" + result);
            return true;
        }
        /// <summary>
        /// 同一行间隔小于多少像素可以合并
        /// </summary>
        //int intervalPixel = ConfigHelper.Config.Get("IntervalPixelInSameLine", 60);
        static bool IsInSameLine(TextBlock t1, TextBlock t2)
        {
            //同一行间隔小于多少像素可以合并
            int intervalPixel = ConfigHelper.Config.Get("IntervalPixelInSameLine", 60);
            int p1y1 = t1.BoxPoints[0].Y;
            int p1y2 = t1.BoxPoints[3].Y;

            int p2y1 = t2.BoxPoints[0].Y;
            int p2y2 = t2.BoxPoints[3].Y;

            int p1x0 = t1.BoxPoints[0].X;
            int p1x1 = t1.BoxPoints[1].X;
            int p2x0 = t2.BoxPoints[0].X;
            int p2x1 = t2.BoxPoints[1].X;
            if (p1y1 > p2y2 || p1y2 < p2y1) { return false; }
            else
            {
                if(p1x0<p2x0)//t1在左侧
                {
                    if (Math.Abs(p1x1 - p2x0) > intervalPixel) return false;
                    else
                        return true;
                }
                else
                {
                    if (Math.Abs(p2x1 - p1x0) > intervalPixel) return false;
                    else
                        return true;
                }

            }
        }
    }
}