简介

从摄像头采集到的数据都是YUV格式,而在图像处理上,我们经常使用的是RGB颜色空间,对此,我们必须先把数据从YUV颜色空间转换到RGB颜色空间上,这里我们可以直接根据YUV和RGB之间的换算算法进行转换。

示例

  • YUV420转RGB888函数实现

    def yuv420_to_rgb888(width, height, yuv):
      rgb_bytes = bytearray(width*height*3)
      red_index = 0
      green_index = 1
      blue_index = 2
      y_index = 0
    
      for row in range(0,height):
          u_index = width * height + (row//2)*(width//2)
          v_index = u_index + (width*height)//4
    
          for column in range(0,width):
              Y = yuv[y_index]
              U = yuv[u_index]
              V = yuv[v_index]
              C = (Y - 16) * 298
              D = U - 128
              E = V - 128
              R = (C + 409*E + 128) // 256
              G = (C - 100*D - 208*E + 128) // 256
              B = (C + 516 * D + 128) // 256
    
              R = 255 if (R > 255) else (0 if (R < 0) else R)
              G = 255 if (G > 255) else (0 if (G < 0) else G)
              B = 255 if (B > 255) else (0 if (B < 0) else B)
    
              rgb_bytes[red_index] = R
              rgb_bytes[green_index] = G
              rgb_bytes[blue_index] = B
    
              u_index += (column % 2)
              v_index += (column % 2)
              y_index += 1
              red_index += 3
              green_index += 3
              blue_index += 3
    
      return rgb_bytes
  • RGB888转YUV420函数实现

    def rgb888_to_yuv420(width, height, rgb):
      red_index = 0
      green_index = 1
      blue_index = 2
      yuv=bytearray(int(width*height*1.5))
      for y in range(height):
          u_index = width * height + (y//2)*(width//2)
          v_index = u_index + (width*height)//4
          for x in range(width):
              R = rgb[red_index]
              G = rgb[green_index]
              B = rgb[blue_index]
              red_index += 3
              green_index += 3
              blue_index += 3
              Y = int((66*R + 128*G + 25*B)// 256 + 16)
              yuv[y*width+x] = 255 if (Y > 255) else (0 if (Y < 0) else Y)
              if x%2==0 and y%2==0:
                  V = int((112*R - 94*G - 18*B)// 256 + 128)
                  U = int((-38*R - 74*G + 112*B)// 256 + 128)
                  yuv[u_index] = 255 if (U > 255) else (0 if (U < 0) else U)
                  yuv[v_index] = 255 if (V > 255) else (0 if (V < 0) else V)
                  u_index = u_index + 1
                  v_index = v_index + 1
    
      return yuv
  • 测试
    有了上面的转换函数,我们可以很容易就将YUV和RGB进行互转,接下来我们动手尝试

    import file
    def yuv420_to_rgb888(width, height, yuv):
      rgb_bytes = bytearray(width*height*3)
    
      red_index = 0
      green_index = 1
      blue_index = 2
      y_index = 0
    
      for row in range(0,height):
          u_index = width * height + (row//2)*(width//2)
          v_index = u_index + (width*height)//4
    
          for column in range(0,width):
              Y = yuv[y_index]
              U = yuv[u_index]
              V = yuv[v_index]
              C = (Y - 16) * 298
              D = U - 128
              E = V - 128
              R = (C + 409*E + 128) // 256
              G = (C - 100*D - 208*E + 128) // 256
              B = (C + 516 * D + 128) // 256
    
              R = 255 if (R > 255) else (0 if (R < 0) else R)
              G = 255 if (G > 255) else (0 if (G < 0) else G)
              B = 255 if (B > 255) else (0 if (B < 0) else B)
    
              rgb_bytes[red_index] = R
              rgb_bytes[green_index] = G
              rgb_bytes[blue_index] = B
    
              u_index += (column % 2)
              v_index += (column % 2)
              y_index += 1
              red_index += 3
              green_index += 3
              blue_index += 3
    
      return rgb_bytes
    def rgb888_to_yuv420(width, height, rgb):
      red_index = 0
      green_index = 1
      blue_index = 2
      yuv=bytearray(int(width*height*1.5))
      for y in range(height):
          u_index = width * height + (y//2)*(width//2)
          v_index = u_index + (width*height)//4
          for x in range(width):
              R = rgb[red_index]
              G = rgb[green_index]
              B = rgb[blue_index]
              red_index += 3
              green_index += 3
              blue_index += 3
              Y = int((66*R + 128*G + 25*B)// 256 + 16)
              yuv[y*width+x] = 255 if (Y > 255) else (0 if (Y < 0) else Y)
              if x%2==0 and y%2==0:
                  V = int((112*R - 94*G - 18*B)// 256 + 128)
                  U = int((-38*R - 74*G + 112*B)// 256 + 128)
                  yuv[u_index] = 255 if (U > 255) else (0 if (U < 0) else U)
                  yuv[v_index] = 255 if (V > 255) else (0 if (V < 0) else V)
                  u_index = u_index + 1
                  v_index = v_index + 1
    
      return yuv
    def draw_rect(x0,y0,x1,y1,w,h,rgb):
      for y in range(0,h):
          for x in range(0, w):
              if (x == x0 and y >= y0 and y <= y1) \
              or (x == x1 and y >= y0 and y <= y1) \
              or (y == y0 and x >= x0 and x <= x1) \
              or (y == y1 and x >= x0 and x <= x1):
                  index = (y*w+x)*3
                  rgb[index] = 0
                  rgb[index+1] = 0
                  rgb[index+2] = 0
    data=file.read("image.yuv")
    rgb = yuv420_to_rgb888(320,240,data)
    #画一个矩形框
    draw_rect(0,0,100,100,320,240,rgb)
    yuv = rgb888_to_yuv420(320,240,rgb)
    file.write("rect.yuv",bytes(yuv))
    print("rgb size: ", len(rgb))
    print("yuv size: ", len(yuv))

    这样就实现了两种颜色空间之间的互转,以此为基础,我们可以实现各种各样的图像算法,这里实现了一个矩形框绘制函数,我们通过转换后的RGB进行绘制矩形框,然后再保存为YUV数据,使用YUV查看工具进行查看,就能发现多了一个矩形框。

文档更新时间: 2020-12-21 06:13   作者:cijliu