株式会社 南伸 AIによるコンクリートひび割れ検出
開発手順
概要
開発手順
プログラム例
概要
openCVを使って画像認識を行うプログラムを作成する方法について記述する。openCVはインテルが開発した画像処理ライブラリーであってCやpython等の言語で使用できる。
このライブラリーに含まれる画像認識プログラム使ってアプリケーションを作る。
画像認識は認識したい対象が含まれる画像とそうでない画像を学習させ、分類器を作成し、判定を行いたい画像に、目的のものがあるか否かを求める。ここでは、分類器を作る方法と作成済の分類器を使って画像認識す方法を説明する.
作成方法を説明するプログラムは、橋の橋脚に発生したひびわれを検出するものである。人が容易に近づくことが
できない位置にあるひび割れをドローンにより写真を撮影しその写真からひびわれを検出するものである。
まず、分類器を作成する方法について説明し、次に分類器を使ってひびわれを検出する方法を説明する。
分類器を作る
1.分類器を作る
ひびわれが含まれる画像を準備する。ここでは1200万画素の写真である。この写真を256*256の画像に分割し、ひびわれがある画像を正答画像とし、含まれないものを不正答画像とする。
2 フォルダーの準備
任意フォルダの下に以下のフォルダーを作る。
pos(ひび割れ正答画像)
neg (不正答とする画像)
vec (機械学習の結果が入る)
save (結果の画像を入れる)
pospre(正答画像を加工するため)
other(使わない画像)
を作る
neglistはフルパスを指定するの注意する
3 学習用の画像データを作る
pospreのフォルダーにひびわれのある写真を入れる。
その写真を256*256 の写真に切り分ける。
ひびわれがある画像は残す
つかわないデータはother に移動
不正答データはnegに移動
4 正解データを複製する
ひびわれ画像は数が少ないので
fukusei.py を使って、元の画像の複製をつくる
画像は256*256の正方形であるので90度ごとに回転や
反転などさせても画像の形は変わらない。プログラムは
回転 90 180 270
反転 左右 上下 左右上下の画像を作成する。
fileには元の名前に上記がわかる名を追記する。
ひびわれは、水平方向や鉛直方向に発生しやすいので
90度ごととした。斜め45度に発生するひびわれもあるが
今のアプリには含めていない。
正答画像のリストを作る。
4 検出目標のデータを作る
正答画像のリストを作る。
pospre フォルダーに移動
以下のコマンドでフォルダー内のファイルリストを作る。
dir *.jpg /b > poslist,txt
各ファイルに検出画像の位置を記述する。
ファイル名 位置の個数 左上座標 x1 y1 範囲の横幅 縦幅
256*256全体を検出対象する場合
ou11-1.jpg 1 0 0 255 255
個数 左上座標 x1 y1 横 縦
検出範囲が1個の場合
ou11-1.jpeg 1 10 10 245 245
個数 左上座標 x1 y1 横 縦
検出範囲が2個の場合
ou11-1.jpeg 2 10 10 245 245 100 0 50 255
検出位置の取得に際して以下のプログラムを使用する。
画像座標検出プログラム pixel.py
画像ファイル input
検出物 左上 クリック x1,y1
検出物 右下 クリック xe,ye
横は xb=xe - x1
縦は yh=ye - y1
255> x1+xb
255> y1+ye
poslist.txtが完成したらposフォルダーにコピーする。
6.neglistのリストを作る
> dir *.jpg /b > neglist.txt
neg フォルダーにフルパスで記述
neglist.txt
C:\Users\kumeh\documents\2024cvcascade\neg\out0-13.jpg
C:\Users\kumeh\documents\2024cvcascade\neg\out0-14.jpg
C:\Users\kumeh\documents\2024cvcascade\neg\out1-7.jpg
7 ベクトル *.vec の作成
pos データからvecを作る
opencv_createsamples -info posform/poslist0714.txt -w 24 -h 24 -vec posform.vec
8 カスケード分類器を作る
以下のコマンド例を使う。
1行目は posフォルダの中のposlist,txtを使って、vecフォルダのなかにcrack1の名のベクトルファイルを作る。-w 24 -h24は固定。
opencv_createsamples -info pos/poslist.txt -w 24 -h 24 -vec crack1.vec
2行目は-data cascade/は分類器 cascade.xmlができる。 -vecはvec/crack1.vec -bgはneglist.txtの記述でnegファイルはneglist.txtに書いてある場所。コマンドを実行する前にcascadeフォルダの中を消去する。
opencv_traincascade.exe -data cascade/ -vec vec/crack1.vec -bg neg/neglist.txt -numPos 100 -numNeg 231
9 表示
cascade.xml を 使って、写真上の目標物を検出
添付のken.py を実行。検出場所が矩形で示される。
矩形の範囲を指定して,opencvのライブラリcannyでエッジ検出を行うとひび割れが検出できる。
プログラム例
256*256のデータに切り分ける 2024cv2/case1******************************************cv2-1.pyimport sysimport cv2def outfile(fn,input_img,bx,by): jx = bx * 256 jy = by * 256 imgcut = input_img[jx:jx+256,jy:jy+256] cv2.imwrite(fn,imgcut)# end def outfile# program maininput_img = cv2.imread("S1001526.JPG")height,width = input_img.shape[:2]print("w:" + str(width))print("h:" + str(height))start = 0stop = widthbymax = int(width/256)bxmax = int(height/256)bx = 0for bx in range(bxmax): by = 0 for by in range(bymax): fn ='out'+str(bx)+'-'+str(by)+'.jpg' outfile(fn,input_img,bx,by)
************************************
import cv2
fn = input('filename:')
img = cv2.imread(fn)
print(type(img))
# <class 'numpy.ndarray'>
print(img.shape)
# (225, 400, 3)
img_flip_ud = cv2.flip(img, 0)
cv2.imwrite('flip_ud.jpg', img_flip_ud)
# True
img_flip_lr = cv2.flip(img, 1)
cv2.imwrite('flip_lr.jpg', img_flip_lr)
# True
img_flip_ud_lr = cv2.flip(img, -1)
cv2.imwrite('flip_ud_lr.jpg', img_flip_ud_lr)
img_rotate_90_clockwise = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
cv2.imwrite('cv_rotate_90_clockwise.jpg', img_rotate_90_clockwise)
# True
img_rotate_90_counterclockwise = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
cv2.imwrite('cv_rotate_90_counterclockwise.jpg', img_rotate_90_counterclockwise)
# True
img_rotate_180 = cv2.rotate(img, cv2.ROTATE_180)
cv2.imwrite('cv_rotate_180.jpg', img_rotate_180)
# True
# True
***********************************
pixel.py
********************************
import cv2
def onMouse(event, x, y, flags, params):
if event == cv2.EVENT_LBUTTONDOWN:
print(x, y)
fname = input('enter fname: ')
print(fname)
img = cv2.imread(fname)
#img = cv2.imread('out23-5.jpg')
cv2.imshow('sample', img)
cv2.setMouseCallback('sample', onMouse)
cv2.waitKey(0)
*****************************
read.py ***************************** fname = input('enter fname: ') print(fname) iph = 0 with open(fname) as f: for line in f: # print (line) iph = iph+1 res = line.split() # print(res) fn = res[0] nn = int(res[1]) x0 = int(res[2]) y0 = int(res[3]) b = int(res[4]) h = int(res[5]) xt = x0 + b yt = y0 + h print(fn,x0,y0,b,h,xt,yt) if xt>=256 or yt>=256: print('***') if nn == 2: x0 = int(res[6]) y0 = int(res[7]) b = int(res[8]) h = int(res[9]) xt = x0 + b yt = y0 + h print(x0,y0,b,h,xt,yt) if xt>=256 or yt>=256: print('***') if nn == 3: x0 = int(res[6]) y0 = int(res[7]) b = int(res[8]) h = int(res[9]) xt = x0 + b yt = y0 + h print(x0,y0,b,h,xt,yt) if xt>=256 or yt>=256: print('***') print('num=',iph) *****************************
表示するプログラム ken.py import cv2 # カスケード分類器の読み込み form_cascade = cv2.CascadeClassifier('cascadeform/cascade.xml') image_path = 'ordpic/S1001526.JPG' image = cv2.imread(image_path) # グレースケールに変換 #gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 型枠を検出 forms = form_cascade.detectMultiScale(image, scaleFactor=1.1, minNeighbors=5) # 検出し場所に矩形を描画 for (x, y, w, h) in forms: cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2) # 結果を保存 output_path = 'save/output_p3.jpg' cv2.imwrite(output_path, image) print(f"検出結果を {output_path} に保存しました。") *******************************