OpenCV-Python Tutorials (1) ~Core Operations~ 前半
OpenCV-Python Tutorialsをやっているのでメモしながら進めていこうと思います.
3つ目の章Core Operationsから始めます.
公式: Core Operations — OpenCV-Python Tutorials 1 documentation
Core Operations
基本的な操作
目標
- ピクセル値の利用,修正
- 画像の属性の利用
- 画像の一部の操作
- 画像の切り取り,合成
ピクセル値の利用と修正
最初にカラー画像を読み込む.
In [1]: import cv2 In [2]: import numpy as np In [3]: img = cv2.imread('messi5.jpg')
これで,行,列の値の組み合わせからピクセル値を取得できる. BGRの画像に対しては,Blue, Green, Red の値の Array を返す.グレースケールの画像に対しては,対応するものを返す.
In [4]: px = img[100,100] In [5]: print(px) [157 166 200] # blue のピクセルだけを取得 In [6]: blue = img[100, 100, 0] In [7]: print(blue) 157
同様のやり方でピクセル値を修正できる.
In [8]: img[100,100] = [255,255,255] In [9]: print(img[100,100]) [255 255 255]
より良いやり方は:
# RED の値を取得 In [10]: img.item(10,10,2) # RED の値を修正 In [11]: img.itemset((10,10,2),100) In [12]: img.item(10,10,2) Out[12]: 100
画像の属性の利用
画像の属性は行,列,チャンネルの数,画像データの型,ピクセルの数を含んでいる.
画像の形は img.shape
で利用できる.(カラー画像の場合は)行,列,チャンネルの数の Array を返す:
In [13]: print(img.shape) (2448, 3264, 3)
画像全体のピクセル数は img.size
で利用できる:
In [14]: print(img.size) 23970816
画像データの型は img.dtype
に含まれている:
In [15]: print(img.dtype) uint8
画像の一部の操作
Numpyのindexを利用することで画像の一部を操作できる.
In [16]: ball = img[280:340, 330:390] In [17]: img[273:333, 100:160] = ball
画像の切り取り,合成
画像の B,G,R のチャンネルはそれぞれの独立した面に分けることができる. そして,独立したチャンネルを合わせて戻すことで BGR 画像に戻すことができる.
In [18]: b,g,r = cv2.split(img) In [19]: img = cv2.merge((b,g,r))
または
In [21]: img[:,:,2] = 0
画像の境界を作る(パディング)
画像の周りの境界を作りたい場合は, cv2.copyMakeBorder()
を使うことができる.これは次のような引数を持つ:
- src - 入力画像
- top, bottom, left, right - 境界の幅
- borderType - 以下のFlagでどの種類の境界が足されるかを定義する
- cv2.BORDER_CONSTANT
- cv2.BORDER_REFLECT
- cv2.BORDER_REFLECT_101 or cv2.BORDER_DEFAULT
- cv2.BORDER_REPLICATE
- cv2.BORDER_WRAP
- value -
cv2.BORDER_CONSTANT
の場合の境界線の色
デモ用のサンプルコードは以下:
In [1]: import cv2 In [2]: import numpy as np In [3]: from matplotlib import pyplot as plt In [4]: BLUE = [255,0,0] In [5]: img1 = cv2.imread('opencv_logo.png') In [6]: replicate = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REPLICATE) In [7]: reflect = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT) In [8]: reflect = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT_101) In [9]: reflect = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT) In [10]: reflect101 = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT_101) In [11]: wrap = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_WRAP) In [12]: constant = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_CONSTANT,value=BLUE) In [13]: plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL') Out[13]: (<matplotlib.axes._subplots.AxesSubplot at 0x107ebf780>, <matplotlib.image.AxesImage at 0x11316b278>, <matplotlib.text.Text at 0x113132c50>) In [14]: plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE') Out[14]: (<matplotlib.axes._subplots.AxesSubplot at 0x113180898>, <matplotlib.image.AxesImage at 0x108830550>, <matplotlib.text.Text at 0x11316ba20>) In [15]: plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT') Out[15]: (<matplotlib.axes._subplots.AxesSubplot at 0x108830be0>, <matplotlib.image.AxesImage at 0x108882278>, <matplotlib.text.Text at 0x10885e978>) In [16]: plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101') Out[16]: (<matplotlib.axes._subplots.AxesSubplot at 0x108882898>, <matplotlib.image.AxesImage at 0x1088b6f28>, <matplotlib.text.Text at 0x108895898>) In [17]: plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP') Out[17]: (<matplotlib.axes._subplots.AxesSubplot at 0x1088bf5f8>, <matplotlib.image.AxesImage at 0x10898e160>, <matplotlib.text.Text at 0x1088e7860>) In [18]: plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT') Out[18]: (<matplotlib.axes._subplots.AxesSubplot at 0x10898e780>, <matplotlib.image.AxesImage at 0x1088d44a8>, <matplotlib.text.Text at 0x1089b4470>) In [19]: plt.show()
画像への算術的操作
目標
- 足し算,引き算,ビット演算などといった算術的操作を学ぶ
cv2.add()
,cv2.addWeighted()
といったものを学ぶ
画像の足し算
cv2.add()
という OpenCV の機能,または numpy の操作 res = img1 + img2
によって2つの画像を足すことができる.
In [1]: import cv2 In [2]: import numpy as np In [3]: x = np.uint8([250]) In [4]: y = np.uint8([10]) In [5]: print(cv2.add(x,y)) # 250+10 = 260 => 255 [[255]] In [6]: print(x+y) # 250+10 = 260 % 256 = 4 [4]
画像の組み合わせ
これも画像の足し算だが,組み合わせの比重を与えることができる.次式のように画像が加えられる.
の値をと変化させることで,ある画像がら次の画像への移り変わりを表現出来る.
次に示すものが2つの画像を組み合わせだ.1つ目の画像の比率を0.3,2つ目を0.7として,次式にcv2.addWeighted()
を当てはめる.
ここではの値は0をとっている.
In [1]: import cv2 In [2]: img1 = cv2.imread('ml.jpg') In [3]: img2 = cv2.imread('lego.jpg') In [4]: dst = cv2.addWeighted(img1,0.7,img2,0.3,0) In [5]: cv2.imwrite('blending.jpg',dst)
結果はこんな感じに.
ビット演算
これらはビットごとの AND,OR,NOT,XOR 演算を含んでいる.これらは画像の一部を切り出す時や長方形でない領域を定義したり扱ったりする時にとても便利だ.これから画像の特定の領域をどうやって変えるのかの例を見ていこう.
In [1]: import cv2 In [2]: img1 = cv2.imread('messi.jpg') In [3]: img2 = cv2.imread('logo.png') In [4]: rows, cols, channels = img2.shape In [5]: roi = img1[0:rows, 0:cols] In [6]: img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) In [7]: ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY) In [8]: mask_inv = cv2.bitwise_not(mask) In [9]: img1_bg = cv2.bitwise_and(roi, roi, mask = mask_inv) In [10]: img2_fg = cv2.bitwise_and(img2, img2, mask = mask) In [11]: dst = cv2.add(img1_bg, img2_fg) In [12]: img1[0:rows, 0:cols] = dst In [13]: cv2.imwrite('rslt.png', img1) Out[13]: True In [14]: # ついでにどうなってるかテスト In [15]: cv2.imwrite('c', mask_inv) Out[15]: True In [16]: cv2.imwrite('img1_bg.png', img1_bg) Out[16]: True In [17]: cv2.imwrite('img2_fg.png', img2_fg) Out[17]: True
結果は次のように.
rslt.png
mask_inv.png | img1_bg.png | img2_fg.png |
---|---|---|
追加資料
練習
cv2.addWeighted
を使って,フォルダにある画像が滑らかに移り変わるスライドショーを作ってみよう.