OpenCV
Open Source Computer Vision Library
Julia.iconでもできるのでもう一度なぞってみるあんも.icon
各環境での画像の表示のおまじない
Python
code:py
import cv2
img=cv2.imread("sample.jpg")
cv2.imshow("img",img)
cv2.waitKey(0) # キー入力を待つ
WSLだとREPLに戻ってこれない
通信がうまくいっていない?あんも.icon
なにか入れたらいい感じになったりしないかな?
code:GoogleColab.py
import cv2
from google.colab.patches import cv2_imshow
img = cv2.imread("sample.jpg")
cv2_imshow(img)
code:ipynb.py
import cv2
import matplotlib.pyplot as plt
img = cv2.imread("sample.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()
$ rye init opencv && cd opencv/
$ rye add numpy opencv-python matplotlib
$ rye sync
ブランク画像を⽣成する
code:blank.py
import numpy as np
import cv2
width = 200
height = 100
value = 128
## width=200、height=100、画素値0で埋めたグレースケール画像を⽣成
img0 = np.zeros((height,width),np.uint8)
## width=200、height=100、画素値128で埋めたグレースケール画像を⽣成
img128 = np.full((height,width),value,np.uint8)
## 画像を保存する
cv2.imwrite('img0.jpg',img0)
cv2.imwrite('img128.jpg',img128)
code:colorblank.py
import numpy as np
import cv2
width=200
height=100
channels = 3
## width=200、height=100、3チャンネルとも画素値0で埋めたカラー画像を⽣成
cimg_b = np.zeros((height,width,channels),np.uint8)
## width=200、height=100、画素値(B=0,G=0,R=255)で埋めたカラー画像を⽣成
cimg_r = np.full((height,width,channels),value,np.uint8)
## 画像を保存する
cv2.imwrite('cimg_b.jpg',cimg_b)
cv2.imwrite('cimg_r.jpg',cimg_r)
カラー画像を読み込む
code:color.py
import numpy as np
import cv2
## 画像ファイルをカラーで読み込み
img = cv2.imread('anm.png',cv2.IMREAD_COLOR)
y,x,channel = img.shape:3 ## 座標値(x,y)の画素値を参照(Blue、Green、Red)
## 座標値指定がy、xの順になっている点に注意
print(f'bgr_val({x},{y})={bgr_val}')
## 0番目のチャンネル(=Blue)の画素値を参照
## 座標値指定がy、xの順になっている点に注意
print(f'b_val({x},{y})={b_val}')
画像の表⽰と⼀部切り出し
code:cut.py
import cv2
sample_img = "anm.png"
## 画像ファイルをカラーで読み込み
img = cv2.imread(sample_img, cv2.IMREAD_COLOR)
## ROI{topbottom,left:right]を使って画像データを切り出す
## 画像を保存する
# cv2.imwrite('img.jpg',img)
cv2.imwrite('img_roi.jpg',img_roi)
2つの画像に対してピクセルごとに値を加減算
np.uint8の場合、255を越えた値は255に、0未満は0になる
加算: cv2.add()
減算: cv2.subtract()
重み付け加算: cv2.addWeighted()
差分の絶対値: cv2.absdiff()
AND演算: cv2.bitwise_and()
OR演算: cv2.bitwise_or()
マスクができる
code:cal.py
import numpy as np
import cv2
sample_img = "anm.png"
## 画像ファイルをカラーで読み込み
src1 = cv2.imread(sample_img, cv2.IMREAD_COLOR)
## マスク画像を⽣成する
height, width, channels = src1.shape:3 src2 = np.zeros((height, width, channels),np.uint8)
cv2.rectangle(src2,(120,550),(850,720),(255,255,255),thickness=-1)
musked_img = cv2.bitwise_and(src1, src2) # AND演算
## 画像を保存する
cv2.imwrite("musked_img.jpg", musked_img)
画像の統計値
画素値の最小値: cv2.max()
画素値の最大値: cv2.min()
cv2.minMaxLoc()
画素値の平均値: cv2.mean()
画素値の総和: cv2.sum()
非ゼロの画素数: cv2.countNonZero()
グレースケール画像(1チャンネル)の画像を想定している
画像の分割
チャンネルで分割する
輪郭を取り出しやすくするのに利用できる
code:split.py
import cv2
sample_img = "anm.png"
## 画像ファイルをカラーで読み込み
img = cv2.imread(sample_img, cv2.IMREAD_COLOR)
## ブレーンの抽出
b_plane, g_plane, r_plane = cv2.split(img)
cv2.imwrite("b_plane.jpg", b_plane)
cv2.imwrite("g_plane.jpg", g_plane)
cv2.imwrite("r_plane.jpg", r_plane)
画像の結合
3チャンネルに分けたものを合成してもとの画像にする
code:mage.py
import cv2
b_plane=cv2.imread('b_plane.jpg',cv2.IMREAD_GRAYSCALE)
g_plane=cv2.imread('g_plane.jpg',cv2.IMREAD_GRAYSCALE)
r_plane=cv2.imread('r_plane.jpg',cv2.IMREAD_GRAYSCALE)
merged = cv2.merge((b_plane, g_plane, r_plane))
cv2.imwrite('merged.jpg',merged)
⾊空間の変換
code:cnvert.py
import cv2
sample_img = "anm.png"
img_bgr = cv2.imread(sample_img)
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
cv2.imwrite("BGR.jpg", img_bgr)
cv2.imwrite("GRAY.jpg", img_gray)
HSVのH値で青色をマスクする
PythonのREPLではインデントの下に改行がないとシンタックスエラーになる
Pythonを書かないので知らないあんも.icon
code:hsv.py
import cv2
import matplotlib.pyplot as plt
sample_img = "anm.png"
img_bgr = cv2.imread(sample_img)
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(img_hsv)
bmask = cv2.inRange(h, 90, 140)
bmasked_img = cv2.bitwise_and(img_bgr, img_bgr, mask=bmask) # マスクを適用
plt.figure(figsize=(12, 6))
for i in range(images.__len__()):
plt.subplot(2, 3, i+1)
plt.imshow(imagesi, cmap='gray') plt.axis('off')
plt.tight_layout() # レイアウトの調整
plt.show()
plt.savefig("plot.png")
閾値処理
2値化
0と1や0と255の2つの値のみをとるデータに変換する
ブロックサイズとパラメータで挙動を確認する
np.where(condition, x, y)で条件に合うものをx合わないものをyに置換したndarrayを返す
code:gaussian_blur_thresh.py
import cv2
import numpy as np
def gaussian_blur_threshold(sample_img, block_size=15, c=25):
img = cv2.cvtColor(cv2.imread(sample_img), cv2.COLOR_BGR2GRAY)
blur_img = cv2.GaussianBlur(img, (block_size, block_size), 0)
diff_img = blur_img - img
result_img = np.where(blur_img - c > img, 0, 255)
# 画像を保存
cv2.imwrite(f"gb_original.jpg", img)
cv2.imwrite(f"gb_blur_{block_size}_{c}.jpg", blur_img)
cv2.imwrite(f"gb_diff_{block_size}_{c}.jpg", diff_img)
cv2.imwrite(f"gb_result_{block_size}_{c}.jpg", result_img.astype(np.uint8))
sample_img = "anm.png"
gaussian_blur_threshold(sample_img)
輪郭を抽出して個数を数える
写っている魚の数を数えるタスクを考える
輪郭を抽出しやすいように古典的な前処理をする
平滑化
フィルタリング
色空間の変換
色と輝度を分離して、照明条件に対して堅牢になる
場所によって閾値を変える
cv2.adaptiveThreshold()
形状分析
code:fish.py
import cv2
import numpy as np
img_bgr = cv2.imread("fish.jpg")
img_bgr = cv2.resize(img_bgr, (500, 400))
## ガウシアンブラーによる輪郭強調関数
def gaussian_blur_threshold(img_gray, block_size=15, c=25):
blur_img = cv2.GaussianBlur(img_gray, (block_size, block_size), 0)
diff_img = blur_img - img_gray
result_img = np.where(blur_img - c > img_gray, 0, 255)
return result_img.astype(np.uint8)
## 画像の前処理
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY) # グレースケールに変換
# ベーシックな処理
#ret, img_bin = cv2.threshold(img_gray, 140, 255, cv2.THRESH_BINARY) # グレースケール画像を二値化 # ガウシアンブラーによる処理
img_bin = gaussian_blur_threshold(img_gray, block_size=75, c=30)
contours, hierarchy = cv2.findContours(img_bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 輪郭を検出する
contours = list(filter(lambda x: cv2.contourArea(x) > 800, contours)) # 面積の大きさでフィルタリング
result_img = cv2.drawContours(img_bgr.copy(), contours, -1, (0, 255, 0), 5) # 輪郭を描画する
for c in contours: # 輪郭を囲む矩形を描画する
x, y, w, h = cv2.boundingRect(c)
result_img = cv2.rectangle(result_img, (x, y), (x + w, y + h), (255, 0, 0), 4)
# 画像を保存
cv2.imwrite("result.jpg", result_img)
射影変換
code:py
import cv2
import numpy as np
#from matplotlib import pyplot as plt img = cv2.imread("load.jpg") # 750*460pix
top_left, top_right = (360, 220), (385, 220)
bottom_left, bottom_right = (0, 360), (750, 360)
M = cv2.getPerspectiveTransform(src_pts,dst_pts)
dst_img = cv2.warpPerspective(img, M, (500,500))
cv2.drawMarker(img, top_left, (0,0,255),cv2.MARKER_TILTED_CROSS,markerSize=50,thickness=10)
cv2.drawMarker(img, top_right, (0,0,255),cv2.MARKER_TILTED_CROSS,markerSize=50,thickness=10)
cv2.drawMarker(img, bottom_left, (0,0,255),cv2.MARKER_TILTED_CROSS,markerSize=50,thickness=10)
cv2.drawMarker(img, bottom_right, (0,0,255),cv2.MARKER_TILTED_CROSS,markerSize=50,thickness=10)
cv2.imwrite("load_p.jpg", cv2.cvtColor(dst_img,cv2.COLOR_BGR2RGB))