rgb 到 yuv 的转换和访问 Y、U 和 V 通道

Posted

技术标签:

【中文标题】rgb 到 yuv 的转换和访问 Y、U 和 V 通道【英文标题】:rgb to yuv conversion and accessing Y, U and V channels 【发布时间】:2017-10-14 11:04:19 【问题描述】:

我一直在寻找这种转换。 Linux下使用Python将RGB图像转换为YUV图像以及访问Y、U、V通道的方法有哪些? (使用 opencv、skimage 等...)

更新: 我用过opencv

img_yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV)
y, u, v = cv2.split(img_yuv)

cv2.imshow('y', y)
cv2.imshow('u', u)
cv2.imshow('v', v)
cv2.waitKey(0)

并得到了这个结果,但它们看起来都是灰色的。无法获得类似 wikipedia page

的结果

我做错了吗?

【问题讨论】:

得到一堆可爱的YUV值后你想做什么?您使用的是什么操作系统? 我正在使用 linux。试图减少图像上的细节以在机器学习项目中使用它们。我找到了yuv=cv2.cvtColor(image, cv2.COLOR_BGR2YUV),但是当我尝试像img_yuv[:,:,0] 或在其他2 个索引中访问Y 通道时,它们都是灰色的。所以我可能从一开始就做错了什么,想学得更好 那是因为它们是单通道图像,imshow 将其视为灰度。如果您希望它们以假颜色显示,例如在您提到的示例中,您将需要应用颜色映射(或 LUT),将 U 和 V 值映射到可以显示的适当 BGR 值。 所以根据我的理解,它被正确分割,但由于它们是一维的,我看到它们是灰色的。正确的 ?我只是想确认一下,因为我不知道 LUT 正确。看看草,它是绿色的,在 U 和 V 方向上很暗,因为两者都很低。看看天空,在 U 中是亮(高),在 V 中是(低)暗,因为它是蓝色的。 【参考方案1】:

使用所描述的 LUT 值可能正是 Wikipedia 文章图像的制作方式,但描述暗示它是任意的,并且可能因为它很简单而被使用。这不是任意的;结果基本上与 RGB YUV 转换的工作方式相匹配。如果您使用的是 OpenCV,则 BGR2YUV 和 YUV2BGR 方法使用同一 Wikipedia YUV 文章中的转换公式给出结果。 (我使用 Java 生成的图像稍微暗一些,其他情况相同。)

附录:在 Dan Mašek 通过向我们展示查找表技巧完美而机敏地回答问题后,我觉得我选择了他,这让我感到很遗憾。 Wikipedia YUV 文章的作者在描述文章中显示的绿-蓝和绿-红渐变方面做得不错,但正如 Dan Mašek 指出的那样,它并不完美。 U 和 V 的颜色图像确实有点类似于实际发生的情况,所以我称它们为夸张颜色而不是假颜色。***上关于 YCrCb 的文章很相似,但在某种程度上有所不同。

// most of the Java program which should work in other languages with OpenCV:
// everything duplicated to do both the U and V at the same time
Mat src = new Mat();
Mat dstA = new Mat();
Mat dstB = new Mat();
src = Imgcodecs.imread("shed.jpg", Imgcodecs.IMREAD_COLOR);

List<Mat> channelsYUVa = new ArrayList<Mat>();
List<Mat> channelsYUVb = new ArrayList<Mat>();

Imgproc.cvtColor(src, dstA, Imgproc.COLOR_BGR2YUV); // convert bgr image to yuv
Imgproc.cvtColor(src, dstB, Imgproc.COLOR_BGR2YUV);

Core.split(dstA, channelsYUVa); // isolate the channels y u v
Core.split(dstB, channelsYUVb);

