TensorFlow Object Detection API 超詳細教程和踩坑過程

安裝Anacondhttps://blog.csdn.net/ITLearnHall/article/details/81708148

安裝Pycharm:https://blog.csdn.net/qq_15698613/article/details/86502371

一:MyQR 生成動態二維碼100個

import random 
from MyQR import myqr
import os

for i in range(1,101):
    z=''.join(str(random.choice(range(10))) for _ in range(10))#生成長度爲10的隨機數
    name=z+".png"#設置圖片名字
    myqr.run(
    version=1,  # 設置容錯率
    level='L',
    brightness=1.0,
    words=z,
    save_name=name
)

 

 

二:下載圖片,將圖片和二維碼大小進行修改

需要安裝opencv參考

https://blog.csdn.net/iracer/article/details/80498732

import os
import cv2

#讀取文件夾下文件
def read_directory(directory_name,save_img):
    i=0
    for fileName in os.listdir(directory_name):
        #print(fileName)
        obsPath=directory_name+"/"+fileName
        obsSave_path=save_img+"/"+fileName
        resize_img(obsPath,obsSave_path)
        i+=1
        if(i==100):
            break
def resize_img(path_img,save_img):
    im1 = cv2.imread(path_img)
    im2 = cv2.resize(im1,(716,1000),)  # 爲圖片重新指定尺寸
    cv2.imwrite(save_img,im2)

read_directory("D:/pythonLearnDemo/AnacondaJqueryDemo/neg/neg","D:/pythonLearnDemo/AnacondaJqueryDemo/neg/resize_neg")

三:將照片和二維碼進行隨機合併

import cv2
import numpy as np
import matplotlib.pyplot as plt
import random
#讀取照片
directory_name="D:/pythonLearnDemo/AnacondaJqueryDemo/neg/resize_neg"
myqrPaths=os.listdir("D:/pythonLearnDemo/AnacondaJqueryDemo/neg/myqrCode")
lens=len(os.listdir(directory_name))
for fileName in os.listdir(directory_name):
    obsPathName=directory_name+"/"+fileName
    yNum=0
    xNum=0
    for i in range(1,3):
        
        dst = cv2.imread(obsPathName)#背景圖
        ranNum=random.randint(0,lens)
        print("ranNum:",ranNum,"NAME:",myqrPaths[ranNum])
        srcPath="D:/pythonLearnDemo/AnacondaJqueryDemo/neg/myqrCode"+"/"+myqrPaths[ranNum]
        x_loc=0
        y_loc=0
        
        if(i==1):
            y_loc=random.randint(141,350)
            yNum=y_loc
            x_loc=random.randint(141,260)
            xNum=x_loc
        else:
            y_loc=random.randint(yNum+170,641)
            x_loc=random.randint(xNum+141,500)
        center = (x_loc,y_loc)
        #dst = cv2.imread("D:/pythonLearnDemo/AnacondaJqueryDemo/neg/opencv-seamless-cloning-example.jpg.jpg")
        print(srcPath)
        src = cv2.imread(srcPath)
        src_mask = np.zeros(src.shape, src.dtype)
        poly = np.array([[0, 2], [258, 2], [258, 260], [0, 260]], np.int32)
        cv2.fillPoly(src_mask, [poly], (255, 255, 255))
        output = cv2.seamlessClone(src, dst, src_mask, center, cv2.NORMAL_CLONE)
        mrgPath="D:/pythonLearnDemo/AnacondaJqueryDemo/neg/images"+"/"+fileName
        obsPathName=mrgPath
        cv2.imwrite(mrgPath, output);

下載安裝Tensorflow object detection API :https://github.com/tensorflow/models下載到本地,解壓放到需要使用的路徑下

 四:Protobuf 安裝與配置

  Protobuf(Google Protocol Buffers)是GG開發的的一套用於數據存儲,網絡通信時用於協議編解碼的工具庫。和XML,Json數據差不多,把數據按某種形式保存起來。相對與XML和Json的不同之處,它是一種二進制的數據格式,具有更高的傳輸,打包和解包效率。

  在https://github.com/google/protobuf/releases 網站中選擇windows 版本,解壓後將bin文件夾中的【protoc.exe】放到models中的research目錄下,執行下面的代碼,將object_detection/protos下的.proto文件轉換成.py文件

'''

需要到protoc所在的目錄下執行protoc

'''

import os

os.chdir( 'models-master/research' )#可以寫

