Tensorflow:如何编码和读取bmp图像?

时间:2018-06-15 07:51:45

标签: python image tensorflow bmp

我正在尝试读取.bmp图像,对它们进行一些扩充,将它们保存到.tfrecords文件,然后打开.tfrecords文件并使用图像进行图像分类。我知道有一个tf.image.encode_jpeg()和一个tf.image.encode_png()函数,但是没有tf.image.encode_bmp()函数。我知道.bmp图像是未压缩的,所以我试图简单地对图像进行base64-encode,np.tostring()和np.tobytes(),但是在尝试解码这些格式时出现以下错误: / p>

tensorflow.python.framework.errors_impl.InvalidArgumentError: channels attribute 3 does not match bits per pixel from file <some long number>

我的看法是,在编码为jpeg或png时,tensorflow会对图像的字节编码做一些额外的处理;保存有关数组维度等的信息。但是,我对此毫无头绪,所以任何帮助都会很棒!

一些代码显示我想要实现的目标:

with tf.gfile.FastGFile(filename, 'rb') as f:
    image_data = f.read()
    bmp_data = tf.placeholder(dtype=tf.string)
    decode_bmp = tf.image.decode_bmp(self._decode_bmp_data, channels=3)
    augmented_bmp = <do some augmentation on decode_bmp>
    sess = tf.Session()
    np_img = sess.run(augmented_bmp, feed_dict={bmp_data: image_data})
    byte_img = np_img.tostring()

    # Write byte_img to file using tf.train.Example
    writer = tf.python_io.TFRecordWriter(<output_tfrecords_filename>)
    example = tf.train.Example(features=tf.train.Features(feature={
        'encoded_img': tf.train.Feature(bytes_list=tf.train.BytesList(value=[byte_img])}))
    writer.write(example.SerializeToString())

    # Read img from file
    dataset = tf.data.TFRecordDataset(<img_file>)
    dataset = dataset.map(parse_img_fn)

parse_img_fn可能会缩小为以下内容:

def parse_img_fn(serialized_example):
    features = tf.parse_single_example(serialized_example, feature_map)
    image = features['encoded_img']
    image = tf.image.decode_bmp(image, channels=3) # This is where the decoding fails
    features['encoded_img']

    return features

2 个答案:

答案 0 :(得分:2)

你评论中的

,当然你的意思是编码而不是加密

BMP file format非常简单,由一堆标题和几乎原始的像素数据组成。这就是BMP图像如此之大的原因。我想这也是为什么TensorFlow开发人员没有费心去编写一个函数来将数组(代表图像)编码成这种格式的原因。很少有人仍然使用它。建议使用PNG代替PNG,它可以对图像进行无损压缩。或者,如果您可以处理有损压缩,请使用JPG。

TensorFlow对编码图像没有任何特殊作用。它只返回表示该格式的图像的字节,类似于matplotlib在执行save_fig时所执行的操作(除了MPL还将字节写入文件)。

假设您生成一个numpy数组,其中顶行为0,底行为255.这是一个数字数组,如果您认为它是图片,代表2个水平带,顶部一个黑色,底部一个白色。

如果要在其他程序(GIMP)中查看此图片,则需要以标准格式(如PNG)对此信息进行编码。编码意味着添加一些标头和元数据,并可选择压缩数据。

现在更清楚的是编码是什么,我建议您使用PNG图像。

with tf.gfile.FastGFile('image.png', 'rb') as f:
    # get the bytes representing the image
    # this is a 1D array (string) which includes header and stuff
    raw_png = f.read()

    # decode the raw representation into an array
    # so we have 2D array representing the image (3D if colour) 
    image = tf.image.decode_png(raw_png)

    # augment the image using e.g.
    augmented_img = tf.image.random_brightness(image)

    # convert the array back into a compressed representation
    # by encoding it into png
    # we now end up with a string again
    augmented_png = tf.image.encode_png(augmented_img, compression=9) 

    # Write augmented_png to file using tf.train.Example
    writer = tf.python_io.TFRecordWriter(<output_tfrecords_filename>)
    example = tf.train.Example(features=tf.train.Features(feature={
        'encoded_img': tf.train.Feature(bytes_list=tf.train.BytesList(value=[augmented_png])}))
    writer.write(example.SerializeToString())

    # Read img from file
    dataset = tf.data.TFRecordDataset(<img_file>)
    dataset = dataset.map(parse_img_fn)

有一些重要的建议:

  • 请勿使用numpy.tostring。这将返回 HUUGE 表示,因为每个像素都表示为一个浮点数,并且它们都是连接的。没有压缩,没有。尝试检查文件大小:)

  • 不需要使用tf.Session传回python。您可以在TF端执行所有操作。这样,您就可以使用输入图表作为输入管道的一部分。

答案 1 :(得分:0)

tensorflow主包中没有encode_bmp,但是如果导入tensorflow_io(也是Google官方支持的包),则可以在其中找到encode_bmp方法。

有关文档,请参见: https://www.tensorflow.org/io/api_docs/python/tfio/image/encode_bmp