自定模型17種花卉

網路上有另一種辨識17種花卉的討論,請先安裝如下套件

pip install tensorflow==2.10.1 matplotlib opencv-python

收集圖片

請由如下網址下載 flows_17.zip,然後解開後置於專案之下。

下載 : flowers_17.zip

label.txt

flowers圖片共有17種,每種 80 張圖片,所以共有1360張圖片,1~80是水仙(Narcissus),81~160是雪花蓮(Snowdrop),請先於專案下新增 label.txt,然後輸入如下資料。

1       80      Narcissus
81      160     Snowdrop
161     240     LilyValley
241     320     Bluebell
321     400     Crocus
401     480     Iris
481     560     Tigerlily
561     640     Daffodil
641     720     Fritillary
721     800     Sunflower
801     880     Daisy
881     960     ColtsFoot
961     1040    Dandelion
1041    1120    Cowslip
1121    1200    Buttercup
1201    1280    Windflower
1281    1360    Pansy

分類訓練圖片及驗証圖片

將所有的圖片分類成 train_images及 test_images二個目錄,每個目錄又有17種花卉目錄。

請新增 “分割資料.py” 檔,程式碼如下。

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import random
import shutil
import numpy as np
flowers=[]
#flowers_array=np.empty(0, dtype=object)
flowers_array=[]
with open('label.txt')as file:
    for line in file:
        line=line.strip()
        cols=line.split()
        s=int(cols[0])
        e=int(cols[1])
        flower=cols[2]
        flowers.append(cols[2])
        #flowers_array = np.r_[flowers_array, [flower] * (e-s+1)]
        flowers_array += [flower] * (e-s+1)
flowers_array=np.array(flowers_array)
print(flowers_array)
in_path="flowers_17"
train_path='train_images'
test_path='test_images'
if os.path.exists(train_path):
    shutil.rmtree(train_path)
os.mkdir(train_path)
if os.path.exists(test_path):
    shutil.rmtree(test_path)
os.mkdir(test_path)

for flower in flowers:
    os.mkdir(os.path.join(train_path, flower))
    os.mkdir(os.path.join(test_path, flower))

datas=list(zip(os.listdir(in_path),flowers_array))
random.seed(1)
random.shuffle(datas)
print(datas)

train=int(len(datas)*0.9)

for file, dir in datas[:train]:
    source = os.path.join(in_path, file)
    dest = os.path.join(train_path, dir, file)
    print(f'copy {source}  => {dest}')
    shutil.copy(source, dest)

for file, dir in datas[train:]:
    source = os.path.join(in_path, file)
    dest = os.path.join(test_path, dir, file)
    print(f'copy {source}  => {dest}')
    shutil.copy(source, dest)

list 相加與 np.r_ 效能

上述代碼中,原本是使用 np.r_ 建立陣列,但這種方式的效能極差,所以改用 list += 來加速。由如下程式碼可知,list 相加的效能確實高出許多

import numpy as np
import time
a=[]
t1=time.time()
for i in range(1000):
    a+=["hello"]*1000
a=np.array(a)
t2=time.time()
print(a)
print(f'list相加 : {t2-t1}秒')

a=np.empty(0,dtype=object)
t1=time.time()
for i in range(1000):
    a=np.r_[a, ["hello"]*1000]
t2=time.time()
print(a)
print(f'np.r_ : {t2-t1}秒')

結果:
['hello' 'hello' 'hello' ... 'hello' 'hello' 'hello']
list相加 : 0.10912036895751953秒
['hello' 'hello' 'hello' ... 'hello' 'hello' 'hello']
np.r_ : 4.773515701293945秒

訓練模型

建立模型跟上述的5種花卉雷同。

import os
import shutil
import cv2
from keras import Sequential
from keras.applications import VGG19
from keras.layers import GlobalAveragePooling2D, Dense, BatchNormalization, Dropout
from keras.optimizers import Adam
import pylab as plt

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import numpy as np
flowers=[]
with open('label.txt','r')as file:
    for line in file:
        line=line.strip()
        cols=line.split()
        flowers.append(cols[2])

train_imgs=[]
train_labels=[]
test_imgs=[]
test_labels=[]
train_path="train_images"
test_path="test_images"