for each in os.listdir( 'object_detection/protos' ):#可以寫models-master(Tensorflow object detection API 解壓後文件)可對路徑

    if each.endswith('proto'):

        os.system('protoc object_detection/protos/%s --python_out=.' % each)

 

運行jupyter notebook,找到../models-master/research/object_detection下的

object_detection_tutorial.ipynb進行運行

demo結果

  如果代碼成功運行的話,運行結果如下圖所示:

給圖片打標籤

  使用打標籤工具LabelImg,下載頁面鏈接:https://tzutalin.github.io/labelImg/

  下載後解壓,打開:

  在輸入法爲英文輸入的情況下,按鍵盤上的w鍵則可以開始繪製方框,方框會框住圖片中的物體。完成繪製方框後,還需要爲方框標上類別,如下圖所示。

  注意:每完成一張圖的打標籤,一定要記得保存!!!,初次使用可以在edit選項中設置正方形和矩形框:

 每次打完標籤,會生成對應的xml數據,感興趣的可以查看一下某個xml文件,其中記錄了標籤及bounding box座標:

<annotation>
    <folder>images</folder>
    <filename>1.jpg</filename>
    <path>D:\pythonLearnDemo\AnacondaJqueryDemo\neg\images\1.jpg</path>
    <source>
        <database>Unknown</database>
    </source>
    <size>
        <width>716</width>
        <height>1000</height>
        <depth>3</depth>
    </size>
    <segmented>0</segmented>
    <object>
        <name>qrCode</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <difficult>0</difficult>
        <bndbox>
            <xmin>141</xmin>
            <ymin>222</ymin>
            <xmax>355</xmax>
            <ymax>436</ymax>
        </bndbox>
    </object>
    <object>
        <name>qrCode</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <difficult>0</difficult>
        <bndbox>
            <xmin>369</xmin>
            <ymin>422</ymin>
            <xmax>561</xmax>
            <ymax>605</ymax>
        </bndbox>
    </object>
</annotation>

xml轉csv

 xml轉csv的意思是,將xml文件中的信息整合到csv文件中,其中利用的是xml模塊

# -*- coding: utf-8 -*-
"""
@author: Zbb
將文件夾內所有XML文件的信息記錄到CSV文件中
"""

import os
import pandas as pd
import xml.etree.ElementTree as ET
from sklearn.model_selection import train_test_split


path = 'D:/pythonLearnDemo/saveLabels'

def xml_to_csv(path):
    xml_list = []
    for xml_file in glob.glob(path + '/*.xml'):
        tree = ET.parse(xml_file)
        root = tree.getroot()
        for member in root.findall('object'):
            value = (root.find('filename').text,
                     int(root.find('size')[0].text),
                     int(root.find('size')[1].text),
                     member[0].text,
                     int(member[4][0].text),
                     int(member[4][1].text),
                     int(member[4][2].text),
                     int(member[4][3].text)
                     )
            xml_list.append(value)
    column_name = ['filename', 'width', 'height', 'class', 'xmin', 'ymin', 'xmax', 'ymax']
    xml_df = pd.DataFrame(xml_list, columns=column_name)
    return xml_df


def xmlPath_list_to_df(xmlPath_list):
    xmlContent_list = []
    for xmlPath in xmlPath_list:
        print(xmlPath)
        tree = ET.parse(xmlPath)
        root = tree.getroot()

        for member in root.findall('object'):
            value = (root.find('filename').text,  # 文件名
                     int(root.find('size')[0].text),  # width
                     int(root.find('size')[1].text),  # height
                     member[0].text,  # 標籤
                     int(member[4][0].text),  # xmin
                     int(member[4][1].text),  # ymin
                     int(member[4][2].text),  # xmax
                     int(member[4][3].text)  # ymax
                     )
            xmlContent_list.append(value)

    column_name = ['filename', 'width', 'height', 'class', 'xmin', 'ymin', 'xmax', 'ymax']

    xmlContent_df = pd.DataFrame(xmlContent_list, columns=column_name)

    return xmlContent_df


def main():
    image_path = path
    xml_df = xml_to_csv(image_path)
    xml_df.to_csv('tv_vehicle_labels.csv', index=None)
    print('Successfully converted xml to csv.')


