【问题标题】:Open CV imshow() - ARGB32 to OpenCV image打开 CV imshow() - ARGB32 到 OpenCV 图像
【发布时间】:2021-12-05 05:31:02
【问题描述】:

我正在尝试使用 OpenCV Python 处理来自 Unity3D WebCamTexture 图形格式(ARGB32)的图像。但我无法解释 Open CV 端的图像。图片全是蓝色(可能是ARGB)

try:
    while(True):
        data = sock.recv(480 * 640 * 4)
        if(len(data) == 480 * 640 * 4):
            image = numpy.fromstring(data, numpy.uint8).reshape( 480, 640, 4 )
            #imageNoAlpha = image[:,:,0:2]
            cv2.imshow('Image', image) #further do image processing
            
            key = cv2.waitKey(1) & 0xFF
            if key == ord("q"):
                break
finally:
    sock.close()

【问题讨论】:

  • 您是否查看了字节以确保您得到您认为的内容?您绝对确定它是 ARGB,每个组件 8 位,没有标题?
  • 是的,我得到的图形格式为 88 stackoverflow.com/questions/66706477/…,纹理的宽度和高度为 640 * 480,数据大小为 480*640*4 = 1228800(所以一切加起来)
  • 当然数据是1,228,800;这就是你所要求的。 TCP 不是数据包协议,它是流协议。例如,如果另一端向您发送 4 个 640x480x1 的不同图像,您仍然会得到 1,228,800 字节。您需要转储第一组字节并确保它看起来像像素数据。
  • @TimRoberts 我检查过,但事实并非如此。我附上了输出图像。管道是红色的!!。
  • 好的,让我指出您说“图像全是蓝色”。你的形象绝对不是“全蓝”。如果您一开始就发布了这张图片,我们可以立即识别出 BGR/RGB 反转。

标签: python python-3.x numpy opencv opencv-python


【解决方案1】:

原因是频道的顺序。我认为发件人将图像读取为 RGB 图像,而您将其显示为 BGR 图像,反之亦然。 改变R和B通道的顺序即可解决问题:

image = image[..., [0,3,2,1]] # swap 3 and 1 represent for B and R

如果您使用PIL.ImageOpenCV,您会经常遇到此问题。 PIL.Image 将图像读取为 RGB,cv2 将读取为 BGR,这就是图像中所有红点变为蓝色的原因。

【讨论】:

    【解决方案2】:

    OpenCV 在处理彩色图像 [1][2] 时使用 BGR(包含 alpha 时为 BGRA)排序,这适用于使用 imread()imwrite() 读取/写入的图像;使用VideoCapture 获取的图像;绘图函数ellipse()rectangle();等等。这个约定在库中是自洽的,如果你用imread() 读取图像并用imshow() 显示它,就会出现正确的颜色。

    OpenCV 是我所知道的唯一使用这种排序的库,例如PIL 和 Matplotlib 都使用 RGB。如果您想从一种颜色空间转换为另一种颜色空间,请使用cvtColor(),例如:

    # Convert RGB to BGR.
    new_image = cvtColor(image, cv2.COLOR_RGB2BGR)
    

    查看ColorConversionCodes 枚举以了解所有支持的转换对。不幸的是,没有 ARGB 到 BGR,但您始终可以手动操作 NumPy 数组:

    # Reverse channels ARGB to BGRA.
    image_bgra = image[..., ::-1]
    
    # Convert ARGB to BGR.
    image_bgr = image[..., [3, 2, 1]]
    

    还有一个 mixChannels() 函数和一堆其他数组操作实用程序,但其中大部分在 OpenCV Python 中是多余的,因为图像由 NumPy 数组支持,因此使用 NumPy 对应物更容易。

    OpenCV 使用 BGR 似乎是出于历史原因:Why OpenCV Using BGR Colour Space Instead of RGB


    参考资料:

    [1] OpenCV: Mat - The Basic Image Container(在存储方法下搜索“BGR”。)

    [2]OpenCV: How to scan images, lookup tables and time measurement with OpenCV

    来自 [2] 的图像显示内存中的 BGR 布局。

    【讨论】:

    • 我尝试使用image_bgr = image[..., [3, 2, 1]],但现在它就像一个蓝色滤镜应用于实际图像。
    • @ThinkalVB 嗯,这很奇怪,你的输入图像肯定是 ARGB 而不是 RGBA?如果是 RGBA,似乎会发生这种情况。
    • 如果是 RGBA,那么你需要image[..., [2, 1, 0]],或者使用cvtColor()cv2.COLOR_RGBA2BGR
    • @ThinkalVB 我对 Unity 不太熟悉,抱歉,当它发送图像而你收到它时,可能还有其他事情发生。如果是网络摄像头视频,我假设 alpha 通道将固定在一个恒定的最大值 (255) 值,因此您可以使用它来检查哪个通道是 alpha 通道(第一个或最后一个索引)。如果 unity 有一些奇怪的行为,您可以尝试专门提出一个新问题,看看其他人是否有更好的想法。
    • @ThinkalVB 下次可以通过numpy.save 将图片转储到npy 文件中,然后将其与您的问题一起上传。我们会更容易为您提供帮助和解释。
    【解决方案3】:
    IMAGE_WIDTH = 640
    IMAGE_HEIGHT = 480
    IMAGE_SIZE = IMAGE_HEIGHT * IMAGE_WIDTH * 4
    
    try:
        while(True):
            data = sock.recv(IMAGE_SIZE)
            dataLen = len(data)
            if(dataLen == IMAGE_SIZE):
                image = numpy.fromstring(data, numpy.uint8).reshape(IMAGE_HEIGHT, IMAGE_WIDTH, 4)
                imageDisp = cv2.cvtColor(image, cv2.COLOR_RGBA2BGR)
                cv2.imshow('Image', imageDisp)
                key = cv2.waitKey(1) & 0xFF
                if key == ord("q"):
                    break
    finally:
        sock.close()
    

    根据评论的建议进行编辑

    【讨论】:

    • 您可以通过为图像的高度和宽度设置变量来改进您的代码,而不是在不同的地方重复 640 和 480 - 因为这对维护来说是一场噩梦。此外,如果大小错误,您的 np.reshape() 将在您的 if dataLen==IMAGE_SIZE 之前失败,因此您的 if 语句更早属于您的代码。
    猜你喜欢
    • 1970-01-01
    • 2021-05-03
    • 2021-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-29
    • 1970-01-01
    • 2014-09-10
    相关资源
    最近更新 更多