[OpenCV4.5.0] 画像をランダムフォレストで学習して判定したい3 ~ 判定

学習データを coffee.pkl に保存します。

clf = RandomForestClassifier()
clf.fit(x_train, y_train)

joblib.dump(clf, 'coffee.pkl')

学習データの画像とは別に判定したいターゲット画像を用意します。

fire_11.jpg

black_11.jpg

georgia_11.jpg

学習データを作ったように同じようリサイズ、リシェイプして判定(predict)します。

import cv2
import joblib

def predict_coffee(filename):
	clf = joblib.load("coffee.pkl")

	path = "img/target/"
	img = cv2.imread(path + filename)
	img = cv2.resize(img, (48, 64))
	img = img.reshape((-1, 9216))
	res = clf.predict(img)

	if res[0] == 0:
		print(filename + " = BLACK無糖")
	elif res[0] == 1:
		print(filename + " = FIRE微糖")
	else:
		print(filename + " = Georgia blend")
	

predict_coffee("black_11.jpg")
predict_coffee("fire_11.jpg")
predict_coffee("georgia_11.jpg")

$ python3 app.py
black_11.jpg = BLACK無糖
fire_11.jpg = FIRE微糖
georgia_11.jpg = Georgia blend

やば。。。。
blackに関しては、”Black”の文字ないのに判定できちゃうんだ。。。

ちょっと人生頑張ってみるわ。。

[OpenCV4.5.0] 画像をランダムフォレストで学習して判定したい2 ~学習

画像を用意済み。

画像サイズは864x1152pxなので、(48, 64)にします。
データラベルは、FIRE微糖=0、Georgia blend=1、BLACK無糖=2 とします。
リサイズして、一次元に展開して配列に入れる。

import cv2
import os, glob
import joblib

from sklearn.model_selection import train_test_split
from sklearn import datasets, metrics
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score


image_size = (48, 64) # 864:1152(3:4)の画像の為
path_black = "img/black"
path_fire = "img/fire"
path_georgia = "img/georgia"

x = [] # 画像
y = [] # ラベル

def read_dir(path, label):
	files = glob.glob(path + "/*.jpg")
	for f in files:
		img = cv2.imread(f)
		img = cv2.resize(img, image_size)
		img_data = img.reshape(-1, )
		x.append(img_data)
		y.append(label)

read_dir(path_black, 0)
read_dir(path_fire, 1)
read_dir(path_georgia, 2)

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)

clf = RandomForestClassifier()
clf.fit(x_train, y_train)

y_pred = clf.predict(x_test)
print(accuracy_score(y_test, y_pred))

6回テストしてaccuracy_scoreはこんな感じ。平均して91%くらい。
$ python3 app.py
0.8333333333333334
$ python3 app.py
1.0
$ python3 app.py
1.0
$ python3 app.py
1.0
$ python3 app.py
0.6666666666666666
$ python3 app.py
1.0

91%の精度ってどうなんだろう。画像を取る角度を一定にすれば、もっと精度は上がりそうな気がする。

[OpenCV4.5.0] 画像をランダムフォレストで学習して判定したい1 ~写真の用意

まず画像の用意から。
缶コーヒーで(1)FIRE微糖、(2)Georgia blend、(3)BLACK無糖を用意する。

続いて、各缶コーヒーの写真を取る。取り敢えず、10枚ずつ位。
(1)FIRE微糖

(2)Georgia blend

(3)BLACK無糖

どの写真がどの缶コーヒーかラベリングをしたいので、画像の名前を変更する。
fireは fire_${i}.jpg、 Georgia blendは georgia_${i}.jpg、BLACK無糖は black_${i}.jpgにする。

centos8
imgフォルダの中にblack, fire, georgiaフォルダを作成し、その中にそれぞれの画像を入れる。

続いて、これらの画像を学習していきます。

[OpenCV4.5.0] 画像の差分を抽出

2つ画像を用意します。
※プロントで作業しています。ワイヤレスマウスUBS

import cv2
import numpy as np

img_last = cv2.imread(“a.jpg”)
img_last = cv2.cvtColor(img_last, cv2.COLOR_BGR2GRAY) # 白黒化
img_last = cv2.GaussianBlur(img_last, (9, 9), 0) # ぼかし
img_last = cv2.threshold(img_last, 100, 255, cv2.THRESH_BINARY)[1] # 画像の二値化

img = cv2.imread(“b.jpg”)
img_current = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_current = cv2.GaussianBlur(img_current, (9, 9), 0)
img_current = cv2.threshold(img_current, 100, 255, cv2.THRESH_BINARY)[1]

img_diff = cv2.absdiff(img_last, img_current)
cnts = cv2.findContours(img_diff, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]

for pt in cnts:
x, y, w, h = cv2.boundingRect(pt)
if w < 30: continue cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2) cv2.imwrite("result.png", img) [/python]

OK, Let’s Gooooooooooooooooooooo

[OpenCV4.5.0]NumPyを使って赤色のみ抽出

import cv2
import numpy as np

img = cv2.imread("rose.jpg")

img[:, :, 0] = 0
img[:, :, 1] = 0

cv2.imwrite("result.png", img)

before

after

### HSVで赤っぽい部分の輪郭を表示

import cv2
import numpy as np

img = cv2.imread("rose.jpg")

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV_FULL)
h = hsv[:, :, 0]
s = hsv[:, :, 1]
v = hsv[:, :, 2]

img2 = np.zeros(h.shape, dtype=np.uint8)
img2[(h > 200)  & (s > 100)] = 255

cv2.imwrite("result.png", img2)

ほう

OpenCV+vagrantでmac内蔵カメラが効かない?

ブラウザ上でカメラを起動するのであれば、httpsサーバに変更してChromeでカメラを許可にすれば良いんだが… openCVでカメラ画像の読み込もうとしてエラーになった。。。

import cv2
import numpy as np

cap = cv2.VideoCapture(-1)
while True:

	_, frame = cap.read()
	frame = cv2.resize(frame, (500, 300))

	cv2.imshow('OpenCV web camera', frame)

	k = cv2.waitKey(1)
	if k == 27 or k == 13: break

cap.release()
cv2.destroyAllWindows()

$ python3 app.py
[ WARN:0] global /root/opencv_build/opencv/modules/videoio/src/cap_v4l.cpp (880) open VIDEOIO(V4L2): can’t find camera device
Traceback (most recent call last):
File “app.py”, line 8, in
frame = cv2.resize(frame, (500, 300))
cv2.error: OpenCV(4.5.0-dev) /root/opencv_build/opencv/modules/imgproc/src/resize.cpp:4051: error: (-215:Assertion failed) !ssize.empty() in function ‘resize’

No /dev/video in WSL (1 or 2).が原因っぽいが。。
Videoは今すぐは使わないが、、、
とりあえず動画ファイルの読み込みVideoCapture(‘*.mp4’)で再度やってみよう

cap = cv2.VideoCapture("fuji.mp4")
print(type(cap))
print(cap.isOpened())

$ python3 app.py

False

isOpened()でfalseなので、読み込めてない。

build infoを見る
Video I/O:
DC1394: NO
FFMPEG: NO
avcodec: NO
avformat: NO
avutil: NO
swscale: NO
avresample: NO
GStreamer: NO
v4l/v4l2: YES (linux/videodev2.h)

Video I/Oに問題があるみたい。
なるほど、buildか。。

[OpenCV4.5.0] RPAっぽい葉書から郵便番号の抽出2

元画像

scikit-learnの Handwritten Digits Data SetのSVMの学習済データから予想する。

import cv2
import matplotlib.pyplot as plt

def detect_zipno(fname):
	img = cv2.imread(fname)
	h, w = img.shape[:2]
	img = img[0:h//6, w//3:]

	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
	gray = cv2.GaussianBlur(gray, (1, 1), 0)
	im2 = cv2.threshold(gray, 140, 255, cv2.THRESH_BINARY_INV)[1]

	cnts = cv2.findContours(im2, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0]

	result = []
	for pt in cnts:
		x, y, w, h = cv2.boundingRect(pt)
		if not(50 < w < 70): continue
		result.append([x, y, w, h])
	result = sorted(result, key=lambda x: x[0])

	result2 = []
	lastx = -100
	for x, y, w, h in result:
		if(x - lastx) < 10: continue
		result2.append([x, y, w, h])
		lastx = x
	for x, y, w, h in result2:
		cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 3)
	return result2, img

if __name__ == '__main__':

	cnts, img = detect_zipno("postcard.png")

	cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
	cv2.imwrite("result.png", img)

$ python3 predict_zip.py
[9]
[2]
[5]
[4]
[3]
[4]
[8]

駄目だ、2と4しか合ってない
ただ、やり方の流れはわかった。
データセットの量を多くして、二次元配列を8x8ピクセルではなく、もう少し細かくしたら、結果が変わりそうだ。

[OpenCV4.5.0] RPAっぽい葉書から郵便番号の抽出

まず、葉書の郵便番号部分を抽出する。
元画像

import cv2
import matplotlib.pyplot as plt

def detect_zipno(fname):
	img = cv2.imread(fname)
	h, w = img.shape[:2]
	img = img[0:h//2, w//3:]

	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
	gray = cv2.GaussianBlur(gray, (3, 3), 0)
	im2 = cv2.threshold(gray, 140, 255, cv2.THRESH_BINARY_INV)[1]

	cnts = cv2.findContours(im2, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0]

	result = []
	for pt in cnts:
		x, y, w, h = cv2.boundingRect(pt)
		if not(50 < w < 70): continue
		result.append([x, y, w, h])
	result = sorted(result, key=lambda x: x[0])

	result2 = []
	lastx = -100
	for x, y, w, h in result:
		if(x - lastx) < 10: continue
		result2.append([x, y, w, h])
		lastx = x
	for x, y, w, h in result2:
		cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 3)
	return result2, img

if __name__ == '__main__':

	cnts, img = detect_zipno("postcard.png")

	cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
	cv2.imwrite("result.png", img)

$ python3 app.py

なんでやねん。なんで"2"と"4"が抽出されない。。。
前処理を少し変える。

	img = img[0:h//5, w//3:] # h//3 -> h//5

4が抽出されない。
なぜだ?? ぼかしの周囲のサイズを変えてみる。

	gray = cv2.GaussianBlur(gray, (1, 1), 0)

おおおおおおおおおおおおおおおおお
AI開発で、パラメータを調整するって、こういうこと????
うん、ちょっと興奮しました。
デバッグとはなんか感覚が違いますね。

あれ、というかこれ、記入する領域がわかってたらtesseractでOCRすりゃいいんだから、RPAできんじゃん。。
選挙システムとか注文書とか。。

[OpenCV4.5.0] 輪郭抽出

まず花の写真を用意します。 コスモスかな。

二値化

import cv2
import matplotlib.pyplot as plt

img = cv2.imread("flower.jpg")
img = cv2.resize(img, (300, 169))

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # gray化
gray = cv2.GaussianBlur(gray, (7, 7), 0) # Gaussianぼかし
im2 = cv2.threshold(gray, 140, 240, cv2.THRESH_BINARY_INV)[1] # threshold閾値処理 グレースケール画像を2値画像化

cv2.imwrite("threshold.png", im2)

GaussianBlurは細かな箇所を抽出しないようにぼかす。
findContoursで輪郭を抽出する。

import cv2
import matplotlib.pyplot as plt

img = cv2.imread("flower.jpg")
img = cv2.resize(img, (300, 169))

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # gray化
gray = cv2.GaussianBlur(gray, (7, 7), 0) # Gaussianぼかし
im2 = cv2.threshold(gray, 140, 240, cv2.THRESH_BINARY_INV)[1] # threshold閾値処理 グレースケール画像を2値画像化

# cv2.imwrite("threshold.png", im2)
cnts = cv2.findContours(im2, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0]

for pt in cnts:
	x, y, w, h = cv2.boundingRect(pt)

	# if w < 30 or w > 200: continue
	print(x,y,w,h)
	cv2.rectangle(img, (x,y), (x+w, y+h), (0, 255, 0), 2)

cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imwrite("find.png", img)

$ python3 app.py
245 91 2 1
182 76 20 18
0 0 300 169

花びらを輪郭にしたかったんですが、雄しべ雌しべが輪郭になってしまいました。
画像を変えてみましょう。

こちらは上手くいきました。
入力値のスクリーニングが鍵やな。

[OpenCV4.5.0] 顔検知 + モザイク

顔を検知し、モザイク処理を施す

import cv2
from mosaic import mosaic as mosaic

cascade_file = "haarcascades/haarcascade_frontalface_alt.xml"
cascade = cv2.CascadeClassifier(cascade_file)

img = cv2.imread("1.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

face_list = cascade.detectMultiScale(img_gray, minSize=(50,50))

if len(face_list) == 0:
	print("false")
	quit()

for (x,y,w,h) in face_list:
	img = mosaic(img, (x, y, x+w, y+h), 10)

cv2.imwrite("mosaic.png", img)

before

after

OK
後はユースケース特化型、画像のデータセットを学習させて検知する方法をマスターしたい。
まー、課題です。