当前位置: 首页 > news >正文

网站建设管理经验专业零基础网站建设教学公司

网站建设管理经验,专业零基础网站建设教学公司,网站建设如何赚钱,网站设计开发平台1 基本概念 YUV 颜色空间从模拟电视时代开始就被广泛应用于彩色图像的转换与处理。其基于一个 3x3 的矩阵#xff0c;通过线性变换将 RGB 像素转换为一个亮度#xff08;Luma#xff09;分量 Y 以及两个色度#xff08;Chroma#xff09;分量 U 和 V。由于模拟电视存在着多…1 基本概念 YUV 颜色空间从模拟电视时代开始就被广泛应用于彩色图像的转换与处理。其基于一个 3x3 的矩阵通过线性变换将 RGB 像素转换为一个亮度Luma分量 Y 以及两个色度Chroma分量 U 和 V。由于模拟电视存在着多种制式如 NTSC 与 PAL 等等考虑到具体硬件与技术上的差异它们通常会采用不同的转换矩阵系数。即便到了如今的数字电视时代业界依旧会保留这些差异以保证兼容性但同时又会根据需求发展出更多新的转换系数。这就导致了 YUV 颜色空间其实是一个非常混乱的概念甚至于 YUV 本身也只是一个约定俗成的统称其实际可能为 YCbCr, Y’CbCr, Y’UV, YPbPr, YCC 等等标准叫法中的一种。因此如果不清楚具体的转换系数在 RGB 转 YUV 再转回 RGB 的过程中就可能存在转换矩阵不互逆而产生颜色偏差的问题。但是要完整地阐明 YUV 的各种转换系数是比较困难的具体可网上查阅 Wiki 等相关资料。本文主要从实用性出发对 OpenCV 中的 YUV 颜色空间转换进行一些梳理毕竟 OpenCV 在图像预处理中是非常常用的。 首先要说明的是尽管 RGB 与 YUV 的转换可通过一个 3x3 的矩阵变换来实现但实际上这个 3x3 矩阵中的 9 个数字并不是完全独立选取的。YUV 另一个比较通用的叫法是 YCbCr即 U 对应 CbV 对应 Cr。YCbCr 中的亮度 Y 由 R / G / B 加权求和所得对应的是单通道的灰度图而 Cb 反映了蓝色 B 分量与亮度 Y 的差异Cr 反映了红色 R 分量与亮度 Y 的差异Cb 与 Cr 统称为色差或色度。具体的转换公式如下 Y R2Y * R G2Y * G B2Y * B Cb (B - Y) * YCB delta Cr (R - Y) * YCR delta其中 [ R2Y, G2Y, B2Y, YCB, YCR ] 决定了不同的转换矩阵它们都是非负的。由于 Cb 与 Cr 反映的是色差所以它们的数值分布应该关于原点 0 对称因此需要加上一个 delta 偏移使其尽量落在与 Y 一致的区间常用的是 delta 128。通常来说RGB 与 YUV 的转换不是正交变换因此对于 256 x 256 x 256 正立方体分布的 RGB 值转换所得的 YUV 分布并不同样满足正立方体的分布而通常是一个截断的锥体。如果在 YUV 转换回 RGB 时使用了锥体外的 YUV 值所得 RGB 值在现实中则是不存在的因而也无法显示。 对于 RGB 转 YUV 或者 YUV 转 RGBOpenCV 可通过调用 dst cvtColor(src, code) 来实现code 决定了所使用的转换系数以及 src 与 dst 的存储格式。注意OpenCV 通常使用 BGR 而非 RGB 颜色顺序但其依旧保留了对 RGB 顺序输入的支持它们除了内存访问顺序不一样外并没有什么区别因此在后续讨论 code 时文章不会对 BGR 与 RGB 进行区分。通过查阅 OpenCV 源码中的 imgproc.hpp可得 code 主要有 // YCbCr 4:4:4 -- BGR COLOR_BGR2YCrCb 36, COLOR_YCrCb2BGR 38, // YUV 4:4:4 -- BGR COLOR_BGR2YUV 82, COLOR_YUV2BGR 84, // YUV_FOCC 4:2:0 -- BGR COLOR_YUV2BGR_NV12 91, COLOR_YUV2BGR_NV21 93, COLOR_YUV420sp2BGR COLOR_YUV2BGR_NV21, COLOR_YUV2BGR_YV12 99, COLOR_YUV2BGR_IYUV 101, COLOR_YUV2BGR_I420 COLOR_YUV2BGR_IYUV, COLOR_YUV420p2BGR COLOR_YUV2BGR_YV12, // YUV_FOCC 4:2:2 -- BGR COLOR_YUV2BGR_UYVY 108, COLOR_YUV2BGR_Y422 COLOR_YUV2BGR_UYVY, COLOR_YUV2BGR_UYNV COLOR_YUV2BGR_UYVY, COLOR_YUV2BGR_YUY2 116, COLOR_YUV2BGR_YVYU 118, COLOR_YUV2BGR_YUYV COLOR_YUV2BGR_YUY2, COLOR_YUV2BGR_YUNV COLOR_YUV2BGR_YUY2, // BGR -- YUV_FOCC 4:2:0 COLOR_BGR2YUV_I420 128, COLOR_BGR2YUV_IYUV COLOR_BGR2YUV_I420, COLOR_BGR2YUV_YV12 132,可以看到关于 RGB 与 YUV 转换的命名非常繁杂混乱但以上的 code 实际所涉及的转换系数可分为三类。其中第一类为 COLOR_BGR2YUV 及其反变换 COLOR_YUV2BGR第二类为 COLOR_BGR2YCrCb 及其反变换 COLOR_YCrCb2BGR第三类为带有 FOCC (Four-Character Code) 后缀的 COLOR_BGR2YUV_FOCC 及其反变换 COLOR_YUV2BGR_FOCC。而通过进一步探究可知前两类用于非下采样 YUV 的转换而第三类则用于经过下采样的 YUV 的转换。在这里我们先简单地介绍一下 YUV 的下采样格式这对于后续的理解十分有帮助。 YUV 由一个亮度分量 Y 与两个色度分量 U 和 V 组成而根据色彩科学的研究人眼对亮度变化更加敏感而对色度变化的感知则比较弱。因此为了降低图像数据传输所需的带宽通常会对色度分量 U 和 V 进行下采样同时完整地保留 Y这样可以尽可能地以较低成本维持相同的视觉主观体验。一般来说U 和 V 的下采样位置是一样的。色度分量的下采样通常以每相邻的 4 个像素作为一个下采样单位在其中保留 1 或 2 或 4 个像素然而这相邻 4 个像素以及保留像素的选取方式是多样的这就产生了非常繁杂的下采样格式它们通常用 YUV 4 : m : n 来表示。下图是三种比较常用的下采样格式。 YUV 4 : m : n 通常是一种约定俗成的概念m 与 n 并不一定具有实际意义。YUV 4:4:4 等同于保留所有的色度像素这种格式通常只在 YUV 与 RGB 转换时使用。YUV 4:2:2 表示色度分量在水平方向上进行 1/2 的下采样而垂直方向则不进行下采样即 4 个像素中只保留 2 个其中水平方向 1/2 下采样通常保留左侧像素而丢弃右侧像素但这并不是强制的在具体硬件实现中通常有多种模式选择包括只保留右侧像素或者两个像素求平均等等。YUV 4:2:2 通常只用在比较高端的摄像机图像处理芯片中。YUV 4:2:0 表示水平与垂直方向都进行 1/2 的下采样即 4 个像素只保留 1 个通常为左上角像素但正如 YUV 4:2:2其具体的实现也是可选的。YUV 4:2:0 是绝大多数图像处理芯片所使用的格式。YUV 4:1:1 类似于 YUV 4:2:0 只保留 4 个像素中的 1 个但其只在水平方向上进行 1/4 的下采样而垂直方向则完整保留这种格式的应用相对较少。除了以上的格式以外我们通常用 YUV 4:0:0 来表示灰度图即只保留亮度 Y 而完全丢弃色度 U 和 V。当需要从下采样格式恢复到完整的 4:4:4 格式时通常只需要把下采样时所保留的像素复制到所丢弃的像素位置即可当然这不可避免会导致失真但由于人眼对色度变化不敏感这种失真是可接受的。 2 YUV 4:4:4 转换 对于非下采样 YUV或者称为 YUV 4:4:4 格式OpenCV 提供了两类转换系数。 对于第一类 COLOR_BGR2YUV 及其反变换 COLOR_YUV2BGR虽然它的名字非常符合我们的认知直觉但根据 Wikipedia 其应该属于比较久远的 BT.470 标准目前已不多用。在 OpenCV 源码的 color_yuv.simd.hpp 中可以看到 //to YUV static const float B2YF 0.114f; static const float G2YF 0.587f; static const float R2YF 0.299f; static const float B2UF 0.492f; static const float R2VF 0.877f;代入前面的转换公式可得具体的转换系数与公式如下 [ Y U V ] [ 0.299 0.587 0.114 − 0.147 − 0.289 0.436 0.615 − 0.515 − 0.100 ] [ R G B ] [ 0 128 128 ] \left[ {\begin{array}{c} Y \\ U \\ V \end{array}} \right] \left[ {\begin{array}{c} {0.299}{0.587}{0.114} \\ { - 0.147}{ - 0.289}{0.436} \\ {0.615}{ - 0.515}{ - 0.100} \end{array}} \right]\left[ {\begin{array}{c} R \\ G \\ B \end{array}} \right] \left[ {\begin{array}{c} 0 \\ {128} \\ {128} \end{array}} \right] ​YUV​ ​ ​0.299−0.1470.615​0.587−0.289−0.515​0.1140.436−0.100​ ​ ​RGB​ ​ ​0128128​ ​ [ R G B ] [ 1 0 1.140 1 − 0.395 − 0.581 1 2.032 0 ] [ Y U − 128 V − 128 ] \left[ {\begin{array}{c} R \\ G \\ B \end{array}} \right] \left[ {\begin{array}{c} 10{1.140} \\ 1{ - 0.395}{ - 0.581} \\ 1{2.032}0 \end{array}} \right]\left[ {\begin{array}{c} Y \\ {U - 128} \\ {V - 128} \end{array}} \right] ​RGB​ ​ ​111​0−0.3952.032​1.140−0.5810​ ​ ​YU−128V−128​ ​ 要注意到当 R G 0 , B 255 RG0, B255 RG0,B255 时 U U U 取得最大值 U m a x 239 U_{max}239 Umax​239。依此计算可得 Y ∈ [ 0 , 255 ] Y \in [0, 255] Y∈[0,255] U ∈ [ 17 , 239 ] U \in [17, 239] U∈[17,239] V ∈ [ − 29 , 285 ] V \in [-29, 285] V∈[−29,285]。因此Y / U / V 三者的量程在 BT.470 标准下并不一样这大概是为了弥补模拟电视对于不同分量的响应差异。在数字信号处理中因为图像通常使用 uint8 来表示像素值所以 V 在存储前需要截断从而丢失部分色彩信息。 对于第二类 COLOR_BGR2YCrCb 及其反变换 COLOR_YCrCb2BGR要注意的是 OpenCV 使用的是 YCrCb 而非 YUV 所对应的 YCbCr 顺序在使用时应该小心但具体这么做的原因未知。实际上 COLOR_BGR2YCrCb 所使用的转换系数才是我们比较熟知且常用的 BT.601 标准。在 OpenCV 源码的 color_yuv.simd.hpp 中可以看到 //to YCbCr static const float B2YF 0.114f; static const float G2YF 0.587f; static const float R2YF 0.299f; static const float YCBF 0.564f; // 1/2/(1-B2YF) static const float YCRF 0.713f; // 1/2/(1-R2YF)代入转换公式可得具体的转换系数与公式如下 [ Y C b C r ] [ 0.299 0.587 0.114 − 0.169 − 0.331 0.500 0.500 − 0.419 − 0.081 ] [ R G B ] [ 0 128 128 ] \left[ {\begin{array}{c} Y \\ {Cb} \\ {Cr} \end{array}} \right] \left[ {\begin{array}{c} {0.299}{0.587}{0.114} \\ { - 0.169}{ - 0.331}{0.500} \\ {0.500}{ - 0.419}{ - 0.081} \end{array}} \right]\left[ {\begin{array}{c} R \\ G \\ B \end{array}} \right] \left[ {\begin{array}{c} 0 \\ {128} \\ {128} \end{array}} \right] ​YCbCr​ ​ ​0.299−0.1690.500​0.587−0.331−0.419​0.1140.500−0.081​ ​ ​RGB​ ​ ​0128128​ ​ [ R G B ] [ 1 0 1.402 1 − 0.344 − 0.714 1 1.772 0 ] [ Y C b − 128 C r − 128 ] \left[ {\begin{array}{c} R \\ G \\ B \end{array}} \right] \left[ {\begin{array}{c} 10{1.402} \\ 1{ - 0.344}{ - 0.714} \\ 1{1.772}0 \end{array}} \right]\left[ {\begin{array}{c} Y \\ {Cb - 128} \\ {Cr - 128} \end{array}} \right] ​RGB​ ​ ​111​0−0.3441.772​1.402−0.7140​ ​ ​YCb−128Cr−128​ ​ 通过对比 COLOR_BGR2YUV 的转换公式可知它们的亮度分量是相等的但不同的地方在于 YCbCr 各个分量的量程都为 [ 0 , 255 ] [0, 255] [0,255]从而无需截断即可存储在 uint8 类型内而这正是为了适应数字信号处理而对色度分量范围的调整。不考虑存储精度的损失使用 COLOR_BGR2YCrCb 及其反变换 COLOR_YCrCb2BGR 进行颜色空间转换不会造成颜色失真。注意在旧版本的 OpenCV 中可能还存在 COLOR_BGR2YCR_CB它和 COLOR_BGR2YCrCb 其实是一个东西一般不使用。 3 YUV 下采样格式转换 除了支持 YUV 4:4:4 格式的颜色空间转换以外OpenCV 还支持 RGB 直接转换为 YUV 下采样格式或者 YUV 下采样格式直接转换为 RGB也就是前面所说的第三类 code。第三类 code 可表示为带有某个 FOCC 后缀的 COLOR_BGR2YUV_FOCC 以及反变换的 COLOR_YUV2BGR_FOCC其中 FOCC 指由 4 个 ASCII 字符所组成的代码即 Four-Character Code有点类似于 C/C 中的 enum。FOCC 在个人程序中通常可以任意定义但是也存在一些约定俗成或者标准化的命名例如编解码标准中的 JPEG, MPG4, H264 等等。在第一节中我们提到过 YUV 中的色度分量通常要进行下采样以节省系统带宽。进一步地经过下采样后的 YUV 数据中亮度和色度的像素个数是不一样的我们不能像 RGB 那样将其表示为一个 [H, W, 3] 的矩阵所以下采样的 YUV 数据存在多种不同的存储方式这些就构成了各种繁乱的关于 YUV 格式的 FOCC。 为了正确使用 OpenCV 进行下采样格式的 YUV 数据颜色空间转换这里简单地对 YUV 的存储方式进行介绍。常用的存储方式分为三种即 Planar, Semi-Planar 以及 Interleave。 Planar 即平面式存储。其在内存空间中先完整地顺序存储所有 Y 像素然后再完整地顺序存储所有经过下采样的 U 数据最后完整地顺序存储所有经过下采样的 V 数据例如 Y1 Y2 Y3 … Yend U1 U2 U3 … Uend V1 V2 V3 … Vend。它的优点是可以适应任意的下采样格式并且在只对单个分量如 Y 分量进行操作时无需对其他分量进行存取缺点是在内存中 Y / U / V 数据间的跨度太大当需要同时处理 Y / U / V 数据时不利于数据的连续突发传输或者需要多个数据并行存取分支。注意有时候也会先存储 V 再存储 U这时要通过具体的 FOCC 进行区分。 Semi-Planar 即半平面式存储。其在内存空间中也是先完整地顺序存储所有 Y 像素但由于 U 和 V 的数据量是相等的且绝大多数算法都需要同时用到 U 和 V所以 U 和 V 之间并不需要分开存储而是可以进行交叉例如 Y1 Y2 Y3 … Yend U1 V1 U2 V2 U3 V3 … Uend Vend。它也具有 Planar 格式的适应性以及亮度与色度分量独立存储的优点但是能够将 U 和 V 的数据访问操作进行合并改善了内存突发传输性能所以 Semi-Planar 格式在硬件中反而是更加常用的。和 Planar 同理有时候也会先存储 V 再存储 U这时要通过具体的 FOCC 进行区分。 Interleave 即交叉式存储。不同于 Semi-Planar 只将 U 和 V 进行交叉Interleave 将 Y / U / V 数据都交织在一起可以最大化 YUV 数据的突发传输性能缺点是在只需要亮度分量时必须把色度分量也进行传输。它通常用于亮度与色度数据量相等的情况如 YUV 4:2:2 格式这时两个 Y 对应着一个 U 和一个 V根据四者的顺序的不同存在着多种 Interleave 格式并对应着不同的 FOCC。YUV 4:2:2 常用的交叉式存储顺序有 YUYV, YVYU, UYVY, VYUY 等等其中的两个 Y 需按像素顺序排列。例如对于 YUYV在内存中有 Y1 U1 Y2 V1 Y3 U2 Y4 V2 …。实际上大多数硬件都支持内存隔点并行存取的操作因此对于 YUV 4:2:2 而言将亮度与色度分量进行交叉存储并不会造成太大的数据传输负担所以 YUV 4:2:2 数据的处理通常采用此存储格式。 在第一节中我们已经列出了 OpenCV 所支持的 FOCC但要注意 COLOR_BGR2YUV_FOCC 与 COLOR_YUV2BGR_FOCC 所支持的 FOCC 并不是对称的例如 COLOR_BGR2YUV_FOCC 并不支持 RGB 到 YUV 4:2:2 的转换如果有这方面的需求则需要利用第二节的 COLOR_BGR2YCrCb 将 RGB 转换到 YUV 4:4:4 并手动进行下采样。不过要注意的是COLOR_BGR2YCrCb 和 COLOR_BGR2YUV_FOCC 的转换系数是有差异的这个留到后面讨论。另外有些 FOCC 的意义是重复的。这里先对各个 FOCC 所对应的下采样及存储格式进行明确 NV12 YUV 4:2:0 Semi-Planar格式其中色度分量先存 U 再存 V。NV21 / 420S YUV 4:2:0 Semi-Planar格式其中色度分量先存 V 再存 U。IYUV / I420 YUV 4:2:0 Planar 格式其中色度分量先存 U 再存 V。YV12 / 420P YUV 4:2:0 Planar 格式其中色度分量先存 V 再存 U。UYVY / Y222 / UYNV YUV 4:2:2 Interleave 格式存储顺序为 UYVY。YUY2 / YUYV / YUNV YUV 4:2:2 Interleave 格式存储顺序为 YUYV。YVYU YUV 4:2:2 Interleave 格式存储顺序为 YVYU。 在 OpenCV 中虽然 YUV 经过了下采样但还是会把 YUV 数据打包为一个矩阵方便处理。对于 YUV 4:2:0色度分量 U 和 V 的尺寸分别为亮度 Y 的 1/4为了将它们打包在一起OpenCV 使用一个 [H*3/2, W] 的二维矩阵进行存储其中 [:H, :W] 存储的是 Y 数据而 [H : HH/2, :W] 则根据 Planar 或 Semi-Planar 格式顺序对 U 和 V 数据进行存储。根据以上的 FOCC 对应的格式它们在二维矩阵中的分布如下图所示 而对于 YUV 4:2:2色度分量 U 和 V 的尺寸分别为亮度 Y 的 1/2即色度分量的数据量和亮度分量是一样的所以 OpenCV 使用一个 [H, W, 2] 的三维矩阵进行存储。因为矩阵在内存中的索引顺序通常从最后的维度开始所以根据 FOCC 顺序对 YUV 4:2:2 数据进行存储时应该在两个 [H, W] 平面上交替写入。以 UYVY 为例它们在三维矩阵中的分布如下图所示其他 FOCC 可自行推理这里不赘述 在了解了 YUV 下采样格式的存储方式及对应的 FOCC 以后我们就能基于 OpenCV 中的 COLOR_BGR2YUV_FOCC 与 COLOR_YUV2BGR_FOCC 直接将下采样后的 YUV 数据转换为 RGB或者直接将 RGB 转换为特定下采样及存储方式的 YUV 数据了。实际上第三类 COLOR_BGR2YUV_FOCC 可看作是第二类 COLOR_BGR2YCrCb 即 BT.601 的继承但是又有些不同。在信号处理中一个很重要的概念是系统响应频域的滤波等操作通常会在时域或空域中引入震荡或过冲最常见的就是理想低通滤波器中的 Gibbs 现象。数字 YUV 信号最终需要转换为模拟电平信号才能驱动显示器工作例如通过电压控制液晶的偏转角度等等而离散时间信号在还原为模拟连续时间信号时需连接一个低通滤波器以此过滤掉由采样定理所引入的高频延拓分量因此这时就有可能出现信号过冲的问题。因为 COLOR_BGR2YCrCb 所得 YUV 数据的取值范围都为 [0, 255]如果数模转换的过程中把 0 映射为 0 电平而 255 映射为最高电平经过系统滤波响应以后信号实际的电平就有可能超出系统所能处理的范围。为了解决这个问题ITU-R 组织在 BT.601 转换系数的基础上对 COLOR_BGR2YCrCb 所得结果进行缩放与偏移保留大约 10% 的过冲余量从而得到了 OpenCV 第三类 code 所对应的转换系数其通常配合特定的 YUV 下采样及存储格式使用。通过查阅 OpenCV 源码的 color_yuv.simd.hpp可以看到 // Coefficients for RGB to YUV420p conversion static const int ITUR_BT_601_SHIFT 20; static const int ITUR_BT_601_CRY 269484; static const int ITUR_BT_601_CGY 528482; static const int ITUR_BT_601_CBY 102760; static const int ITUR_BT_601_CRU -155188; static const int ITUR_BT_601_CGU -305135; static const int ITUR_BT_601_CBU 460324; static const int ITUR_BT_601_CGV -385875; static const int ITUR_BT_601_CBV -74448; //R 1.164(Y - 16) 1.596(V - 128) //G 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) //B 1.164(Y - 16) 2.018(U - 128)其中未标明的 ITUR_BT_601_CRV 和 ITUR_BT_601_CBU 是一样的。转换为浮点后可得带有 FOCC 后缀的 RGB 与 YUV 转换系数与如下 [ Y ′ U ′ V ′ ] [ 0.257 0.504 0.098 − 0.148 − 0.291 0.439 0.439 − 0.368 − 0.071 ] [ R G B ] [ 16 128 128 ] \left[ {\begin{array}{c} {Y} \\ {U} \\ {V} \end{array}} \right] \left[ {\begin{array}{c} {0.257}{0.504}{0.098} \\ { - 0.148}{ - 0.291}{0.439} \\ {0.439}{ - 0.368}{ - 0.071} \end{array}} \right]\left[ {\begin{array}{c} R \\ G \\ B \end{array}} \right] \left[ {\begin{array}{c} {16} \\ {128} \\ {128} \end{array}} \right] ​Y′U′V′​ ​ ​0.257−0.1480.439​0.504−0.291−0.368​0.0980.439−0.071​ ​ ​RGB​ ​ ​16128128​ ​ [ R G B ] [ 1.164 0 1.596 1.164 − 0.391 − 0.813 1.164 2.018 0 ] [ Y ′ − 16 U ′ − 128 V ′ − 128 ] \left[ {\begin{array}{c} R \\ G \\ B \end{array}} \right] \left[ {\begin{array}{c} {1.164}0{1.596} \\ {1.164}{ - 0.391}{ - 0.813} \\ {1.164}{2.018}0 \end{array}} \right]\left[ {\begin{array}{c} {Y - 16} \\ {U - 128} \\ {V - 128} \end{array}} \right] ​RGB​ ​ ​1.1641.1641.164​0−0.3912.018​1.596−0.8130​ ​ ​Y′−16U′−128V′−128​ ​ 容易算得此时 Y ∈ [ 16 , 235 ] Y \in [16, 235] Y∈[16,235]而 U , V ∈ [ 16 , 240 ] U,V \in [16, 240] U,V∈[16,240]。即 YUV 数据的左右两侧都预留了一定的空间使得一般的操作都不会导致数据的溢出从而可以在硬件中减少一些截断操作。当然其代价是数据的表示范围有所缩减不能最大化 uint8 类型所能表示的精度但总体上还是利大于弊的所以这种非满量程的 YUV 也被 ITU-R 组织作为一种标准进行推广。前面我们提到COLOR_BGR2YUV_FOCC 是对 COLOR_BGR2YCrCb 进行缩放与偏移得到的结果事实也是如此只需对比两者的转换矩阵即可如下 [ 0.257 0.504 0.098 − 0.148 − 0.291 0.439 0.439 − 0.368 − 0.071 ] ≈ 1 255 [ 219 224 224 ] [ 0.299 0.587 0.114 − 0.169 − 0.331 0.500 0.500 − 0.419 − 0.081 ] \left[ {\begin{array}{c} {0.257}{0.504}{0.098} \\ { - 0.148}{ - 0.291}{0.439} \\ {0.439}{ - 0.368}{ - 0.071} \end{array}} \right] \approx \frac{1}{{255}}\left[ {\begin{array}{c} {219}{}{} \\ {}{224}{} \\ {}{}{224} \end{array}} \right]\left[ {\begin{array}{c} {0.299}{0.587}{0.114} \\ { - 0.169}{ - 0.331}{0.500} \\ {0.500}{ - 0.419}{ - 0.081} \end{array}} \right] ​0.257−0.1480.439​0.504−0.291−0.368​0.0980.439−0.071​ ​≈2551​ ​219​224​224​ ​ ​0.299−0.1690.500​0.587−0.331−0.419​0.1140.500−0.081​ ​ 4 验证 为了验证以上的分析是否正确这里提供了一个测试脚本有兴趣的可以自行复制运行。 # -*- coding: utf-8 -*- import numpy as np import cv2rgb2yuv_470_full np.array([[ 0.299, 0.587, 0.114],[-0.147, -0.289, 0.436],[ 0.615, -0.515, -0.100] ])rgb2yuv_601_full np.array([[ 0.299, 0.587, 0.114],[-0.169, -0.331, 0.500],[ 0.500, -0.419, -0.081] ])rgb2yuv_709_full np.array([[ 0.2126, 0.7152, 0.0722],[-0.1146, -0.3854, 0.5000],[ 0.5000, -0.4542, -0.0458] ])yuv2rgb_470_full np.linalg.inv(rgb2yuv_470_full) yuv2rgb_601_full np.linalg.inv(rgb2yuv_601_full) yuv2rgb_709_full np.linalg.inv(rgb2yuv_709_full) print(rgb2yuv_470_full) print(rgb2yuv_601_full) print(yuv2rgb_470_full) print(yuv2rgb_601_full) print(rgb2yuv_601_full) print(rgb2yuv_601_full) print(yuv2rgb_601_full) print(yuv2rgb_601_full) print(rgb2yuv_709_full) print(rgb2yuv_709_full) print(yuv2rgb_709_full) print(yuv2rgb_709_full) rgb2yuv_601_comp 1./255 * np.diag([219, 224, 224]).dot(rgb2yuv_601_full) rgb2yuv_709_comp 1./255 * np.diag([219, 224, 224]).dot(rgb2yuv_709_full)yuv2rgb_601_comp np.linalg.inv(rgb2yuv_601_comp) yuv2rgb_709_comp np.linalg.inv(rgb2yuv_709_comp) print(rgb2yuv_601_comp) print(rgb2yuv_601_comp) print(yuv2rgb_601_comp) print(yuv2rgb_601_comp) print(rgb2yuv_709_comp) print(rgb2yuv_709_comp) print(yuv2rgb_709_comp) print(yuv2rgb_709_comp) def convert_bgr_to_yuv(bgr):h, w bgr.shape[:2]assert h % 4 0 and w % 4 0b, g, r bgr.transpose(2, 0, 1)y 0.299 * r 0.587 * g 0.114 * b# COLOR_BGR2YUVu -0.147 * r - 0.289 * g 0.436 * b 128v 0.615 * r - 0.515 * g - 0.100 * b 128yuv_470 np.clip(np.array([y, u, v]).transpose(1, 2, 0), 0, 255).astype(uint8)# COLOR_BGR2YCrCbu -0.169 * r - 0.331 * g 0.500 * b 128v 0.500 * r - 0.419 * g - 0.081 * b 128yvu_601 np.clip(np.array([y, v, u]).transpose(1, 2, 0), 0, 255).astype(uint8)# COLOR_BGR2YUV_FOCCy y * 219. / 255 16u u * 224. / 255 16v v * 224. / 255 16yuv_fcc np.clip(np.array([y, u, v]).transpose(1, 2, 0), 0, 255).astype(uint8)return yuv_470, yvu_601, yuv_fccdef convert_yuv_to_fcc(yuv, fcc):fcc_list_420 [NV12, NV21, 420S, YV12, IYUV, I420, 420P]fcc_list_422 [UYVY, Y422, UYNV, YUY2, YVYU, YUYV, YUNV]assert fcc in fcc_list_420 fcc_list_422h, w yuv.shape[:2]assert h % 4 0 and w % 4 0y, u, v yuv.transpose(2, 0, 1)if fcc in fcc_list_420:yuv420 np.zeros([3*h//2, w], dtypeuint8)yuv420[:h] yif fcc NV12:yuv420[h:, 0::2] u[::2, ::2]yuv420[h:, 1::2] v[::2, ::2]elif fcc NV21 or fcc 420S:yuv420[h:, 0::2] v[::2, ::2]yuv420[h:, 1::2] u[::2, ::2]elif fcc YV12 or fcc 420P:yuv420[h: hh//4] v[::2, ::2].reshape([-1, w])yuv420[-h//4: ] u[::2, ::2].reshape([-1, w])elif fcc IYUV or fcc I420:yuv420[h: hh//4] u[::2, ::2].reshape([-1, w])yuv420[-h//4: ] v[::2, ::2].reshape([-1, w])return yuv420elif fcc in fcc_list_422:yuv422 np.zeros([h, w, 2], dtypeuint8)if fcc UYVY or fcc Y422 or fcc UYNV:yuv422[:, 0::2, 0] u[:, ::2]yuv422[:, 1::2, 0] v[:, ::2]yuv422[:, :, 1] yelif fcc YUY2 or fcc YUYV or fcc YUNV:yuv422[:, :, 0] yyuv422[:, 0::2, 1] u[:, ::2]yuv422[:, 1::2, 1] v[:, ::2]elif fcc YVYU:yuv422[:, :, 0] yyuv422[:, 0::2, 1] v[:, ::2]yuv422[:, 1::2, 1] u[:, ::2]return yuv422else:return yuvdef convert_yuv470_to_bgr(yuv470):rgb (yuv470 - np.array([0, 128, 128])).dot(yuv2rgb_470_full.T)bgr np.clip(rgb[..., ::-1], 0, 255).astype(uint8)return bgrdef convert_yvu601_to_bgr(yvu601):rgb (yvu601[..., [0, 2, 1]] - np.array([0, 128, 128])).dot(yuv2rgb_601_full.T)bgr np.clip(rgb[..., ::-1], 0, 255).astype(uint8)return bgrdef test_yuv2bgr_fcc(yuv):fcc_dict_420 {NV12: cv2.COLOR_YUV2BGR_NV12,NV21: cv2.COLOR_YUV2BGR_NV21, 420S: cv2.COLOR_YUV420sp2BGR,YV12: cv2.COLOR_YUV2BGR_YV12, 420P: cv2.COLOR_YUV420p2BGR,IYUV: cv2.COLOR_YUV2BGR_IYUV, I420: cv2.COLOR_YUV2BGR_I420}fcc_dict_422 {UYVY: cv2.COLOR_YUV2BGR_UYVY, Y422: cv2.COLOR_YUV2BGR_Y422, UYNV: cv2.COLOR_YUV2BGR_UYNV,YUY2: cv2.COLOR_YUV2BGR_YUY2, YUYV: cv2.COLOR_YUV2BGR_YUYV, YUNV: cv2.COLOR_YUV2BGR_YUNV,YVYU: cv2.COLOR_YUV2BGR_YVYU}yuv420up yuv.copy()yuv420up[::2, 1::2, 1:] yuv420up[::2, ::2, 1:]yuv420up[1::2, :, 1:] yuv420up[::2, :, 1:]rgb (yuv420up - np.array([16, 128, 128])).dot(yuv2rgb_601_comp.T)bgr420 np.clip(rgb[..., ::-1], 0, 255).astype(int)yuv422up yuv.copy()yuv422up[:, 1::2, 1:] yuv422up[:, ::2, 1:]rgb (yuv422up - np.array([16, 128, 128])).dot(yuv2rgb_601_comp.T)bgr422 np.clip(rgb[..., ::-1], 0, 255).astype(int)for fcc, code in fcc_dict_420.items():yuv_fcc convert_yuv_to_fcc(yuv, fcc)bgr_cv cv2.cvtColor(yuv_fcc, code)print({} bgr max diff: {}.format(fcc, np.max(np.abs(bgr420 - bgr_cv))))for fcc, code in fcc_dict_422.items():yuv_fcc convert_yuv_to_fcc(yuv, fcc)bgr_cv cv2.cvtColor(yuv_fcc, code)print({} bgr max diff: {}.format(fcc, np.max(np.abs(bgr422 - bgr_cv))))if __name__ __main__:w, h 128, 128bgr np.random.randint(0, 256, [h, w, 3], dtypeuint8)yuv470, yvu601, yuv_fcc convert_bgr_to_yuv(bgr)# test COLOR_BGR2YUVy0 cv2.cvtColor(bgr, cv2.COLOR_BGR2YUV)x0 cv2.cvtColor(y0, cv2.COLOR_YUV2BGR)x1 convert_yuv470_to_bgr(yuv470)d0 np.max(yuv470.astype(int) - y0)d1 np.max(x1.astype(int) - x0)print(470 max diff: yuv{}, bgr{}.format(d0, d1))# test COLOR_BGR2YCrCby0 cv2.cvtColor(bgr, cv2.COLOR_BGR2YCrCb)x0 cv2.cvtColor(y0, cv2.COLOR_YCrCb2BGR)x1 convert_yvu601_to_bgr(yvu601)d0 np.max(yvu601.astype(int) - y0)d1 np.max(x1.astype(int) - x0)print(601 max diff: yuv{}, bgr{}.format(d0, d1))# test fcc yuv2bgrtest_yuv2bgr_fcc(yuv_fcc)# test fcc br2yuvy0 cv2.cvtColor(bgr, cv2.COLOR_BGR2YUV_I420)y1 convert_yuv_to_fcc(yuv_fcc, I420)print(I420 yuv max diff: {}.format(np.max(np.abs(y1.astype(int) - y0))))y0 cv2.cvtColor(bgr, cv2.COLOR_BGR2YUV_IYUV)y1 convert_yuv_to_fcc(yuv_fcc, IYUV)print(IYUV yuv max diff: {}.format(np.max(np.abs(y1.astype(int) - y0))))y0 cv2.cvtColor(bgr, cv2.COLOR_BGR2YUV_YV12)y1 convert_yuv_to_fcc(yuv_fcc, YV12)print(YV12 yuv max diff: {}.format(np.max(np.abs(y1.astype(int) - y0))))
http://www.pierceye.com/news/360301/

