Python 画像処理

ちまたに書籍が溢れているので,詳しくはそちらをどうぞ.

BMP file の読み込み

画像ファイルを読み込むだけなら,OpenCVなどのパッケージを使いましょう.
ここでは,.bmp ファイルの構造のお勉強目的でのサンプルです.

以下は,ヘッダをファイルからまともに読み込む例.
これを応用すれば,構造さえわかればいかなるデータフォーマットでも読み込める.

参考データ:windows bmp file のヘッダを表すC構造体.詳しくは Windows SDK などの wingdi.h を参照.

typedef struct tagBITMAPFILEHEADER {
  WORD  bfType;
  DWORD bfSize;
  WORD  bfReserved1;
  WORD  bfReserved2;
  DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER {
  DWORD biSize;
  LONG  biWidth;
  LONG  biHeight;
  WORD  biPlanes;
  WORD  biBitCount;
  DWORD biCompression;
  DWORD biSizeImage;
  LONG  biXPelsPerMeter;
  LONG  biYPelsPerMeter;
  DWORD biClrUsed;
  DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;

その1

structでファイル読み込み解析. bufをunpack()

#   find every bmp files in directory, open and read it
#   using Structure

#   x	padding a byte  1
#   c	char	        1
#   b	signed char	1
#   B	uchar, BYTE	1
#   ?	_Bool	        1
#   h	short	        2
#   H	ushort, WORD	2
#   i	int     	4
#   I	uint, DWORD	4
#   l	long, LONG	4
#   L	ulong, ULONG	4
#   q	long long, LONGLONG	8
#   Q	ulong long, ULONGLONG	8
#   f	float	        4
#   d	double	        8

import os
import struct
    
BMFH = struct.Struct("=HIHHI")
BMIH = struct.Struct("=IllHHIIllII")
RGBQ = struct.Struct("=BBBB")

print('Start reading bmp files...')

for img_fname in os.listdir('.'):

    if not img_fname.endswith('.bmp'):
        continue

    print('filename is', img_fname)

    with open(img_fname, mode='rb') as f:

        # read bmfh
        buf = f.read(14)    # sizeof(BITMAPFILEHEADER)
        bmfh = BMFH.unpack(buf)
        print('bfType    =', hex(bmfh[0]))
        print('bfOffBits =', bmfh[4])

        # read bmih
        buf = f.read(40)    # sizeof(BITMAPINFOHEADER)
        bmih = BMIH.unpack(buf)
        w = bmih[1]
        h = bmih[2]
        bpp = bmih[4]
        print('biSize =', bmih[0])
        print('Width  =', w)
        print('Height =', h)
        print('BPP    =', bpp)

        # read image body
        f.seek(bmfh[4])
        img = f.read(w*h)
        print(img[0])

    f.close()

その2

classでデータストラクチャを定義, メンバ名でアクセスできる.

#   find every bmp files in directory, open and read it
#   using ctypes ans class definition.
#   Image is shown by using matplotlib
#

import os
from ctypes import *
import numpy as np
import matplotlib.pyplot as plt

class BITMAPFILEHEADER(Structure):
    _fields_ = [
        ('bfType', c_uint16),
        ('bfSize', c_uint32),
        ('bfReserved1', c_uint16),
        ('bfReserved2', c_uint16),
        ('bfOffBits', c_uint32),
    ]
    _pack_ = 1

class BITMAPINFOHEADER(Structure):
    _fields_ = [
        ('biSize',        c_uint32),
        ('biWidth',       c_int32),
        ('biHeight',      c_int32),
        ('biPlanes',      c_uint16),
        ('biBitCount',    c_uint16),
        ('biCompression', c_uint32),
        ('biSizeImage',   c_uint32),
        ('biXPPM',        c_int32),
        ('biYPP',         c_int32),
        ('biClrUsed',     c_uint32),
        ('biClrImportant',c_uint32),
        ('bfType',        c_uint16),
        ('bfSize',        c_uint32),
        ('bfReserved1',   c_uint16),
        ('bfReserved2',   c_uint16),
        ('bfOffBits',     c_uint32),
    ]
    _pack_ = 1
    

    print('Start reading bmp files...')
    for img_fname in os.listdir('.'):

    if not img_fname.endswith('.bmp'):
        continue

    print('filename is', img_fname)

    with open(img_fname, mode='rb') as f:

        #   read and parse bmfh
        bmfh = BITMAPFILEHEADER()
        f.readinto(bmfh)

        if(bmfh.bfType != 0x4d42):
            print('ERROR : wrong bmfh.bfType')
            continue;

        if(bmfh.bfOffBits != 1078):
            print('ERROR : wrong bmfh')
            continue;

        #   read and parse bmih
        bmih = BITMAPINFOHEADER()
        f.readinto(bmih)

        print('w , h =', str(bmih.biWidth), 'x', str(bmih.biHeight)+' pixel')

        if(bmih.biBitCount != 8):
            print('ERROR : wrong bit count')
            continue;


        w = bmih.biWidth
        h = bmih.biHeight
        f.seek(bmfh.bfOffBits)
        img = f.read(w*h)

        dt = np.dtype(('<u1', (w, h)))
        x = np.frombuffer(img, dt)

        #Remove unnecessary dimension that numpy gave us
        x = x[0,:,:]
#        print(x[0][0])

        plt.imshow(x, extent=[0,w,0,h], aspect="auto")
        plt.show()



    f.close()