#製作訓練資料
for flower in flowers:
    for file in os.listdir(os.path.join(train_path, flower)):
        full=os.path.join(train_path, flower, file)
        img=cv2.imdecode(
            np.fromfile(full, dtype=np.uint8), 
            cv2.IMREAD_COLOR
         )[:,:,::-1].copy()
        img=cv2.resize(img, (224,224), interpolation=cv2.INTER_LINEAR)
        train_imgs.append(img)
        train_labels.append(flower)
train_imgs=np.array(train_imgs)

#製作測試資料
for flower in flowers:
    for file in os.listdir(os.path.join(test_path, flower)):
        img=cv2.imdecode(np.fromfile(os.path.join(test_path, flower, file), dtype=np.uint8), cv2.IMREAD_UNCHANGED)
        img=cv2.resize(img, (224,224), interpolation=cv2.INTER_LINEAR)
        test_imgs.append(img)
        test_labels.append(flower)
test_imgs=np.array(test_imgs)

#one hot
train_onehot=np.zeros([len(train_labels),17], dtype=np.int32)
test_onehot=np.zeros([len(test_labels),17], dtype=np.int32)
for i in range(len(train_onehot)):
    train_onehot[i][flowers.index(train_labels[i])]=1
    print(train_onehot[i])
for i in range(len(test_onehot)):
    test_onehot[i][flowers.index(test_labels[i])]=1
    print(test_labels[i],test_onehot[i])

#建模
model_base=VGG19(weights='imagenet', include_top=False, input_shape=(224,224,3))
for layer in model_base.layers:
    layer.trainable=False
model=Sequential()
model.add(model_base)
model.add(GlobalAveragePooling2D())
model.add(Dense(256,activation='relu'))
model.add(BatchNormalization())
model.add(Dense(64,activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(0.2))
model.add(Dense(17, activation='softmax'))

model.compile(optimizer=Adam(learning_rate=0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy']
              )
#訓練
history=model.fit(
    train_imgs,
    train_onehot,
    batch_size=64,
    epochs=50,
    validation_data=(test_imgs, test_onehot)
)
if os.path.exists('./flower_17_model'):
    shutil.rmtree('./flower_17_model')
model.save("flower_17_model")
p1=plt.plot(history.history['accuracy'], label='training acc')
p2=plt.plot(history.history['val_accuracy'], label='val acc')
p3=plt.plot(history.history['loss'], label='training loss')
p4=plt.plot(history.history['val_loss'], label='val loss')
plt.legend()
plt.show()

辨識圖片

上述模型若是無法訓練的話,請由如下網址下載本人已訓練好的模型

下載模型 : flower_17_model

將要辨識的圖片放在 ./images裏面,然後開始辨識。

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import keras
import cv2
import numpy as np
import pylab as plt
from keras.applications.vgg19 import preprocess_input
model=keras.models.load_model('flower_17_model')
flowers=[]
with open('label.txt')as file:
    for line in file:
        line=line.strip()
        cols=line.split()
        flowers.append(cols[2])
print(flowers)
img_path='./images'
plt.figure(figsize=(12,6))
for i, file in enumerate(os.listdir(img_path)):
    img=cv2.imdecode(
        np.fromfile(os.path.join(img_path, file), dtype=np.uint8),
        cv2.IMREAD_UNCHANGED
    )
    x=cv2.resize(img, (224, 224), interpolation=cv2.INTER_LINEAR)
    x=cv2.cvtColor(x, cv2.COLOR_BGR2RGB)

    #VGG19規定在偵測(predict)時,必需傳入 #(1,224,224,3)的資料格式
    x=np.expand_dims(x, axis=0)

    #預處理圖片及偵測圖片
    x=preprocess_input(x)
    out=model.predict(x)
    print(out)

    idx=out[0].argmax()
    score=out[0][idx]
    name=flowers[idx]
    print(name)

    txt=f'{name}\n{score*100:.2f}%'
    plt.subplot(2,5,i+1)
    plt.title(txt)
    plt.axis("off")
    plt.imshow(img[:,:,::-1].copy())
plt.show()

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *