我一直在寻找这种转换。有什么方法可以在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
上显示结果我做错了吗?
答案 0 :(得分:7)
NB :YUV< - >在3.2.0之前的OpenCV版本中的RGB转换是buggy!例如,在许多情况下,U和V通道的顺序被交换。据我所知,从2.4.13.2版本开始,2.x仍然被打破。
它们出现灰度的原因是在split
3通道YUV图像中,您创建了三个1通道图像。由于包含像素的数据结构不存储有关值值的任何信息,因此imshow
将任何单通道图像视为灰度显示。同样,它会将任何3通道图像视为BGR。
您在Wikipedia example中看到的是色度通道的伪彩色渲染。为实现此目的,您需要apply a pre-defined colormap或使用自定义look-up table (LUT)。这会将U和V值映射到适当的BGR值,然后可以显示。
事实证明,维基百科示例中使用的色彩图非常简单。
绿色和蓝色之间的简单进展:
colormap_u = np.array([[[i,255-i,0] for i in range(256)]],dtype=np.uint8)
绿色和红色之间的简单进展:
colormap_v = np.array([[[0,255-i,i] for i in range(256)]],dtype=np.uint8)
现在,我们可以将它们放在一起,重新创建示例:
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)
结果:
答案 1 :(得分:0)
使用所描述的LUT值可能完全是Wikipedia文章图像的制作方式,但是描述暗示它是任意的并且可能是因为它很简单而被使用。这不是任意的。结果基本上与RGB <-> YUV转换的工作方式匹配。如果使用的是OpenCV,则方法BGR2YUV和YUV2BGR使用在同一Wikipedia YUV文章中找到的转换公式给出结果。 (我使用Java生成的图像稍暗一些,否则相同。)
附录:我为DanMašek展示了查找表的技巧而完美而敏锐地回答了这个问题,这让我感到很难过。 Wikipedia YUV文章的作者在描述文章中显示的绿蓝色和绿红色渐变方面做得不错,但是正如DanMašek指出的那样,这并不完美。 U和V的彩色图像确实类似于实际发生的情况,因此我将其称为夸大颜色而不是虚假颜色。 Wikipedia上有关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);