X
217 Rate this article:
No rating

INTERNAL: Reading Monochrome Bitmap Files

Zachary Norman
Topic:
The purpose of this Tech Tip is to provide information and sample code that can be used to read monochrome bitmap files with IDL. The monochrome bitmap format is not supported by the routine READ_BMP.

Discussion:
Monochrome bitmap files are images where each bit of data in the file corresponds to a pixel in the image. It is more common to see images in which a byte of data corresponds to a pixel in the image. Therefore, each pixel in the image can have a value ranging from 0 to 255. With monochrome bitmap images each pixel can have a value of 1 (white) or 0 (black). Monochrome bitmap images can be generated using MS Paint. A example image is shown below:

errorbars_nocropping

Reading monochrome bitmap images with IDL can be difficult because there is not BIT type. Therefore, the data has to be read in as bytes, which then need to be expanded into their bit values. In order to read the file, you must know something about the bitmap file format. The Wikipedia page for bitmap files has some good information about this topic. The table below shows the bitmap file format information that can be used to read a monochrome bitmap file.

                           
Byte Number Field Type Use or Explanation
1-2 File type 2 byte array Confirms file BMP type ("BM")
3-6 File size (BYTES) Long Used to determine array size needed to read image
7-10 Junk Long Not used
11-14    Byte offset of BMP data Long Byte number where image data starts
15-18    Header bytes Long Byte length of header data
19-22    Width of image (Pixels) Long Used to determine array size needed to read image
23-26 Height of image (Pixels) Long Used to determine array size needed to read image
27-28 Bit planes Integer Not very useful for monochrome images
27-28 Bits per pixel Integer Confirms monochrome image (should equal 1)


One thing that complicates the reading of monochrome bitmap files is that the files are padded so that the stored data is a multiple of 4 bytes. To account for this problem, you can check if the modulous of the image width (bytes) and 32 (4 bytes; word size) is equal to zero. If it is equal to zero, then the image width is equal to width of the data stored in the file. If it is not equal to zero, then the image width will not be equal to the data stored in the file because extra zeros were added to the data to make it a multiple of 32. To account for this, you can use the equation below to determine the width of the data inside the file:

data width = (image_width_pix/32L+1)*32L

Below is an example function called "read_mono_bmp" that reads monochrome bitmap images and outputs an 2-D array or binary data. This function uses the BINARY command from the Coyote library.

NOTE: "read_mono_bmp" is met to be an example program. It has not been robustly tested and it might be very slow or not work with some files. This code is not official Exelis VIS code.

An example of how to use the "read_mono_bmp" routine is shown below:
IDL>img = read_mono_bmp(DIALOG_PICKFILE()) ; pick a monochrome bmp image
IDL> tvscl, img

'img' is a 2-D array of ones and zeros. Therefore, to display the image (without further processing) the user must use TVSCL instead of TV.



Solution:
;+
;
; This is a program that reads in a Monochrome Bitmap file
; and ouputs image data in ones and zeros 
; 
;
; :Uses: Read_binary, binary (Coyote Library)
; :Author: David Staruck, Exelis VIS, 2011
;-

function read_mono_bmp, file_a

  on_error, 2

  

  openu, lun, file_a, /GET_LUN
  
  f_type=BYTARR(2); type of file should be BM
  f_size=0L ; size of file in bytes
  junk=0L ; empty space
  f_off=0L ; Image data offset from top of file
  
  head_bytes=0L ;bytes in header
  width_pix=0L ;width of image (pixels)
  height_pix=0L ;height of image (pixels
  biplanes=0  ; number of bit planes
  bibitcount=0 ; bit per pixel count (should be 1)
  
  
  img_index=0L ;index used for final image
  
  ;read some of the header infomation about the file (don't care about color info)
  readu, lun, f_type, f_size, junk, f_off
  readu, lun, head_bytes, width_pix, height_pix, biplanes, bibitcount
 
  ;Error handle
  ;Confirm file is a bitmap image
  if string(f_type) ne 'BM' then message, 'File is not in bitmap format' 
  ;Cofirm file is a monochrome bitmap image
  if bibitcount ne 1 then message, 'File is not a monochrome bitmap image'
  
  close, lun ;close the file. will reopen with read_binary function

  data_width_pix = width_pix ;width of image in file (with padding)
  
  ;Calculate data width pixel numbers. Add extra data to account for padding.
  if (data_width_pix MOD 32 NE 0) then begin
  mult = data_width_pix/32L + 1 
  data_width_pix = mult*32L
  endif 
 

  ;Pixel array rowsize =(pixel_width*BBP)/32 * 4 
  x=byte(width_pix/32.*4)  ;BBP (bits per pixel) equals 1 in this case
  

  
  ;set up array dimensions
  dim=[x, height_pix]
  
  ;use read binary to get image information (in BYTES)
  img=READ_BINARY(file_a, DATA_DIMS=dim, DATA_START=f_off)
 

   
  ;declare final image array 
  tmp_img=BYTARR(data_width_pix,height_pix)
  
  ;loop through each element in img and convert BYTE to Binary and fill fin_img with information
  for i = 0L, N_ELEMENTS(img)-1 do begin
        b=binary(img[i]) ;used binary function from Coyote library
        for j = 0L, N_ELEMENTS(b)-1 do begin
            tmp_img[img_index]=b[j]
            img_index=img_index+1
        endfor
  endfor

  ;Display the final image
  ;tvscale, fin_img
  fin_img=tmp_img[0:width_pix-1, *]
  return, fin_img