トマトの選別用画像処理①

ブログを始めた理由について

みなさんこんにちは。私、「畑の奇天烈」が、農作業の傍ら、「あんな機械があったら良いな」、「こんなこと出来たらいいな」という思いのままに、勉強したりしたこと、開発していることなどについて書き残していこうと思います。
プログラミングや、電子工作などは素人ですが色々な考えやアイディアを共有できる場に出来たらという思いでやろうと思ってます。
これからプログラミングや電子工作等をはじめたい方、園芸や畑に応用してみようかなって思っているような方、大歓迎です!

トマトの選別、箱詰めロボット開発について

トマトの収穫後、大きさや色で選別したり、傷物や形の悪いものをより分けたりした後に、パックつめする作業って結構大変ですよね。とくに、人によっても基準はまちまちになってしまいますし、選別の作業は頭を使うため疲れてしまいがちです。

そういった作業を自動でこなしてくれるロボットがあったらいいなって、
思いました。

もちろん専用の機械は既に世の中にたくさん出回っておりますが、導入するにはお金かかるし、やっぱり自分で作ってみたいですよね!

画像処理ってどうやるの?

トマトを選別していく上で欠かせないのは、カメラで撮った写真でトマトを選別すること。今はやりのAIによる画像処理ってどうやるのかについて検討してみました。

使用するもの

プログラミング言語:Python (機械学習が得意なプログラミング言語)
画像処理ライブラリ:OpenCV (画像をあれこれ操作できるやつ)
開発環境:Colaboratory
(googleの提供するプログラミングがネット上で出来る素晴らしいサービス。有料プランもあるけど無料で使うことが出来る。)
トマトの画像:カメラでたくさん撮ってください

それでは始めていきましょう!


データの準備

まずは、トマトの写真をとります。今回は試験的に形の綺麗なトマト「normal」と、形のごつごつしたトマト「gotugotu」の写真を撮りそれぞれフォルダを作って整理します。また、学習のトレーニング用フォルダ「train」と検証用フォルダ「Valid」を作ってそれぞれの下に各フォルダを入れます。トレーニング用の画像と検証用の画像は別のものを使用してください。ファイル形式は.jpg 画像サイズは244X244ピクセルで用意しました。
 

形の綺麗なトマト(例)
ごつごつしたトマト


googleドライブにアクセスし、フォルダごとアップロードします。

プログラミング開発環境

(参考サイト:画像認識を用いたトマトの葉の病気診断アプリ作成 - Qiita

まずはgoogle Colaboratoryにアクセスします。
(google.com)https://colab.research.google.com/?hl=ja


左上のファイルタブから「ノートブックの新規作成」をクリックしてください。

上のようなテキストボックスが出てくると思います。ここにプログラムの内容を記載します。再生ボタンを押すとプログラムが実行されます。手持ちのパソコンにプログラムの実行環境や、必要なライブラリをインストールするにはひと手間かかりますが、このサービスを使えば簡単にどんなことができるのかを試すことが出来ます。(実際ロボット運用する段階ではパソコンに実行環境をインストールしますが、それに関しては後日記載します)

動かすコードは下記の通り

from google.colab import drive
drive.mount('/content/drive')
from tensorflow.keras.layers import Input, Dense, Flatten
from tensorflow.keras import Model
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.preprocessing import image
from tensorflow.keras.models import Sequential
import numpy as np
import pandas as pd

img_size = 224
image_size = [img_size, img_size]
# vgg16インタンス作成
vgg = VGG16(input_shape = image_size + [3], weights = 'imagenet', include_top =  False)

# vgg16による特徴抽出部分の重みを固定
for layer in vgg.layers:
    layer.trainable = False
    
# マウントしたドライブから画像フォルダを取得
from glob import glob
folders = glob('/content/drive/MyDrive/test/train/*')
folders

# モデル作成
x = Flatten()(vgg.output)
prediction = Dense(len(folders), activation = 'softmax')(x)
# モデルの連結
model = Model(inputs = vgg.input, outputs = prediction)
model.summary()

model.compile(loss = 'categorical_crossentropy', optimizer = 'adam', metrics = ['accuracy'])
# 該当するフォルダのファイルを取得
folders1 = glob(folders[0] + '/*.jpg')
img_Normal = []
train_range = 15
# rangeの数だけ画像ファイルを取得
import cv2
for i in range(train_range):
    img = cv2.imread(folders1[i])
    img = cv2.resize(img, (img_size, img_size))
    img_Normal.append(img)

folders2 = glob(folders[1] + '/*.jpg')
img_Gotugotu = []
for i in range(train_range):
    img = cv2.imread(folders2[i])
    img = cv2.resize(img, (img_size, img_size))
    img_Gotugotu.append(img)

# 学習データ作成
X_train = []
X_train.extend(img_Normal)
X_train.extend(img_Gotugotu)

# 正解ラベルを作成
y_train = []
i = 0
while i < 2:
  y_train.extend([i] * train_range)
  i += 1
 #検証データ作成 
X_test = []
# 画像フォルダ取得
test_folders = glob('/content/drive/MyDrive/test/valid/*')
test_folders
test_range = 5

# 該当するフォルダのファイルを取得(斑点病)
folders1 = glob(test_folders[0] + '/*.jpg')
img_Normal = []

# rangeの数だけ画像ファイルを取得(斑点病)
import cv2
for i in range(test_range):
    img = cv2.imread(folders1[i])
    img = cv2.resize(img, (img_size, img_size))
    img_Normal.append(img)

folders2 = glob(test_folders[1] + '/*.jpg')
img_Gotugotu = []
for i in range(test_range):
    img = cv2.imread(folders2[i])
    img = cv2.resize(img, (img_size, img_size))
    img_Gotugotu.append(img)

# 検証データ作成
X_test = []
X_test.extend(img_Normal)
X_test.extend(img_Gotugotu)

# 正解ラベルを作成
y_test = []
i = 0
while i < 2:
  y_test.extend([i] * test_range)
  i += 1




X_train = np.array(X_train)
y_train = np.array(y_train)
X_test = np.array(X_test)
y_test = np.array(y_test)

from tensorflow.keras.utils import to_categorical
# 正解ラベルをone-hotの形にします
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

# モデルの学習
model.fit(X_train, y_train, batch_size=100, epochs=10, verbose=1)

score = model.evaluate(X_test, y_test, verbose=1)
print('Test loss:', score[0])
print('Test accuracy:', score[1])


import os
from google.colab import files #resultsディレクトリを作成 
result_dir = 'results'
if not os.path.exists(result_dir):
    os.mkdir(result_dir)
# 重みを保存
model.save(os.path.join(result_dir, 'model.h5'))

files.download( '/content/results/model.h5' )

import os
from flask import Flask, request, redirect, render_template, flash
from werkzeug.utils import secure_filename
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.preprocessing import image

import numpy as np

 #classes  = ["0","1"]
leaf_classes = ["正常", "ごつごつ"]
image_size = 224

UPLOAD_FOLDER = "uploads"
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])

app = Flask(__name__)

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

 #model  = load_model('./model.h5')#学習済みモデルをロード

from google.colab import files
uploaded_file = files.upload()

uploaded_file_name = next(iter(uploaded_file))
print(uploaded_file_name)

orig = cv2.imread(uploaded_file_name)
img = cv2.cvtColor(orig, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (img_size, img_size))
from matplotlib import pyplot as plt

plt.imshow(img)

img = image.img_to_array(img)  
data = np.array([img])
result = model.predict(data)[0]
predicted = result.argmax()
predicted
pred_answer = "これは「" + leaf_classes[predicted] + "」です。"
pred_answer

こんな感じで順次再生ボタンを押して実行して行ってください。
詳細については、また後日記事をアップします!

この記事が気に入ったらサポートをしてみませんか?