Skip to content

添加PaddleOcrAll.BytesPerPixel,像素内存分别支持3通道BGR、4通道BGRA - #7

Closed
shonescript wants to merge 3 commits into
sdcb:mainfrom
shonescript:main
Closed

shonescript wants to merge 3 commits into
sdcb:mainfrom
shonescript:main

Conversation

@shonescript

Copy link
Copy Markdown

修改内容

  1. 在 PaddleOcrAll.cs 中添加了静态属性 BytesPerPixel(默认 3,赋值时校验必须为 3 或 4),并将项目中所有与"输入像素字节"相关的硬编码进行替换,验证测试通过。
  2. 优化WinForms RunPipline,改用直接访问内存,提升性能。

修改说明

  1. 源/crop 像素始终按 PixelBytesNum 字节布局(BGR=3 或 BGRA=4)。
  2. 中间 int 行缓冲 Row0/Row1 仍按 3 通道/像素存(ResizeWorkspace.Ensure 不变),因为下游 NCHW 永远是 3 平面。
  3. ONNX 模型输入永远是 3 通道 NCHW(batch348*width 不变)。
  4. 4 字节模式下 crop 中的 A 字节为未初始化垃圾,下游预处理只读 BGR 三字节,不影响识别结果。
  5. AVX/AVX512 的 LoadPixelAvx* 用 Sse41.ConvertToVector128Int32 读 4 字节零扩展为 4 个 int32,对 3 字节 BGR(第 4 字节是下个像素 B,被忽略)和 4 字节 BGRA(第 4 字节是 A,被忽略)都自动正确,只换了像素间距。

验证结果

  1. dotnet build 库(net10.0 + netstandard2.0):0 警告 0 错误;
  2. 单元测试项目构建并通过 26/26 测试;
  3. Bench/TestReport/ImageSharp.AspNetCore 示例全部构建成功;
  4. 手工测试WinForms示例,3/4通道均成功。
image

…与"输入像素字节"相关的硬编码进行替换,验证测试通过。

优化WinForms RunPipline,改用直接访问内存,提升性能。

@sdcb sdcb left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

总是让SimdPaddleOCR原生就支持bpp=3/4,以及rgb/bgr/rgba/bgra的切换,是合理的,但实现架构需要调整一下

Vector256<double> wx0 = Avx2.Permute4x64(wx, 0x00), wx1 = Avx2.Permute4x64(wx, 0x55);
Vector256<double> wx2 = Avx2.Permute4x64(wx, 0xAA), wx3 = Avx2.Permute4x64(wx, 0xFF);
byte* row = source + (yBase - 1) * stride + (xBase - 1) * 3;
byte* row = source + (yBase - 1) * stride + (xBase - 1) * PaddleOcrAll.BytesPerPixel;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kernel层不应该引用业务逻辑层的PaddleOcrAll.BytesPerPixel

Comment thread src/Sdcb.SimdPaddleOCR/PaddleOcrAll.cs Outdated
@sdcb

sdcb commented Sep 17, 2026

Copy link
Copy Markdown
Owner

谢谢这份 PR,BGR / BGRA 这个需求是对的。main 上已经用另一套方式落地了,比全局 BytesPerPixel 更稳,所以先关掉,避免再合进去两套契约。

你这边的做法是 PaddleOcrAll.BytesPerPixel(3 或 4)加像素间距,4 字节时把第 4 字节当可忽略的 A。这能覆盖 GDI+ Format32bppArgb / BGRA,但有几处我们后来想避开:

  1. 进程级静态开关。 一次只能一种布局,并发里一张 BGR、一张 BGRA 会对不上;调用方也容易忘了改回去。
  2. 只区分 3/4 字节,不区分通道序。 ImageSharp 常见是 RGBA,Skia / GDI+ 是 BGRA,OpenCV 是 BGR。4 字节一律当 BGRA 的话,RGBA 会把 R/B 走反。
  3. crop 的 A 是未初始化垃圾。 下游只读 BGR 时碰巧能过,但缓冲语义不干净。
  4. AVX 读 4 字节再丢掉第 4 通道 对紧排 BGR 也依赖「多读 1 字节」,行尾 / 有 stride padding 时要更小心。

现在 main 上的公开契约是每趟 Run / Detect / Classify / Recognize 末尾的 ImagePixelFormat(默认 Bgr24,源码兼容):

  • Bgr24 / Rgb24 / Bgra32 / Rgba32
  • 在 resize / warp 里就地 gather,不先摊一张中间 BGR
  • stride 按行距走,紧排可以传 0
  • crop 输出仍是 3 字节 BGR,CLS/REC 不用再带 format

WinForms 示例也已经 LockBits 后直接 Bgra32 送进去,不再整图拷一份。CI 上正确率和 1.3 一致,工作集还低了一截。

如果你那边还有这套覆盖不到的布局(比如灰度、预乘 alpha),开 issue 即可。

@sdcb sdcb closed this Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants