前処理① 画像に対する前処理(リサイズ/色補正など)
やりたいこと
画像に対して下記のような前処理を実施する
リサイズ
反転
トリミング/パディング
グレースケール変換/2値化/ノイズ除去
色補正
opencvではpandasのようなチートシートがあれば参考としたかったが、見つからなかったので下記のようにまとめてみた。 (ひとまず画像読み込みなどの基本機能から前処理まで。エッジ検出による特徴抽出、物体検出などは別途取り扱う)
実装
上記機能を1つのクラスにまとめて取り扱えるように実装した。
クラスのインスタンス生成時にファイルから画像を self.imgに取り込み、他関数呼び出しで変換後の画像を出力する仕組みとしている。
リサイズ処理
OpenCV機能を使い、サイズ直接入力・比率の両方で指定できるように実装
def resize_img_aspect_ratio(self,ratio=1.0): ''' 画像を拡大縮小する (比率指定) ''' if self.img is None: return None else: result = cv2.resize(self.img , (int(self.img.shape[0]*ratio), int(self.img.shape[1]* ratio))) return result def resize_img_pix_size(self,height = 200, width = 150): ''' 画像を拡大縮小する (ピクセルサイズ指定) ''' if self.img is None: return None else: result = cv2.resize(self.img , (int(width), int(height))) return result
反転処理
横・縦・両方の軸をパラメータ指定して反転できるように実装した。
def flip_img(self,mode="x"): ''' 画像を反転させる x: 横方向反転、y:縦方向反転 xy:両方向反転 ''' if self.img is None: return None else: if mode == "x": #X軸方向反転 result = cv2.flip(self.img,1) elif mode == "y": #Y軸方向反転 result = cv2.flip(self.img,0) elif mode == "xy": #両方向反転 result = cv2.flip(self.img,-1) else: result = self.img return result
トリミング
比率ベースのトリミング/座標直接指定のトリミングの両方ができるように実装した。
def trim_img_aspect_ratio(self,left=0.10, right = 0.10, up=0.10, down = 0.10): ''' 画像をトリミングする (左右上下それぞれでカットする部分の比率を0-1.0の間で指定) ''' if self.img is None: return None else: left = max(min(0.5,left),0.0) right = max(min(0.5,right),0.0) up = max(min(0.5,up),0.0) down = max(min(0.5,down),0.0) left_edge = int(self.img.shape[0]*left) right_edge = int(self.img.shape[0] - self.img.shape[0]*right) up_edge = int(self.img.shape[1]*up) down_edge = int(self.img.shape[1] - self.img.shape[1]*down) result = self.img[up_edge:down_edge,left_edge:right_edge] return result def trim_img_pix_size(self,left_edge = 0, right_edge = 0, up_edge = 0, down_edge = 0): ''' 画像をトリミングする (ピクセル指定。画像サイズ以上の場合は無視) left_edge,right_edge,up_edge,down_edge ''' if self.img is None: return None else: left = max(min(self.img.shape[0],left_edge),0.0) right = max(min(self.img.shape[0],right_edge),0.0) up = max(min(self.img.shape[1],up_edge),0.0) down = max(min(self.img.shape[1],down_edge),0.0) result = self.img[up:down,left:right] return result
パディング
指定幅だけ上下左右同じ幅ゼロ埋めする関数とした。 (その他反転するパディングなども可能。opencv公式リファレンスを参照のこと)
def zero_padding_img(self,pad_width = 10): ''' 画像の境界領域をゼロ埋めする pad_width:パディング幅サイズ ''' if self.img is None: return None else: PAD_COL = [0,0,0] #ゼロパディング result= cv2.copyMakeBorder(self.img,pad_width,pad_width,pad_width,pad_width,cv2.BORDER_CONSTANT,value=PAD_COL) return result
グレースケール・2値化処理
入力画像をグレースケース変換し、2値化アルゴリズムで0 or 255の2値に変換する処理を作成した。 2値化アルゴリズムはパラメータ切り替えで変更できる (デフォルトは大津の二値化)
def get_gray_img(self,color_im= "None"): ''' グレースケール画像を取得する (color_im:カラー画像データ(option)) ''' if color_im is "None": if self.img is None: return None else: return cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY) else: return cv2.cvtColor(color_im, cv2.COLOR_BGR2GRAY) def get_binary_img(self,prm="OTSU"): ''' 2値化処理 prm: "OTSU":大津の2値化、"BIN":静的な2値化、"ADAPT":ローカル閾値 ''' if self.img is None: return None gray_img = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY) if prm == "OTSU": _, result = cv2.threshold(gray_img, 0, 255, cv2.THRESH_OTSU) elif prm == "BIN": _, result = cv2.threshold(gray_img, 128, 255, cv2.THRESH_BINARY) elif prm == "ADAPT": result = cv2.adaptiveThreshold(gray_img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 55, 20) else: result = self.img return result
モルフォジー変換によるノイズ除去
2値データに対して膨張・収縮・オープニング・クロージング (膨張と収縮を組み合わせる)ことでノイズを消去する手法を実装した。
(手書き文字認識などのスキャンデータ、ROSの障害物地図データなどの処理などに利用できる)
パラメータは公式のままなので画像サイズや特性に応じて設定が必要
def get_morphology_img(self,prm="Ero",binimg="None"): ''' モルフォロジー変換 prm: "Ero":収縮、"Dil":膨張、"Ope":オープニング(膨張+縮小) "Clo":"クロージング(縮小+膨張)" ''' if binimg is "None": if self.img is None: return None gray_img = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY) _, bin_img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_OTSU) else: bin_img = binimg kernel = np.ones((3,3),np.uint8) if prm == "Ero": result = cv2.erode(bin_img, kernel,iterations = 2) elif prm == "Dil": result = cv2.dilate(bin_img, kernel,iterations = 2) elif prm == "Ope": result = cv2.morphologyEx(bin_img, cv2.MORPH_OPEN, kernel) elif prm == "Clo": result = cv2.morphologyEx(bin_img, cv2.MORPH_CLOSE, kernel) else: result = self.img return result
色補正フィルタ
画像の色を補正するためガンマ補正(色濃淡・明るさ)、ガウシアンフィルタ(ジャギー低減)、鮮鋭化フィルタ(エッジ強調)を実装した。
あくまで一般的な例なので、パラメータや他フィルタについても必要に応じて実装する必要がある。
def get_gamma_img(self,gamma=1.0): ''' ガンマ補正変換 (濃淡の補正) gamma: 1.0がデフォルト 小さくするほど薄く白っぽく、高くするほど濃く黒っぽい画像になる ''' if self.img is None: return None LTB = np.empty((1,256), np.uint8) for i in range(256): LTB[0,i] = np.clip(pow( float(i) / 255.0, gamma) * 255.0, 0, 255) #Look Up Tableの生成 result = cv2.LUT(self.img, LTB) #輝度値のガンマ補正 return result def get_gausian_filter_img(self,filtsize=5): ''' ガウシアンフィルタ画像:ぼかしフィルタ (ジャギーなどの低減に有効) filtsize:フィルタサイズ(整数型かつ奇数) ''' if self.img is None: return None # Look up tableを使って画像の輝度値を変更 result = cv2.GaussianBlur(self.img,(filtsize,filtsize),0) return result def get_sharp_filter_img(self): ''' 鮮鋭化フィルタ画像:ボケた画像のエッジ・テクスチャ協調に有効 ''' if self.img is None: return None kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]], np.float32) result = cv2.filter2D(self.img, -1, kernel) return result
ソースコードは下記で公開している。