def dirPath_to_csv(dirPath):
    fileName_list = os.listdir(dirPath)
    all_xmlPath_list = [os.path.join(dirPath, fileName) for fileName in fileName_list if '.xml' in fileName]
    train_xmlPath_list, test_xmlPath_list = train_test_split(all_xmlPath_list, test_size=0.1, random_state=1)
    train_df = xmlPath_list_to_df(train_xmlPath_list)
    train_df.to_csv('train.csv')
    print('成功產生文件train.csv,訓練集共有%d張圖片' % len(train_xmlPath_list))

    test_df = xmlPath_list_to_df(test_xmlPath_list)
    test_df.to_csv('test.csv')
    print('成功產生文件test.csv,測試集共有%d張圖片' % len(test_xmlPath_list))
#main()
dirPath_to_csv(path)

csv轉tfrecord

  由於下面的代碼我們需要模塊

1

from object_detection.utils import dataset_util

  該模塊是我們在Tensorflow object detection API中下載的,要想使用該模塊,我們需要添加環境變量PATHPATH。方法如下:右鍵計算機->屬性

其中變量值包含下載的objec_detection路徑及slim路徑,如E:\ML\models-master\research;E:\ML\models-master\research\slim 


# -*- coding: utf-8 -*-
"""
@author: Zbb
將文件夾內所有XML文件的信息記錄到CSV文件中
"""

import os
import io
import pandas as pd
import tensorflow as tf

from PIL import Image
from object_detection.utils import dataset_util
from collections import namedtuple, OrderedDict

import os
import pandas as pd
import tensorflow as tf
from object_detection.utils import dataset_util
import shutil


def csv2tfrecord(csv_path, imageDir_path, tfrecord_path):
    objectInfo_df = pd.read_csv(csv_path)
    tfrecord_writer = tf.python_io.TFRecordWriter(tfrecord_path)
    for filename, group in objectInfo_df.groupby('filename'):
        height = group.iloc[0]['height']
        width = group.iloc[0]['width']
        filename_bytes = filename.encode('utf-8')
        image_path = os.path.join(imageDir_path, filename)

        with open(image_path, 'rb') as file:
            encoded_jpg = file.read()

        image_format = b'jpg'
        xmin_list = list(group['xmin'] / width)
        xmax_list = list(group['xmax'] / width)
        ymin_list = list(group['ymin'] / height)
        ymax_list = list(group['ymax'] / height)

        classText_list = [classText.encode('utf-8') for classText in group['class']]
        classLabel_list = [classText_to_classLabel(classText) for classText in group['class']]

        tf_example = tf.train.Example(features=tf.train.Features(
            feature={
                'image/height': dataset_util.int64_feature(height),
                'image/width': dataset_util.int64_feature(width),
                'image/filename': dataset_util.bytes_feature(filename_bytes),
                'image/source_id': dataset_util.bytes_feature(filename_bytes),
                'image/encoded': dataset_util.bytes_feature(encoded_jpg),
                'image/format': dataset_util.bytes_feature(image_format),
                'image/object/bbox/xmin': dataset_util.float_list_feature(xmin_list),
                'image/object/bbox/xmax': dataset_util.float_list_feature(xmax_list),
                'image/object/bbox/ymin': dataset_util.float_list_feature(ymin_list),
                'image/object/bbox/ymax': dataset_util.float_list_feature(ymax_list),
                'image/object/class/text': dataset_util.bytes_list_feature(classText_list),
                'image/object/class/label': dataset_util.int64_list_feature(classLabel_list),

            }))
        tfrecord_writer.write(tf_example.SerializeToString())

    tfrecord_writer.close()
    print('成功產生tfrecord文件,保存在路徑:%s' % tfrecord_path)


# 如果訓練自己的模型,目標檢測類別不同,需要修改此處
def classText_to_classLabel(row_label):
    if row_label == 'fish':
        return 1
    elif row_label == 'human_face':
        return 2
    else:
        return None


dir_name = 'training'
if not os.path.isdir(dir_name):
    os.mkdir(dir_name)

csv2tfrecord('D:/pythonLearnDemo/train.csv', 'D:/pythonLearnDemo/AnacondaJqueryDemo/neg/images', 'D:/pythonLearnDemo/training/train.tfrecord')
csv2tfrecord('D:/pythonLearnDemo/test.csv', 'D:/pythonLearnDemo/AnacondaJqueryDemo/neg/images', 'D:/pythonLearnDemo/training/test.tfrecord')

  運行上面的代碼,目標檢測文件夾中會產生一個文件夾training,如下圖所示:

編寫pbtxt文件

  目標檢測的文件夾training中,創建文本文件my_label_map.pbtxt。複製下面一段內容到文本文件my_label_map.pbtxt中:

item {
    name : "qrCode"
    id : 1
}

 

 

 

