BGRA 与 GRAY 颜色空间的转换

原理

在图像处理中,会需要从一个颜色空间转换到另一个颜色空间。 OpenCV 中关于颜色空间转换的公式可见链接GBRAGRAY 空间的转换与 RGB[A]GRAY 的计算公式并无不同

bgra2gray

  • 浮点计算公式

  • 整数移位计算公式

gray2bgra

实现

具体的实现需要一些 trick, 比如使用移位运算代替浮点运算,使用向量运算指令或者 intrinsics 防止编译器做负优化. (写这种代码真是心累)
实际上这么常用的功能一定有人已经做过,找到了一篇博文(12年的,不知道有没有过时),当然 github 上面也有几乎完全符合要求的开源项目(ヾ(✿゚▽゚)ノ), 整理下方法,然后 copy and paste.

实现颜色空间转换的几种途径

  • 使用 OpenCV 中的 CV::cvtColor
  • 使用内联 ARM Neon 指令
  • 使用 Neon intrinsics
  • 多线程并行处理

比较下性能当然是最后一种最好,在使用 ARM Neon 向量运算指令的加速下,多线程并行处理,速度一般可以达到 OpenCV 的 1.5 到 6 倍以上。
博文中的并行实现是使用OpenCV 中的 cv::paralled_for, 这个接口将用户代码与多线程后端实现分离,使用这个接口需要实现 cv::parallelLoopBody 函子。
目前的项目没有使用 OpenCV, 所以使用其他方法并行化,OpenMP 应该是可以使用的。但是使用 ASM 内联汇编的话 OpenMP 无法针对汇编级代码并行化,可以试试 intrinsics 和 OpenMP.

实现时需要注意的是系数与具体公式中的系数并不相同。一般的 BGRA 图像的深度为 8 位,计算的精度要求并不高,公式中实现右移 14 位只是误差最小的描述,具体实现时的公式为

其实就是等比缩小 而已。

注意事项

奇怪,项目中的灰度图的深度居然是都是 f32, 是我理解错了吗,从来没见过这种深度。
(半天后添加)这里使用的灰度图只是在神经网络作为中间计算结果,不作为显示,后续运算的特征图像素为 float 类型,所以这里直接将像素转为 float 类型。