[Python] クラスを使ってソースコードを整理する

Python
この記事は約9分で読めます。
具体的な例が気に入らない女
具体的な例が気に入らない女

ビットマップ画像を読み込ませる記事を見たんだけど、ソースコードが長くて読みずらかったから、全く読む気がしなかったわ。こんな記事は目の毒ね。

気に入ってもらいたいモグラ
気に入ってもらいたいモグラ

初学者でも分かり易いようにと、先日の記事ではあえて関数やクラスは用いないコードを示しました。申し訳ありません。今日の記事では、Pythonのクラスを用いてコーディングしたら、どんな風にコードをまとめる事が出来るのかを示したいと思います。

本記事に記載のPythonスクリプト動作確認環境

OS : Windows10(64bit版)
Python version : 3.7.3

スポンサーリンク

Pythonのクラスって何?

クラスというのはPython固有の言語仕様ではなく、オブジェクト指向言語(OOP)の概念です。Python以外にも C++やJAVA,ruby といったOOPは、クラスを定義して使う事が出来ます。

Pythonのクラスを使ってソースコードを整理する

自作したRGBクラスを用いて、整理したソースコードを示します。

main.py
### 作成したRGBクラス ###
from RGB import RGB

### ファイルパス設定###
directory_path  = r"C:\Python_source\02_BinaryFile"
input_filename  = "resize_image.bmp"
output_filename = "resize_image_out.bmp"

### BMPファイル読み込み ###
rgb = RGB(directory_path+"/"+input_filename)
### 画像処理 ###
rgb.gain(gain=1.2)
### BMPファイル保存 ###
rgb.SaveBMP(directory_path+"/"+output_filename)

2行目で自作したRGBクラスを読み込み、5~7行目で入出力ファイルの名前とそのディレクトリを変数として代入しています。

10行目で入力ファイルを引数として、rgbというRGBクラスのインスタンスを生成し、12行目で、RGBクラスのgainメソッドを用いて画像処理を行い、14行目でRGBクラスのSaveBMPメソッドに出力ファイルを引数として与える事で、ビットマップ形式で画像を保存します。

この環境であれば、RGBクラスに色々な画像処理メソッドを追加して、効果を確認する事に集中出来るかと思います。

では次に、RGBクラスを定義したファイルを見てみましょう。”RGB.py” ファイルを作成して、その中でRGBクラスを定義しています。RGBクラスの中では、初期化メソッド__init__()と、main.py中で使用したgainメソッドSaveBMPメソッドを定義しています。

Pythonでクラスを定義して関数と変数をまとめる

自作したRGBクラスのソースファイル ”RGB.py” を示します。

RGB.py
import sys