8)編寫配置文件

  可以在object_detection文件夾中的samples/config路徑下,找到原生配置文件ssdlite_mobilenet_v2_coco.config,先複製1份到桌面文件目標檢測的文件夾training中,並做如下修改:

  1. 第9行的num_classes,對於本文來說,此數設置爲1
  2. 第141行的batch_size,對於本文來說,此數設置爲3,讀者根據自己的電腦配置,可以調高或者調低
  3. 第177行input_path設置成"D:/pythonLearnDemo/training/train.tfrecord"(我設置的爲絕對路徑)
  4. 第179行label_map_path設置成"D:/pythonLearnDemo/training/my_label_map.pbtxt"
  5. 第191行input_path設置成"D:/pythonLearnDemo/training/test.tfrecord"
  6. 第193行label_map_path設置成"D:/pythonLearnDemo/training/my_label_map.pbtxt"
  7. 第158、159這2行需要刪除
  8. 第二處爲eval_config中的num_examples,它表示在驗證階段需要執行的圖片數量,本次驗證數量爲10(可以在create_pascal_tf_record.py中,輸出對應的examples_list長度,就可以知道這個大小)。

  修改配置文件ssdlite_mobilenet_v2_coco.config並保存後,此時文件夾training中有4個文件,如下圖所示:

# SSD with Mobilenet v1 configuration for MSCOCO Dataset.
# Users should configure the fine_tune_checkpoint field in the train config as
# well as the label_map_path and input_path fields in the train_input_reader and
# eval_input_reader. Search for "PATH_TO_BE_CONFIGURED" to find the fields that
# should be configured.

model {
  ssd {
    num_classes: 1
    box_coder {
      faster_rcnn_box_coder {
        y_scale: 10.0
        x_scale: 10.0
        height_scale: 5.0
        width_scale: 5.0
      }
    }
    matcher {
      argmax_matcher {
        matched_threshold: 0.5
        unmatched_threshold: 0.5
        ignore_thresholds: false
        negatives_lower_than_unmatched: true
        force_match_for_each_row: true
      }
    }
    similarity_calculator {
      iou_similarity {
      }
    }
    anchor_generator {
      ssd_anchor_generator {
        num_layers: 6
        min_scale: 0.2
        max_scale: 0.95
        aspect_ratios: 1.0
        aspect_ratios: 2.0
        aspect_ratios: 0.5
        aspect_ratios: 3.0
        aspect_ratios: 0.3333
      }
    }
    image_resizer {
      fixed_shape_resizer {
        height: 300
        width: 300
      }
    }
    box_predictor {
      convolutional_box_predictor {
        min_depth: 0
        max_depth: 0
        num_layers_before_predictor: 0
        use_dropout: false
        dropout_keep_probability: 0.8
        kernel_size: 1
        box_code_size: 4
        apply_sigmoid_to_scores: false
        conv_hyperparams {
          activation: RELU_6,
          regularizer {
            l2_regularizer {
              weight: 0.00004
            }
          }
          initializer {
            truncated_normal_initializer {
              stddev: 0.03
              mean: 0.0
            }
          }
          batch_norm {
            train: true,
            scale: true,
            center: true,
            decay: 0.9997,
            epsilon: 0.001,
          }
        }
      }
    }
    feature_extractor {
      type: 'ssd_mobilenet_v1'
      min_depth: 16
      depth_multiplier: 1.0
      conv_hyperparams {
        activation: RELU_6,
        regularizer {
          l2_regularizer {
            weight: 0.00004
          }
        }
        initializer {
          truncated_normal_initializer {
            stddev: 0.03
            mean: 0.0
          }
        }
        batch_norm {
          train: true,
          scale: true,
          center: true,
          decay: 0.9997,
          epsilon: 0.001,
        }
      }
    }
    loss {
      classification_loss {
        weighted_sigmoid {
        }
      }
      localization_loss {
        weighted_smooth_l1 {
        }
      }
      hard_example_miner {
        num_hard_examples: 3000
        iou_threshold: 0.99
        loss_type: CLASSIFICATION
        max_negatives_per_positive: 3
        min_negatives_per_image: 0
      }
      classification_weight: 1.0
      localization_weight: 1.0
    }
    normalize_loss_by_num_matches: true
    post_processing {
      batch_non_max_suppression {
        score_threshold: 1e-8
        iou_threshold: 0.6
        max_detections_per_class: 100
        max_total_detections: 100
      }
      score_converter: SIGMOID
    }
  }
}

