Darkflow 설치 및 사용법 on Windows

  • 이 github 페이지를 참조했습니다.

  • Anaconda, tensorflow-gpu, opencv3, numpy가 설치되어 있는 환경에서 진행했습니다.

  • Python 3.5가 권장된다고 합니다. 저는 3.6.5에서 진행했습니다.

  • 선택사항으로 가상 환경(virtualenv, conda, pipenv)에서 진행해도 된다고 하는데, 저는 아직 가상 환경에 대한 체감이 없어서 그냥 base env에서 진행했습니다.

사전 준비

  • pip3 install --upgrade tensorflow
  • pip3 install cython
  • pip3 install opencv-python

repo Download

  • Darkflow github Page에서 repo를 다운로드 받고 그 디렉토리에서 다음을 실행합니다.
    • python setup.py build_ext --inplace
    • python flow --h
    • Microsoft Visual C++ 14.0 is required error가 생기는 경우 이 곳을 참조해서 해보세요. 저는 해당되지 않아서 자세히는 잘 모르겠습니다.

시작 방법

  • 3가지 방법이 있다.
    • python setup.py build_ext --inplace
      • 이 방법을 쓰면 ./flow로 명령을 실행해야한다고 한다.
    • pip install -e .
    • pip install .
  • 나는 세번째가 제일 짧아서 세번째걸로 했다. 별 문제 없이 됐다.

학습 방법(Training on your own dataset)

  • cfg 디렉토리에서 cfg 파일을 복사해서 원하는 대로 이름을 변경한다.(Original cfg를 건드리지 않는것이 좋다.)

  • 복사한 cfg 파일의 [region] 부분 밑에 class 수를 원하는대로 변경한다. 나는 일단 신호등 하나만 할거라서 1로 했다.

    [region]
    anchors =  0.57273, 0.677385, 1.87446, 2.06253, 3.33843, 5.47434, 7.88282, 3.52778, 9.77052, 9.16828
    bias_match=1
    classes=1
    coords=4
    num=5
    softmax=1
    jitter=.3
    rescore=1
  • 바로 위의 [convolutional] 부분을 수정해야한다. filters 값을 num * (class + 5)로 한다. 나는 num이 5고 class는 1이어서 5 * (1 + 5) = 30으로 바꿨다.

    [convolutional]
    size=1
    stride=1
    pad=1
    filters=30
    activation=linear
  • labels.txt에 class명을 적는다.

    traffic light
  • Train Command 예시

    • bash
      • python flow --model cfg/my.cfg --train --load yolo.weights --dataset data/train_traffic_light --annotation data/annotations --gpu 1.0
    • cmd
      • python flow --model cfg\my.cfg --train --load yolo.weights --dataset data\train_traffic_light --annotation data\annotations --gpu 1.0
  • Argument

    • --train : 학습 시킬때
    • --load : weights 파일 Load, -1을 주면 ckpt/checkpoint에서 가장 최근걸 불러온다.
    • --trainer adam : Adam optimizer로 완전히 새로운 weights 파일로 시작.
    • --model : cfg 파일 경로
    • --annotation : xml 파일 경로
    • --dataset : 학습 image 파일 경로
    • --demo : video test시 video 파일 경로 입력
    • --imgdir : image test시 image 파일 경로 입력
  • defaults.py

    • 수정할 수 있는 부분이 많다. 추후 업데이트.

YOLO Annotation (txt) to VOC Annotation (xml)

YOLO 학습때 사용한 annotation 파일은 txt 형식이고, 간결하다.

darkflow로 학습하려니 annotation 형식이 달라서 학습이 되지 않았다.

xml 형식이 필요하대서 찾아보니까 txt에 비해 많이 복잡했다.

하나하나 다시 박스 처리를 해주는건 미친짓이기에 txt 파일을 xml로 변환했다.

나와 같은 어려움을 겪는 사람이 있을게 분명하기에 코드를 공유해봅니다..

convert.py

from lxml import etree
from PIL import Image
import csv
import os

# fw is txt file that composed train image file path

IMG_PATH = "D:/__Project__/darkflow-master/data/train_traffic_light"
fw = os.listdir(IMG_PATH)
# path of save xml file
save_path = 'D:/__Project__/darkflow-master/data/annotations/'

