Skip to content

Commit

Permalink
Merge pull request #2 from sdcb/ir-queue-raw-ir
Browse files Browse the repository at this point in the history
0.5.1
  • Loading branch information
sdcb authored Oct 31, 2023
2 parents 15c180d + 9a21d70 commit a9d344a
Show file tree
Hide file tree
Showing 29 changed files with 639 additions and 182 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[*.cs]

# xUnit1004: Test methods should not be skipped
dotnet_diagnostic.xUnit1004.severity = silent
6 changes: 3 additions & 3 deletions build/00-common.linq
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ static void DotNetRun(string args) => Run("dotnet", args.Dump(), Encoding.GetEnc
static void Run(string exe, string args, Encoding encoding) => Util.Cmd(exe, args, encoding);
static ProjectVersion[] Projects = new[]
{
new ProjectVersion("Sdcb.OpenVINO", "0.4.5"),
new ProjectVersion("Sdcb.OpenVINO.Extensions.OpenCvSharp4", "0.1.0"),
new ProjectVersion("Sdcb.OpenVINO.PaddleOCR", "0.3.1"),
new ProjectVersion("Sdcb.OpenVINO", "0.5.1"),
new ProjectVersion("Sdcb.OpenVINO.Extensions.OpenCvSharp4", "0.2.0"),
new ProjectVersion("Sdcb.OpenVINO.PaddleOCR", "0.5.1"),
new ProjectVersion("Sdcb.OpenVINO.PaddleOCR.Models.Online", "0.2"),
};

Expand Down
18 changes: 16 additions & 2 deletions projects/PaddleOCR/Sdcb.OpenVINO.PaddleOCR.Tests/CrashTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ await Task.WhenAll(Enumerable.Range(0, threadCount).Select(i => Task.Run(() =>
})));
}

[Fact(Skip = "Crash test only")]
[Fact(Skip = "Crash test only"), Obsolete("QueuedPaddleOcrAll")]
public async Task QueuedTest()
{
using Mat src = Cv2.ImRead("./samples/vsext.png");
using Mat src = Cv2.ImRead("./samples/vsext.png");
//using Mat src = Cv2.ImDecode(await new HttpClient().GetByteArrayAsync("https://io.starworks.cc:88/paddlesharp/ocr/samples/xdr5450.webp"), ImreadModes.Color);

FullOcrModel model = await OnlineFullModels.ChineseV4.DownloadAsync();
Expand All @@ -130,4 +130,18 @@ public async Task QueuedTest()

await Task.WhenAll(Enumerable.Range(0, 100).Select(i => queued.Run(src)));
}

[Fact]
public async Task OcrIsThreadSafe()
{
using Mat src = Cv2.ImRead("./samples/vsext.png");
using PaddleOcrAll ocr = new(await OnlineFullModels.ChineseV4.DownloadAsync());
Task[] tasks = Enumerable.Range(0, 2).Select(tidx => Task.Run(() =>
{
ocr.Run(src);
_console.WriteLine($"tid {tidx}: Good");
})).ToArray();

await Task.WhenAll(tasks);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public async Task ClsCPUBatch()
ClsAsserts(cls, new[] { false, true }, new[] { src, src2 });
}

[Fact]
[Fact(Skip = "GPU too slow")]
public async Task ClsGpu()
{
using Mat src = Cv2.ImRead("./samples/5ghz.jpg");
Expand All @@ -48,7 +48,7 @@ public async Task ClsGpu()
ClsAsserts(cls, true, src);
}

[Fact]
[Fact(Skip = "GPU too slow")]
public async Task ClsGpuBatch()
{
using Mat src = Cv2.ImRead("./samples/5ghz.jpg");
Expand All @@ -59,7 +59,7 @@ public async Task ClsGpuBatch()
ClsAsserts(cls, new[] { false, true }, new[] { src, src2 });
}

[Fact]
[Fact(Skip = "GPU too slow")]
public async Task ClsGpuBatch10()
{
using Mat src = Cv2.ImRead("./samples/5ghz.jpg");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,34 @@ public async Task FastCheckOCR()
_console.WriteLine("Detected all texts: \n" + result.Text);
foreach (PaddleOcrResultRegion region in result.Regions)
{
_console.WriteLine($"Text: {region.Text}, Score: {region.Score}, RectCenter: {region.Rect.Center}, RectSize: {region.Rect.Size}, Angle: {region.Rect.Angle}");
_console.WriteLine($"Text: {region.Text}, Score: {region.Score}, RectCenter: {region.Rect.Center}, RectSize: {region.Rect.Size}, Angle: {region.Rect.Angle}");
}
}
}
}

[Fact]
public async Task NoRotateTest()
{
FullOcrModel model = await OnlineFullModels.EnglishV3.DownloadAsync();

byte[] sampleImageData = File.ReadAllBytes(@"./samples/vsext.png");

using (PaddleOcrAll all = new(model)
{
AllowRotateDetection = false,
Enable180Classification = false,
})
{
using (Mat src = Cv2.ImDecode(sampleImageData, ImreadModes.Color))
{
PaddleOcrResult result = all.Run(src);
_console.WriteLine(result.Text);
Assert.Contains("IDE", result.Text);
}
}
}

[Fact]
public async Task FastCheckOCRWith180Cls()
{
Expand Down Expand Up @@ -76,7 +98,7 @@ public async Task FastCheckOCRWith180Cls()
}
}

[Fact]
[Fact(Skip = "GPU too slow")]
public async Task GPUFastCheckOCR()
{
FullOcrModel model = await OnlineFullModels.EnglishV3.DownloadAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public async Task RecCPUSmallerShape()
RecAsserts(rec, src);
}

[Fact]
[Fact(Skip = "GPU too slow")]
public async Task RecGpu()
{
using Mat src = Cv2.ImRead("./samples/5ghz.jpg");
Expand All @@ -69,7 +69,7 @@ public async Task RecGpu()
RecAsserts(rec, src);
}

