LoginSignup
160
169

More than 5 years have passed since last update.

Pythonを用いた画像処理(openCV,skimage)

Last updated at Posted at 2018-12-20

はじめに

今年、独学でPythonと機械学習について勉強を始めました。
機械学習をする際に、学習させる画像をいろいろな方法で画像処理や特徴量の抽出を行ったので簡単にまとめたいとおもいます。

余談になりますが、私周辺の知り合いに
「何故Pythonを勉強してるのか?、JavaやC++を勉強しないのか?」
と聞かれることが多いです。
たしかにPythonは他の言語より実行が遅く、実行速度が重要視されるようなシステム開発には向いてないと思います。しかし、私みたいなプログラミング初心者から見ると、他の言語よりコードの書き方の統一感があって他人のソースコードを理解しやすい、パッケージ(モジュール)が豊富で情報工学などの知識が疎遠な私でも作りたいものを簡単に作ることができる利点があると思います。
なので、本記事はPythonを用いた画像処理についてまとめたいと思います。

OpenCV

OpenCVのインストール

OpenCV(Open Source Computer Vision Library)とは、画像や動画を処理するのに必要な様々な機能を提供するライブラリであり、画像の変換やフィルタ処理や、物体判定、物体認識、カメラの入出力などの機能が備わっています。
今回自分のPCでは、バージョン管理の環境構築のためにpyenvを導入して、OS Xでpythonを利用しています。
Windowsの場合はコマンドライン(Anaconda Prompt)から、pipコマンドを利用してOpenCVをインストールできます。

pip install opencv-python==3.4.2.16
[user@baya]# pip install opencv-python                                                                                                                                              [/Users/taka.baya]
Collecting opencv-python
  Downloading https://files.pythonhosted.org/packages/b3/0b/055f90609d6b22885ba178565a439563b00fe58b81a9acd3bbf46212190f/opencv_python-3.4.4.19-cp36-cp36m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl (48.7MB)
    100% |████████████████████████████████| 48.7MB 520kB/s
Requirement already satisfied: numpy>=1.11.3 in ./.pyenv/versions/3.6.0/lib/python3.6/site-packages (from opencv-python) (1.14.5)
Installing collected packages: opencv-python
Successfully installed opencv-python-3.4.4.19

次に拡張モジュール群である contrib を導入します。
商用利用が制限されているアルゴリズムが含まれているため、導入には注意が必要です(非自由/特許アルゴリズムが含まれているため)

pip install opencv-contrib-python==3.4.2.16
[user@baya]# pip install opencv-contrib-python==3.4.2.16                                                                                                                            [/Users/taka.baya]
Collecting opencv-contrib-python==3.4.2.16
  Using cached https://files.pythonhosted.org/packages/b8/26/9c631442c828ec88d4b0017ec39bb6ed655d81b3e99010ad1c841d104d54/opencv_contrib_python-3.4.2.16-cp36-cp36m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl
Requirement already satisfied: numpy>=1.11.3 in ./.pyenv/versions/3.6.0/lib/python3.6/site-packages (from opencv-contrib-python==3.4.2.16) (1.14.5)
Installing collected packages: opencv-contrib-python
Successfully installed opencv-contrib-python-3.4.2.16

OpenCVがインストールされているかどうかは、コマンドラインからPythonの対話型実行環境を実行して、OpenCVのライブラリcv2が利用できるかどうかで確認できます。

[user@baya]# python                                                                                                                                                                 [/Users/user]
Python 3.6.0 (default, Jun  3 2018, 12:06:09)
[GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>>

以下二つのモジュールも使う場面が多いのでインストールしとくといいと思います。

pip install numpy
pip install matplotlib

画像処理

lenaの画像をベースに何点か画像処理について紹介する
lena.jpg

画像を二値化(白黒画像)

import cv2

filename = "lena.jpg"
gry = cv2.imread(filename, 0)
cv2.imwrite('gray.jpg', gry)

imread(filename, flags)の第2引数を以下から選択することによって、任意の画像読み込み方法を選択することが可能です。

機能
-1 無変換
0 グレー
1 カラー
2 任意の深度
3 任意のカラー

gray.jpg

指定範囲の色のみ抽出

ソースコードにあるlower_colorとupper_colorを調節すれば任意の色を調節することが可能です。

import cv2
import numpy as np

filename = "lena.jpg"
img = cv2.imread(filename,1)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# 取得する色の範囲を指定する
lower_color = np.array([20, 50, 50])
upper_color = np.array([255, 255, 255])

# 指定した色に基づいたマスク画像の生成
img_mask = cv2.inRange(hsv, lower_color, upper_color)

# フレーム画像とマスク画像の共通の領域を抽出する。
img_color = cv2.bitwise_and(img, img, mask=img_mask)

cv2.imwrite("hsv.jpg", img_color)

hsv.jpg

画像のエッジ部分を抽出

import cv2
import numpy as np

filename = "lena.jpg"
# 白黒画像で画像を読み込み
img = cv2.imread(filename,0)
#エッジ検出
canny_img = cv2.Canny(img, 50, 110)

cv2.imwrite("canny.jpg", canny_img)

canny.jpg

画像をリサイズ

個人的に機械学習を行うにあたって、学習データ量を小さくするために画像のリサイズをかなりの頻度で行いました。

import cv2
import numpy as np

filename = "lena.jpg"
# 白黒画像で画像を読み込み
img = cv2.imread(filename,1)
# 画像の高さ幅を指定
width,height=60,60
# 画像をリサイズ
img = cv2.resize(img,(width,height))

cv2.imwrite("resize_lena.jpg", img)

resize_lena.jpg

画像のヒストグラムを可視化

ヒストグラムとはその画像がどのような濃度値(緑・赤・青)を持った画素から成り立っているかの情報をまとめたものです。
二値化(白黒画像化)することによって、濃度値(白黒)も得ることができます。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('lena.jpg')
color = ('b','g','r')
for i,col in enumerate(color):
    histr = cv2.calcHist([img],[i],None,[256],[0,256])
    plt.plot(histr,color = col)
    plt.xlim([0,256])
plt.show()

Figure_1.png

特徴点抽出

ORB特徴点抽出

import cv2
import numpy as np

filename = "lena.jpg"
# 白黒画像で画像を読み込み
img = cv2.imread(filename,1)

# ORB
detector = cv2.ORB_create()

# 特徴検出
keypoints = detector.detect(img)

# 画像への特徴点の書き込み
img_orb = cv2.drawKeypoints(img, keypoints, None)

cv2.imwrite("orb.jpg", img_orb)

orb.jpg

OpenCVでは、ORB以外のアルゴリズムでも特徴点を抽出することができます。
プログラムのdetector = (任意)を切り替えるだけでアルゴリズムを変更することができます。

アルゴリズム 書き方
ORB cv2.ORB_create()
FAST cv2.FastFeatureDetector_create()
AKAZE cv2.AKAZE_create()
BRISK cv2.BRISK_create()
KAZE cv2.KAZE_create()
SIFT cv2.ORB_create()
MSER cv2.MSER_create()
AgastFeatureDetector cv2.AgastFeatureDetector_create()

特徴点のマッチング

import cv2
import numpy as np

filename = "lena.jpg"
# 白黒画像で画像を読み込み
img = cv2.imread(filename,0)

# 画像サイズの取得(横, 縦)
size = tuple([img.shape[1], img.shape[0]])

# 画像の中心位置(x, y)
center = tuple([int(size[0]/2), int(size[1]/2)])

# 回転させたい角度(正の値は反時計回り)
angle = 180.0

# 拡大比率
scale = 1.0

# 回転変換行列の算出
rot_matrix = cv2.getRotationMatrix2D(center, angle, scale)

# アフィン変換
rot_img = cv2.warpAffine(img, rot_matrix, size, flags=cv2.INTER_CUBIC)

# ORB (Oriented FAST and Rotated BRIEF)
detector = cv2.ORB_create()

# 特徴検出
kp1, des1 = detector.detectAndCompute(img, None)
kp2, des2 = detector.detectAndCompute(rot_img, None)

# マッチング処理
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
matches = sorted(matches, key = lambda x:x.distance)

# マッチング上位20個の特徴点を線でリンクして画像に書き込む
match_img = cv2.drawMatches(img, kp1, rot_img, kp2, matches[:20], None, flags=2)

cv2.imwrite("matcher.jpg", match_img)

matcher.jpg

マッチング距離の計算

import cv2
import numpy as np

filename1 = "lena.jpg"
filename2 = "lena2.jpg"
# 白黒画像で画像を読み込み
img1 = cv2.imread(filename1,1)
img2 = cv2.imread(filename2,1)

# ORB (Oriented FAST and Rotated BRIEF)
detector = cv2.ORB_create()

# 特徴検出
kp1, des1 = detector.detectAndCompute(img1, None)
kp2, des2 = detector.detectAndCompute(img2, None)

# マッチング処理
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# 特徴記述子のマッチング
matches = bf.match(des1, des2)
# 距離でソートする
matches = sorted(matches, key = lambda x:x.distance)

distance = 0
for m in matches:
        #print(m.distance)
        distance = distance + m.distance

print("マッチング距離:",distance)

# マッチング上位20個の特徴点を線でリンクして画像に書き込む
match_img = cv2.drawMatches(img1, kp1, img2, kp2, matches[:20], None, flags=2)

cv2.imwrite("matcher.jpg", match_img)
マッチング距離: 13162.0

matcher.jpg

skimage

skimageとは画像処理に関するアルゴリズムを集めたライブラリです。
無料で扱うことができるみたいです。
OpenCVと同様にターミナルまたはコマンドラインからskimageをインストールすることができる。
skimageのサイトにてサンプルソースがゴロゴロ転がっているので、もっと知りたい人はそちらを見てください。

pip install -U scikit-image

画像処理

Region Adjacency Graph(RAG)

画像の色の違いの部分を切り分けたりします。ここで説明するとかなり長くなるので、気になる人は調べてみてください。

import matplotlib.pyplot as plt
import cv2
from skimage import data, segmentation, color
from skimage.future import graph

img = cv2.imread('lena.jpg',1)

labels1 = segmentation.slic(img, compactness=30, n_segments=400)
out1 = color.label2rgb(labels1, img, kind='avg')

g = graph.rag_mean_color(img, labels1, mode='similarity')
labels2 = graph.cut_normalized(labels1, g)
out2 = color.label2rgb(labels2, img, kind='avg')

fig, ax = plt.subplots(nrows=2, sharex=True, sharey=True, figsize=(6, 8))

ax[0].imshow(out1)
ax[1].imshow(out2)

plt.show()

cv2.waitKey(0)

スクリーンショット 2018-12-19 20.57.53.png

特徴量抽出

Dense DAISY特徴量の抽出

DAISYとは、画像の各画素における特徴量を記述する手法の一つです。DAISYを用いることで,カメラ間隔が長く撮影方向が大きく異なる多視点画像に対して比較的強い特徴量らしいです。

import matplotlib.pyplot as plt
import cv2
from skimage.feature import daisy
from skimage import data, exposure

img = cv2.imread('lena.jpg',0)

descs, descs_img = daisy(img, step=180, radius=58, rings=2, histograms=6,
                         orientations=8, visualize=True)

fig, ax = plt.subplots()
ax.axis('off')
ax.imshow(descs_img)
descs_num = descs.shape[0] * descs.shape[1]
ax.set_title('%i DAISY descriptors extracted:' % descs_num)
plt.show()

Figure_4.png

HoG特徴量の抽出と可視化

HOG(Histograms of Oriented Gradients)とは局所領域 (セル) の輝度の勾配方向をヒストグラム化したものです。
勾配情報をもとにしているので、異なるサイズの画像を比較対象としても同じサイズにリサイズすることで比較可能になります。
実行した際にコンソール画面にて警告が出た場合は以下記事を参考にして対処してください。
【備忘録】pythonのパッケージ 「hog」でWarningが出る

import matplotlib.pyplot as plt
import cv2
from skimage.feature import hog
from skimage import data, exposure

image = cv2.imread('lena.jpg')

fd, hog_image = hog(image, orientations=8, pixels_per_cell=(16, 16),
                    cells_per_block=(1, 1), visualize=True, multichannel=True)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4), sharex=True, sharey=True)

ax1.axis('off')
ax1.imshow(image, cmap=plt.cm.gray)
ax1.set_title('Input image')

hog_image_rescaled = exposure.rescale_intensity(hog_image, in_range=(0, 10))

ax2.axis('off')
ax2.imshow(hog_image_rescaled, cmap=plt.cm.gray)
ax2.set_title('Histogram of Oriented Gradients')
plt.show()

Figure_3.png

まとめ

特徴点・特徴量についてどのようなアルゴリズムや手法なのかを説明せずにサンプルソースと実行結果の画像をただ淡々とあげてしましました。
処理した画像を可視化するだけでも楽しいので、少しでも画像処理について興味持って頂けたらと思っています。
CTFのforensics問を解く際にも役に立ちます。

160
169
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
160
169