PythonでOpenCVを使うには
import cv2
import numpy as np
PythonとOpenCVのインストールの方法はこちらです。インストールが終わったなら早速始めてみましょう。OpenCVを使うために、OpenCVのモジュールをインポートします。”import opencv”ではないので注意してください。関数を使うときもcv2.resize()というようにして使います。numpyも画像を行列として保持するために必要なので一緒にインポートしておきます。as npとすることで、np.array()というように短く書くことができるようになります。
画像とは何か
OpenCVで読み込んだ画像はNumPyの配列として保持されます。縦N×横Mピクセルの画像で、グレースケールの画像であれば(すなわち1チャンネルの画像であれば)、N×Mの行列として保持され、カラー画像であれば、BGRの3チャンネルなのでN×M×3の行列として保持されます。下は、縦横200*300の画像をimgという行列として読み込み、その行列の形状をimg.shapeとすることで取得し、表示するコードです。
画像を扱う上で重要なのが、左上端が原点(0,0)となることです。右に行くに従ってx座標が増えていくのは普通に感じると思いますが、下に行くに従ってy座標が増えていくのには違和感を覚えるかもしれません。しかし、これは画像処理ライブラリ全般によく見られる仕様です。
import cv2
import numpy as np
img = cv2.imread("/Users/ym/Desktop/sample.png", cv2.IMREAD_COLOR)
print(img.shape)
(200, 300, 3)
img.shapeで取得できる形状は(縦、横、チャンネル数)の順となることに注意してください。画素にアクセスするときにも、img[x,y]ではなく、img[y,x]となります。
画像を読み込む
import cv2
import numpy as np
img = cv2.imread("/Users/ym/Desktop/sample.png", cv2.IMREAD_COLOR)
print("IMREAD_COLOR:", img.shape)
img = cv2.imread("/Users/ym/Desktop/sample.png", cv2.IMREAD_GRAYSCALE)
print("IMREAD_GRAYSCALE:", img.shape)
IMREAD_COLOR: (200, 300, 3) IMREAD_GRAYSCALE: (200, 300)
すでに出てきていますが、cv2.imread関数を使います。画像とは何か、のセクションではIMREAD_COLORという定数を指定していましたが、IMREAD_GRAYSCALEを指定すると、グレースケールで読み込めます。このとき、画像を格納する行列の形状を出力すると、(縦、横)となり、チャンネル数に相当する軸は表示されません。
画像を表示する
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("/Users/ym/Desktop/sample.png", cv2.IMREAD_COLOR)
plt.imshow(img)
plt.show()
まず、matplotlib.pyplotをpltとして読み込んでいます。imgに画像を読み込んだ後に、plt.imshow() plt.show()とすることで、画像を表示できます。しかし、青い画像を読み込んだはずなのに、赤い画像が表示されています。これは、OpenCVがBGRの順で画像を読み込むのに対し、matplotlibはRGBの順で画像を解釈しようとするためです。これを解決すつためにはcv2.cvtColor関数を使います。img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)によってBGRからRGBに変換します。2はto(〜へ)の意味です。
import cv2
import numpy as np
import matplotlib.pyplot as plt
imgBGR = cv2.imread("/Users/ym/Desktop/sample.png", cv2.IMREAD_COLOR)
imgRGB = cv2.cvtColor(imgBGR, cv2.COLOR_BGR2RGB)
plt.imshow(imgRGB)
plt.show()
画像を保存する
import cv2
import numpy as np
img = cv2.imread("/Users/ym/Desktop/sample.png", cv2.IMREAD_COLOR)
cv2.imwrite("/Users/ym/Desktop/output.png", img)
cv2,imwrite関数で保存します。引数には保存するファイル名のパスと、保存したい画像が格納されているnumpy配列を指定します。画像の拡張子に使えるのは以下の通りです。
- Windows bitmaps –
*.bmp, *.dib
(always supported) - JPEG files –
*.jpeg, *.jpg, *.jpe
- JPEG 2000 files –
*.jp2
- Portable Network Graphics –
*.png
- Portable image format –
*.pbm, *.pgm, *.ppm
(always supported) - Sun rasters –
*.sr, *.ras
(always supported) - TIFF files –
*.tiff, *.tif
これらの拡張子をつける限り、自動的にその形式で保存されます。ちなみに、imread関数で読み込めるのもこれらの形式です。
画像をグレースケール化する
これ以降は次の画像を用いることにします。
グレースケール化する前に、まずmatplotlibでBGRをRGBにしてから表示します。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("/Users/ym/Desktop/green.jpg", cv2.IMREAD_COLOR)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()
次にグレースケールにしてから表示してみます。または、はじめからIMREAD_GRAYSCALEを指定することによってグレースケールで読み込みます。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("/Users/ym/Desktop/green.jpg", cv2.IMREAD_COLOR)
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(img)
plt.show()
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("/Users/ym/Desktop/green.jpg", cv2.IMREAD_GRAYSCALE)
plt.imshow(img)
plt.show()
予想していた灰色の画像とは違っていたかもしれません。実はmatplotlibはグレースケール画像は自動的に疑似カラーで表示します。ひとまず、カラーバーを表示してみましょう。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("/Users/ym/Desktop/green.jpg", cv2.IMREAD_GRAYSCALE)
plt.imshow(img)
plt.colorbar()
plt.show()
次に、疑似カラーではないグレースケール画像そのものを出力したいとします。そのときにはimshowのオプションとしてcmap=”gray”を指定します。cmapはカラーマップの意味です。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("/Users/ym/Desktop/green.jpg", cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap="gray")
plt.colorbar()
plt.show()
カラーマップ
グレーの画像が表示できました。ちなみに、私がよく使うカラーマップは “gray” “jet” “hsv” です。jetもhsvも、きれいなグラデーションですが、hsvは最大値と最小値が同じ赤色となります。したがって、角度など最大値と最小値が同じ意味を持つ場合にhsvを使っています(0度と360度は同じ意味を持つということです)。
画像をリサイズする
cv2.resize関数でリサイズを行います。注意が必要なのはresize関数の中で指定する各軸の長さの順序が(x,y)の順になっていることです。shapeで取得される順とは異なるので注意が必要です。横100 縦200にリサイズする場合には次のようにします。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("/Users/ym/Desktop/green.jpg", cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img, (100,200))
cv2.imwrite("/User/ym/Desktop/resized.png", img)
縦横半分にリサイズする場合には次のようにします。resize関数の中で指定する各軸の長さの順序とshapeで取得される順が異なるので注意が必要です。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("/Users/ym/Desktop/green.jpg", cv2.IMREAD_COLOR)
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# img.shape => (300,200)
w = img.shape[1]
h = img.shape[0]
img = cv2.resize(img, (w//2,h//2))
plt.imshow(img, cmap="jet")
plt.colorbar()
plt.show()
動画の処理
cv2.VideoCaptureで動画ファイルを再生できます。動画ファイルはパラパラ漫画のようなもので、単なる静止画像が連続して格納されただけのものです。cv2.VideoCaptureは動画ファイルから静止画像を1枚ずつ取り出してくれます。cap.read()とすることで、次のフレームを読み込みます。
import cv2
import numpy as np
# 動画ファイルの指定
cap = cv2.VideoCapture("video.mp4")
# 動画終了まで繰り返し
while(cap.isOpened()):
# フレームの取得
ret, frame = cap.read()
# 表示
cv2.imshow("image", frame)
# qが押されたら終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()