├── .gitignore ├── OcrLib ├── AngleNet.cs ├── CrnnNet.cs ├── DbNet.cs ├── OcrLib.csproj ├── OcrLite.cs ├── OcrResult.cs ├── OcrUtils.cs ├── Properties │ └── AssemblyInfo.cs ├── ScaleParam.cs └── packages.config ├── OcrOnnxForm ├── App.config ├── FormOcr.Designer.cs ├── FormOcr.cs ├── FormOcr.resx ├── OcrOnnxForm.csproj ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings └── packages.config ├── README.md └── RapidOcrOnnxCs.sln /.gitignore: -------------------------------------------------------------------------------- 1 | /.svn/entries 2 | .svn 3 | ## Ignore Visual Studio temporary files, build results, and 4 | ## files generated by popular Visual Studio add-ons. 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.sln.docstates 10 | 11 | # Build results 12 | 13 | [Dd]ebug/ 14 | [Rr]elease/ 15 | x64/ 16 | build/ 17 | [Bb]in/ 18 | [Oo]bj/ 19 | 20 | # MSTest test Results 21 | [Tt]est[Rr]esult*/ 22 | [Bb]uild[Ll]og.* 23 | 24 | *_i.c 25 | *_p.c 26 | *.ilk 27 | *.meta 28 | *.obj 29 | *.pch 30 | *.pdb 31 | *.pgc 32 | *.pgd 33 | *.rsp 34 | *.sbr 35 | *.tlb 36 | *.tli 37 | *.tlh 38 | *.tmp 39 | *.tmp_proj 40 | *.log 41 | *.vspscc 42 | *.vssscc 43 | .builds 44 | *.pidb 45 | *.log 46 | *.scc 47 | 48 | # Visual C++ cache files 49 | ipch/ 50 | *.aps 51 | *.ncb 52 | *.opensdf 53 | *.sdf 54 | *.cachefile 55 | 56 | # Visual Studio profiler 57 | *.psess 58 | *.vsp 59 | *.vspx 60 | 61 | # Guidance Automation Toolkit 62 | *.gpState 63 | 64 | # ReSharper is a .NET coding add-in 65 | _ReSharper*/ 66 | *.[Rr]e[Ss]harper 67 | 68 | # TeamCity is a build add-in 69 | _TeamCity* 70 | 71 | # DotCover is a Code Coverage Tool 72 | *.dotCover 73 | 74 | # NCrunch 75 | *.ncrunch* 76 | .*crunch*.local.xml 77 | 78 | # Installshield output folder 79 | [Ee]xpress/ 80 | 81 | # DocProject is a documentation generator add-in 82 | DocProject/buildhelp/ 83 | DocProject/Help/*.HxT 84 | DocProject/Help/*.HxC 85 | DocProject/Help/*.hhc 86 | DocProject/Help/*.hhk 87 | DocProject/Help/*.hhp 88 | DocProject/Help/Html2 89 | DocProject/Help/html 90 | 91 | # Click-Once directory 92 | publish/ 93 | 94 | # Publish Web Output 95 | *.Publish.xml 96 | *.pubxml 97 | 98 | # NuGet Packages Directory 99 | # Enable nuget packages restore when building 100 | !packages/ 101 | packages/* 102 | !packages/repositories.config 103 | 104 | # Windows Azure Build Output 105 | csx 106 | *.build.csdef 107 | 108 | # Windows Store app package directory 109 | AppPackages/ 110 | 111 | # Others 112 | sql/ 113 | *.Cache 114 | ClientBin/ 115 | [Ss]tyle[Cc]op.* 116 | ~$* 117 | *~ 118 | *.dbmdl 119 | *.[Pp]ublish.xml 120 | *.pfx 121 | *.publishsettings 122 | 123 | # RIA/Silverlight projects 124 | Generated_Code/ 125 | 126 | #Visual Studio LightSwitch 127 | _Pvt_Extensions/ 128 | GeneratedArtifacts/ 129 | ServiceConfiguration.cscfg 130 | ModelManifest.xml 131 | generated.parameters.xml 132 | ## TODO: Comment the next line if you want version controls the generated client .xap file 133 | *.Client.xap 134 | 135 | # Backup & report files from converting an old project file to a newer 136 | # Visual Studio version. Backup files are not needed, because we have git ;-) 137 | _UpgradeReport_Files/ 138 | Backup*/ 139 | UpgradeLog*.XML 140 | UpgradeLog*.htm 141 | 142 | # SQL Server files 143 | App_Data/*.mdf 144 | App_Data/*.ldf 145 | 146 | # ========================= 147 | # Windows detritus 148 | # ========================= 149 | 150 | # Windows image file caches 151 | Thumbs.db 152 | ehthumbs.db 153 | 154 | # Folder config file 155 | Desktop.ini 156 | 157 | # Recycle Bin used on file shares 158 | $RECYCLE.BIN/ 159 | 160 | # Mac crap 161 | .DS_Store 162 | 163 | # VisualStudioCode 164 | .vs 165 | -------------------------------------------------------------------------------- /OcrLib/AngleNet.cs: -------------------------------------------------------------------------------- 1 | using Emgu.CV; 2 | using Emgu.CV.CvEnum; 3 | using Emgu.CV.Structure; 4 | using Microsoft.ML.OnnxRuntime; 5 | using Microsoft.ML.OnnxRuntime.Tensors; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Drawing; 9 | using System.Linq; 10 | 11 | namespace OcrLiteLib 12 | { 13 | class AngleNet 14 | { 15 | private readonly float[] MeanValues = { 127.5F, 127.5F, 127.5F }; 16 | private readonly float[] NormValues = { 1.0F / 127.5F, 1.0F / 127.5F, 1.0F / 127.5F }; 17 | private const int angleDstWidth = 192; 18 | private const int angleDstHeight = 48; 19 | private const int angleCols = 2; 20 | private InferenceSession angleNet; 21 | private List inputNames; 22 | 23 | public AngleNet() { } 24 | 25 | ~AngleNet() 26 | { 27 | angleNet.Dispose(); 28 | } 29 | 30 | public void InitModel(string path, int numThread) 31 | { 32 | try 33 | { 34 | SessionOptions op = new SessionOptions(); 35 | op.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_EXTENDED; 36 | op.InterOpNumThreads = numThread; 37 | op.IntraOpNumThreads = numThread; 38 | angleNet = new InferenceSession(path, op); 39 | inputNames = angleNet.InputMetadata.Keys.ToList(); 40 | } 41 | catch (Exception ex) 42 | { 43 | Console.WriteLine(ex.Message + ex.StackTrace); 44 | throw ex; 45 | } 46 | } 47 | 48 | public List GetAngles(List partImgs, bool doAngle, bool mostAngle) 49 | { 50 | List angles = new List(); 51 | if (doAngle) 52 | { 53 | for (int i = 0; i < partImgs.Count; i++) 54 | { 55 | var startTicks = DateTime.Now.Ticks; 56 | var angle = GetAngle(partImgs[i]); 57 | var endTicks = DateTime.Now.Ticks; 58 | var angleTime = (endTicks - startTicks) / 10000F; 59 | angle.Time = angleTime; 60 | angles.Add(angle); 61 | } 62 | } 63 | else 64 | { 65 | for (int i = 0; i < partImgs.Count; i++) 66 | { 67 | var angle = new Angle(); 68 | angle.Index = -1; 69 | angle.Score = 0F; 70 | angles.Add(angle); 71 | } 72 | } 73 | //Most Possible AngleIndex 74 | if (doAngle && mostAngle) 75 | { 76 | List angleIndexes = new List(); 77 | angles.ForEach(x => angleIndexes.Add(x.Index)); 78 | 79 | double sum = angleIndexes.Sum(); 80 | double halfPercent = angles.Count / 2.0f; 81 | int mostAngleIndex; 82 | if (sum < halfPercent) 83 | {//all angle set to 0 84 | mostAngleIndex = 0; 85 | } 86 | else 87 | {//all angle set to 1 88 | mostAngleIndex = 1; 89 | } 90 | Console.WriteLine($"Set All Angle to mostAngleIndex({mostAngleIndex})"); 91 | for (int i = 0; i < angles.Count; ++i) 92 | { 93 | Angle angle = angles[i]; 94 | angle.Index = mostAngleIndex; 95 | angles[i] = angle; 96 | } 97 | } 98 | return angles; 99 | } 100 | 101 | private Angle GetAngle(Mat src) 102 | { 103 | Angle angle = new Angle(); 104 | Mat angleImg = new Mat(); 105 | CvInvoke.Resize(src, angleImg, new Size(angleDstWidth, angleDstHeight)); 106 | Tensor inputTensors = OcrUtils.SubstractMeanNormalize(angleImg, MeanValues, NormValues); 107 | var inputs = new List 108 | { 109 | NamedOnnxValue.CreateFromTensor(inputNames[0], inputTensors) 110 | }; 111 | try 112 | { 113 | using (IDisposableReadOnlyCollection results = angleNet.Run(inputs)) 114 | { 115 | var resultsArray = results.ToArray(); 116 | Console.WriteLine(resultsArray); 117 | float[] outputData = resultsArray[0].AsEnumerable().ToArray(); 118 | return ScoreToAngle(outputData, angleCols); 119 | } 120 | } 121 | catch (Exception ex) 122 | { 123 | Console.WriteLine(ex.Message + ex.StackTrace); 124 | //throw ex; 125 | } 126 | return angle; 127 | 128 | } 129 | 130 | private Angle ScoreToAngle(float[] srcData, int angleCols) 131 | { 132 | Angle angle = new Angle(); 133 | int angleIndex = 0; 134 | float maxValue = -1000.0F; 135 | for (int i = 0; i < angleCols; i++) 136 | { 137 | if (i == 0) maxValue = srcData[i]; 138 | else if (srcData[i] > maxValue) 139 | { 140 | angleIndex = i; 141 | maxValue = srcData[i]; 142 | } 143 | } 144 | angle.Index = angleIndex; 145 | angle.Score = maxValue; 146 | return angle; 147 | } 148 | 149 | private Mat AdjustTargetImg(Mat src, int dstWidth, int dstHeight) 150 | { 151 | Mat srcResize = new Mat(); 152 | float scale = (float)dstHeight / (float)src.Rows; 153 | int angleWidth = (int)((float)src.Cols * scale); 154 | CvInvoke.Resize(src, srcResize, new Size(angleWidth, dstHeight)); 155 | Mat srcFit = new Mat(dstHeight, dstWidth, DepthType.Cv8U, 3); 156 | //srcFit.SetTo(new MCvScalar(255,255,255)); 157 | if (angleWidth < dstWidth) 158 | { 159 | CvInvoke.CopyMakeBorder(srcResize, srcFit, 0, 0, 0, dstWidth - angleWidth, BorderType.Isolated, new MCvScalar(255, 255, 255)); 160 | } 161 | else 162 | { 163 | Rectangle rect = new Rectangle(0, 0, dstWidth, dstHeight); 164 | Mat partAngle = new Mat(srcResize, rect); 165 | partAngle.CopyTo(srcFit); 166 | } 167 | return srcFit; 168 | } 169 | 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /OcrLib/CrnnNet.cs: -------------------------------------------------------------------------------- 1 | using Emgu.CV; 2 | using Microsoft.ML.OnnxRuntime; 3 | using Microsoft.ML.OnnxRuntime.Tensors; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Drawing; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | 11 | namespace OcrLiteLib 12 | { 13 | class CrnnNet 14 | { 15 | private readonly float[] MeanValues = { 127.5F, 127.5F, 127.5F }; 16 | private readonly float[] NormValues = { 1.0F / 127.5F, 1.0F / 127.5F, 1.0F / 127.5F }; 17 | private const int crnnDstHeight = 48; 18 | private const int crnnCols = 6625; 19 | 20 | private InferenceSession crnnNet; 21 | private List keys; 22 | private List inputNames; 23 | 24 | public CrnnNet() { } 25 | 26 | ~CrnnNet() 27 | { 28 | crnnNet.Dispose(); 29 | } 30 | 31 | public void InitModel(string path, string keysPath, int numThread) 32 | { 33 | try 34 | { 35 | SessionOptions op = new SessionOptions(); 36 | op.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_EXTENDED; 37 | op.InterOpNumThreads = numThread; 38 | op.IntraOpNumThreads = numThread; 39 | crnnNet = new InferenceSession(path, op); 40 | inputNames = crnnNet.InputMetadata.Keys.ToList(); 41 | keys = InitKeys(keysPath); 42 | } 43 | catch (Exception ex) 44 | { 45 | Console.WriteLine(ex.Message + ex.StackTrace); 46 | throw ex; 47 | } 48 | } 49 | private List InitKeys(string path) 50 | { 51 | StreamReader sr = new StreamReader(path, Encoding.UTF8); 52 | List keys = new List(); 53 | keys.Add("#"); 54 | String line; 55 | while ((line = sr.ReadLine()) != null) 56 | { 57 | //Console.WriteLine(line.ToString()); 58 | keys.Add(line); 59 | } 60 | keys.Add(" "); 61 | Console.WriteLine($"keys Size = {keys.Count}"); 62 | return keys; 63 | } 64 | 65 | public List GetTextLines(List partImgs) 66 | { 67 | List textLines = new List(); 68 | for (int i = 0; i < partImgs.Count; i++) 69 | { 70 | var startTicks = DateTime.Now.Ticks; 71 | var textLine = GetTextLine(partImgs[i]); 72 | var endTicks = DateTime.Now.Ticks; 73 | var crnnTime = (endTicks - startTicks) / 10000F; 74 | textLine.Time = crnnTime; 75 | textLines.Add(textLine); 76 | } 77 | return textLines; 78 | } 79 | 80 | private TextLine GetTextLine(Mat src) 81 | { 82 | TextLine textLine = new TextLine(); 83 | 84 | float scale = (float)crnnDstHeight / (float)src.Rows; 85 | int dstWidth = (int)((float)src.Cols * scale); 86 | 87 | Mat srcResize = new Mat(); 88 | CvInvoke.Resize(src, srcResize, new Size(dstWidth, crnnDstHeight)); 89 | Tensor inputTensors = OcrUtils.SubstractMeanNormalize(srcResize, MeanValues, NormValues); 90 | var inputs = new List 91 | { 92 | NamedOnnxValue.CreateFromTensor(inputNames[0], inputTensors) 93 | }; 94 | try 95 | { 96 | using (IDisposableReadOnlyCollection results = crnnNet.Run(inputs)) 97 | { 98 | var resultsArray = results.ToArray(); 99 | var dimensions = resultsArray[0].AsTensor().Dimensions; 100 | float[] outputData = resultsArray[0].AsEnumerable().ToArray(); 101 | 102 | return ScoreToTextLine(outputData, dimensions[1], dimensions[2]); 103 | } 104 | } 105 | catch (Exception ex) 106 | { 107 | Console.WriteLine(ex.Message + ex.StackTrace); 108 | //throw ex; 109 | } 110 | 111 | return textLine; 112 | } 113 | 114 | private TextLine ScoreToTextLine(float[] srcData, int h, int w) 115 | { 116 | StringBuilder sb = new StringBuilder(); 117 | TextLine textLine = new TextLine(); 118 | 119 | int lastIndex = 0; 120 | List scores = new List(); 121 | 122 | for (int i = 0; i < h; i++) 123 | { 124 | int maxIndex = 0; 125 | float maxValue = -1000F; 126 | for (int j = 0; j < w; j++) 127 | { 128 | int idx = i * w + j; 129 | if (srcData[idx] > maxValue) 130 | { 131 | maxIndex = j; 132 | maxValue = srcData[idx]; 133 | } 134 | } 135 | 136 | if (maxIndex > 0 && maxIndex < keys.Count && (!(i > 0 && maxIndex == lastIndex))) 137 | { 138 | scores.Add(maxValue); 139 | sb.Append(keys[maxIndex]); 140 | } 141 | lastIndex = maxIndex; 142 | } 143 | textLine.Text = sb.ToString(); 144 | textLine.CharScores = scores; 145 | return textLine; 146 | } 147 | 148 | } 149 | } -------------------------------------------------------------------------------- /OcrLib/DbNet.cs: -------------------------------------------------------------------------------- 1 | using ClipperLib; 2 | using Emgu.CV; 3 | using Emgu.CV.CvEnum; 4 | using Emgu.CV.Structure; 5 | using Emgu.CV.Util; 6 | using Microsoft.ML.OnnxRuntime; 7 | using Microsoft.ML.OnnxRuntime.Tensors; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Drawing; 11 | using System.Linq; 12 | 13 | namespace OcrLiteLib 14 | { 15 | class DbNet 16 | { 17 | private readonly float[] MeanValues = { 0.485F * 255F, 0.456F * 255F, 0.406F * 255F }; 18 | private readonly float[] NormValues = { 1.0F / 0.229F / 255.0F, 1.0F / 0.224F / 255.0F, 1.0F / 0.225F / 255.0F }; 19 | 20 | private InferenceSession dbNet; 21 | 22 | private List inputNames; 23 | 24 | public DbNet() { } 25 | 26 | ~DbNet() 27 | { 28 | dbNet.Dispose(); 29 | } 30 | 31 | public void InitModel(string path, int numThread) 32 | { 33 | try 34 | { 35 | SessionOptions op = new SessionOptions(); 36 | op.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_EXTENDED; 37 | op.InterOpNumThreads = numThread; 38 | op.IntraOpNumThreads = numThread; 39 | dbNet = new InferenceSession(path, op); 40 | inputNames = dbNet.InputMetadata.Keys.ToList(); 41 | } 42 | catch (Exception ex) 43 | { 44 | Console.WriteLine(ex.Message + ex.StackTrace); 45 | throw ex; 46 | } 47 | } 48 | 49 | public List GetTextBoxes(Mat src, ScaleParam scale, float boxScoreThresh, float boxThresh, float unClipRatio) 50 | { 51 | Mat srcResize = new Mat(); 52 | CvInvoke.Resize(src, srcResize, new Size(scale.DstWidth, scale.DstHeight)); 53 | Tensor inputTensors = OcrUtils.SubstractMeanNormalize(srcResize, MeanValues, NormValues); 54 | var inputs = new List 55 | { 56 | NamedOnnxValue.CreateFromTensor(inputNames[0], inputTensors) 57 | }; 58 | try 59 | { 60 | using (IDisposableReadOnlyCollection results = dbNet.Run(inputs)) 61 | { 62 | var resultsArray = results.ToArray(); 63 | Console.WriteLine(resultsArray); 64 | var textBoxes = GetTextBoxes(resultsArray, srcResize.Rows, srcResize.Cols, scale, boxScoreThresh, boxThresh, unClipRatio); 65 | return textBoxes; 66 | } 67 | } 68 | catch (Exception ex) 69 | { 70 | Console.WriteLine(ex.Message + ex.StackTrace); 71 | } 72 | return null; 73 | } 74 | 75 | private static List GetTextBoxes(DisposableNamedOnnxValue[] outputTensor, int rows, int cols, ScaleParam s, float boxScoreThresh, float boxThresh, float unClipRatio) 76 | { 77 | float maxSideThresh = 3.0f;//长边门限 78 | List rsBoxes = new List(); 79 | //-----Data preparation----- 80 | float[] predData = outputTensor[0].AsEnumerable().ToArray(); 81 | List cbufData = new List(); 82 | foreach (float data in predData) 83 | { 84 | var val = data * 255; 85 | cbufData.Add(Convert.ToByte(val)); 86 | } 87 | Mat predMat = new Mat(rows, cols, DepthType.Cv32F, 1); 88 | predMat.SetTo(predData); 89 | 90 | Mat cbufMat = new Mat(rows, cols, DepthType.Cv8U, 1); 91 | cbufMat.SetTo(cbufData.ToArray()); 92 | 93 | //-----boxThresh----- 94 | Mat thresholdMat = new Mat(); 95 | CvInvoke.Threshold(cbufMat, thresholdMat, boxThresh * 255.0, 255.0, ThresholdType.Binary); 96 | 97 | //-----dilate----- 98 | Mat dilateMat = new Mat(); 99 | Mat dilateElement = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(2, 2), new Point(-1, -1)); 100 | CvInvoke.Dilate(thresholdMat, dilateMat, dilateElement, new Point(-1, -1), 1, BorderType.Default, new MCvScalar(128, 128, 128)); 101 | 102 | VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); 103 | 104 | CvInvoke.FindContours(dilateMat, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); 105 | 106 | for (int i = 0; i < contours.Size; i++) 107 | { 108 | if (contours[i].Size <= 2) 109 | { 110 | continue; 111 | } 112 | float maxSide = 0; 113 | List minBox = GetMiniBox(contours[i], out maxSide); 114 | if (maxSide < maxSideThresh) 115 | { 116 | continue; 117 | } 118 | double score = GetScore(contours[i], predMat); 119 | if (score < boxScoreThresh) 120 | { 121 | continue; 122 | } 123 | List clipBox = Unclip(minBox, unClipRatio); 124 | if (clipBox == null) 125 | { 126 | continue; 127 | } 128 | 129 | List clipMinBox = GetMiniBox(clipBox, out maxSide); 130 | if (maxSide < maxSideThresh + 2) 131 | { 132 | continue; 133 | } 134 | List finalPoints = new List(); 135 | foreach (var item in clipMinBox) 136 | { 137 | int x = (int)(item.X / s.ScaleWidth); 138 | int ptx = Math.Min(Math.Max(x, 0), s.SrcWidth); 139 | 140 | int y = (int)(item.Y / s.ScaleHeight); 141 | int pty = Math.Min(Math.Max(y, 0), s.SrcHeight); 142 | Point dstPt = new Point(ptx, pty); 143 | finalPoints.Add(dstPt); 144 | } 145 | 146 | TextBox textBox = new TextBox(); 147 | textBox.Score = (float)score; 148 | textBox.Points = finalPoints; 149 | rsBoxes.Add(textBox); 150 | } 151 | rsBoxes.Reverse(); 152 | return rsBoxes; 153 | } 154 | 155 | private static List GetMiniBox(List contours, out float minEdgeSize) 156 | { 157 | VectorOfPoint vop = new VectorOfPoint(); 158 | vop.Push(contours.ToArray()); 159 | return GetMiniBox(vop, out minEdgeSize); 160 | } 161 | 162 | private static List GetMiniBox(VectorOfPoint contours, out float minEdgeSize) 163 | { 164 | List box = new List(); 165 | RotatedRect rrect = CvInvoke.MinAreaRect(contours); 166 | PointF[] points = CvInvoke.BoxPoints(rrect); 167 | minEdgeSize = Math.Min(rrect.Size.Width, rrect.Size.Height); 168 | 169 | List thePoints = new List(points); 170 | thePoints.Sort(CompareByX); 171 | 172 | int index_1 = 0, index_2 = 1, index_3 = 2, index_4 = 3; 173 | if (thePoints[1].Y > thePoints[0].Y) 174 | { 175 | index_1 = 0; 176 | index_4 = 1; 177 | } 178 | else 179 | { 180 | index_1 = 1; 181 | index_4 = 0; 182 | } 183 | 184 | if (thePoints[3].Y > thePoints[2].Y) 185 | { 186 | index_2 = 2; 187 | index_3 = 3; 188 | } 189 | else 190 | { 191 | index_2 = 3; 192 | index_3 = 2; 193 | } 194 | 195 | box.Add(thePoints[index_1]); 196 | box.Add(thePoints[index_2]); 197 | box.Add(thePoints[index_3]); 198 | box.Add(thePoints[index_4]); 199 | 200 | return box; 201 | } 202 | 203 | public static int CompareByX(PointF left, PointF right) 204 | { 205 | if (left == null && right == null) 206 | { 207 | return 1; 208 | } 209 | 210 | if (left == null) 211 | { 212 | return 0; 213 | } 214 | 215 | if (right == null) 216 | { 217 | return 1; 218 | } 219 | 220 | if (left.X > right.X) 221 | { 222 | return 1; 223 | } 224 | 225 | if (left.X == right.X) 226 | { 227 | return 0; 228 | } 229 | 230 | return -1; 231 | } 232 | 233 | private static double GetScore(VectorOfPoint contours, Mat fMapMat) 234 | { 235 | short xmin = 9999; 236 | short xmax = 0; 237 | short ymin = 9999; 238 | short ymax = 0; 239 | 240 | try 241 | { 242 | foreach (Point point in contours.ToArray()) 243 | { 244 | if (point.X < xmin) 245 | { 246 | //var xx = nd[point.X]; 247 | xmin = (short)point.X; 248 | } 249 | 250 | if (point.X > xmax) 251 | { 252 | xmax = (short)point.X; 253 | } 254 | 255 | if (point.Y < ymin) 256 | { 257 | ymin = (short)point.Y; 258 | } 259 | 260 | if (point.Y > ymax) 261 | { 262 | ymax = (short)point.Y; 263 | } 264 | } 265 | 266 | int roiWidth = xmax - xmin + 1; 267 | int roiHeight = ymax - ymin + 1; 268 | 269 | Image bitmap = fMapMat.ToImage(); 270 | Image roiBitmap = new Image(roiWidth, roiHeight); 271 | float[,,] dataFloat = bitmap.Data; 272 | float[,,] data = roiBitmap.Data; 273 | 274 | for (int j = ymin; j < ymin + roiHeight; j++) 275 | { 276 | for (int i = xmin; i < xmin + roiWidth; i++) 277 | { 278 | try 279 | { 280 | data[j - ymin, i - xmin, 0] = dataFloat[j, i, 0]; 281 | } 282 | catch (Exception ex2) 283 | { 284 | Console.WriteLine(ex2.Message); 285 | } 286 | } 287 | } 288 | 289 | Mat mask = Mat.Zeros(roiHeight, roiWidth, DepthType.Cv8U, 1); 290 | List pts = new List(); 291 | foreach (Point point in contours.ToArray()) 292 | { 293 | pts.Add(new Point(point.X - xmin, point.Y - ymin)); 294 | } 295 | 296 | using (VectorOfPoint vp = new VectorOfPoint(pts.ToArray())) 297 | using (VectorOfVectorOfPoint vvp = new VectorOfVectorOfPoint(vp)) 298 | { 299 | CvInvoke.FillPoly(mask, vvp, new MCvScalar(1)); 300 | } 301 | 302 | return CvInvoke.Mean(roiBitmap, mask).V0; 303 | } 304 | catch (Exception ex) 305 | { 306 | Console.WriteLine(ex.Message + ex.StackTrace); 307 | } 308 | 309 | return 0; 310 | } 311 | 312 | private static List Unclip(List box, float unclip_ratio) 313 | { 314 | RotatedRect clipRect = CvInvoke.MinAreaRect(box.ToArray()); 315 | if (clipRect.Size.Height < 1.001 && clipRect.Size.Width < 1.001) 316 | { 317 | return null; 318 | } 319 | 320 | List theCliperPts = new List(); 321 | foreach (PointF pt in box) 322 | { 323 | IntPoint a1 = new IntPoint((int)pt.X, (int)pt.Y); 324 | theCliperPts.Add(a1); 325 | } 326 | 327 | float area = Math.Abs(SignedPolygonArea(box.ToArray())); 328 | double length = LengthOfPoints(box); 329 | double distance = area * unclip_ratio / length; 330 | 331 | ClipperOffset co = new ClipperOffset(); 332 | co.AddPath(theCliperPts, JoinType.jtRound, EndType.etClosedPolygon); 333 | List> solution = new List>(); 334 | co.Execute(ref solution, distance); 335 | if (solution.Count == 0) 336 | { 337 | return null; 338 | } 339 | 340 | List retPts = new List(); 341 | foreach (IntPoint ip in solution[0]) 342 | { 343 | retPts.Add(new Point((int)ip.X, (int)ip.Y)); 344 | } 345 | 346 | return retPts; 347 | } 348 | 349 | private static float SignedPolygonArea(PointF[] Points) 350 | { 351 | // Add the first point to the end. 352 | int num_points = Points.Length; 353 | PointF[] pts = new PointF[num_points + 1]; 354 | Points.CopyTo(pts, 0); 355 | pts[num_points] = Points[0]; 356 | 357 | // Get the areas. 358 | float area = 0; 359 | for (int i = 0; i < num_points; i++) 360 | { 361 | area += 362 | (pts[i + 1].X - pts[i].X) * 363 | (pts[i + 1].Y + pts[i].Y) / 2; 364 | } 365 | 366 | return area; 367 | } 368 | 369 | private static double LengthOfPoints(List box) 370 | { 371 | double length = 0; 372 | 373 | PointF pt = box[0]; 374 | double x0 = pt.X; 375 | double y0 = pt.Y; 376 | double x1 = 0, y1 = 0, dx = 0, dy = 0; 377 | box.Add(pt); 378 | 379 | int count = box.Count; 380 | for (int idx = 1; idx < count; idx++) 381 | { 382 | PointF pts = box[idx]; 383 | x1 = pts.X; 384 | y1 = pts.Y; 385 | dx = x1 - x0; 386 | dy = y1 - y0; 387 | 388 | length += Math.Sqrt(dx * dx + dy * dy); 389 | 390 | x0 = x1; 391 | y0 = y1; 392 | } 393 | 394 | box.RemoveAt(count - 1); 395 | return length; 396 | } 397 | 398 | } 399 | } 400 | 401 | -------------------------------------------------------------------------------- /OcrLib/OcrLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {AB10D356-2D95-4460-96CA-9A7129AD0A76} 9 | Library 10 | Properties 11 | OcrLib 12 | OcrLib 13 | v4.6.1 14 | 512 15 | true 16 | 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | x64 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | true 39 | bin\x64\Debug\ 40 | DEBUG;TRACE 41 | full 42 | x64 43 | 7.3 44 | prompt 45 | 46 | 47 | bin\x64\Release\ 48 | TRACE 49 | true 50 | pdbonly 51 | x64 52 | 7.3 53 | prompt 54 | 55 | 56 | 57 | ..\packages\clipper_library.6.2.1\lib\net40\clipper_library.dll 58 | 59 | 60 | ..\packages\Emgu.CV.4.4.0.4099\lib\netstandard2.0\Emgu.CV.Platform.NetStandard.dll 61 | 62 | 63 | ..\packages\Microsoft.ML.OnnxRuntime.Managed.1.12.1\lib\netstandard2.0\Microsoft.ML.OnnxRuntime.dll 64 | 65 | 66 | ..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll 67 | True 68 | True 69 | 70 | 71 | 72 | ..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll 73 | True 74 | True 75 | 76 | 77 | ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll 78 | 79 | 80 | 81 | ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll 82 | True 83 | True 84 | 85 | 86 | 87 | ..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll 88 | 89 | 90 | 91 | ..\packages\System.Drawing.Primitives.4.3.0\lib\net45\System.Drawing.Primitives.dll 92 | 93 | 94 | ..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll 95 | True 96 | True 97 | 98 | 99 | ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll 100 | True 101 | True 102 | 103 | 104 | 105 | ..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll 106 | True 107 | True 108 | 109 | 110 | ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll 111 | True 112 | True 113 | 114 | 115 | ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll 116 | True 117 | True 118 | 119 | 120 | ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll 121 | 122 | 123 | ..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll 124 | True 125 | True 126 | 127 | 128 | ..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll 129 | True 130 | True 131 | 132 | 133 | 134 | ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll 135 | 136 | 137 | ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll 138 | 139 | 140 | ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll 141 | 142 | 143 | ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll 144 | True 145 | True 146 | 147 | 148 | ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll 149 | True 150 | True 151 | 152 | 153 | ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll 154 | True 155 | True 156 | 157 | 158 | ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll 159 | True 160 | True 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll 169 | True 170 | True 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /OcrLib/OcrLite.cs: -------------------------------------------------------------------------------- 1 | using Emgu.CV; 2 | using Emgu.CV.CvEnum; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Drawing; 6 | using System.Text; 7 | 8 | namespace OcrLiteLib 9 | { 10 | public class OcrLite 11 | { 12 | public bool isPartImg { get; set; } 13 | public bool isDebugImg { get; set; } 14 | private DbNet dbNet; 15 | private AngleNet angleNet; 16 | private CrnnNet crnnNet; 17 | 18 | public OcrLite() 19 | { 20 | dbNet = new DbNet(); 21 | angleNet = new AngleNet(); 22 | crnnNet = new CrnnNet(); 23 | } 24 | 25 | public void InitModels(string detPath, string clsPath, string recPath, string keysPath, int numThread) 26 | { 27 | try 28 | { 29 | dbNet.InitModel(detPath, numThread); 30 | angleNet.InitModel(clsPath, numThread); 31 | crnnNet.InitModel(recPath, keysPath, numThread); 32 | } 33 | catch (Exception ex) 34 | { 35 | Console.WriteLine(ex.Message + ex.StackTrace); 36 | throw ex; 37 | } 38 | } 39 | 40 | public OcrResult Detect(string img, int padding, int maxSideLen, float boxScoreThresh, float boxThresh, 41 | float unClipRatio, bool doAngle, bool mostAngle) 42 | { 43 | Mat originSrc = CvInvoke.Imread(img, ImreadModes.Color);//default : BGR 44 | int originMaxSide = Math.Max(originSrc.Cols, originSrc.Rows); 45 | 46 | int resize; 47 | if (maxSideLen <= 0 || maxSideLen > originMaxSide) 48 | { 49 | resize = originMaxSide; 50 | } 51 | else 52 | { 53 | resize = maxSideLen; 54 | } 55 | resize += 2 * padding; 56 | Rectangle paddingRect = new Rectangle(padding, padding, originSrc.Cols, originSrc.Rows); 57 | Mat paddingSrc = OcrUtils.MakePadding(originSrc, padding); 58 | 59 | ScaleParam scale = ScaleParam.GetScaleParam(paddingSrc, resize); 60 | 61 | return DetectOnce(paddingSrc, paddingRect, scale, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle); 62 | } 63 | 64 | private OcrResult DetectOnce(Mat src, Rectangle originRect, ScaleParam scale, float boxScoreThresh, float boxThresh, 65 | float unClipRatio, bool doAngle, bool mostAngle) 66 | { 67 | Mat textBoxPaddingImg = src.Clone(); 68 | int thickness = OcrUtils.GetThickness(src); 69 | Console.WriteLine("=====Start detect====="); 70 | var startTicks = DateTime.Now.Ticks; 71 | 72 | Console.WriteLine("---------- step: dbNet getTextBoxes ----------"); 73 | var textBoxes = dbNet.GetTextBoxes(src, scale, boxScoreThresh, boxThresh, unClipRatio); 74 | var dbNetTime = (DateTime.Now.Ticks - startTicks) / 10000F; 75 | 76 | Console.WriteLine($"TextBoxesSize({textBoxes.Count})"); 77 | textBoxes.ForEach(x => Console.WriteLine(x)); 78 | //Console.WriteLine($"dbNetTime({dbNetTime}ms)"); 79 | 80 | Console.WriteLine("---------- step: drawTextBoxes ----------"); 81 | OcrUtils.DrawTextBoxes(textBoxPaddingImg, textBoxes, thickness); 82 | //CvInvoke.Imshow("ResultPadding", textBoxPaddingImg); 83 | 84 | //---------- getPartImages ---------- 85 | List partImages = OcrUtils.GetPartImages(src, textBoxes); 86 | if (isPartImg) 87 | { 88 | for (int i = 0; i < partImages.Count; i++) 89 | { 90 | CvInvoke.Imshow($"PartImg({i})", partImages[i]); 91 | } 92 | } 93 | 94 | Console.WriteLine("---------- step: angleNet getAngles ----------"); 95 | List angles = angleNet.GetAngles(partImages, doAngle, mostAngle); 96 | //angles.ForEach(x => Console.WriteLine(x)); 97 | 98 | //Rotate partImgs 99 | for (int i = 0; i < partImages.Count; ++i) 100 | { 101 | if (angles[i].Index == 1) 102 | { 103 | partImages[i] = OcrUtils.MatRotateClockWise180(partImages[i]); 104 | } 105 | if (isDebugImg) 106 | { 107 | CvInvoke.Imshow($"DebugImg({i})", partImages[i]); 108 | } 109 | } 110 | 111 | Console.WriteLine("---------- step: crnnNet getTextLines ----------"); 112 | List textLines = crnnNet.GetTextLines(partImages); 113 | //textLines.ForEach(x => Console.WriteLine(x)); 114 | 115 | List textBlocks = new List(); 116 | for (int i = 0; i < textLines.Count; ++i) 117 | { 118 | TextBlock textBlock = new TextBlock(); 119 | textBlock.BoxPoints = textBoxes[i].Points; 120 | textBlock.BoxScore = textBoxes[i].Score; 121 | textBlock.AngleIndex = angles[i].Index; 122 | textBlock.AngleScore = angles[i].Score; 123 | textBlock.AngleTime = angles[i].Time; 124 | textBlock.Text = textLines[i].Text; 125 | textBlock.CharScores = textLines[i].CharScores; 126 | textBlock.CrnnTime = textLines[i].Time; 127 | textBlock.BlockTime = angles[i].Time + textLines[i].Time; 128 | textBlocks.Add(textBlock); 129 | } 130 | //textBlocks.ForEach(x => Console.WriteLine(x)); 131 | 132 | var endTicks = DateTime.Now.Ticks; 133 | var fullDetectTime = (endTicks - startTicks) / 10000F; 134 | //Console.WriteLine($"fullDetectTime({fullDetectTime}ms)"); 135 | 136 | //cropped to original size 137 | Mat boxImg = new Mat(textBoxPaddingImg, originRect); 138 | 139 | StringBuilder strRes = new StringBuilder(); 140 | textBlocks.ForEach(x => strRes.AppendLine(x.Text)); 141 | 142 | OcrResult ocrResult = new OcrResult(); 143 | ocrResult.TextBlocks = textBlocks; 144 | ocrResult.DbNetTime = dbNetTime; 145 | ocrResult.BoxImg = boxImg; 146 | ocrResult.DetectTime = fullDetectTime; 147 | ocrResult.StrRes = strRes.ToString(); 148 | 149 | return ocrResult; 150 | } 151 | 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /OcrLib/OcrResult.cs: -------------------------------------------------------------------------------- 1 | using Emgu.CV; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Text; 5 | 6 | namespace OcrLiteLib 7 | { 8 | public sealed class TextBox 9 | { 10 | public List Points { get; set; } 11 | public float Score { get; set; } 12 | public override string ToString() 13 | { 14 | return $"TextBox[score({Score}),[x: {Points[0].X}, y: {Points[0].Y}], [x: {Points[1].X}, y: {Points[1].Y}], [x: {Points[2].X}, y: {Points[2].Y}], [x: {Points[3].X}, y: {Points[3].Y}]]"; 15 | } 16 | } 17 | 18 | public sealed class Angle 19 | { 20 | public int Index { get; set; } 21 | public float Score { get; set; } 22 | public float Time { get; set; } 23 | public override string ToString() 24 | { 25 | string header = Index >= 0 ? "Angle" : "AngleDisabled"; 26 | return $"{header}[Index({Index}), Score({Score}), Time({Time}ms)]"; 27 | } 28 | } 29 | public sealed class TextLine 30 | { 31 | public string Text { get; set; } 32 | public List CharScores { get; set; } 33 | public float Time { get; set; } 34 | public override string ToString() 35 | { 36 | StringBuilder sb = new StringBuilder(); 37 | CharScores.ForEach(x => sb.Append($"{x},")); 38 | return $"TextLine[Text({Text}),CharScores({sb.ToString()}),Time({Time}ms)]"; 39 | } 40 | } 41 | public sealed class TextBlock 42 | { 43 | public List BoxPoints { get; set; } 44 | public float BoxScore { get; set; } 45 | public int AngleIndex { get; set; } 46 | public float AngleScore { get; set; } 47 | public float AngleTime { get; set; } 48 | public string Text { get; set; } 49 | public List CharScores { get; set; } 50 | public float CrnnTime { get; set; } 51 | public float BlockTime { get; set; } 52 | public override string ToString() 53 | { 54 | StringBuilder sb = new StringBuilder(); 55 | sb.AppendLine("├─TextBlock"); 56 | string textBox = $"│ ├──TextBox[score({BoxScore}),[x: {BoxPoints[0].X}, y: {BoxPoints[0].Y}], [x: {BoxPoints[1].X}, y: {BoxPoints[1].Y}], [x: {BoxPoints[2].X}, y: {BoxPoints[2].Y}], [x: {BoxPoints[3].X}, y: {BoxPoints[3].Y}]]"; 57 | sb.AppendLine(textBox); 58 | string header = AngleIndex >= 0 ? "Angle" : "AngleDisabled"; 59 | string angle = $"│ ├──{header}[Index({AngleIndex}), Score({AngleScore}), Time({AngleTime}ms)]"; 60 | sb.AppendLine(angle); 61 | StringBuilder sbScores = new StringBuilder(); 62 | CharScores.ForEach(x => sbScores.Append($"{x},")); 63 | string textLine = $"│ ├──TextLine[Text({Text}),CharScores({sbScores.ToString()}),Time({CrnnTime}ms)]"; 64 | sb.AppendLine(textLine); 65 | sb.AppendLine($"│ └──BlockTime({BlockTime}ms)"); 66 | return sb.ToString(); 67 | } 68 | } 69 | public sealed class OcrResult 70 | { 71 | public List TextBlocks { get; set; } 72 | public float DbNetTime { get; set; } 73 | public Mat BoxImg { get; set; } 74 | public float DetectTime { get; set; } 75 | public string StrRes { get; set; } 76 | 77 | public override string ToString() 78 | { 79 | StringBuilder sb = new StringBuilder(); 80 | sb.AppendLine("OcrResult"); 81 | TextBlocks.ForEach(x => sb.Append(x)); 82 | sb.AppendLine($"├─DbNetTime({DbNetTime}ms)"); 83 | sb.AppendLine($"├─DetectTime({DetectTime}ms)"); 84 | sb.AppendLine($"└─StrRes({StrRes})"); 85 | return sb.ToString(); 86 | } 87 | 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /OcrLib/OcrUtils.cs: -------------------------------------------------------------------------------- 1 | using Emgu.CV; 2 | using Emgu.CV.CvEnum; 3 | using Emgu.CV.Structure; 4 | using Microsoft.ML.OnnxRuntime.Tensors; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Drawing; 8 | using System.Linq; 9 | 10 | namespace OcrLiteLib 11 | { 12 | class OcrUtils 13 | { 14 | public static Tensor SubstractMeanNormalize(Mat src, float[] meanVals, float[] normVals) 15 | { 16 | int cols = src.Cols; 17 | int rows = src.Rows; 18 | int channels = src.NumberOfChannels; 19 | Image srcImg = src.ToImage(); 20 | byte[,,] imgData = srcImg.Data; 21 | Tensor inputTensor = new DenseTensor(new[] { 1, channels, rows, cols }); 22 | for (int r = 0; r < rows; r++) 23 | { 24 | for (int c = 0; c < cols; c++) 25 | { 26 | for (int ch = 0; ch < channels; ch++) 27 | { 28 | var value = imgData[r, c, ch]; 29 | float data = (float)(value * normVals[ch] - meanVals[ch] * normVals[ch]); 30 | inputTensor[0, ch, r, c] = data; 31 | } 32 | } 33 | } 34 | return inputTensor; 35 | } 36 | 37 | public static Mat MakePadding(Mat src, int padding) 38 | { 39 | if (padding <= 0) return src; 40 | MCvScalar paddingScalar = new MCvScalar(255, 255, 255); 41 | Mat paddingSrc = new Mat(); 42 | CvInvoke.CopyMakeBorder(src, paddingSrc, padding, padding, padding, padding, BorderType.Isolated, paddingScalar); 43 | return paddingSrc; 44 | } 45 | 46 | public static int GetThickness(Mat boxImg) 47 | { 48 | int minSize = boxImg.Cols > boxImg.Rows ? boxImg.Rows : boxImg.Cols; 49 | int thickness = minSize / 1000 + 2; 50 | return thickness; 51 | } 52 | 53 | public static void DrawTextBox(Mat boxImg, List box, int thickness) 54 | { 55 | if (box == null || box.Count == 0) 56 | { 57 | return; 58 | } 59 | var color = new MCvScalar(0, 0, 255);//B(0) G(0) R(255) 60 | CvInvoke.Line(boxImg, box[0], box[1], color, thickness); 61 | CvInvoke.Line(boxImg, box[1], box[2], color, thickness); 62 | CvInvoke.Line(boxImg, box[2], box[3], color, thickness); 63 | CvInvoke.Line(boxImg, box[3], box[0], color, thickness); 64 | } 65 | 66 | public static void DrawTextBoxes(Mat src, List textBoxes, int thickness) 67 | { 68 | for (int i = 0; i < textBoxes.Count; i++) 69 | { 70 | TextBox t = textBoxes[i]; 71 | DrawTextBox(src, t.Points, thickness); 72 | } 73 | } 74 | 75 | public static List GetPartImages(Mat src, List textBoxes) 76 | { 77 | List partImages = new List(); 78 | for (int i = 0; i < textBoxes.Count; ++i) 79 | { 80 | Mat partImg = GetRotateCropImage(src, textBoxes[i].Points); 81 | //Mat partImg = new Mat(); 82 | //GetRoiFromBox(src, partImg, textBoxes[i].Points); 83 | partImages.Add(partImg); 84 | } 85 | return partImages; 86 | } 87 | 88 | public static Mat GetRotateCropImage(Mat src, List box) 89 | { 90 | List points = new List(); 91 | points.AddRange(box); 92 | 93 | int[] collectX = { box[0].X, box[1].X, box[2].X, box[3].X }; 94 | int[] collectY = { box[0].Y, box[1].Y, box[2].Y, box[3].Y }; 95 | int left = collectX.Min(); 96 | int right = collectX.Max(); 97 | int top = collectY.Min(); 98 | int bottom = collectY.Max(); 99 | 100 | Rectangle rect = new Rectangle(left, top, right - left, bottom - top); 101 | Mat imgCrop = new Mat(src, rect); 102 | 103 | for (int i = 0; i < points.Count; i++) 104 | { 105 | var pt = points[i]; 106 | pt.X -= left; 107 | pt.Y -= top; 108 | points[i] = pt; 109 | } 110 | 111 | int imgCropWidth = (int)(Math.Sqrt(Math.Pow(points[0].X - points[1].X, 2) + 112 | Math.Pow(points[0].Y - points[1].Y, 2))); 113 | int imgCropHeight = (int)(Math.Sqrt(Math.Pow(points[0].X - points[3].X, 2) + 114 | Math.Pow(points[0].Y - points[3].Y, 2))); 115 | 116 | var ptsDst0 = new PointF(0, 0); 117 | var ptsDst1 = new PointF(imgCropWidth, 0); 118 | var ptsDst2 = new PointF(imgCropWidth, imgCropHeight); 119 | var ptsDst3 = new PointF(0, imgCropHeight); 120 | 121 | PointF[] ptsDst = { ptsDst0, ptsDst1, ptsDst2, ptsDst3 }; 122 | 123 | 124 | var ptsSrc0 = new PointF(points[0].X, points[0].Y); 125 | var ptsSrc1 = new PointF(points[1].X, points[1].Y); 126 | var ptsSrc2 = new PointF(points[2].X, points[2].Y); 127 | var ptsSrc3 = new PointF(points[3].X, points[3].Y); 128 | 129 | PointF[] ptsSrc = { ptsSrc0, ptsSrc1, ptsSrc2, ptsSrc3 }; 130 | 131 | Mat M = CvInvoke.GetPerspectiveTransform(ptsSrc, ptsDst); 132 | 133 | Mat partImg = new Mat(); 134 | CvInvoke.WarpPerspective(imgCrop, partImg, M, 135 | new Size(imgCropWidth, imgCropHeight), Inter.Nearest, Warp.Default, 136 | BorderType.Replicate); 137 | 138 | if (partImg.Rows >= partImg.Cols * 1.5) 139 | { 140 | Mat srcCopy = new Mat(); 141 | CvInvoke.Transpose(partImg, srcCopy); 142 | CvInvoke.Flip(srcCopy, srcCopy, 0); 143 | return srcCopy; 144 | } 145 | else 146 | { 147 | return partImg; 148 | } 149 | } 150 | 151 | public static Mat MatRotateClockWise180(Mat src) 152 | { 153 | CvInvoke.Flip(src, src, FlipType.Vertical); 154 | CvInvoke.Flip(src, src, FlipType.Horizontal); 155 | return src; 156 | } 157 | 158 | public static Mat MatRotateClockWise90(Mat src) 159 | { 160 | CvInvoke.Rotate(src, src, RotateFlags.Rotate90CounterClockwise); 161 | return src; 162 | } 163 | 164 | } 165 | } 166 | 167 | -------------------------------------------------------------------------------- /OcrLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("OcrLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("OcrLib")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("ab10d356-2d95-4460-96ca-9a7129ad0a76")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /OcrLib/ScaleParam.cs: -------------------------------------------------------------------------------- 1 | using Emgu.CV; 2 | using System; 3 | 4 | namespace OcrLiteLib 5 | { 6 | class ScaleParam 7 | { 8 | int srcWidth; 9 | int srcHeight; 10 | int dstWidth; 11 | int dstHeight; 12 | float scaleWidth; 13 | float scaleHeight; 14 | 15 | public int SrcWidth { get => srcWidth; set => srcWidth = value; } 16 | public int SrcHeight { get => srcHeight; set => srcHeight = value; } 17 | public int DstWidth { get => dstWidth; set => dstWidth = value; } 18 | public int DstHeight { get => dstHeight; set => dstHeight = value; } 19 | public float ScaleWidth { get => scaleWidth; set => scaleWidth = value; } 20 | public float ScaleHeight { get => scaleHeight; set => scaleHeight = value; } 21 | 22 | public ScaleParam(int srcWidth, int srcHeight, int dstWidth, int dstHeight, float scaleWidth, float scaleHeight) 23 | { 24 | this.srcWidth = srcWidth; 25 | this.srcHeight = srcHeight; 26 | this.dstWidth = dstWidth; 27 | this.dstHeight = dstHeight; 28 | this.scaleWidth = scaleWidth; 29 | this.scaleHeight = scaleHeight; 30 | } 31 | 32 | public override string ToString() 33 | { 34 | return $"sw:{this.srcWidth},sh:{this.srcHeight},dw:{this.dstWidth},dh:{this.dstHeight},{this.scaleWidth},{this.scaleHeight}"; 35 | } 36 | 37 | public static ScaleParam GetScaleParam(Mat src, int dstSize) 38 | { 39 | int srcWidth, srcHeight, dstWidth, dstHeight; 40 | srcWidth = src.Cols; 41 | dstWidth = src.Cols; 42 | srcHeight = src.Rows; 43 | dstHeight = src.Rows; 44 | 45 | float scale = 1.0F; 46 | if (dstWidth > dstHeight) 47 | { 48 | scale = (float)dstSize / (float)dstWidth; 49 | dstWidth = dstSize; 50 | dstHeight = (int)((float)dstHeight * scale); 51 | } 52 | else 53 | { 54 | scale = (float)dstSize / (float)dstHeight; 55 | dstHeight = dstSize; 56 | dstWidth = (int)((float)dstWidth * scale); 57 | } 58 | if (dstWidth % 32 != 0) 59 | { 60 | dstWidth = (dstWidth / 32 - 1) * 32; 61 | dstWidth = Math.Max(dstWidth, 32); 62 | } 63 | if (dstHeight % 32 != 0) 64 | { 65 | dstHeight = (dstHeight / 32 - 1) * 32; 66 | dstHeight = Math.Max(dstHeight, 32); 67 | } 68 | float scaleWidth = (float)dstWidth / (float)srcWidth; 69 | float scaleHeight = (float)dstHeight / (float)srcHeight; 70 | return new ScaleParam(srcWidth, srcHeight, dstWidth, dstHeight, scaleWidth, scaleHeight); 71 | } 72 | 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /OcrLib/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /OcrOnnxForm/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /OcrOnnxForm/FormOcr.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace BaiPiaoOcrOnnxCs 2 | { 3 | partial class FormOcr 4 | { 5 | /// 6 | /// 必需的设计器变量。 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// 清理所有正在使用的资源。 12 | /// 13 | /// 如果应释放托管资源,为 true;否则为 false。 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows 窗体设计器生成的代码 24 | 25 | /// 26 | /// 设计器支持所需的方法 - 不要修改 27 | /// 使用代码编辑器修改此方法的内容。 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.label8 = new System.Windows.Forms.Label(); 32 | this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); 33 | this.modelsTextBox = new System.Windows.Forms.TextBox(); 34 | this.label9 = new System.Windows.Forms.Label(); 35 | this.modelsBtn = new System.Windows.Forms.Button(); 36 | this.pathTextBox = new System.Windows.Forms.TextBox(); 37 | this.openBtn = new System.Windows.Forms.Button(); 38 | this.label1 = new System.Windows.Forms.Label(); 39 | this.numThreadNumeric = new System.Windows.Forms.NumericUpDown(); 40 | this.label6 = new System.Windows.Forms.Label(); 41 | this.detNameTextBox = new System.Windows.Forms.TextBox(); 42 | this.label10 = new System.Windows.Forms.Label(); 43 | this.clsNameTextBox = new System.Windows.Forms.TextBox(); 44 | this.label11 = new System.Windows.Forms.Label(); 45 | this.recNameTextBox = new System.Windows.Forms.TextBox(); 46 | this.label12 = new System.Windows.Forms.Label(); 47 | this.keysNameTextBox = new System.Windows.Forms.TextBox(); 48 | this.label5 = new System.Windows.Forms.Label(); 49 | this.boxThreshNumeric = new System.Windows.Forms.NumericUpDown(); 50 | this.label7 = new System.Windows.Forms.Label(); 51 | this.unClipRatioNumeric = new System.Windows.Forms.NumericUpDown(); 52 | this.doAngleCheckBox = new System.Windows.Forms.CheckBox(); 53 | this.mostAngleCheckBox = new System.Windows.Forms.CheckBox(); 54 | this.label4 = new System.Windows.Forms.Label(); 55 | this.imgResizeNumeric = new System.Windows.Forms.NumericUpDown(); 56 | this.label3 = new System.Windows.Forms.Label(); 57 | this.paddingNumeric = new System.Windows.Forms.NumericUpDown(); 58 | this.label2 = new System.Windows.Forms.Label(); 59 | this.boxScoreThreshNumeric = new System.Windows.Forms.NumericUpDown(); 60 | this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); 61 | this.pictureBox = new System.Windows.Forms.PictureBox(); 62 | this.strRestTextBox = new System.Windows.Forms.TextBox(); 63 | this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); 64 | this.partImgCheckBox = new System.Windows.Forms.CheckBox(); 65 | this.debugCheckBox = new System.Windows.Forms.CheckBox(); 66 | this.detectBtn = new System.Windows.Forms.Button(); 67 | this.initBtn = new System.Windows.Forms.Button(); 68 | this.ocrResultTextBox = new System.Windows.Forms.TextBox(); 69 | this.tableLayoutPanel2.SuspendLayout(); 70 | ((System.ComponentModel.ISupportInitialize)(this.numThreadNumeric)).BeginInit(); 71 | ((System.ComponentModel.ISupportInitialize)(this.boxThreshNumeric)).BeginInit(); 72 | ((System.ComponentModel.ISupportInitialize)(this.unClipRatioNumeric)).BeginInit(); 73 | ((System.ComponentModel.ISupportInitialize)(this.imgResizeNumeric)).BeginInit(); 74 | ((System.ComponentModel.ISupportInitialize)(this.paddingNumeric)).BeginInit(); 75 | ((System.ComponentModel.ISupportInitialize)(this.boxScoreThreshNumeric)).BeginInit(); 76 | this.tableLayoutPanel3.SuspendLayout(); 77 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit(); 78 | this.tableLayoutPanel1.SuspendLayout(); 79 | this.SuspendLayout(); 80 | // 81 | // label8 82 | // 83 | this.label8.AutoSize = true; 84 | this.label8.Location = new System.Drawing.Point(3, 180); 85 | this.label8.Name = "label8"; 86 | this.label8.Size = new System.Drawing.Size(47, 12); 87 | this.label8.TabIndex = 8; 88 | this.label8.Text = "ImgFile"; 89 | // 90 | // tableLayoutPanel2 91 | // 92 | this.tableLayoutPanel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 93 | | System.Windows.Forms.AnchorStyles.Right))); 94 | this.tableLayoutPanel2.ColumnCount = 3; 95 | this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 100F)); 96 | this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); 97 | this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80F)); 98 | this.tableLayoutPanel2.Controls.Add(this.modelsTextBox, 1, 0); 99 | this.tableLayoutPanel2.Controls.Add(this.label9, 0, 0); 100 | this.tableLayoutPanel2.Controls.Add(this.modelsBtn, 2, 0); 101 | this.tableLayoutPanel2.Controls.Add(this.label8, 0, 6); 102 | this.tableLayoutPanel2.Controls.Add(this.pathTextBox, 1, 6); 103 | this.tableLayoutPanel2.Controls.Add(this.openBtn, 2, 6); 104 | this.tableLayoutPanel2.Controls.Add(this.label1, 0, 5); 105 | this.tableLayoutPanel2.Controls.Add(this.numThreadNumeric, 1, 5); 106 | this.tableLayoutPanel2.Controls.Add(this.label6, 0, 1); 107 | this.tableLayoutPanel2.Controls.Add(this.detNameTextBox, 1, 1); 108 | this.tableLayoutPanel2.Controls.Add(this.label10, 0, 2); 109 | this.tableLayoutPanel2.Controls.Add(this.clsNameTextBox, 1, 2); 110 | this.tableLayoutPanel2.Controls.Add(this.label11, 0, 3); 111 | this.tableLayoutPanel2.Controls.Add(this.recNameTextBox, 1, 3); 112 | this.tableLayoutPanel2.Controls.Add(this.label12, 0, 4); 113 | this.tableLayoutPanel2.Controls.Add(this.keysNameTextBox, 1, 4); 114 | this.tableLayoutPanel2.Location = new System.Drawing.Point(14, 12); 115 | this.tableLayoutPanel2.Name = "tableLayoutPanel2"; 116 | this.tableLayoutPanel2.RowCount = 7; 117 | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 118 | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 119 | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 120 | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 121 | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 122 | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 123 | this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 124 | this.tableLayoutPanel2.Size = new System.Drawing.Size(675, 211); 125 | this.tableLayoutPanel2.TabIndex = 14; 126 | // 127 | // modelsTextBox 128 | // 129 | this.modelsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 130 | | System.Windows.Forms.AnchorStyles.Right))); 131 | this.modelsTextBox.Location = new System.Drawing.Point(103, 3); 132 | this.modelsTextBox.Name = "modelsTextBox"; 133 | this.modelsTextBox.Size = new System.Drawing.Size(489, 21); 134 | this.modelsTextBox.TabIndex = 1; 135 | // 136 | // label9 137 | // 138 | this.label9.AutoSize = true; 139 | this.label9.Location = new System.Drawing.Point(3, 0); 140 | this.label9.Name = "label9"; 141 | this.label9.Size = new System.Drawing.Size(41, 12); 142 | this.label9.TabIndex = 9; 143 | this.label9.Text = "Models"; 144 | // 145 | // modelsBtn 146 | // 147 | this.modelsBtn.Location = new System.Drawing.Point(598, 3); 148 | this.modelsBtn.Name = "modelsBtn"; 149 | this.modelsBtn.Size = new System.Drawing.Size(74, 23); 150 | this.modelsBtn.TabIndex = 2; 151 | this.modelsBtn.Text = "Models"; 152 | this.modelsBtn.UseVisualStyleBackColor = true; 153 | this.modelsBtn.Click += new System.EventHandler(this.modelsBtn_Click); 154 | // 155 | // pathTextBox 156 | // 157 | this.pathTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 158 | | System.Windows.Forms.AnchorStyles.Right))); 159 | this.pathTextBox.Location = new System.Drawing.Point(103, 183); 160 | this.pathTextBox.Name = "pathTextBox"; 161 | this.pathTextBox.Size = new System.Drawing.Size(489, 21); 162 | this.pathTextBox.TabIndex = 6; 163 | // 164 | // openBtn 165 | // 166 | this.openBtn.Location = new System.Drawing.Point(598, 183); 167 | this.openBtn.Name = "openBtn"; 168 | this.openBtn.Size = new System.Drawing.Size(74, 23); 169 | this.openBtn.TabIndex = 0; 170 | this.openBtn.Text = "Open"; 171 | this.openBtn.UseVisualStyleBackColor = true; 172 | this.openBtn.Click += new System.EventHandler(this.openBtn_Click); 173 | // 174 | // label1 175 | // 176 | this.label1.AutoSize = true; 177 | this.label1.Location = new System.Drawing.Point(3, 150); 178 | this.label1.Name = "label1"; 179 | this.label1.Size = new System.Drawing.Size(59, 12); 180 | this.label1.TabIndex = 3; 181 | this.label1.Text = "numThread"; 182 | // 183 | // numThreadNumeric 184 | // 185 | this.numThreadNumeric.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 186 | | System.Windows.Forms.AnchorStyles.Right))); 187 | this.numThreadNumeric.Location = new System.Drawing.Point(103, 153); 188 | this.numThreadNumeric.Maximum = new decimal(new int[] { 189 | 128, 190 | 0, 191 | 0, 192 | 0}); 193 | this.numThreadNumeric.Minimum = new decimal(new int[] { 194 | 1, 195 | 0, 196 | 0, 197 | 0}); 198 | this.numThreadNumeric.Name = "numThreadNumeric"; 199 | this.numThreadNumeric.Size = new System.Drawing.Size(489, 21); 200 | this.numThreadNumeric.TabIndex = 4; 201 | this.numThreadNumeric.Value = new decimal(new int[] { 202 | 4, 203 | 0, 204 | 0, 205 | 0}); 206 | // 207 | // label6 208 | // 209 | this.label6.AutoSize = true; 210 | this.label6.Location = new System.Drawing.Point(3, 30); 211 | this.label6.Name = "label6"; 212 | this.label6.Size = new System.Drawing.Size(23, 12); 213 | this.label6.TabIndex = 11; 214 | this.label6.Text = "det"; 215 | // 216 | // detNameTextBox 217 | // 218 | this.detNameTextBox.Location = new System.Drawing.Point(103, 33); 219 | this.detNameTextBox.Name = "detNameTextBox"; 220 | this.detNameTextBox.Size = new System.Drawing.Size(489, 21); 221 | this.detNameTextBox.TabIndex = 12; 222 | this.detNameTextBox.Text = "ch_PP-OCRv3_det_infer.onnx"; 223 | // 224 | // label10 225 | // 226 | this.label10.AutoSize = true; 227 | this.label10.Location = new System.Drawing.Point(3, 60); 228 | this.label10.Name = "label10"; 229 | this.label10.Size = new System.Drawing.Size(23, 12); 230 | this.label10.TabIndex = 13; 231 | this.label10.Text = "cls"; 232 | // 233 | // clsNameTextBox 234 | // 235 | this.clsNameTextBox.Location = new System.Drawing.Point(103, 63); 236 | this.clsNameTextBox.Name = "clsNameTextBox"; 237 | this.clsNameTextBox.Size = new System.Drawing.Size(489, 21); 238 | this.clsNameTextBox.TabIndex = 14; 239 | this.clsNameTextBox.Text = "ch_ppocr_mobile_v2.0_cls_infer.onnx"; 240 | // 241 | // label11 242 | // 243 | this.label11.AutoSize = true; 244 | this.label11.Location = new System.Drawing.Point(3, 90); 245 | this.label11.Name = "label11"; 246 | this.label11.Size = new System.Drawing.Size(23, 12); 247 | this.label11.TabIndex = 15; 248 | this.label11.Text = "rec"; 249 | // 250 | // recNameTextBox 251 | // 252 | this.recNameTextBox.Location = new System.Drawing.Point(103, 93); 253 | this.recNameTextBox.Name = "recNameTextBox"; 254 | this.recNameTextBox.Size = new System.Drawing.Size(489, 21); 255 | this.recNameTextBox.TabIndex = 16; 256 | this.recNameTextBox.Text = "ch_PP-OCRv3_rec_infer.onnx"; 257 | // 258 | // label12 259 | // 260 | this.label12.AutoSize = true; 261 | this.label12.Location = new System.Drawing.Point(3, 120); 262 | this.label12.Name = "label12"; 263 | this.label12.Size = new System.Drawing.Size(29, 12); 264 | this.label12.TabIndex = 17; 265 | this.label12.Text = "keys"; 266 | // 267 | // keysNameTextBox 268 | // 269 | this.keysNameTextBox.Location = new System.Drawing.Point(103, 123); 270 | this.keysNameTextBox.Name = "keysNameTextBox"; 271 | this.keysNameTextBox.Size = new System.Drawing.Size(489, 21); 272 | this.keysNameTextBox.TabIndex = 18; 273 | this.keysNameTextBox.Text = "ppocr_keys_v1.txt"; 274 | // 275 | // label5 276 | // 277 | this.label5.AutoSize = true; 278 | this.label5.Location = new System.Drawing.Point(5, 98); 279 | this.label5.Name = "label5"; 280 | this.label5.Size = new System.Drawing.Size(59, 12); 281 | this.label5.TabIndex = 14; 282 | this.label5.Text = "boxThresh"; 283 | // 284 | // boxThreshNumeric 285 | // 286 | this.boxThreshNumeric.DecimalPlaces = 3; 287 | this.boxThreshNumeric.Increment = new decimal(new int[] { 288 | 1, 289 | 0, 290 | 0, 291 | 65536}); 292 | this.boxThreshNumeric.Location = new System.Drawing.Point(87, 101); 293 | this.boxThreshNumeric.Maximum = new decimal(new int[] { 294 | 1, 295 | 0, 296 | 0, 297 | 0}); 298 | this.boxThreshNumeric.Minimum = new decimal(new int[] { 299 | 1, 300 | 0, 301 | 0, 302 | 131072}); 303 | this.boxThreshNumeric.Name = "boxThreshNumeric"; 304 | this.boxThreshNumeric.Size = new System.Drawing.Size(74, 21); 305 | this.boxThreshNumeric.TabIndex = 15; 306 | this.boxThreshNumeric.Value = new decimal(new int[] { 307 | 3, 308 | 0, 309 | 0, 310 | 65536}); 311 | // 312 | // label7 313 | // 314 | this.label7.AutoSize = true; 315 | this.label7.Location = new System.Drawing.Point(5, 130); 316 | this.label7.Name = "label7"; 317 | this.label7.Size = new System.Drawing.Size(71, 12); 318 | this.label7.TabIndex = 21; 319 | this.label7.Text = "unClipRatio"; 320 | // 321 | // unClipRatioNumeric 322 | // 323 | this.unClipRatioNumeric.DecimalPlaces = 1; 324 | this.unClipRatioNumeric.Increment = new decimal(new int[] { 325 | 1, 326 | 0, 327 | 0, 328 | 65536}); 329 | this.unClipRatioNumeric.Location = new System.Drawing.Point(87, 133); 330 | this.unClipRatioNumeric.Maximum = new decimal(new int[] { 331 | 10, 332 | 0, 333 | 0, 334 | 0}); 335 | this.unClipRatioNumeric.Minimum = new decimal(new int[] { 336 | 1, 337 | 0, 338 | 0, 339 | 65536}); 340 | this.unClipRatioNumeric.Name = "unClipRatioNumeric"; 341 | this.unClipRatioNumeric.Size = new System.Drawing.Size(74, 21); 342 | this.unClipRatioNumeric.TabIndex = 22; 343 | this.unClipRatioNumeric.Value = new decimal(new int[] { 344 | 16, 345 | 0, 346 | 0, 347 | 65536}); 348 | // 349 | // doAngleCheckBox 350 | // 351 | this.doAngleCheckBox.AutoSize = true; 352 | this.doAngleCheckBox.Checked = true; 353 | this.doAngleCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; 354 | this.doAngleCheckBox.Location = new System.Drawing.Point(5, 165); 355 | this.doAngleCheckBox.Name = "doAngleCheckBox"; 356 | this.doAngleCheckBox.Size = new System.Drawing.Size(66, 16); 357 | this.doAngleCheckBox.TabIndex = 26; 358 | this.doAngleCheckBox.Text = "doAngle"; 359 | this.doAngleCheckBox.UseVisualStyleBackColor = true; 360 | // 361 | // mostAngleCheckBox 362 | // 363 | this.mostAngleCheckBox.AutoSize = true; 364 | this.mostAngleCheckBox.Location = new System.Drawing.Point(87, 165); 365 | this.mostAngleCheckBox.Name = "mostAngleCheckBox"; 366 | this.mostAngleCheckBox.Size = new System.Drawing.Size(78, 16); 367 | this.mostAngleCheckBox.TabIndex = 27; 368 | this.mostAngleCheckBox.Text = "mostAngle"; 369 | this.mostAngleCheckBox.UseVisualStyleBackColor = true; 370 | // 371 | // label4 372 | // 373 | this.label4.AutoSize = true; 374 | this.label4.Location = new System.Drawing.Point(5, 66); 375 | this.label4.Name = "label4"; 376 | this.label4.Size = new System.Drawing.Size(71, 24); 377 | this.label4.TabIndex = 12; 378 | this.label4.Text = "boxScoreThresh"; 379 | // 380 | // imgResizeNumeric 381 | // 382 | this.imgResizeNumeric.Location = new System.Drawing.Point(87, 37); 383 | this.imgResizeNumeric.Maximum = new decimal(new int[] { 384 | 99999, 385 | 0, 386 | 0, 387 | 0}); 388 | this.imgResizeNumeric.Name = "imgResizeNumeric"; 389 | this.imgResizeNumeric.Size = new System.Drawing.Size(74, 21); 390 | this.imgResizeNumeric.TabIndex = 10; 391 | this.imgResizeNumeric.Value = new decimal(new int[] { 392 | 1024, 393 | 0, 394 | 0, 395 | 0}); 396 | // 397 | // label3 398 | // 399 | this.label3.AutoSize = true; 400 | this.label3.Location = new System.Drawing.Point(5, 34); 401 | this.label3.Name = "label3"; 402 | this.label3.Size = new System.Drawing.Size(65, 12); 403 | this.label3.TabIndex = 9; 404 | this.label3.Text = "maxSideLen"; 405 | // 406 | // paddingNumeric 407 | // 408 | this.paddingNumeric.Location = new System.Drawing.Point(87, 5); 409 | this.paddingNumeric.Maximum = new decimal(new int[] { 410 | 200, 411 | 0, 412 | 0, 413 | 0}); 414 | this.paddingNumeric.Name = "paddingNumeric"; 415 | this.paddingNumeric.Size = new System.Drawing.Size(74, 21); 416 | this.paddingNumeric.TabIndex = 7; 417 | this.paddingNumeric.Value = new decimal(new int[] { 418 | 50, 419 | 0, 420 | 0, 421 | 0}); 422 | // 423 | // label2 424 | // 425 | this.label2.AutoSize = true; 426 | this.label2.Location = new System.Drawing.Point(5, 2); 427 | this.label2.Name = "label2"; 428 | this.label2.Size = new System.Drawing.Size(47, 12); 429 | this.label2.TabIndex = 6; 430 | this.label2.Text = "padding"; 431 | // 432 | // boxScoreThreshNumeric 433 | // 434 | this.boxScoreThreshNumeric.DecimalPlaces = 3; 435 | this.boxScoreThreshNumeric.Increment = new decimal(new int[] { 436 | 1, 437 | 0, 438 | 0, 439 | 65536}); 440 | this.boxScoreThreshNumeric.Location = new System.Drawing.Point(87, 69); 441 | this.boxScoreThreshNumeric.Maximum = new decimal(new int[] { 442 | 1, 443 | 0, 444 | 0, 445 | 0}); 446 | this.boxScoreThreshNumeric.Minimum = new decimal(new int[] { 447 | 1, 448 | 0, 449 | 0, 450 | 131072}); 451 | this.boxScoreThreshNumeric.Name = "boxScoreThreshNumeric"; 452 | this.boxScoreThreshNumeric.Size = new System.Drawing.Size(74, 21); 453 | this.boxScoreThreshNumeric.TabIndex = 13; 454 | this.boxScoreThreshNumeric.Value = new decimal(new int[] { 455 | 5, 456 | 0, 457 | 0, 458 | 65536}); 459 | // 460 | // tableLayoutPanel3 461 | // 462 | this.tableLayoutPanel3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 463 | | System.Windows.Forms.AnchorStyles.Right))); 464 | this.tableLayoutPanel3.ColumnCount = 3; 465 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 170F)); 466 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); 467 | this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); 468 | this.tableLayoutPanel3.Controls.Add(this.pictureBox, 1, 0); 469 | this.tableLayoutPanel3.Controls.Add(this.strRestTextBox, 2, 0); 470 | this.tableLayoutPanel3.Controls.Add(this.tableLayoutPanel1, 0, 0); 471 | this.tableLayoutPanel3.Location = new System.Drawing.Point(14, 229); 472 | this.tableLayoutPanel3.Name = "tableLayoutPanel3"; 473 | this.tableLayoutPanel3.RowCount = 1; 474 | this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); 475 | this.tableLayoutPanel3.Size = new System.Drawing.Size(757, 268); 476 | this.tableLayoutPanel3.TabIndex = 16; 477 | // 478 | // pictureBox 479 | // 480 | this.pictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 481 | | System.Windows.Forms.AnchorStyles.Right))); 482 | this.pictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 483 | this.pictureBox.Location = new System.Drawing.Point(173, 3); 484 | this.pictureBox.Name = "pictureBox"; 485 | this.pictureBox.Size = new System.Drawing.Size(287, 260); 486 | this.pictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; 487 | this.pictureBox.TabIndex = 3; 488 | this.pictureBox.TabStop = false; 489 | // 490 | // strRestTextBox 491 | // 492 | this.strRestTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 493 | | System.Windows.Forms.AnchorStyles.Right))); 494 | this.strRestTextBox.Location = new System.Drawing.Point(466, 3); 495 | this.strRestTextBox.Multiline = true; 496 | this.strRestTextBox.Name = "strRestTextBox"; 497 | this.strRestTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; 498 | this.strRestTextBox.Size = new System.Drawing.Size(288, 260); 499 | this.strRestTextBox.TabIndex = 0; 500 | // 501 | // tableLayoutPanel1 502 | // 503 | this.tableLayoutPanel1.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Outset; 504 | this.tableLayoutPanel1.ColumnCount = 2; 505 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80F)); 506 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 96F)); 507 | this.tableLayoutPanel1.Controls.Add(this.boxScoreThreshNumeric, 1, 2); 508 | this.tableLayoutPanel1.Controls.Add(this.label4, 0, 2); 509 | this.tableLayoutPanel1.Controls.Add(this.imgResizeNumeric, 1, 1); 510 | this.tableLayoutPanel1.Controls.Add(this.label3, 0, 1); 511 | this.tableLayoutPanel1.Controls.Add(this.paddingNumeric, 1, 0); 512 | this.tableLayoutPanel1.Controls.Add(this.label2, 0, 0); 513 | this.tableLayoutPanel1.Controls.Add(this.label5, 0, 3); 514 | this.tableLayoutPanel1.Controls.Add(this.boxThreshNumeric, 1, 3); 515 | this.tableLayoutPanel1.Controls.Add(this.label7, 0, 4); 516 | this.tableLayoutPanel1.Controls.Add(this.unClipRatioNumeric, 1, 4); 517 | this.tableLayoutPanel1.Controls.Add(this.doAngleCheckBox, 0, 5); 518 | this.tableLayoutPanel1.Controls.Add(this.mostAngleCheckBox, 1, 5); 519 | this.tableLayoutPanel1.Controls.Add(this.partImgCheckBox, 0, 6); 520 | this.tableLayoutPanel1.Controls.Add(this.debugCheckBox, 1, 6); 521 | this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); 522 | this.tableLayoutPanel1.Name = "tableLayoutPanel1"; 523 | this.tableLayoutPanel1.RowCount = 8; 524 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 525 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 526 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 527 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 528 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 529 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 530 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 531 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); 532 | this.tableLayoutPanel1.Size = new System.Drawing.Size(164, 260); 533 | this.tableLayoutPanel1.TabIndex = 2; 534 | // 535 | // partImgCheckBox 536 | // 537 | this.partImgCheckBox.AutoSize = true; 538 | this.partImgCheckBox.Location = new System.Drawing.Point(5, 197); 539 | this.partImgCheckBox.Name = "partImgCheckBox"; 540 | this.partImgCheckBox.Size = new System.Drawing.Size(66, 16); 541 | this.partImgCheckBox.TabIndex = 28; 542 | this.partImgCheckBox.Text = "PartImg"; 543 | this.partImgCheckBox.UseVisualStyleBackColor = true; 544 | this.partImgCheckBox.CheckedChanged += new System.EventHandler(this.partImgCheckBox_CheckedChanged); 545 | // 546 | // debugCheckBox 547 | // 548 | this.debugCheckBox.AutoSize = true; 549 | this.debugCheckBox.Location = new System.Drawing.Point(87, 197); 550 | this.debugCheckBox.Name = "debugCheckBox"; 551 | this.debugCheckBox.Size = new System.Drawing.Size(72, 16); 552 | this.debugCheckBox.TabIndex = 29; 553 | this.debugCheckBox.Text = "DebugImg"; 554 | this.debugCheckBox.UseVisualStyleBackColor = true; 555 | this.debugCheckBox.CheckedChanged += new System.EventHandler(this.debugCheckBox_CheckedChanged); 556 | // 557 | // detectBtn 558 | // 559 | this.detectBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 560 | this.detectBtn.Location = new System.Drawing.Point(697, 12); 561 | this.detectBtn.Name = "detectBtn"; 562 | this.detectBtn.Size = new System.Drawing.Size(74, 114); 563 | this.detectBtn.TabIndex = 12; 564 | this.detectBtn.Text = "Detect"; 565 | this.detectBtn.UseVisualStyleBackColor = true; 566 | this.detectBtn.Click += new System.EventHandler(this.detectBtn_Click); 567 | // 568 | // initBtn 569 | // 570 | this.initBtn.Location = new System.Drawing.Point(697, 132); 571 | this.initBtn.Name = "initBtn"; 572 | this.initBtn.Size = new System.Drawing.Size(74, 91); 573 | this.initBtn.TabIndex = 15; 574 | this.initBtn.Text = "重新初始化"; 575 | this.initBtn.UseVisualStyleBackColor = true; 576 | this.initBtn.Click += new System.EventHandler(this.initBtn_Click); 577 | // 578 | // ocrResultTextBox 579 | // 580 | this.ocrResultTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 581 | | System.Windows.Forms.AnchorStyles.Left) 582 | | System.Windows.Forms.AnchorStyles.Right))); 583 | this.ocrResultTextBox.Font = new System.Drawing.Font("宋体", 9F); 584 | this.ocrResultTextBox.Location = new System.Drawing.Point(14, 503); 585 | this.ocrResultTextBox.Multiline = true; 586 | this.ocrResultTextBox.Name = "ocrResultTextBox"; 587 | this.ocrResultTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; 588 | this.ocrResultTextBox.Size = new System.Drawing.Size(757, 246); 589 | this.ocrResultTextBox.TabIndex = 13; 590 | // 591 | // FormOcr 592 | // 593 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 594 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 595 | this.ClientSize = new System.Drawing.Size(784, 761); 596 | this.Controls.Add(this.tableLayoutPanel2); 597 | this.Controls.Add(this.tableLayoutPanel3); 598 | this.Controls.Add(this.detectBtn); 599 | this.Controls.Add(this.initBtn); 600 | this.Controls.Add(this.ocrResultTextBox); 601 | this.Name = "FormOcr"; 602 | this.Text = "RapidOcrOnnxCs v1.2.0"; 603 | this.Load += new System.EventHandler(this.Form1_Load); 604 | this.tableLayoutPanel2.ResumeLayout(false); 605 | this.tableLayoutPanel2.PerformLayout(); 606 | ((System.ComponentModel.ISupportInitialize)(this.numThreadNumeric)).EndInit(); 607 | ((System.ComponentModel.ISupportInitialize)(this.boxThreshNumeric)).EndInit(); 608 | ((System.ComponentModel.ISupportInitialize)(this.unClipRatioNumeric)).EndInit(); 609 | ((System.ComponentModel.ISupportInitialize)(this.imgResizeNumeric)).EndInit(); 610 | ((System.ComponentModel.ISupportInitialize)(this.paddingNumeric)).EndInit(); 611 | ((System.ComponentModel.ISupportInitialize)(this.boxScoreThreshNumeric)).EndInit(); 612 | this.tableLayoutPanel3.ResumeLayout(false); 613 | this.tableLayoutPanel3.PerformLayout(); 614 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit(); 615 | this.tableLayoutPanel1.ResumeLayout(false); 616 | this.tableLayoutPanel1.PerformLayout(); 617 | this.ResumeLayout(false); 618 | this.PerformLayout(); 619 | 620 | } 621 | 622 | #endregion 623 | 624 | private System.Windows.Forms.Label label8; 625 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; 626 | private System.Windows.Forms.TextBox modelsTextBox; 627 | private System.Windows.Forms.Label label9; 628 | private System.Windows.Forms.Button modelsBtn; 629 | private System.Windows.Forms.TextBox pathTextBox; 630 | private System.Windows.Forms.Button openBtn; 631 | private System.Windows.Forms.Label label1; 632 | private System.Windows.Forms.NumericUpDown numThreadNumeric; 633 | private System.Windows.Forms.Label label6; 634 | private System.Windows.Forms.TextBox detNameTextBox; 635 | private System.Windows.Forms.Label label10; 636 | private System.Windows.Forms.TextBox clsNameTextBox; 637 | private System.Windows.Forms.Label label11; 638 | private System.Windows.Forms.TextBox recNameTextBox; 639 | private System.Windows.Forms.Label label12; 640 | private System.Windows.Forms.TextBox keysNameTextBox; 641 | private System.Windows.Forms.Label label5; 642 | private System.Windows.Forms.NumericUpDown boxThreshNumeric; 643 | private System.Windows.Forms.Label label7; 644 | private System.Windows.Forms.NumericUpDown unClipRatioNumeric; 645 | private System.Windows.Forms.CheckBox doAngleCheckBox; 646 | private System.Windows.Forms.CheckBox mostAngleCheckBox; 647 | private System.Windows.Forms.Label label4; 648 | private System.Windows.Forms.NumericUpDown imgResizeNumeric; 649 | private System.Windows.Forms.Label label3; 650 | private System.Windows.Forms.NumericUpDown paddingNumeric; 651 | private System.Windows.Forms.Label label2; 652 | private System.Windows.Forms.NumericUpDown boxScoreThreshNumeric; 653 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; 654 | private System.Windows.Forms.PictureBox pictureBox; 655 | private System.Windows.Forms.TextBox strRestTextBox; 656 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; 657 | private System.Windows.Forms.CheckBox partImgCheckBox; 658 | private System.Windows.Forms.CheckBox debugCheckBox; 659 | private System.Windows.Forms.Button detectBtn; 660 | private System.Windows.Forms.Button initBtn; 661 | private System.Windows.Forms.TextBox ocrResultTextBox; 662 | } 663 | } 664 | 665 | -------------------------------------------------------------------------------- /OcrOnnxForm/FormOcr.cs: -------------------------------------------------------------------------------- 1 | using Emgu.CV; 2 | using Emgu.CV.CvEnum; 3 | using OcrLiteLib; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.Data; 8 | using System.Drawing; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | using System.Windows.Forms; 14 | 15 | namespace BaiPiaoOcrOnnxCs 16 | { 17 | public partial class FormOcr : Form 18 | { 19 | private OcrLite ocrEngin; 20 | 21 | public FormOcr() 22 | { 23 | InitializeComponent(); 24 | } 25 | 26 | private void Form1_Load(object sender, EventArgs e) 27 | { 28 | string appPath = AppDomain.CurrentDomain.BaseDirectory; 29 | string appDir = Directory.GetParent(appPath).FullName; 30 | string modelsDir = appPath + "models"; 31 | modelsTextBox.Text = modelsDir; 32 | string detPath = modelsDir + "\\" + detNameTextBox.Text; 33 | string clsPath = modelsDir + "\\" + clsNameTextBox.Text; 34 | string recPath = modelsDir + "\\" + recNameTextBox.Text; 35 | string keysPath = modelsDir + "\\" + keysNameTextBox.Text; 36 | bool isDetExists = File.Exists(detPath); 37 | if (!isDetExists) 38 | { 39 | MessageBox.Show("模型文件不存在:" + detPath); 40 | } 41 | bool isClsExists = File.Exists(clsPath); 42 | if (!isClsExists) 43 | { 44 | MessageBox.Show("模型文件不存在:" + clsPath); 45 | } 46 | bool isRecExists = File.Exists(recPath); 47 | if (!isRecExists) 48 | { 49 | MessageBox.Show("模型文件不存在:" + recPath); 50 | } 51 | bool isKeysExists = File.Exists(recPath); 52 | if (!isKeysExists) 53 | { 54 | MessageBox.Show("Keys文件不存在:" + keysPath); 55 | } 56 | if (isDetExists && isClsExists && isRecExists && isKeysExists) 57 | { 58 | ocrEngin = new OcrLite(); 59 | ocrEngin.InitModels(detPath, clsPath, recPath, keysPath, (int)numThreadNumeric.Value); 60 | } 61 | else 62 | { 63 | MessageBox.Show("初始化失败,请确认模型文件夹和文件后,重新初始化!"); 64 | } 65 | } 66 | 67 | private void initBtn_Click(object sender, EventArgs e) 68 | { 69 | string modelsDir = modelsTextBox.Text; 70 | string detPath = modelsDir + "\\" + detNameTextBox.Text; 71 | string clsPath = modelsDir + "\\" + clsNameTextBox.Text; 72 | string recPath = modelsDir + "\\" + recNameTextBox.Text; 73 | string keysPath = modelsDir + "\\" + keysNameTextBox.Text; 74 | bool isDetExists = File.Exists(detPath); 75 | if (!isDetExists) 76 | { 77 | MessageBox.Show("模型文件不存在:" + detPath); 78 | } 79 | bool isClsExists = File.Exists(clsPath); 80 | if (!isClsExists) 81 | { 82 | MessageBox.Show("模型文件不存在:" + clsPath); 83 | } 84 | bool isRecExists = File.Exists(recPath); 85 | if (!isRecExists) 86 | { 87 | MessageBox.Show("模型文件不存在:" + recPath); 88 | } 89 | bool isKeysExists = File.Exists(recPath); 90 | if (!isKeysExists) 91 | { 92 | MessageBox.Show("Keys文件不存在:" + keysPath); 93 | } 94 | if (isDetExists && isClsExists && isRecExists && isKeysExists) 95 | { 96 | ocrEngin = new OcrLite(); 97 | ocrEngin.InitModels(detPath, clsPath, recPath, keysPath, (int)numThreadNumeric.Value); 98 | } 99 | else 100 | { 101 | MessageBox.Show("初始化失败,请确认模型文件夹和文件后,重新初始化!"); 102 | } 103 | } 104 | 105 | private void openBtn_Click(object sender, EventArgs e) 106 | { 107 | using (var dlg = new OpenFileDialog()) 108 | { 109 | dlg.Multiselect = false; 110 | dlg.Filter = "(*.JPG,*.PNG,*.JPEG,*.BMP,*.GIF)|*.JPG;*.PNG;*.JPEG;*.BMP;*.GIF|All files(*.*)|*.*"; 111 | if (dlg.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(dlg.FileName)) 112 | { 113 | pathTextBox.Text = dlg.FileName; 114 | Mat src = CvInvoke.Imread(dlg.FileName, ImreadModes.Color); 115 | pictureBox.Image = src.ToBitmap(); 116 | } 117 | } 118 | } 119 | 120 | private void modelsBtn_Click(object sender, EventArgs e) 121 | { 122 | using (var dlg = new FolderBrowserDialog()) 123 | { 124 | dlg.SelectedPath = Environment.CurrentDirectory + "\\models"; 125 | if (dlg.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(dlg.SelectedPath)) 126 | { 127 | modelsTextBox.Text = dlg.SelectedPath; 128 | } 129 | } 130 | } 131 | 132 | private void detectBtn_Click(object sender, EventArgs e) 133 | { 134 | if (ocrEngin == null) 135 | { 136 | MessageBox.Show("未初始化,无法执行!"); 137 | return; 138 | } 139 | string targetImg = pathTextBox.Text; 140 | if (!File.Exists(targetImg)) 141 | { 142 | MessageBox.Show("目标图片不存在,请用Open按钮打开"); 143 | return; 144 | } 145 | int padding = (int)paddingNumeric.Value; 146 | int imgResize = (int)imgResizeNumeric.Value; 147 | float boxScoreThresh = (float)boxScoreThreshNumeric.Value; 148 | float boxThresh = (float)boxThreshNumeric.Value; 149 | float unClipRatio = (float)unClipRatioNumeric.Value; 150 | bool doAngle = doAngleCheckBox.Checked; 151 | bool mostAngle = mostAngleCheckBox.Checked; 152 | OcrResult ocrResult = ocrEngin.Detect(pathTextBox.Text, padding, imgResize, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle); 153 | ocrResultTextBox.Text = ocrResult.ToString(); 154 | strRestTextBox.Text = ocrResult.StrRes; 155 | pictureBox.Image = ocrResult.BoxImg.ToBitmap(); 156 | } 157 | 158 | private void partImgCheckBox_CheckedChanged(object sender, EventArgs e) 159 | { 160 | ocrEngin.isPartImg = partImgCheckBox.Checked; 161 | } 162 | 163 | private void debugCheckBox_CheckedChanged(object sender, EventArgs e) 164 | { 165 | ocrEngin.isDebugImg = debugCheckBox.Checked; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /OcrOnnxForm/FormOcr.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /OcrOnnxForm/OcrOnnxForm.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {43A96152-8891-4505-8389-32276F3A9422} 8 | WinExe 9 | RapidOcrOnnxCs 10 | RapidOcrOnnxCs 11 | v4.6.1 12 | 512 13 | true 14 | true 15 | 16 | 17 | x64 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | true 37 | bin\x64\Debug\ 38 | DEBUG;TRACE 39 | full 40 | x64 41 | 7.3 42 | prompt 43 | true 44 | 45 | 46 | bin\x64\Release\ 47 | TRACE 48 | true 49 | pdbonly 50 | x64 51 | 7.3 52 | prompt 53 | true 54 | 55 | 56 | 57 | ..\packages\Emgu.CV.Bitmap.4.4.0.4099\lib\netstandard2.0\Emgu.CV.Bitmap.dll 58 | 59 | 60 | ..\packages\Emgu.CV.4.4.0.4099\lib\netstandard2.0\Emgu.CV.Platform.NetStandard.dll 61 | 62 | 63 | 64 | 65 | 66 | ..\packages\System.Drawing.Common.4.7.0\lib\net461\System.Drawing.Common.dll 67 | 68 | 69 | ..\packages\System.Drawing.Primitives.4.3.0\lib\net45\System.Drawing.Primitives.dll 70 | 71 | 72 | ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | Form 87 | 88 | 89 | FormOcr.cs 90 | 91 | 92 | 93 | 94 | FormOcr.cs 95 | 96 | 97 | ResXFileCodeGenerator 98 | Resources.Designer.cs 99 | Designer 100 | 101 | 102 | True 103 | Resources.resx 104 | True 105 | 106 | 107 | 108 | SettingsSingleFileGenerator 109 | Settings.Designer.cs 110 | 111 | 112 | True 113 | Settings.settings 114 | True 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | {ab10d356-2d95-4460-96ca-9a7129ad0a76} 123 | OcrLib 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /OcrOnnxForm/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace BaiPiaoOcrOnnxCs 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// 应用程序的主入口点。 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new FormOcr()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /OcrOnnxForm/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("BaiPiaoOcrOnnxCs")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("BaiPiaoOcrOnnxCs")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("43a96152-8891-4505-8389-32276f3a9422")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | // 方法是按如下所示使用“*”: : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /OcrOnnxForm/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace RapidOcrOnnxCs.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RapidOcrOnnxCs.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性,对 51 | /// 使用此强类型资源类的所有资源查找执行重写。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /OcrOnnxForm/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /OcrOnnxForm/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace RapidOcrOnnxCs.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /OcrOnnxForm/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OcrOnnxForm/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RapidOcrOnnxCs 2 | 3 | ### 联系方式 4 | 5 | [QQ群](https://rapidai.github.io/RapidOCRDocs/main/communicate/#qq) 6 | 7 | ### 介绍 8 | * 本项目为Windows平台C# WinForm范例。 9 | * 依赖的包:Emgu.CV、MicroSoft.ML.OnnxRuntime、clipper_library 10 | 11 | ### Demo下载(win、mac、linux) 12 | 编译好的demo文件比较大,可以到Q群共享内下载 13 | 14 | ### 编译环境 15 | 1. Windows 10 x64 16 | 2. Visual Studio 2017或以上 17 | 18 | ### 编译说明 19 | 1. Vs2019打开RapidOcrOnnxCs.sln。 20 | 2. 解决方案资源管理器->OcrLib->右键->管理NuGet程序包->浏览->搜索->安装 21 | * 注意:Emgu.CV要选作者是“Emgu Corporation” 22 | * Emgu.CV 4.5.5.4823 23 | * Emgu.CV.runtime.windows 4.5.5.4823 24 | * MicroSoft.ML.OnnxRuntime 1.12.1 25 | * clipper_library 6.2.1 26 | 3. 解决方案资源管理器->OcrLiteOnnxForm->右键->管理NuGet程序包->浏览->搜索->安装 27 | * 注意:Emgu.CV要选作者是“Emgu Corporation” 28 | * Emgu.CV 4.5.5.4823 29 | * Emgu.CV.Bitmap 4.5.5.4823 30 | 4. 确保:OcrLiteOnnxForm设为启动项目 31 | 5. 确保:OcrLiteOnnxForm->右键->属性->生成->平台目标:x64 32 | 6. 确保:OcrLiteLib->右键->属性->生成->平台目标:x64 33 | 7. 生成解决方案 34 | 8. 把models文件夹复制到```\RapidOcrOnnxCs\OcrOnnxForm\bin\Debug(或Release)``` 35 | * [模型下载地址](https://github.com/znsoftm/BaiPiaoOCR/tree/main/models) 36 | 9. 运行 37 | 38 | ### 其它 39 | * 修改模型路径,模型名称,线程数,必须“重新初始化”才能生效 40 | * 输入参数说明请参考[RapidOcrOnnx](https://github.com/RapidAI/RapidOcrOnnx/tree/61d7b434d2b773eb61dab85328240789f69b3ae0#%E8%BE%93%E5%85%A5%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E) 41 | -------------------------------------------------------------------------------- /RapidOcrOnnxCs.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.32929.386 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OcrOnnxForm", "OcrOnnxForm\OcrOnnxForm.csproj", "{43A96152-8891-4505-8389-32276F3A9422}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OcrLib", "OcrLib\OcrLib.csproj", "{AB10D356-2D95-4460-96CA-9A7129AD0A76}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|x64 = Debug|x64 14 | Release|Any CPU = Release|Any CPU 15 | Release|x64 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {43A96152-8891-4505-8389-32276F3A9422}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {43A96152-8891-4505-8389-32276F3A9422}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {43A96152-8891-4505-8389-32276F3A9422}.Debug|x64.ActiveCfg = Debug|x64 21 | {43A96152-8891-4505-8389-32276F3A9422}.Debug|x64.Build.0 = Debug|x64 22 | {43A96152-8891-4505-8389-32276F3A9422}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {43A96152-8891-4505-8389-32276F3A9422}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {43A96152-8891-4505-8389-32276F3A9422}.Release|x64.ActiveCfg = Release|x64 25 | {43A96152-8891-4505-8389-32276F3A9422}.Release|x64.Build.0 = Release|x64 26 | {AB10D356-2D95-4460-96CA-9A7129AD0A76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {AB10D356-2D95-4460-96CA-9A7129AD0A76}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {AB10D356-2D95-4460-96CA-9A7129AD0A76}.Debug|x64.ActiveCfg = Debug|x64 29 | {AB10D356-2D95-4460-96CA-9A7129AD0A76}.Debug|x64.Build.0 = Debug|x64 30 | {AB10D356-2D95-4460-96CA-9A7129AD0A76}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {AB10D356-2D95-4460-96CA-9A7129AD0A76}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {AB10D356-2D95-4460-96CA-9A7129AD0A76}.Release|x64.ActiveCfg = Release|x64 33 | {AB10D356-2D95-4460-96CA-9A7129AD0A76}.Release|x64.Build.0 = Release|x64 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {6B47A7DB-6FE4-4943-9806-6D54D2BEC392} 40 | EndGlobalSection 41 | EndGlobal 42 | --------------------------------------------------------------------------------