train_config: {
  batch_size: 3
  optimizer {
    rms_prop_optimizer: {
      learning_rate: {
        exponential_decay_learning_rate {
          initial_learning_rate: 0.004
          decay_steps: 800720
          decay_factor: 0.95
        }
      }
      momentum_optimizer_value: 0.9
      decay: 0.9
      epsilon: 1.0
    }
  }
  #fine_tune_checkpoint: "PATH_TO_BE_CONFIGURED/model.ckpt"
  #from_detection_checkpoint: true
  # Note: The below line limits the training process to 200K steps, which we
  # empirically found to be sufficient enough to train the pets dataset. This
  # effectively bypasses the learning rate schedule (the learning rate will
  # never decay). Remove the below line to train indefinitely.
  num_steps: 200000
  data_augmentation_options {
    random_horizontal_flip {
    }
  }
  data_augmentation_options {
    ssd_random_crop {
    }
  }
}

train_input_reader: {
  tf_record_input_reader {
    input_path: "D:/pythonLearnDemo/training/train.tfrecord"
  }
  label_map_path: "D:/pythonLearnDemo/training/my_label_map.pbtxt"
}

eval_config: {
  num_examples: 10
  # Note: The below line limits the evaluation process to 10 evaluations.
  # Remove the below line to evaluate indefinitely.
  max_evals: 10
}

eval_input_reader: {
  tf_record_input_reader {
    input_path: "D:/pythonLearnDemo/training/test.tfrecord"
  }
  label_map_path: "D:/pythonLearnDemo/training/my_label_map.pbtxt"
  shuffle: false
  num_readers: 1
}
 

三、模型訓練

 1)錯誤一:

  在桌面的目標檢測文件夾中打開cmd,即在路徑中輸入cmd後按Enter鍵運行。在cmd中運行命令:

1

1.    python D:/tensorflowObject/models-master/research/object_detection/model_main.py  
--pipeline_config_path=D:/pythonLearnDemo/training/ssd_mobilenet_v1_coco.config  
--model_dir=D:/pythonLearnDemo/training/model_training
 --alsologtostderr

 

 

2.  python3 object_detection/model_main.py 
    --pipeline_config_path=D:/pythonLearnDemo/training/ssd_mobilenet_v1_coco.config  
    --model_dir=D:/pythonLearnDemo/training/model_training
    --num_train_steps=500000 #設置訓練步長
    --num_eval_steps=2000
    --alsologtostderr

  運行結果如下圖所示:

  可以看出缺少pycocotools庫,在linux系統中安裝pycocotools庫只需要運行命令:pip install pycocotools但是在Windows上安裝則複雜得多:

 首先下載Microsoft C++ build 14.0,鏈接:https://go.microsoft.com/fwlink/?LinkId=691126,初始化安裝程序->自定義->選擇功能只勾選Windows 10 SDK 10.0.10240->安裝,過程比較漫長,一般安裝有VS完整版的,不會缺失

  然後下載安裝pycocotools,鏈接:https://github.com/philferriere/cocoapi,解壓到當前文件夾,進入文件夾cocoapi-master中的文件夾PythonAPI,在此文件夾下打開cmd,輸入:python setup.py build_ext install

 

 然後重新訓練,模型訓練穩定地進行一段時間後,會做一次模型評估,如下圖所示。所以如果讀者看到下圖中的情況,則說明模型訓練很順利:

 

將訓練模型導出

python D:/tensorflowObject/models-master/research/object_detection/export_inference_graph.py 
--input_type=image_tensor  
--pipeline_config_path=D:/pythonLearnDemo/training/ssd_mobilenet_v1_coco.config  
--trained_checkpoint_prefix=D:/pythonLearnDemo/training/model_training/model.ckpt-20000  #之前默認設置20000次
--output_directory=fish_inference_graph 

3)查看模型訓練狀況

  模型訓練穩定地進行後,在桌面的目標檢測文件夾中重新打開cmd。在cmd中運行命令:

D:/pythonLearnDemo/training/model_training(路徑爲之前保存訓練模型的地方)--trained_checkpoint_prefix=D:/pythonLearnDemo/training/model_training/

tensorboard --logdir=D:/pythonLearnDemo/training/model_training --host=127.0.0.1

可查看數據

測試

測試代碼下載地址
鏈接:https://pan.baidu.com/s/1kqFlP6vdsMgwyYRPFPmxnA 
提取碼:68rc 

在測試過程中,出現不了展示圖片大的效果,然後修改成了保存

 

 

 

 

 

訓練結果

 

 

後續需要進行動態視頻測試!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章