class RGB :

  def __init__(self, file):

    ### 入出力画像ファイルのオブジェクトを生成 ###
    f = open(file,"rb")
    ### BMPファイルヘッダ ###
    bfType             = f.read(2).decode()
    bfSize             = f.read(4) # not use
    bfReserved1        = f.read(2) # not use
    bfReserved2        = f.read(2) # not use
    bfOffBitsbfOffBits = int.from_bytes(f.read(4), "little")

    ### 情報ヘッダ ###
    bcSize         = int.from_bytes(f.read(4), "little")
    self.xsize     = int.from_bytes(f.read(4), "little")
    self.ysize     = int.from_bytes(f.read(4), "little")
    bcPlanes       = f.read(2) # not use
    bcBitCount     = int.from_bytes(f.read(2), "little")
    biCompression  = int.from_bytes(f.read(4), "little")
    biSizeImage    = f.read(4) # not use
    biXPixPerMeter = f.read(4) # not use
    biYPixPerMeter = f.read(4) # not use
    biClrUsed      = f.read(4) # not use
    biCirImportant = f.read(4) # not use
   
    ### 想定する画像フォーマットでない場合は、ここで処理を終了 ###
    if (bfType!="BM") or \
       (bcSize!=40)   or \
       (bcBitCount!=24) or \
       (biCompression!=0):
      print ("### This file format is not supported! ###")
      sys.exit()

    ### 画像データ本体へJump。ほどんど不要かも。###
    offset = bfOffBitsbfOffBits-54
    f.read(offset)

    self.R =  [[0 for y in range(self.ysize )] for x in range(self.xsize )]
    self.G =  [[0 for y in range(self.ysize )] for x in range(self.xsize )]
    self.B =  [[0 for y in range(self.ysize )] for x in range(self.xsize )]

    ### RGBデータ本体読み込み ###
    dummy_size=0
    mod = (self.xsize*3)%4
    if (mod!=0) : dummy_size = 4-mod
    for y in range(self.ysize):
      for x in range(self.xsize):
        self.R[x][y] = int.from_bytes(f.read(1), "little")
        self.G[x][y] = int.from_bytes(f.read(1), "little")
        self.B[x][y] = int.from_bytes(f.read(1), "little")
      f.read(dummy_size)

    f.close()

  ######################################################################## 
  def gain(self, gain=1.0):
    for y in range(self.ysize):
      for x in range(self.xsize):
       ### ゲイン処理と整数化 ###
       tmpR = int(self.R[x][y] * gain)
       tmpG = int(self.G[x][y] * gain)
       tmpB = int(self.B[x][y] * gain)
       ### クリップ ###
       self.R[x][y] = min(tmpR, 255)
       self.G[x][y] = min(tmpG, 255)
       self.B[x][y] = min(tmpB, 255)
  
  ########################################################################
  def SaveBMP(self,file):

    ### メソッドで使用する変数 ###   
    xsize = self.xsize
    ysize = self.ysize
    dummy_size=0
    mod = (self.xsize*3)%4
    if (mod!=0) : dummy_size = 4 - mod
    bfSize = (xsize*3+dummy_size)*ysize

    ### 出力ファイルオープン ###
    f = open(file,"wb")
    ### 出力ファイルヘッダ ###
    f.write(b"BM"                  )
    f.write(bfSize.to_bytes(4,"little"))
    f.write((2).to_bytes(2,"little"))
    f.write((2).to_bytes(2,"little"))
    f.write((54).to_bytes(4,"little"))
    f.write((40).to_bytes(4,"little"))
    f.write(xsize.to_bytes(4,"little"))
    f.write(ysize.to_bytes(4,"little"))
    f.write((1).to_bytes(2,"little"))
    f.write((24).to_bytes(2,"little"))
    for i in range(6):
      f.write((0).to_bytes(4,"little"))

    ### RGBデータ本体へ書き込み ###
    for y in range(ysize):
      for x in range(xsize):
        f.write(self.R[x][y].to_bytes(1,"little",signed=False))
        f.write(self.G[x][y].to_bytes(1,"little",signed=False))
        f.write(self.B[x][y].to_bytes(1,"little",signed=False))

      ### 画像の横ラインデータサイズを4の倍数にそろえる ###
      for i in range(dummy_size): 
        f.write((255).to_bytes(1,"little",signed=False))
      
    f.close()

    

本日の記事で紹介した2つのファイル “main.py”, “RGB.py” を同じディレクトリに置いて、手持ちのビットマップファイルを指定すれば、ゲイン処理をかける事が出来るかと思います。ゲイン値は、gain()メソッドへの引数を変える事で調整が可能です。引数を与えない場合は等倍(gain=1.0)となります。

この “RGB.py” の中身は先日のベタ書きのソース

をほとんど分割しただけなので、やっている事は理解しやすいかと思いますが、後日に別記事でRGBクラスのソースを詳細に説明したいと思います。本日の記事で仕上げようかなとも思いましたが、記事がスクロール地獄になりそうな予感がしたので止めておきます。

本日も最後まで読んで頂き、ありがとうございました。

タイトルとURLをコピーしました