// zero the 2 channels we do not want to see isolating the 1 channel we want to see
channelsYUVa.set(0, Mat.zeros(channelsYUVa.get(0).rows(),channelsYUVa.get(0).cols(),channelsYUVa.get(0).type()));
channelsYUVa.set(1, Mat.zeros(channelsYUVa.get(0).rows(),channelsYUVa.get(0).cols(),channelsYUVa.get(0).type()));

channelsYUVb.set(0, Mat.zeros(channelsYUVb.get(0).rows(),channelsYUVb.get(0).cols(),channelsYUVb.get(0).type()));
channelsYUVb.set(2, Mat.zeros(channelsYUVb.get(0).rows(),channelsYUVb.get(0).cols(),channelsYUVb.get(0).type()));

Core.merge(channelsYUVa, dstA); // combine channels (two of which are zero)
Core.merge(channelsYUVb, dstB);

Imgproc.cvtColor(dstA, dstA, Imgproc.COLOR_YUV2BGR); // convert to bgr so it can be displayed
Imgproc.cvtColor(dstB, dstB, Imgproc.COLOR_YUV2BGR);

HighGui.imshow("V channel", dstA); // display the image
HighGui.imshow("U channel", dstB);

HighGui.waitKey(0);

【讨论】:

【参考方案2】:

NB:OpenCV 3.2.0 之前版本中的 YUV RGB 转换为 buggy!一方面,在许多情况下,U 和 V 通道的顺序是互换的。据我所知,截至 2.4.13.2 版本,2.x 仍然存在问题。


它们出现灰度的原因是在splitting 3 通道 YUV 图像中,您创建了三个 1 通道图像。由于包含像素的数据结构不存储关于值所代表的什么的任何信息,imshow 将任何 1 通道图像视为灰度显示。同样,它会将任何 3 通道图像视为 BGR。

您在Wikipedia example 中看到的是色度通道的错误颜色渲染。为了实现这一点,您需要apply a pre-defined colormap 或使用自定义look-up table (LUT)。这会将 U 和 V 值映射到适当的 BGR 值,然后可以显示。

事实证明,用于 Wikipedia 示例的颜色图相当简单。

U 通道颜色图

绿色和蓝色之间的简单渐变:

colormap_u = np.array([[[i,255-i,0] for i in range(256)]],dtype=np.uint8)

V 通道颜色图

绿色和红色之间的简单渐变:

colormap_v = np.array([[[0,255-i,i] for i in range(256)]],dtype=np.uint8)

像示例一样可视化 YUV

现在,我们可以将它们放在一起,重新创建示例:

import cv2
import numpy as np


def make_lut_u():
    return np.array([[[i,255-i,0] for i in range(256)]],dtype=np.uint8)

def make_lut_v():
    return np.array([[[0,255-i,i] for i in range(256)]],dtype=np.uint8)


img = cv2.imread('shed.png')

img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
y, u, v = cv2.split(img_yuv)

lut_u, lut_v = make_lut_u(), make_lut_v()

# Convert back to BGR so we can apply the LUT and stack the images
y = cv2.cvtColor(y, cv2.COLOR_GRAY2BGR)
u = cv2.cvtColor(u, cv2.COLOR_GRAY2BGR)
v = cv2.cvtColor(v, cv2.COLOR_GRAY2BGR)

u_mapped = cv2.LUT(u, lut_u)
v_mapped = cv2.LUT(v, lut_v)

result = np.vstack([img, y, u_mapped, v_mapped])

cv2.imwrite('shed_combo.png', result)

结果:

【讨论】:

以上是关于rgb 到 yuv 的转换和访问 Y、U 和 V 通道的主要内容,如果未能解决你的问题,请参考以下文章

图像处理——RGB-YRK-YUV-YCrCb的转换

rgb颜色 红色 转换成yuv颜色空间是啥

将 Yuv420 转换为 rgb 并在 qt pixmap 上显示

NV12格式转RGB的CUDA实现

像素格式

RGB、CMY、CMYK、YUV、HSV、HSI、LAB颜色空间详解