# txt_folder is txt file root that using darknet rectbox
txt_folder = 'D:/__Project__/darkflow-master/data/train_traffic_light_TXT'

# edit ypur label set
labels = ['traffic light']


def csvread(fn):
    with open(fn, 'r') as csvfile:
        list_arr = []
        reader = csv.reader(csvfile, delimiter=' ')

        for row in reader:
            list_arr.append(row)
    return list_arr


def convert_label(txt_file):
    if((txt_file[0]) == str(0)):
        label = 'traffic light'

    return label

# core code = convert the yolo txt file to the x_min,x_max...


def extract_coor(txt_file, img_width, img_height):
    x_rect_mid = float(txt_file[1])
    y_rect_mid = float(txt_file[2])
    width_rect = float(txt_file[3])
    height_rect = float(txt_file[4])

    x_min_rect = ((2 * x_rect_mid * img_width) - (width_rect * img_width)) / 2
    x_max_rect = ((2 * x_rect_mid * img_width) + (width_rect * img_width)) / 2
    y_min_rect = ((2 * y_rect_mid * img_height) -
                  (height_rect * img_height)) / 2
    y_max_rect = ((2 * y_rect_mid * img_height) +
                  (height_rect * img_height)) / 2

    return x_min_rect, x_max_rect, y_min_rect, y_max_rect


for line in fw:
    root = etree.Element("annotation")

    # try debug to check your path
    img_style = IMG_PATH.split('/')[-1]
    img_name = line
    image_info = IMG_PATH + "/" + line
    img_txt_root = txt_folder + "/" + line[:-4]
    txt = ".txt"

    txt_path = img_txt_root + txt
    txt_file = csvread(txt_path)
    ######################################

    # read the image  information
    img_size = Image.open(image_info).size

    img_width = img_size[0]
    img_height = img_size[1]
    img_depth = Image.open(image_info).layers
    ######################################

    folder = etree.Element("folder")
    folder.text = "%s" % (img_style)

    filename = etree.Element("filename")
    filename.text = "%s" % (img_name)

    path = etree.Element("path")
    path.text = "%s" % (IMG_PATH)

    source = etree.Element("source")
    ##################source - element##################
    source_database = etree.SubElement(source, "database")
    source_database.text = "Unknown"
    ####################################################

    size = etree.Element("size")
    ####################size - element##################
    image_width = etree.SubElement(size, "width")
    image_width.text = "%d" % (img_width)

    image_height = etree.SubElement(size, "height")
    image_height.text = "%d" % (img_height)

    image_depth = etree.SubElement(size, "depth")
    image_depth.text = "%d" % (img_depth)
    ####################################################

    segmented = etree.Element("segmented")
    segmented.text = "0"

    root.append(folder)
    root.append(filename)
    root.append(path)
    root.append(source)
    root.append(size)
    root.append(segmented)

    for ii in range(len(txt_file)):

        label = convert_label(txt_file[ii][0])
        x_min_rect, x_max_rect, y_min_rect, y_max_rect = extract_coor(
            txt_file[ii], img_width, img_height)

        object = etree.Element("object")
        ####################object - element##################
        name = etree.SubElement(object, "name")
        name.text = "%s" % (label)

        pose = etree.SubElement(object, "pose")
        pose.text = "Unspecified"

        truncated = etree.SubElement(object, "truncated")
        truncated.text = "0"

        difficult = etree.SubElement(object, "difficult")
        difficult.text = "0"

        bndbox = etree.SubElement(object, "bndbox")
        #####sub_sub########
        xmin = etree.SubElement(bndbox, "xmin")
        xmin.text = "%d" % (x_min_rect)
        ymin = etree.SubElement(bndbox, "ymin")
        ymin.text = "%d" % (y_min_rect)
        xmax = etree.SubElement(bndbox, "xmax")
        xmax.text = "%d" % (x_max_rect)
        ymax = etree.SubElement(bndbox, "ymax")
        ymax.text = "%d" % (y_max_rect)
        #####sub_sub########

        root.append(object)
        ####################################################

    file_output = etree.tostring(root, pretty_print=True, encoding='UTF-8')
    # print(file_output.decode('utf-8'))
    ff = open('%s%s.xml' % (save_path, img_name[:-4]), 'w', encoding="utf-8")
    ff.write(file_output.decode('utf-8'))

+ Recent posts