python pgm 转 bmp

说明

1,输入文件格式为pgm P5格式
2,输出格式为 bmp 格式

格式图解

PGM格式 P5

在这里插入图片描述

BMP格式 24位真彩色

在这里插入图片描述

步骤

1,读取 pgm 文件,得到图片width,height,像素数据 = [G1,G2,…]
2,因为像素数据范围可能是 0–65535,或者其它,取决于文件描述。要重新映射成 0–255 以写入bmp格式的文件
3,pgm是灰度图像,一个像素只有一个值描述:G;输出采用的bmp是24位真彩色,有3个byte描述一个像素,所以令 R = G = B = G

代码

# -*- coding: UTF-8 -*-
# python2

import math

class PGM(object):
    def __init__(self):
        self.magic_number = ''
        self.width = -1
        self.height = -1
        self.deep = -1
        self.bytes_for_pix = -1
        self.data = []

    def __str__(self):
        rtn_str = 'magic_number: ' + self.magic_number + '\n'
        rtn_str += 'width: ' + str(self.width) + '\n'
        rtn_str += 'height: ' + str(self.height) + '\n'
        rtn_str += 'deep: ' + str(self.deep) + '\n'
        rtn_str += 'bytes_for_pix: ' + str(self.bytes_for_pix) + '\n'
        rtn_str += 'data length: ' + str(len(self.data))
        return rtn_str

def read_pgm(pgm_file):
    pgm = PGM()
    with open(pgm_file, 'rb') as fi:
        first_line = fi.readline()  # 读取第一行,是PGM图像的 描述信息, 都是 ASCII 字符
        result = first_line.replace('\n', '').split(' ')  # e.g.['P5', '1280', '960', '4095']
        pgm.magic_number = result[0]  # 魔术字,P2或者P5,本例子只读 P5 格式
        pgm.width = int(result[1])
        pgm.height = int(result[2])
        pgm.deep = int(result[3])  # 本PGM文件描述灰度的数据范围 [0,pgm.deep]
        pgm.bytes_for_pix = 1 if pgm.deep <= 256 else 2  # 每个像素用1个或者2个字节描述灰度
        pgm.data = []
        while True:
            byte = fi.read(pgm.bytes_for_pix)  # 几个字节描述一个像素就读一次读几个字节
            if byte == '':
                break
            val = int(byte.encode('hex'), 16)  # 此像素的灰度值
            pgm.data.append(val)
        return pgm


def write_bmp(pgm):
    def get_size_data(value):
        base_str = '%08x' % value  # 数值转为16进制的 AABBCCDD 字符串
        width_str_list = []
        for i in range(0, len(base_str), 2):
            width_str_list.append(base_str[i:i+2])  # 转为 [AA, BB, CC, DD]
        width_str_list = width_str_list[::-1]  # 转为小端模式 [DD, CC, BB, AA]
        return ' '.join(width_str_list)  # 转为字符串 'DD CC BB AA'

    width_str = get_size_data(pgm.width)
    height_str = get_size_data(pgm.height)

    # bmp文件数据头,54个字节,24位真彩色,各种描述信息不管,只修改 width 和 height 数据,小端模式。
    bmp_head = '42 4d 36 80 01 00 00 00 00 00 36 00 00 00 28 00 00 00 ' + width_str + ' ' + height_str + ' 01 00 18 00 00 00 00 00 00 80 01 00 74 12 00 00 74 12 00 00 00 00 00 00 00 00 00 00'
    bmp_head = bmp_head.split(' ')
    bmp_head = [int(each, 16) for each in bmp_head]

    # 原数据灰度范围是 0 -- pgm.deep, bmp是 0--256,所以要缩放
    factor = int(math.ceil(pgm.deep/256.))  # 向上取整,务使缩放后的数据范围在0--255
    bmp_data = [each/factor for each in pgm.data]

    # 跟原图比是上下倒的,反一下
    bmp_data = bmp_data[::-1]

    # 跟原图比是左右倒的,对每行再反一下
    out_data = []
    for pos in range(0, len(bmp_data), pgm.width):
        out_data += bmp_data[pos: pos + pgm.width][::-1]

    with open('output.bmp', 'wb') as fo:
        for byte in bmp_head:
            # bmp 头数据
            fo.write(('%02x' % byte).decode('hex'))

        import sys

        old = 0
        for i, byte in enumerate(out_data):
            prss = i/(len(out_data) * 1.0) * 100
            if prss > old + 10:
                old += 10
                sys.stdout.write('. ')
            # 因为bmp有 R G B,pgm只有一个灰度,取R=G=B=灰度值
            fo.write(('%02x' % byte).decode('hex'))
            fo.write(('%02x' % byte).decode('hex'))
            fo.write(('%02x' % byte).decode('hex'))


if __name__ == '__main__':
    pgm = read_pgm('img.pgm')
    write_bmp(pgm)
    try:
        input('done')
    except Exception as e:
        pass
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值