0

I am trying to load and display a bmp image in python.
I have tried several modules now (PIL, skimage.io, matplotlib) but the image gets displayed wrongly every time.
This is the original picture and this is how it looks like after loading and displaying it in python. (The original image gets converted to png when uploaded here).
Here is the most recent code I am using:

from skimage import io
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)
image = io.imread('107.bmp')
io.imshow(image)
plt.show()

It looks like there is a problem with the way I am importing the bmp file. When I print the first column of the loaded image with print(image[:,0]) the resulting (494,) array already contains white 255 valued pixels that should only occur in the middle of the image somewhere around image[:, 300]. So far I could not find any options for io.imread() that help solving this problem.

What am I doing wrong? How can I load the bmp image with the correct order of columns?

The original bmp image gets displayed correctly when I open it in the default windows photos app or paint.
I am using python 3.8.5 and scikit-image 0.17.2.

Community
  • 1
  • 1
mrTi
  • 1
  • 1

1 Answers1

0

I was solve able to solve my problem by writing my own read bmp script that pays special attention to where the bmp header ends.

Following the suggested solution of How to read bmp file header in python? I implemented the header reading and received the following information:

  • Type: BM
  • Size: 325142
  • Reserved 1: 0
  • Reserved 2: 0
  • Offset: 54
  • DIB Header Size: 40
  • Width: 656
  • Height: 494
  • Colour Planes: 1
  • Bits per Pixel: 8
  • Compression Method: 0
  • Raw Image Size: 324064
  • Horizontal Resolution: 0
  • Vertical Resolution: 0
  • Number of Colours: 0
  • Important Colours: 0

From Wikipedia I understood that the BMP file header should be 54 bytes large as given by the "Offset: 54" parameter in the header. Each pixel in my grey scale image is described by 1 single byte.
However the difference between "Size: 325142" and "Raw Image Size: 324064" in the header information is 1078 bytes.

I tried a simple "read bmp" script:

import numpy as np
from PIL import Image
bmp = open(filename, 'rb')
bmp.seek(1078)
row = []
rows = []
for j in range(0, 494):
    for I in range(0, 656):
        row.append(int.from_bytes(bmp.read(1), 'little'))
    rows.append(row)
    row = []
data = np.array(rows, dtype = np.uint8)
data = np.flip(data, 0)
img = Image.fromarray(data, 'L')
img.show()
bmp.close()

When I use bmp.seek(1078) the bmp image gets read and displayed correctly just like in windows photos. When I use bmp.seek(54) the bmp image gets displayed wrongly just like when I use img = Image.open(filename) or other python libraries.
According to Wikipedia the bmp header is followed by a color table that has a length 2^n*4=1024 (n = 8: Bites per pixel value). This color table is not added to bmp files with 16 or more bites per pixel (RGB). Since 1024 + 54 = 1078 explains exactly the difference between the header length and the file length I assume that the python modules do not correctly account for the header size when reading grey scale bmp files.
Or am I missing some option in the python implementations that would solve my issue?

mrTi
  • 1
  • 1