[Fact]
[Fact(Skip = "GPU too slow")]
public async Task RecGpuLargerBatchShape()
{
using Mat src = Cv2.ImRead("./samples/5ghz.jpg");
Expand Down
34 changes: 17 additions & 17 deletions projects/PaddleOCR/Sdcb.OpenVINO.PaddleOCR/PaddleOcrClassifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Sdcb.OpenVINO.PaddleOCR;
/// </summary>
public class PaddleOcrClassifier : IDisposable
{
private readonly InferRequest _p;
private readonly CompiledModel _compiledModel;

/// <summary>
/// Rotation threshold value used to determine if the image should be rotated.
Expand All @@ -36,10 +36,11 @@ public class PaddleOcrClassifier : IDisposable
/// </summary>
/// <param name="model">The <see cref="ClassificationModel"/> to use.</param>
/// <param name="device">The device the inference request, pass null to using model's DefaultDevice.</param>
public PaddleOcrClassifier(ClassificationModel model, DeviceOptions? device = null)
public PaddleOcrClassifier(ClassificationModel model,
DeviceOptions? device = null)
{
Shape = model.Shape;
_p = model.CreateInferRequest(device, prePostProcessing: (m, ppp) =>
_compiledModel = model.CreateCompiledModel(device, prePostProcessing: (m, ppp) =>
{
using PreProcessInputInfo ppii = ppp.Inputs.Primary;
ppii.TensorInfo.Layout = Layout.NHWC;
Expand All @@ -50,7 +51,7 @@ public PaddleOcrClassifier(ClassificationModel model, DeviceOptions? device = nu
/// <summary>
/// Releases all resources used by the <see cref="PaddleOcrClassifier"/> object.
/// </summary>
public void Dispose() => _p.Dispose();
public void Dispose() => _compiledModel.Dispose();

/// <summary>
/// Determines whether the image should be rotated by 180 degrees based on the threshold value.
Expand Down Expand Up @@ -103,23 +104,22 @@ private Ocr180DegreeClsResult[] BatchedShouldRotate180(Mat[] srcs)
{
using Mat final = PrepareAndStackImages(srcs);

using InferRequest ir = _compiledModel.CreateInferRequest();
using (Tensor input = final.StackedAsTensor(srcs.Length))
{
_p.Inputs.Primary = input;
_p.Run();
ir.Inputs.Primary = input;
ir.Run();
}

using (Tensor output = _p.Outputs.Primary)
using Tensor output = ir.Outputs.Primary;
ReadOnlySpan<float> data = output.GetData<float>();
Ocr180DegreeClsResult[] results = new Ocr180DegreeClsResult[data.Length / 2];
for (int i = 0; i < results.Length; i++)
{
ReadOnlySpan<float> data = output.GetData<float>();
Ocr180DegreeClsResult[] results = new Ocr180DegreeClsResult[data.Length / 2];
for (int i = 0; i < results.Length; i++)
{
results[i] = new Ocr180DegreeClsResult(data[(i * 2)..((i + 1) * 2)], RotateThreshold);
}

return results;
results[i] = new Ocr180DegreeClsResult(data[(i * 2)..((i + 1) * 2)], RotateThreshold);
}

return results;
}

private Mat PrepareAndStackImages(Mat[] srcs)
Expand All @@ -135,7 +135,7 @@ private Mat PrepareAndStackImages(Mat[] srcs)
{
4 => src.CvtColor(ColorConversionCodes.RGBA2RGB),
1 => src.CvtColor(ColorConversionCodes.GRAY2RGB),
3 => src.WeakRef(),
3 => src.FastClone(),
var x => throw new Exception($"Unexpect src channel: {x}, allow: (1/3/4)")
};
return ResizePadding(channel3, Shape);
Expand Down Expand Up @@ -191,7 +191,7 @@ private static Mat ResizePadding(Mat src, NCHW shape)
double whRatio = 1.0 * shape.Width / shape.Height;
using Mat roi = 1.0 * srcSize.Width / srcSize.Height > whRatio ?
src[0, srcSize.Height, 0, (int)Math.Floor(1.0 * srcSize.Height * whRatio)] :
src.WeakRef();
src.FastClone();

double scaleRate = 1.0 * shape.Height / srcSize.Height;
Mat resized = roi.Resize(new Size(Math.Floor(roi.Width * scaleRate), shape.Height));
Expand Down
26 changes: 14 additions & 12 deletions projects/PaddleOCR/Sdcb.OpenVINO.PaddleOCR/PaddleOcrDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ namespace Sdcb.OpenVINO.PaddleOCR;
/// </summary>
public class PaddleOcrDetector : IDisposable
{
/// <summary>Holds an instance of the InferRequest class.</summary>
readonly InferRequest _p;
readonly CompiledModel _compiledModel;

/// <summary>
/// Gets or sets the maximum size for resizing the input image.
Expand Down Expand Up @@ -66,7 +65,9 @@ public class PaddleOcrDetector : IDisposable
/// <para>If this property is null, network can work with image of any size and h/w ratio (dynamic).</para>
/// <para>Otherwise, network works with fixed size image (static).</para>
/// </param>
public PaddleOcrDetector(DetectionModel model, DeviceOptions? options = null, Size? staticShapeSize = null)
public PaddleOcrDetector(DetectionModel model,
DeviceOptions? options = null,
Size? staticShapeSize = null)
{
if (staticShapeSize != null)
{
Expand All @@ -75,7 +76,7 @@ public PaddleOcrDetector(DetectionModel model, DeviceOptions? options = null, Si
32 * Math.Ceiling(1.0 * staticShapeSize.Value.Height / 32));
}

_p = model.CreateInferRequest(options, afterReadModel: m =>
_compiledModel = model.CreateCompiledModel(options, afterReadModel: m =>
{
if (model.Version != ModelVersion.V4)
{
Expand Down Expand Up @@ -104,7 +105,7 @@ public PaddleOcrDetector(DetectionModel model, DeviceOptions? options = null, Si
/// </summary>
public void Dispose()
{
_p.Dispose();
_compiledModel.Dispose();
}

/// <summary>
Expand Down Expand Up @@ -221,14 +222,15 @@ public unsafe Mat RunRaw(Mat src, out Size resizedSize)
normalized = Normalize(padded);
}

using InferRequest ir = _compiledModel.CreateInferRequest();
using (Mat _ = normalized)
using (Tensor input = normalized.AsTensor())
{
_p.Inputs.Primary = input;
_p.Run();
ir.Inputs.Primary = input;
ir.Run();
}

using (Tensor output = _p.Outputs[0])
using (Tensor output = ir.Outputs[0])
{
Span<float> data = output.GetData<float>();
NCHW shape = output.Shape.ToNCHW();
Expand Down Expand Up @@ -263,23 +265,23 @@ private static float GetScore(Point[] contour, Mat pred)

private static Mat MatResize(Mat src, int? maxSize)
{
if (maxSize == null) return src.WeakRef();
if (maxSize == null) return src.FastClone();

Size size = src.Size();
int longEdge = Math.Max(size.Width, size.Height);
double scaleRate = 1.0 * maxSize.Value / longEdge;

return scaleRate < 1.0 ?
src.Resize(Size.Zero, scaleRate, scaleRate) :
src.WeakRef();
src.FastClone();
}

private static Mat MatResize(Mat src, Size maxSize)
{
Size srcSize = src.Size();
if (srcSize == maxSize)
{
return src.WeakRef();
return src.FastClone();
}

double scale = Math.Min(maxSize.Width / (double)srcSize.Width, maxSize.Height / (double)srcSize.Height);
Expand All @@ -289,7 +291,7 @@ private static Mat MatResize(Mat src, Size maxSize)

if (scale == 1)
{
return src.WeakRef();
return src.FastClone();
}
else
{
Expand Down
24 changes: 12 additions & 12 deletions projects/PaddleOCR/Sdcb.OpenVINO.PaddleOCR/PaddleOcrRecognizer.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using OpenCvSharp;
using Sdcb.OpenVINO.Natives;
using Sdcb.OpenVINO.Extensions.OpenCvSharp4;
using Sdcb.OpenVINO.PaddleOCR.Models;
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace Sdcb.OpenVINO.PaddleOCR;
Expand All @@ -14,7 +12,7 @@ namespace Sdcb.OpenVINO.PaddleOCR;
/// </summary>
public class PaddleOcrRecognizer : IDisposable
{
private readonly InferRequest _p;
private readonly CompiledModel _compiledModel;

/// <summary>
/// Recognization model being used for OCR.
Expand Down Expand Up @@ -53,12 +51,14 @@ public class PaddleOcrRecognizer : IDisposable
/// The value will be rounded to the nearest upper multiple of 32. This parameter is useful for models that require a fixed shape input.
/// Pass `null` if the model supports dynamic input shape.
/// </param>
public PaddleOcrRecognizer(RecognizationModel model, DeviceOptions? deviceOptions = null, int? staticShapeWidth = null)
public PaddleOcrRecognizer(RecognizationModel model,
DeviceOptions? deviceOptions = null,
int? staticShapeWidth = null)
{
Model = model;
StaticShapeWidth = staticShapeWidth.HasValue ? (int)(32 * Math.Ceiling(1.0 * staticShapeWidth.Value / 32)) : null;

_p = model.CreateInferRequest(deviceOptions, prePostProcessing: (m, ppp) =>
_compiledModel = model.CreateCompiledModel(deviceOptions, prePostProcessing: (m, ppp) =>
{
using PreProcessInputInfo ppii = ppp.Inputs.Primary;
ppii.TensorInfo.Layout = Layout.NHWC;
Expand All @@ -75,7 +75,7 @@ public PaddleOcrRecognizer(RecognizationModel model, DeviceOptions? deviceOption
/// <summary>
/// Releases all resources used by the current instance of the <see cref="PaddleOcrRecognizer"/> class.
/// </summary>
public void Dispose() => _p.Dispose();
public void Dispose() => _compiledModel.Dispose();

/// <summary>
/// Run OCR recognition on multiple images in batches.
Expand Down Expand Up @@ -136,14 +136,14 @@ private unsafe PaddleOcrRecognizerResult[] BatchedRun(Mat[] srcs)
}));

using Mat final = PrepareAndStackImages(srcs, modelHeight, maxWidth);

using InferRequest ir = _compiledModel.CreateInferRequest();
using (Tensor input = final.StackedAsTensor(srcs.Length))
{
_p.Inputs.Primary = input;
_p.Run();
ir.Inputs.Primary = input;
ir.Run();
}

using (Tensor output = _p.Outputs.Primary)
using (Tensor output = ir.Outputs.Primary)
{
IntPtr dataPtr = output.DangerousGetDataPtr();
int dataLength = (int)output.Size;
Expand Down Expand Up @@ -218,7 +218,7 @@ private static unsafe Mat PrepareAndStackImages(Mat[] srcs, int modelHeight, int
{
4 => src.CvtColor(ColorConversionCodes.RGBA2RGB),
1 => src.CvtColor(ColorConversionCodes.GRAY2RGB),
3 => src.WeakRef(),
3 => src.FastClone(),
var x => throw new Exception($"Unexpect src channel: {x}, allow: (1/3/4)")
};
return ResizePadding(channel3, modelHeight, maxWidth);
Expand Down
Loading

0 comments on commit a9d344a

Please sign in to comment.