简介

BMP是一种常见的图像格式,我们可以把RGB数据保存为BMP的图像格式方便直接在电脑上查看,之前我们已经学习了YUV和RGB之间相互转换的算法,接下来我们就可以把转换后的RGB数据变成一张BMP图片。

示例

  • bmp类实现
    只要我们把BMP的头文件信息填好,接下来把RGB输入填充进去就可以,由于BMP读取的是BGR顺序,这里我们可以在转RGB时候把RGB顺序修改一下即可。

    from struct import pack, unpack
    class bmp:
      def __init__(self,width,height,depth):
          # BMP Header
          self.BMP_id = b'BM'
          self.BMP_size = None
          self.BMP_reserved1 = b'\x00\x00'
          self.BMP_reserved2 = b'\x00\x00'
          self.BMP_offset = None
    
          # DIB Header
          self.DIB_len = 40
          self.DIB_w = width
          self.DIB_h = height
          self.DIB_planes_num = 1
          self.DIB_depth = depth
          self.DIB_comp = 0
          self.DIB_raw_size = None
          self.DIB_hres = 2835 # 72 DPI * 39.3701 inches/metre.
          self.DIB_vres = 2835
          self.DIB_num_in_plt = 0
          self.DIB_extra = None
    
          self.palette = None
          self.pixels = None
    
          self.ppb = None # Number of pixels per byte for depth <= 8.
          self.row_size = None
          self.padded_row_size = None
    
          self.BMP_offset = 14 + self.DIB_len
          self.row_size = (self.DIB_w * self.DIB_depth + 7) // 8
          self.padded_row_size = (self.row_size + 3) // 4 * 4
          self.DIB_raw_size = self.padded_row_size * self.DIB_h
          self.BMP_size = self.BMP_offset + self.DIB_raw_size
      def save(self, file_path,rgb):
          with open(file_path, 'wb') as bf_io:
              self.DIB_comp = 0
              # BMP Header
              bf_io.write(self.BMP_id)
              bf_io.write(pack("<I", self.BMP_size))
              bf_io.write(self.BMP_reserved1)
              bf_io.write(self.BMP_reserved2)
              bf_io.write(pack("<I", self.BMP_offset))
              # DIB Header
              bf_io.write(pack(
                  "<IiiHHIIiiII",
                  self.DIB_len,
                  self.DIB_w,
                  -self.DIB_h,
                  self.DIB_planes_num,
                  self.DIB_depth,
                  self.DIB_comp,
                  self.DIB_raw_size,
                  self.DIB_hres,
                  self.DIB_vres,
                  self.DIB_num_in_plt,
                  self.DIB_num_in_plt
              ))
              bf_io.write(bytes(rgb))
      def yuv420_to_bgr888(self,yuv):
          width = self.DIB_w
          height = self.DIB_h
          rgb_bytes = bytearray(width*height*3)
          red_index = 2
          green_index = 1
          blue_index = 0
          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
  • 测试

    import file
    from struct import pack, unpack
    class bmp:
      def __init__(self,width,height,depth):
          # BMP Header
          self.BMP_id = b'BM'
          self.BMP_size = None
          self.BMP_reserved1 = b'\x00\x00'
          self.BMP_reserved2 = b'\x00\x00'
          self.BMP_offset = None
    
          # DIB Header
          self.DIB_len = 40
          self.DIB_w = width
          self.DIB_h = height
          self.DIB_planes_num = 1
          self.DIB_depth = depth
          self.DIB_comp = 0
          self.DIB_raw_size = None
          self.DIB_hres = 2835 # 72 DPI * 39.3701 inches/metre.
          self.DIB_vres = 2835
          self.DIB_num_in_plt = 0
          self.DIB_extra = None
    
          self.palette = None
          self.pixels = None
    
          self.ppb = None # Number of pixels per byte for depth <= 8.
          self.row_size = None
          self.padded_row_size = None
    
          self.BMP_offset = 14 + self.DIB_len
          self.row_size = (self.DIB_w * self.DIB_depth + 7) // 8
          self.padded_row_size = (self.row_size + 3) // 4 * 4
          self.DIB_raw_size = self.padded_row_size * self.DIB_h
          self.BMP_size = self.BMP_offset + self.DIB_raw_size
      def save(self, file_path,rgb):
          with open(file_path, 'wb') as bf_io:
              self.DIB_comp = 0
              # BMP Header
              bf_io.write(self.BMP_id)
              bf_io.write(pack("<I", self.BMP_size))
              bf_io.write(self.BMP_reserved1)
              bf_io.write(self.BMP_reserved2)
              bf_io.write(pack("<I", self.BMP_offset))
              # DIB Header
              bf_io.write(pack(
                  "<IiiHHIIiiII",
                  self.DIB_len,
                  self.DIB_w,
                  -self.DIB_h,
                  self.DIB_planes_num,
                  self.DIB_depth,
                  self.DIB_comp,
                  self.DIB_raw_size,
                  self.DIB_hres,
                  self.DIB_vres,
                  self.DIB_num_in_plt,
                  self.DIB_num_in_plt
              ))
              bf_io.write(bytes(rgb))
      def yuv420_to_bgr888(self,yuv):
          width = self.DIB_w
          height = self.DIB_h
          rgb_bytes = bytearray(width*height*3)
          red_index = 2
          green_index = 1
          blue_index = 0
          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
    #测试程序
    data=file.read("image.yuv")
    img=bmp(320,240,24)
    bgr=img.yuv420_to_bgr888(data)
    img.save("image.bmp",bgr)

    这样,我们就实现了BMP图像保存。

文档更新时间: 2020-12-21 08:05   作者:cijliu