相关文章:

  • dw做网站背景图片设置网站建设设计作品怎么写
  • 网站建设推广专员岗位职责济南做企业网站公司
  • 网站不备案能解析吗合肥网站推广 公司哪家好
  • 网站描述怎样写深圳网站制作招聘
  • 二手车网站建设代理网页 国外
  • 广州制作网站静态网站首页更新
  • 个人网站用什么服务器宁波网站建设制作哪家好
  • 视频模板网站企业所得税优惠政策2022年
  • 坪山附近公司做网站建设哪家效益快wordpress 置顶 插件
  • 品牌网站建设服务机构内容网站管理系统
  • 电商网站建设基础ppt个人简单网站页
  • 移动端网站模板专业建站工作室
  • 企业网站建设的重要性及意义建设银行忘记密码网站首页
  • 易雅达网站建设公司广告设计公司设计收费标准
  • 行业门户网站php网站开发程序
  • 广州微信网站建设报价表上海注销营业执照流程
  • 陕西省建设执业资格注册中心网站科技有限公司 翻译
  • 做推广都有哪些网站网站怎么上传源码
  • discuz门户网站模板手机电子商务网站规划书范文
  • vps能同时做网站同时做其它事吗wordpress 支持小工具
  • 网站建设制作网络公司wordpress 汽车模板
  • 有哪些做外贸的网站网站快速搭建平台
  • wordpress搜索代码制做优化精灵
  • 连云港做网站推广东莞seo
  • 专业网站设计公司和普通设计公司的区别微信分销网站建设
  • 青海个人旅游网站建设网站建设教程软件下载
  • 做AMC12的题的网站龙华网站建设专业公司
  • 莱州网站制作友情链接交换形式
  • 如何编写网站做美食类网站现状
  • 一站式推广平台做家装模型的效果图网站