├── README.md ├── __pycache__ ├── car_colour_new.cpython-36.pyc ├── detect_object.cpython-36.pyc ├── speed_check.cpython-36.pyc ├── speed_check_new.cpython-36.pyc └── yolov4inTFNew.cpython-36.pyc ├── app.py ├── app_helper.py ├── app_old.py ├── benchmarks.py ├── car_colour_new.py ├── color_short ├── green │ └── green_0.jpg └── yellow │ └── yellow_0.jpg ├── color_short_output └── green │ └── op_img.jpg ├── command.txt ├── conda-cpu.yml ├── conda-gpu.yml ├── convert_tflite.py ├── convert_trt.py ├── core ├── __pycache__ │ ├── backbone.cpython-36.pyc │ ├── common.cpython-36.pyc │ ├── config.cpython-36.pyc │ ├── utils.cpython-36.pyc │ └── yolov4.cpython-36.pyc ├── backbone.py ├── common.py ├── config.py ├── dataset.py ├── utils.py └── yolov4.py ├── data ├── anchors │ ├── basline_anchors.txt │ ├── basline_tiny_anchors.txt │ ├── yolov3_anchors.txt │ └── yolov4_anchors.txt ├── classes │ ├── coco.names │ ├── license.names │ ├── logo.names │ ├── voc.names │ └── yymnist.names ├── logo.names ├── ss │ ├── dataOutput.png │ ├── result14.jpg │ ├── result15.jpg │ ├── result16.jpg │ ├── result5.png │ ├── result6.jpg │ ├── result7.jpg │ └── result8.jpg ├── yolov4-license.cfg ├── yolov4-logo.cfg └── yolov4.cfg ├── detect.py ├── detect_flask.py ├── detect_object.py ├── detect_video.py ├── evaluate.py ├── mAP ├── extra │ ├── intersect-gt-and-pred.py │ └── remove_space.py └── main.py ├── main.py ├── myhaar.xml ├── new_ocr.py ├── requirements-gpu.txt ├── requirements.txt ├── save_model.py ├── scripts ├── coco_annotation.py ├── coco_convert.py ├── get_coco_dataset_2017.sh ├── google_utils.py ├── voc │ ├── README.md │ ├── get_voc2012.sh │ ├── voc_convert.py │ └── voc_make_names.py └── voc_annotation.py ├── speed_check.py ├── speed_check_new.py ├── static ├── css │ ├── main.css │ └── test.css ├── detections │ ├── data │ │ └── output.csv │ └── speed │ │ └── speed.csv └── img │ ├── images.txt │ └── security-camera.png ├── templates ├── about.html ├── data_done.html ├── index.html ├── layout.html ├── speed.html ├── uploaded copy.html └── uploaded.html └── train.py /README.md: -------------------------------------------------------------------------------- 1 | ## Video Surveillance System 2 | 3 | ### Vehicle Identification and Speed Detection (VISD) 4 | 5 | ### Description: 6 | 7 | VISD extracts vehicle information like License Plate number, Manufacturer and colour from a video and provides this data in the form of a CSV file. VISD can also perform vehicle speed detection on a video. 8 | VISD extracts vehicle information by performing vehicle detection, license plate detection ,logo detection and color detection on frames extracted from the video. Vehicle Detection,license plate detection and logo detection are done using YOLOv4 and color detection is done using pixel method. 9 | Another important feature of VSID is speed detection which is performed using Haarcascade Classifier. 10 | All these features of VSID are provided to the user using a Web Application which is created using Flask (Screenshots included below). 11 | 12 | ### How To Run? 13 | 14 | Download the required Weights File:
15 | 16 |

Pre-Trained YOLOv4 weights : https://drive.google.com/file/d/1OTVtOd3VvCPvw_IHGfINtzZt8OQx4ICn/view?usp=sharing

17 |

License Plate YOLOv4 weights : https://drive.google.com/file/d/1HyLvb-fdGY0FrBxhNm1djGh2nrlNR0T7/view?usp=sharing

18 |

Vehicle Logo YOLOv4 weights : https://drive.google.com/file/d/1nXoFgDE5qhG9DSocsLwm0cXeAPMmAy_o/view?usp=sharing

19 | 20 | Paste all the weights file in /data folder. 21 | 22 | Download the required python modules: 23 | 34 | 35 | Run the main.py file. 36 | Visit 127.0.0.1:7000 on a Web-Browser to access the Web Application. 37 | You can perform Vehicle Data Extraction or Speed Detection by clicking the desired option on the home page. 38 | 39 | ### Screenshots: 40 | 41 |

42 |

43 |

44 |

45 |

46 |

47 |

48 |

49 | 50 | ### Publication: 51 | 52 | Read more about the project at : https://www.jetir.org/papers/JETIR2105673.pdf 53 | 54 | ### Credits: 55 |

The AI Guy : https://github.com/theAIGuysCode

56 | -------------------------------------------------------------------------------- /__pycache__/car_colour_new.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/__pycache__/car_colour_new.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/detect_object.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/__pycache__/detect_object.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/speed_check.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/__pycache__/speed_check.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/speed_check_new.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/__pycache__/speed_check_new.cpython-36.pyc -------------------------------------------------------------------------------- /__pycache__/yolov4inTFNew.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/__pycache__/yolov4inTFNew.cpython-36.pyc -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, Response, request, session, redirect, url_for, send_from_directory, flash 2 | from werkzeug.utils import secure_filename 3 | 4 | from PIL import Image 5 | import os 6 | import sys 7 | import cv2 8 | from yolov4inTFNew import get_image_data 9 | 10 | app = Flask(__name__) 11 | UPLOAD_FOLDER = './static/uploads' 12 | app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER 13 | 14 | @app.route("/") 15 | def index(): 16 | return render_template("index.html") 17 | 18 | @app.route("/about") 19 | def about(): 20 | return render_template("about.html") 21 | 22 | @app.route('/uploader', methods = ['GET', 'POST']) 23 | def upload_file(): 24 | if request.method == 'POST': 25 | f = request.files['file'] 26 | # create a secure filename 27 | filename = secure_filename(f.filename) 28 | print(filename) 29 | # save file to /static/uploads 30 | filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) 31 | print(filepath) 32 | f.save(filepath) 33 | # logo, lp_text = get_image_data(filepath) 34 | 35 | return render_template("uploaded.html", fname=filename,detected_logo=logo, detected_lp_text=lp_text) 36 | 37 | if __name__ == '__main__': 38 | app.run(port=4000, debug=True) 39 | -------------------------------------------------------------------------------- /app_helper.py: -------------------------------------------------------------------------------- 1 | import time 2 | from absl import app, logging 3 | import cv2 4 | import numpy as np 5 | import tensorflow as tf 6 | from yolov3_tf2.models import ( 7 | YoloV3, YoloV3Tiny 8 | ) 9 | from yolov3_tf2.dataset import transform_images, load_tfrecord_dataset 10 | from yolov3_tf2.utils import draw_outputs 11 | from flask import Flask, request, Response, jsonify, send_from_directory, abort 12 | import os 13 | import imageio 14 | 15 | def get_image(image_path , img_name): 16 | classes_path = './data/labels/coco.names' 17 | weights_path = './weights/yolov3.tf' 18 | tiny = False 19 | size = 416 20 | output_path = './static/detections/' 21 | num_classes = 80 22 | 23 | # load in weights and classes 24 | physical_devices = tf.config.experimental.list_physical_devices('GPU') 25 | if len(physical_devices) > 0: 26 | tf.config.experimental.set_memory_growth(physical_devices[0], True) 27 | 28 | if tiny: 29 | yolo = YoloV3Tiny(classes=num_classes) 30 | else: 31 | yolo = YoloV3(classes=num_classes) 32 | 33 | yolo.load_weights(weights_path).expect_partial() 34 | print('weights loaded') 35 | 36 | class_names = [c.strip() for c in open(classes_path).readlines()] 37 | print('classes loaded') 38 | #reading the images & apply detection with loaded weight file 39 | image = imageio.imread(image_path) 40 | filename = img_name 41 | img_raw = tf.image.decode_image( 42 | open(image_path, 'rb').read(), channels=3) 43 | img = tf.expand_dims(img_raw, 0) 44 | img = transform_images(img, size) 45 | 46 | t1 = time.time() 47 | boxes, scores, classes, nums = yolo(img) 48 | t2 = time.time() 49 | print('time: {}'.format(t2 - t1)) 50 | 51 | print('detections:') 52 | for i in range(nums[0]): 53 | print('\t{}, {}, {}'.format(class_names[int(classes[0][i])], 54 | np.array(scores[0][i]), 55 | np.array(boxes[0][i]))) 56 | img = cv2.cvtColor(img_raw.numpy(), cv2.COLOR_RGB2BGR) 57 | img = draw_outputs(img, (boxes, scores, classes, nums), class_names) 58 | cv2.imwrite(output_path + '{}' .format(filename), img) 59 | print('output saved to: {}'.format(output_path + '{}'.format(filename))) -------------------------------------------------------------------------------- /app_old.py: -------------------------------------------------------------------------------- 1 | from __future__ import division, print_function 2 | # coding=utf-8 3 | import sys 4 | import os 5 | import glob 6 | import re 7 | import glob 8 | import os 9 | import cv2 10 | import numpy as np 11 | import pandas as pd 12 | import detect_object 13 | from shutil import copyfile 14 | import shutil 15 | from distutils.dir_util import copy_tree 16 | 17 | # Flask utils 18 | from flask import Flask, redirect, url_for, request, render_template 19 | from werkzeug.utils import secure_filename 20 | from gevent.pywsgi import WSGIServer 21 | 22 | # Define a flask app 23 | app = Flask(__name__) 24 | 25 | for f in os.listdir("static\\similar_images\\"): 26 | os.remove("static\\similar_images\\"+f) 27 | 28 | print('Model loaded. Check http://127.0.0.1:5000/') 29 | 30 | 31 | @app.route('/', methods=['GET']) 32 | def index(): 33 | # Main page 34 | return render_template('index.html') 35 | 36 | 37 | @app.route('/predict', methods=['GET', 'POST']) 38 | def upload(): 39 | if request.method == 'POST': 40 | # Get the file from post request 41 | f = request.files['file'] 42 | 43 | # Save the file to ./uploads 44 | basepath = os.path.dirname(__file__) 45 | file_path = os.path.join( 46 | basepath, 'uploads', secure_filename(f.filename)) 47 | f.save(file_path) 48 | 49 | # Make prediction 50 | get_detected_object = detect_object(file_path) 51 | return get_detected_object 52 | return None 53 | 54 | 55 | if __name__ == '__main__': 56 | app.run(debug=True) 57 | -------------------------------------------------------------------------------- /benchmarks.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | import time 4 | import cv2 5 | from core.yolov4 import YOLOv4, YOLOv3_tiny, YOLOv3, decode 6 | from absl import app, flags, logging 7 | from absl.flags import FLAGS 8 | from tensorflow.python.saved_model import tag_constants 9 | from core import utils 10 | from core.config import cfg 11 | from tensorflow.compat.v1 import ConfigProto 12 | from tensorflow.compat.v1 import InteractiveSession 13 | 14 | flags.DEFINE_boolean('tiny', False, 'yolo or yolo-tiny') 15 | flags.DEFINE_string('framework', 'tf', '(tf, tflite, trt') 16 | flags.DEFINE_string('model', 'yolov4', 'yolov3 or yolov4') 17 | flags.DEFINE_string('weights', './data/yolov4.weights', 'path to weights file') 18 | flags.DEFINE_string('images', './data/images/kite.jpg', 'path to input image') 19 | flags.DEFINE_integer('size', 416, 'resize images to') 20 | 21 | 22 | def main(_argv): 23 | if FLAGS.tiny: 24 | STRIDES = np.array(cfg.YOLO.STRIDES_TINY) 25 | ANCHORS = utils.get_anchors(cfg.YOLO.ANCHORS_TINY, FLAGS.tiny) 26 | else: 27 | STRIDES = np.array(cfg.YOLO.STRIDES) 28 | if FLAGS.model == 'yolov4': 29 | ANCHORS = utils.get_anchors(cfg.YOLO.ANCHORS, FLAGS.tiny) 30 | else: 31 | ANCHORS = utils.get_anchors(cfg.YOLO.ANCHORS_V3, FLAGS.tiny) 32 | NUM_CLASS = len(utils.read_class_names(cfg.YOLO.CLASSES)) 33 | XYSCALE = cfg.YOLO.XYSCALE 34 | 35 | config = ConfigProto() 36 | config.gpu_options.allow_growth = True 37 | session = InteractiveSession(config=config) 38 | input_size = FLAGS.size 39 | physical_devices = tf.config.experimental.list_physical_devices('GPU') 40 | if len(physical_devices) > 0: 41 | tf.config.experimental.set_memory_growth(physical_devices[0], True) 42 | if FLAGS.framework == 'tf': 43 | input_layer = tf.keras.layers.Input([input_size, input_size, 3]) 44 | if FLAGS.tiny: 45 | feature_maps = YOLOv3_tiny(input_layer, NUM_CLASS) 46 | bbox_tensors = [] 47 | for i, fm in enumerate(feature_maps): 48 | bbox_tensor = decode(fm, NUM_CLASS, i) 49 | bbox_tensors.append(bbox_tensor) 50 | model = tf.keras.Model(input_layer, bbox_tensors) 51 | utils.load_weights_tiny(model, FLAGS.weights) 52 | else: 53 | if FLAGS.model == 'yolov3': 54 | feature_maps = YOLOv3(input_layer, NUM_CLASS) 55 | bbox_tensors = [] 56 | for i, fm in enumerate(feature_maps): 57 | bbox_tensor = decode(fm, NUM_CLASS, i) 58 | bbox_tensors.append(bbox_tensor) 59 | model = tf.keras.Model(input_layer, bbox_tensors) 60 | utils.load_weights_v3(model, FLAGS.weights) 61 | elif FLAGS.model == 'yolov4': 62 | feature_maps = YOLOv4(input_layer, NUM_CLASS) 63 | bbox_tensors = [] 64 | for i, fm in enumerate(feature_maps): 65 | bbox_tensor = decode(fm, NUM_CLASS, i) 66 | bbox_tensors.append(bbox_tensor) 67 | model = tf.keras.Model(input_layer, bbox_tensors) 68 | utils.load_weights(model, FLAGS.weights) 69 | elif FLAGS.framework == 'trt': 70 | saved_model_loaded = tf.saved_model.load(FLAGS.weights, tags=[tag_constants.SERVING]) 71 | signature_keys = list(saved_model_loaded.signatures.keys()) 72 | print(signature_keys) 73 | infer = saved_model_loaded.signatures['serving_default'] 74 | 75 | logging.info('weights loaded') 76 | 77 | @tf.function 78 | def run_model(x): 79 | return model(x) 80 | 81 | # Test the TensorFlow Lite model on random input data. 82 | sum = 0 83 | original_image = cv2.imread(FLAGS.image) 84 | original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB) 85 | original_image_size = original_image.shape[:2] 86 | image_data = utils.image_preprocess(np.copy(original_image), [FLAGS.size, FLAGS.size]) 87 | image_data = image_data[np.newaxis, ...].astype(np.float32) 88 | img_raw = tf.image.decode_image( 89 | open(FLAGS.image, 'rb').read(), channels=3) 90 | img_raw = tf.expand_dims(img_raw, 0) 91 | img_raw = tf.image.resize(img_raw, (FLAGS.size, FLAGS.size)) 92 | batched_input = tf.constant(image_data) 93 | for i in range(1000): 94 | prev_time = time.time() 95 | # pred_bbox = model.predict(image_data) 96 | if FLAGS.framework == 'tf': 97 | pred_bbox = [] 98 | result = run_model(image_data) 99 | for value in result: 100 | value = value.numpy() 101 | pred_bbox.append(value) 102 | if FLAGS.model == 'yolov4': 103 | pred_bbox = utils.postprocess_bbbox(pred_bbox, ANCHORS, STRIDES, XYSCALE) 104 | else: 105 | pred_bbox = utils.postprocess_bbbox(pred_bbox, ANCHORS, STRIDES) 106 | bboxes = utils.postprocess_boxes(pred_bbox, original_image_size, input_size, 0.25) 107 | bboxes = utils.nms(bboxes, 0.213, method='nms') 108 | elif FLAGS.framework == 'trt': 109 | pred_bbox = [] 110 | result = infer(batched_input) 111 | for key, value in result.items(): 112 | value = value.numpy() 113 | pred_bbox.append(value) 114 | if FLAGS.model == 'yolov4': 115 | pred_bbox = utils.postprocess_bbbox(pred_bbox, ANCHORS, STRIDES, XYSCALE) 116 | else: 117 | pred_bbox = utils.postprocess_bbbox(pred_bbox, ANCHORS, STRIDES) 118 | bboxes = utils.postprocess_boxes(pred_bbox, original_image_size, input_size, 0.25) 119 | bboxes = utils.nms(bboxes, 0.213, method='nms') 120 | # pred_bbox = pred_bbox.numpy() 121 | curr_time = time.time() 122 | exec_time = curr_time - prev_time 123 | if i == 0: continue 124 | sum += (1 / exec_time) 125 | info = str(i) + " time:" + str(round(exec_time, 3)) + " average FPS:" + str(round(sum / i, 2)) + ", FPS: " + str( 126 | round((1 / exec_time), 1)) 127 | print(info) 128 | 129 | 130 | if __name__ == '__main__': 131 | try: 132 | app.run(main) 133 | except SystemExit: 134 | pass 135 | -------------------------------------------------------------------------------- /car_colour_new.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import cv2 3 | import os 4 | import numpy as np 5 | from PIL import Image 6 | 7 | class Channel_value: 8 | val = -1.0 9 | intensity = -1.0 10 | 11 | def atmospheric_light(img, gray): 12 | top_num = int(img.shape[0] * img.shape[1] * 0.001) 13 | toplist = [Channel_value()] * top_num 14 | dark_channel = dark_channel_find(img) 15 | 16 | for y in range(img.shape[0]): 17 | for x in range(img.shape[1]): 18 | val = img.item(y, x, dark_channel) 19 | intensity = gray.item(y, x) 20 | for t in toplist: 21 | if t.val < val or (t.val == val and t.intensity < intensity): 22 | t.val = val 23 | t.intensity = intensity 24 | break 25 | max_channel = Channel_value() 26 | for t in toplist: 27 | if t.intensity > max_channel.intensity: 28 | max_channel = t 29 | return max_channel.intensity 30 | 31 | #Finding the dark channel i.e. the pixel with the lowest R/G/B value 32 | def dark_channel_find(img): 33 | return np.unravel_index(np.argmin(img), img.shape)[2] 34 | 35 | #Finding a coarse image which gives us a transmission map 36 | def coarse(minimum, x, maximum): 37 | return max(minimum, min(x, maximum)) 38 | 39 | #Uses values from other functions to aggregate and give us a clear image 40 | def dehaze(img, light_intensity, windowSize, t0, w): 41 | size = (img.shape[0], img.shape[1]) 42 | 43 | outimg = np.zeros(img.shape, img.dtype) 44 | 45 | for y in range(size[0]): 46 | for x in range(size[1]): 47 | x_low = max(x-(windowSize//2), 0) 48 | y_low = max(y-(windowSize//2), 0) 49 | x_high = min(x+(windowSize//2), size[1]) 50 | y_high = min(y+(windowSize//2), size[0]) 51 | 52 | sliceimg = img[y_low:y_high, x_low:x_high] 53 | 54 | dark_channel = dark_channel_find(sliceimg) 55 | t = 1.0 - (w * img.item(y, x, dark_channel) / light_intensity) 56 | 57 | outimg.itemset((y,x,0), coarse(0, ((img.item(y,x,0) - light_intensity) / max(t, t0) + light_intensity), 255)) 58 | outimg.itemset((y,x,1), coarse(0, ((img.item(y,x,1) - light_intensity) / max(t, t0) + light_intensity), 255)) 59 | outimg.itemset((y,x,2), coarse(0, ((img.item(y,x,2) - light_intensity) / max(t, t0) + light_intensity), 255)) 60 | return outimg 61 | 62 | # Commented out IPython magic to ensure Python compatibility. 63 | # %pylab inline 64 | import matplotlib.pyplot as plt 65 | import matplotlib.image as mpimg 66 | 67 | def main(): 68 | d="./color_short" 69 | cd="./color_short_output" 70 | folder=os.listdir(d) 71 | for fold in folder: 72 | # print(fold) 73 | files=os.listdir(os.path.join(d,fold)) 74 | for f in files: 75 | # print(f) 76 | img = cv2.imread(os.path.join(d,fold,f)) 77 | imgplot = plt.imshow(img) 78 | plt.show() 79 | 80 | img = np.array(img, dtype=np.uint8) 81 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 82 | light_intensity = atmospheric_light(img, gray) 83 | w = 0.95 84 | t0 = 0.55 85 | outimg = dehaze(img, light_intensity, 20, t0, w) 86 | name = os.path.join(cd,fold,f) 87 | imgplot = plt.imshow(outimg) 88 | plt.show() 89 | # print(name) 90 | cv2.imwrite(name, outimg) 91 | 92 | # main() 93 | 94 | import matplotlib.pyplot as plt 95 | from PIL import Image 96 | 97 | class Colors(object): 98 | class Color(object): 99 | def __init__(self, value): 100 | self.value = value 101 | 102 | def __str__(self): 103 | return "%s : %s" % (self.__class__.__name__, self.value) 104 | 105 | class Red(Color): pass 106 | class Blue(Color): pass 107 | class Green(Color): pass 108 | class Yellow(Color): pass 109 | class White(Color): pass 110 | class Gray(Color): pass 111 | class Black(Color): pass 112 | class Pink(Color): pass 113 | class Teal(Color): pass 114 | 115 | class ColorWheel(object): 116 | def __init__(self, rgb): 117 | r, g, b = rgb 118 | 119 | self.rgb = (Colors.Red(r), Colors.Green(g), Colors.Blue(b), ) 120 | 121 | 122 | def estimate_color(self): 123 | dominant_colors = self.get_dominant_colors() 124 | 125 | total_colors = len(dominant_colors) 126 | 127 | if total_colors == 1: 128 | return dominant_colors[0] 129 | elif total_colors == 2: 130 | color_classes = [x.__class__ for x in dominant_colors] 131 | 132 | if Colors.Red in color_classes and Colors.Green in color_classes: 133 | return Colors.Yellow(dominant_colors[0].value) 134 | elif Colors.Red in color_classes and Colors.Blue in color_classes: 135 | return Colors.Pink(dominant_colors[0].value) 136 | elif Colors.Blue in color_classes and Colors.Green in color_classes: 137 | return Colors.Teal(dominant_colors[0].value) 138 | elif total_colors == 3: 139 | if dominant_colors[0].value > 200: 140 | return Colors.White(dominant_colors[0].value) 141 | elif dominant_colors[0].value > 100: 142 | return Colors.Gray(dominant_colors[0].value) 143 | else: 144 | return Colors.Black(dominant_colors[0].value) 145 | else: 146 | print("Dominant Colors : %s" % dominant_colors) 147 | 148 | def get_dominant_colors(self): 149 | max_color = max([x.value for x in self.rgb]) 150 | 151 | return [x for x in self.rgb if x.value >= max_color * .9] 152 | 153 | def process_image(image): 154 | d={} 155 | image_color_quantities = {} 156 | width, height = image.size 157 | # print(image.size) 158 | 159 | 160 | width_margin = int(width - (width * .65)) 161 | height_margin = int(height - (height * .65)) 162 | # print(width_margin,height_margin) 163 | for x in range(width_margin, width - width_margin): 164 | for y in range(height_margin, height - height_margin): 165 | r, g, b = image.getpixel((x, y)) 166 | 167 | key = "%s:%s:%s" % (r, g, b, ) 168 | 169 | key = (r, g, b, ) 170 | 171 | image_color_quantities[key] = image_color_quantities.get(key, 0) + 1 172 | 173 | total_assessed_pixels = sum([v for k, v in image_color_quantities.items() if v > 10]) 174 | 175 | strongest_color_wheels = [(ColorWheel(k), v / float(total_assessed_pixels) * 100, ) for k, v in image_color_quantities.items() if v > 10] 176 | final_colors = {} 177 | 178 | for color_wheel, strength in strongest_color_wheels: 179 | color = color_wheel.estimate_color() 180 | 181 | final_colors[color.__class__] = final_colors.get(color.__class__, 0) + strength 182 | 183 | for color, strength in final_colors.items(): 184 | d[color.__name__]=strength 185 | return d 186 | 187 | import matplotlib.pyplot as plt 188 | import matplotlib.image as mpimg 189 | 190 | 191 | def get_car_colour(path): 192 | # image = cv2.imread(path) 193 | # img = np.array(image, dtype=np.uint8) 194 | # gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 195 | # light_intensity = atmospheric_light(img, gray) 196 | # w = 0.95 197 | # t0 = 0.55 198 | # outimg = dehaze(img, light_intensity, 20, t0, w) 199 | # op_folder = "./color_short_output/green" 200 | # cv2.imwrite(os.path.join(op_folder, 'op_img.jpg'), outimg) 201 | # outimg = Image.open(os.path.join(op_folder, 'op_img.jpg')) 202 | # d = process_image(outimg) 203 | 204 | image = Image.open(path) 205 | d = process_image(image) 206 | 207 | # print(d) 208 | 209 | colour = max(d, key=d.get) 210 | return(colour) 211 | -------------------------------------------------------------------------------- /color_short/green/green_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/color_short/green/green_0.jpg -------------------------------------------------------------------------------- /color_short/yellow/yellow_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/color_short/yellow/yellow_0.jpg -------------------------------------------------------------------------------- /color_short_output/green/op_img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/color_short_output/green/op_img.jpg -------------------------------------------------------------------------------- /command.txt: -------------------------------------------------------------------------------- 1 | curl.exe -X POST -F image=@suz.jpg "http://localhost:5000/api/test" --output output.png -------------------------------------------------------------------------------- /conda-cpu.yml: -------------------------------------------------------------------------------- 1 | name: yolov4-cpu 2 | 3 | dependencies: 4 | - python==3.7 5 | - pip 6 | - matplotlib 7 | - opencv 8 | - pip: 9 | - opencv-python==4.1.1.26 10 | - lxml 11 | - tqdm 12 | - tensorflow==2.3.0rc0 13 | - absl-py 14 | - easydict 15 | - pillow -------------------------------------------------------------------------------- /conda-gpu.yml: -------------------------------------------------------------------------------- 1 | name: yolov4-gpu 2 | 3 | dependencies: 4 | - python==3.7 5 | - pip 6 | - matplotlib 7 | - opencv 8 | - cudnn 9 | - cudatoolkit==10.1.243 10 | - pip: 11 | - tensorflow-gpu==2.3.0rc0 12 | - opencv-python==4.1.1.26 13 | - lxml 14 | - tqdm 15 | - absl-py 16 | - easydict 17 | - pillow 18 | -------------------------------------------------------------------------------- /convert_tflite.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from absl import app, flags, logging 3 | from absl.flags import FLAGS 4 | import numpy as np 5 | import cv2 6 | from core.yolov4 import YOLOv4, YOLOv3, YOLOv3_tiny, decode 7 | import core.utils as utils 8 | import os 9 | from core.config import cfg 10 | 11 | flags.DEFINE_string('weights', './checkpoints/yolov4-416', 'path to weights file') 12 | flags.DEFINE_string('output', './checkpoints/yolov4-416-fp32.tflite', 'path to output') 13 | flags.DEFINE_integer('input_size', 416, 'path to output') 14 | flags.DEFINE_string('quantize_mode', 'float32', 'quantize mode (int8, float16, float32)') 15 | flags.DEFINE_string('dataset', "/Volumes/Elements/data/coco_dataset/coco/5k.txt", 'path to dataset') 16 | 17 | def representative_data_gen(): 18 | fimage = open(FLAGS.dataset).read().split() 19 | for input_value in range(10): 20 | if os.path.exists(fimage[input_value]): 21 | original_image=cv2.imread(fimage[input_value]) 22 | original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB) 23 | image_data = utils.image_preprocess(np.copy(original_image), [FLAGS.input_size, FLAGS.input_size]) 24 | img_in = image_data[np.newaxis, ...].astype(np.float32) 25 | print("calibration image {}".format(fimage[input_value])) 26 | yield [img_in] 27 | else: 28 | continue 29 | 30 | def save_tflite(): 31 | converter = tf.lite.TFLiteConverter.from_saved_model(FLAGS.weights) 32 | 33 | if FLAGS.quantize_mode == 'float16': 34 | converter.optimizations = [tf.lite.Optimize.DEFAULT] 35 | converter.target_spec.supported_types = [tf.compat.v1.lite.constants.FLOAT16] 36 | converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS] 37 | converter.allow_custom_ops = True 38 | elif FLAGS.quantize_mode == 'int8': 39 | converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] 40 | converter.optimizations = [tf.lite.Optimize.DEFAULT] 41 | converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS] 42 | converter.allow_custom_ops = True 43 | converter.representative_dataset = representative_data_gen 44 | 45 | tflite_model = converter.convert() 46 | open(FLAGS.output, 'wb').write(tflite_model) 47 | 48 | logging.info("model saved to: {}".format(FLAGS.output)) 49 | 50 | def demo(): 51 | interpreter = tf.lite.Interpreter(model_path=FLAGS.output) 52 | interpreter.allocate_tensors() 53 | logging.info('tflite model loaded') 54 | 55 | input_details = interpreter.get_input_details() 56 | print(input_details) 57 | output_details = interpreter.get_output_details() 58 | print(output_details) 59 | 60 | input_shape = input_details[0]['shape'] 61 | 62 | input_data = np.array(np.random.random_sample(input_shape), dtype=np.float32) 63 | 64 | interpreter.set_tensor(input_details[0]['index'], input_data) 65 | interpreter.invoke() 66 | output_data = [interpreter.get_tensor(output_details[i]['index']) for i in range(len(output_details))] 67 | 68 | print(output_data) 69 | 70 | def main(_argv): 71 | save_tflite() 72 | demo() 73 | 74 | if __name__ == '__main__': 75 | try: 76 | app.run(main) 77 | except SystemExit: 78 | pass 79 | 80 | 81 | -------------------------------------------------------------------------------- /convert_trt.py: -------------------------------------------------------------------------------- 1 | from absl import app, flags, logging 2 | from absl.flags import FLAGS 3 | import tensorflow as tf 4 | physical_devices = tf.config.experimental.list_physical_devices('GPU') 5 | if len(physical_devices) > 0: 6 | tf.config.experimental.set_memory_growth(physical_devices[0], True) 7 | import numpy as np 8 | import cv2 9 | from tensorflow.python.compiler.tensorrt import trt_convert as trt 10 | import core.utils as utils 11 | from tensorflow.python.saved_model import signature_constants 12 | import os 13 | from tensorflow.compat.v1 import ConfigProto 14 | from tensorflow.compat.v1 import InteractiveSession 15 | 16 | flags.DEFINE_string('weights', './checkpoints/yolov4-416', 'path to weights file') 17 | flags.DEFINE_string('output', './checkpoints/yolov4-trt-fp16-416', 'path to output') 18 | flags.DEFINE_integer('input_size', 416, 'path to output') 19 | flags.DEFINE_string('quantize_mode', 'float16', 'quantize mode (int8, float16)') 20 | flags.DEFINE_string('dataset', "/media/user/Source/Data/coco_dataset/coco/5k.txt", 'path to dataset') 21 | flags.DEFINE_integer('loop', 8, 'loop') 22 | 23 | def representative_data_gen(): 24 | fimage = open(FLAGS.dataset).read().split() 25 | batched_input = np.zeros((FLAGS.loop, FLAGS.input_size, FLAGS.input_size, 3), dtype=np.float32) 26 | for input_value in range(FLAGS.loop): 27 | if os.path.exists(fimage[input_value]): 28 | original_image=cv2.imread(fimage[input_value]) 29 | original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB) 30 | image_data = utils.image_preporcess(np.copy(original_image), [FLAGS.input_size, FLAGS.input_size]) 31 | img_in = image_data[np.newaxis, ...].astype(np.float32) 32 | batched_input[input_value, :] = img_in 33 | # batched_input = tf.constant(img_in) 34 | print(input_value) 35 | # yield (batched_input, ) 36 | # yield tf.random.normal((1, 416, 416, 3)), 37 | else: 38 | continue 39 | batched_input = tf.constant(batched_input) 40 | yield (batched_input,) 41 | 42 | def save_trt(): 43 | 44 | if FLAGS.quantize_mode == 'int8': 45 | conversion_params = trt.DEFAULT_TRT_CONVERSION_PARAMS._replace( 46 | precision_mode=trt.TrtPrecisionMode.INT8, 47 | max_workspace_size_bytes=4000000000, 48 | use_calibration=True, 49 | max_batch_size=8) 50 | converter = trt.TrtGraphConverterV2( 51 | input_saved_model_dir=FLAGS.weights, 52 | conversion_params=conversion_params) 53 | converter.convert(calibration_input_fn=representative_data_gen) 54 | elif FLAGS.quantize_mode == 'float16': 55 | conversion_params = trt.DEFAULT_TRT_CONVERSION_PARAMS._replace( 56 | precision_mode=trt.TrtPrecisionMode.FP16, 57 | max_workspace_size_bytes=4000000000, 58 | max_batch_size=8) 59 | converter = trt.TrtGraphConverterV2( 60 | input_saved_model_dir=FLAGS.weights, conversion_params=conversion_params) 61 | converter.convert() 62 | else : 63 | conversion_params = trt.DEFAULT_TRT_CONVERSION_PARAMS._replace( 64 | precision_mode=trt.TrtPrecisionMode.FP32, 65 | max_workspace_size_bytes=4000000000, 66 | max_batch_size=8) 67 | converter = trt.TrtGraphConverterV2( 68 | input_saved_model_dir=FLAGS.weights, conversion_params=conversion_params) 69 | converter.convert() 70 | 71 | # converter.build(input_fn=representative_data_gen) 72 | converter.save(output_saved_model_dir=FLAGS.output) 73 | print('Done Converting to TF-TRT') 74 | 75 | saved_model_loaded = tf.saved_model.load(FLAGS.output) 76 | graph_func = saved_model_loaded.signatures[ 77 | signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY] 78 | trt_graph = graph_func.graph.as_graph_def() 79 | for n in trt_graph.node: 80 | print(n.op) 81 | if n.op == "TRTEngineOp": 82 | print("Node: %s, %s" % (n.op, n.name.replace("/", "_"))) 83 | else: 84 | print("Exclude Node: %s, %s" % (n.op, n.name.replace("/", "_"))) 85 | logging.info("model saved to: {}".format(FLAGS.output)) 86 | 87 | trt_engine_nodes = len([1 for n in trt_graph.node if str(n.op) == 'TRTEngineOp']) 88 | print("numb. of trt_engine_nodes in TensorRT graph:", trt_engine_nodes) 89 | all_nodes = len([1 for n in trt_graph.node]) 90 | print("numb. of all_nodes in TensorRT graph:", all_nodes) 91 | 92 | def main(_argv): 93 | config = ConfigProto() 94 | config.gpu_options.allow_growth = True 95 | session = InteractiveSession(config=config) 96 | save_trt() 97 | 98 | if __name__ == '__main__': 99 | try: 100 | app.run(main) 101 | except SystemExit: 102 | pass 103 | 104 | 105 | -------------------------------------------------------------------------------- /core/__pycache__/backbone.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/core/__pycache__/backbone.cpython-36.pyc -------------------------------------------------------------------------------- /core/__pycache__/common.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/core/__pycache__/common.cpython-36.pyc -------------------------------------------------------------------------------- /core/__pycache__/config.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/core/__pycache__/config.cpython-36.pyc -------------------------------------------------------------------------------- /core/__pycache__/utils.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/core/__pycache__/utils.cpython-36.pyc -------------------------------------------------------------------------------- /core/__pycache__/yolov4.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/core/__pycache__/yolov4.cpython-36.pyc -------------------------------------------------------------------------------- /core/backbone.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # coding=utf-8 3 | 4 | import tensorflow as tf 5 | import core.common as common 6 | 7 | def darknet53(input_data): 8 | 9 | input_data = common.convolutional(input_data, (3, 3, 3, 32)) 10 | input_data = common.convolutional(input_data, (3, 3, 32, 64), downsample=True) 11 | 12 | for i in range(1): 13 | input_data = common.residual_block(input_data, 64, 32, 64) 14 | 15 | input_data = common.convolutional(input_data, (3, 3, 64, 128), downsample=True) 16 | 17 | for i in range(2): 18 | input_data = common.residual_block(input_data, 128, 64, 128) 19 | 20 | input_data = common.convolutional(input_data, (3, 3, 128, 256), downsample=True) 21 | 22 | for i in range(8): 23 | input_data = common.residual_block(input_data, 256, 128, 256) 24 | 25 | route_1 = input_data 26 | input_data = common.convolutional(input_data, (3, 3, 256, 512), downsample=True) 27 | 28 | for i in range(8): 29 | input_data = common.residual_block(input_data, 512, 256, 512) 30 | 31 | route_2 = input_data 32 | input_data = common.convolutional(input_data, (3, 3, 512, 1024), downsample=True) 33 | 34 | for i in range(4): 35 | input_data = common.residual_block(input_data, 1024, 512, 1024) 36 | 37 | return route_1, route_2, input_data 38 | 39 | def cspdarknet53(input_data): 40 | 41 | input_data = common.convolutional(input_data, (3, 3, 3, 32), activate_type="mish") 42 | input_data = common.convolutional(input_data, (3, 3, 32, 64), downsample=True, activate_type="mish") 43 | 44 | route = input_data 45 | route = common.convolutional(route, (1, 1, 64, 64), activate_type="mish") 46 | input_data = common.convolutional(input_data, (1, 1, 64, 64), activate_type="mish") 47 | for i in range(1): 48 | input_data = common.residual_block(input_data, 64, 32, 64, activate_type="mish") 49 | input_data = common.convolutional(input_data, (1, 1, 64, 64), activate_type="mish") 50 | 51 | input_data = tf.concat([input_data, route], axis=-1) 52 | input_data = common.convolutional(input_data, (1, 1, 128, 64), activate_type="mish") 53 | input_data = common.convolutional(input_data, (3, 3, 64, 128), downsample=True, activate_type="mish") 54 | route = input_data 55 | route = common.convolutional(route, (1, 1, 128, 64), activate_type="mish") 56 | input_data = common.convolutional(input_data, (1, 1, 128, 64), activate_type="mish") 57 | for i in range(2): 58 | input_data = common.residual_block(input_data, 64, 64, 64, activate_type="mish") 59 | input_data = common.convolutional(input_data, (1, 1, 64, 64), activate_type="mish") 60 | input_data = tf.concat([input_data, route], axis=-1) 61 | 62 | input_data = common.convolutional(input_data, (1, 1, 128, 128), activate_type="mish") 63 | input_data = common.convolutional(input_data, (3, 3, 128, 256), downsample=True, activate_type="mish") 64 | route = input_data 65 | route = common.convolutional(route, (1, 1, 256, 128), activate_type="mish") 66 | input_data = common.convolutional(input_data, (1, 1, 256, 128), activate_type="mish") 67 | for i in range(8): 68 | input_data = common.residual_block(input_data, 128, 128, 128, activate_type="mish") 69 | input_data = common.convolutional(input_data, (1, 1, 128, 128), activate_type="mish") 70 | input_data = tf.concat([input_data, route], axis=-1) 71 | 72 | input_data = common.convolutional(input_data, (1, 1, 256, 256), activate_type="mish") 73 | route_1 = input_data 74 | input_data = common.convolutional(input_data, (3, 3, 256, 512), downsample=True, activate_type="mish") 75 | route = input_data 76 | route = common.convolutional(route, (1, 1, 512, 256), activate_type="mish") 77 | input_data = common.convolutional(input_data, (1, 1, 512, 256), activate_type="mish") 78 | for i in range(8): 79 | input_data = common.residual_block(input_data, 256, 256, 256, activate_type="mish") 80 | input_data = common.convolutional(input_data, (1, 1, 256, 256), activate_type="mish") 81 | input_data = tf.concat([input_data, route], axis=-1) 82 | 83 | input_data = common.convolutional(input_data, (1, 1, 512, 512), activate_type="mish") 84 | route_2 = input_data 85 | input_data = common.convolutional(input_data, (3, 3, 512, 1024), downsample=True, activate_type="mish") 86 | route = input_data 87 | route = common.convolutional(route, (1, 1, 1024, 512), activate_type="mish") 88 | input_data = common.convolutional(input_data, (1, 1, 1024, 512), activate_type="mish") 89 | for i in range(4): 90 | input_data = common.residual_block(input_data, 512, 512, 512, activate_type="mish") 91 | input_data = common.convolutional(input_data, (1, 1, 512, 512), activate_type="mish") 92 | input_data = tf.concat([input_data, route], axis=-1) 93 | 94 | input_data = common.convolutional(input_data, (1, 1, 1024, 1024), activate_type="mish") 95 | input_data = common.convolutional(input_data, (1, 1, 1024, 512)) 96 | input_data = common.convolutional(input_data, (3, 3, 512, 1024)) 97 | input_data = common.convolutional(input_data, (1, 1, 1024, 512)) 98 | 99 | input_data = tf.concat([tf.nn.max_pool(input_data, ksize=13, padding='SAME', strides=1), tf.nn.max_pool(input_data, ksize=9, padding='SAME', strides=1) 100 | , tf.nn.max_pool(input_data, ksize=5, padding='SAME', strides=1), input_data], axis=-1) 101 | input_data = common.convolutional(input_data, (1, 1, 2048, 512)) 102 | input_data = common.convolutional(input_data, (3, 3, 512, 1024)) 103 | input_data = common.convolutional(input_data, (1, 1, 1024, 512)) 104 | 105 | return route_1, route_2, input_data 106 | 107 | def cspdarknet53_tiny(input_data): 108 | input_data = common.convolutional(input_data, (3, 3, 3, 32), downsample=True) 109 | input_data = common.convolutional(input_data, (3, 3, 32, 64), downsample=True) 110 | input_data = common.convolutional(input_data, (3, 3, 64, 64)) 111 | 112 | route = input_data 113 | input_data = common.route_group(input_data, 2, 1) 114 | input_data = common.convolutional(input_data, (3, 3, 32, 32)) 115 | route_1 = input_data 116 | input_data = common.convolutional(input_data, (3, 3, 32, 32)) 117 | input_data = tf.concat([input_data, route_1], axis=-1) 118 | input_data = common.convolutional(input_data, (1, 1, 32, 64)) 119 | input_data = tf.concat([route, input_data], axis=-1) 120 | input_data = tf.keras.layers.MaxPool2D(2, 2, 'same')(input_data) 121 | 122 | input_data = common.convolutional(input_data, (3, 3, 64, 128)) 123 | route = input_data 124 | input_data = common.route_group(input_data, 2, 1) 125 | input_data = common.convolutional(input_data, (3, 3, 64, 64)) 126 | route_1 = input_data 127 | input_data = common.convolutional(input_data, (3, 3, 64, 64)) 128 | input_data = tf.concat([input_data, route_1], axis=-1) 129 | input_data = common.convolutional(input_data, (1, 1, 64, 128)) 130 | input_data = tf.concat([route, input_data], axis=-1) 131 | input_data = tf.keras.layers.MaxPool2D(2, 2, 'same')(input_data) 132 | 133 | input_data = common.convolutional(input_data, (3, 3, 128, 256)) 134 | route = input_data 135 | input_data = common.route_group(input_data, 2, 1) 136 | input_data = common.convolutional(input_data, (3, 3, 128, 128)) 137 | route_1 = input_data 138 | input_data = common.convolutional(input_data, (3, 3, 128, 128)) 139 | input_data = tf.concat([input_data, route_1], axis=-1) 140 | input_data = common.convolutional(input_data, (1, 1, 128, 256)) 141 | route_1 = input_data 142 | input_data = tf.concat([route, input_data], axis=-1) 143 | input_data = tf.keras.layers.MaxPool2D(2, 2, 'same')(input_data) 144 | 145 | input_data = common.convolutional(input_data, (3, 3, 512, 512)) 146 | 147 | return route_1, input_data 148 | 149 | def darknet53_tiny(input_data): 150 | input_data = common.convolutional(input_data, (3, 3, 3, 16)) 151 | input_data = tf.keras.layers.MaxPool2D(2, 2, 'same')(input_data) 152 | input_data = common.convolutional(input_data, (3, 3, 16, 32)) 153 | input_data = tf.keras.layers.MaxPool2D(2, 2, 'same')(input_data) 154 | input_data = common.convolutional(input_data, (3, 3, 32, 64)) 155 | input_data = tf.keras.layers.MaxPool2D(2, 2, 'same')(input_data) 156 | input_data = common.convolutional(input_data, (3, 3, 64, 128)) 157 | input_data = tf.keras.layers.MaxPool2D(2, 2, 'same')(input_data) 158 | input_data = common.convolutional(input_data, (3, 3, 128, 256)) 159 | route_1 = input_data 160 | input_data = tf.keras.layers.MaxPool2D(2, 2, 'same')(input_data) 161 | input_data = common.convolutional(input_data, (3, 3, 256, 512)) 162 | input_data = tf.keras.layers.MaxPool2D(2, 1, 'same')(input_data) 163 | input_data = common.convolutional(input_data, (3, 3, 512, 1024)) 164 | 165 | return route_1, input_data 166 | 167 | 168 | -------------------------------------------------------------------------------- /core/common.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # coding=utf-8 3 | 4 | import tensorflow as tf 5 | # import tensorflow_addons as tfa 6 | class BatchNormalization(tf.keras.layers.BatchNormalization): 7 | """ 8 | "Frozen state" and "inference mode" are two separate concepts. 9 | `layer.trainable = False` is to freeze the layer, so the layer will use 10 | stored moving `var` and `mean` in the "inference mode", and both `gama` 11 | and `beta` will not be updated ! 12 | """ 13 | def call(self, x, training=False): 14 | if not training: 15 | training = tf.constant(False) 16 | training = tf.logical_and(training, self.trainable) 17 | return super().call(x, training) 18 | 19 | def convolutional(input_layer, filters_shape, downsample=False, activate=True, bn=True, activate_type='leaky'): 20 | if downsample: 21 | input_layer = tf.keras.layers.ZeroPadding2D(((1, 0), (1, 0)))(input_layer) 22 | padding = 'valid' 23 | strides = 2 24 | else: 25 | strides = 1 26 | padding = 'same' 27 | 28 | conv = tf.keras.layers.Conv2D(filters=filters_shape[-1], kernel_size = filters_shape[0], strides=strides, padding=padding, 29 | use_bias=not bn, kernel_regularizer=tf.keras.regularizers.l2(0.0005), 30 | kernel_initializer=tf.random_normal_initializer(stddev=0.01), 31 | bias_initializer=tf.constant_initializer(0.))(input_layer) 32 | 33 | if bn: conv = BatchNormalization()(conv) 34 | if activate == True: 35 | if activate_type == "leaky": 36 | conv = tf.nn.leaky_relu(conv, alpha=0.1) 37 | elif activate_type == "mish": 38 | conv = mish(conv) 39 | return conv 40 | 41 | def mish(x): 42 | return x * tf.math.tanh(tf.math.softplus(x)) 43 | # return tf.keras.layers.Lambda(lambda x: x*tf.tanh(tf.math.log(1+tf.exp(x))))(x) 44 | 45 | def residual_block(input_layer, input_channel, filter_num1, filter_num2, activate_type='leaky'): 46 | short_cut = input_layer 47 | conv = convolutional(input_layer, filters_shape=(1, 1, input_channel, filter_num1), activate_type=activate_type) 48 | conv = convolutional(conv , filters_shape=(3, 3, filter_num1, filter_num2), activate_type=activate_type) 49 | 50 | residual_output = short_cut + conv 51 | return residual_output 52 | 53 | # def block_tiny(input_layer, input_channel, filter_num1, activate_type='leaky'): 54 | # conv = convolutional(input_layer, filters_shape=(3, 3, input_channel, filter_num1), activate_type=activate_type) 55 | # short_cut = input_layer 56 | # conv = convolutional(conv, filters_shape=(3, 3, input_channel, filter_num1), activate_type=activate_type) 57 | # 58 | # input_data = tf.concat([conv, short_cut], axis=-1) 59 | # return residual_output 60 | 61 | def route_group(input_layer, groups, group_id): 62 | convs = tf.split(input_layer, num_or_size_splits=groups, axis=-1) 63 | return convs[group_id] 64 | 65 | def upsample(input_layer): 66 | return tf.image.resize(input_layer, (input_layer.shape[1] * 2, input_layer.shape[2] * 2), method='bilinear') 67 | 68 | -------------------------------------------------------------------------------- /core/config.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # coding=utf-8 3 | from easydict import EasyDict as edict 4 | 5 | 6 | __C = edict() 7 | # Consumers can get config by: from config import cfg 8 | 9 | cfg = __C 10 | 11 | # YOLO options 12 | __C.YOLO = edict() 13 | 14 | __C.YOLO.CLASSES = "./data/classes/coco.names" 15 | __C.YOLO.ANCHORS = [12,16, 19,36, 40,28, 36,75, 76,55, 72,146, 142,110, 192,243, 459,401] 16 | __C.YOLO.ANCHORS_V3 = [10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326] 17 | __C.YOLO.ANCHORS_TINY = [23,27, 37,58, 81,82, 81,82, 135,169, 344,319] 18 | __C.YOLO.STRIDES = [8, 16, 32] 19 | __C.YOLO.STRIDES_TINY = [16, 32] 20 | __C.YOLO.XYSCALE = [1.2, 1.1, 1.05] 21 | __C.YOLO.XYSCALE_TINY = [1.05, 1.05] 22 | __C.YOLO.ANCHOR_PER_SCALE = 3 23 | __C.YOLO.IOU_LOSS_THRESH = 0.5 24 | 25 | 26 | # Train options 27 | __C.TRAIN = edict() 28 | 29 | __C.TRAIN.ANNOT_PATH = "./data/dataset/val2017.txt" 30 | __C.TRAIN.BATCH_SIZE = 2 31 | # __C.TRAIN.INPUT_SIZE = [320, 352, 384, 416, 448, 480, 512, 544, 576, 608] 32 | __C.TRAIN.INPUT_SIZE = 416 33 | __C.TRAIN.DATA_AUG = True 34 | __C.TRAIN.LR_INIT = 1e-3 35 | __C.TRAIN.LR_END = 1e-6 36 | __C.TRAIN.WARMUP_EPOCHS = 2 37 | __C.TRAIN.FISRT_STAGE_EPOCHS = 20 38 | __C.TRAIN.SECOND_STAGE_EPOCHS = 30 39 | 40 | 41 | 42 | # TEST options 43 | __C.TEST = edict() 44 | 45 | __C.TEST.ANNOT_PATH = "./data/dataset/val2017.txt" 46 | __C.TEST.BATCH_SIZE = 2 47 | __C.TEST.INPUT_SIZE = 416 48 | __C.TEST.DATA_AUG = False 49 | __C.TEST.DECTECTED_IMAGE_PATH = "./data/detection/" 50 | __C.TEST.SCORE_THRESHOLD = 0.25 51 | __C.TEST.IOU_THRESHOLD = 0.5 52 | 53 | 54 | -------------------------------------------------------------------------------- /core/dataset.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # coding=utf-8 3 | 4 | import os 5 | import cv2 6 | import random 7 | import numpy as np 8 | import tensorflow as tf 9 | import core.utils as utils 10 | from core.config import cfg 11 | 12 | 13 | class Dataset(object): 14 | """implement Dataset here""" 15 | 16 | def __init__(self, FLAGS, is_training: bool, dataset_type: str = "converted_coco"): 17 | self.tiny = FLAGS.tiny 18 | self.strides, self.anchors, NUM_CLASS, XYSCALE = utils.load_config(FLAGS) 19 | self.dataset_type = dataset_type 20 | 21 | self.annot_path = ( 22 | cfg.TRAIN.ANNOT_PATH if is_training else cfg.TEST.ANNOT_PATH 23 | ) 24 | self.input_sizes = ( 25 | cfg.TRAIN.INPUT_SIZE if is_training else cfg.TEST.INPUT_SIZE 26 | ) 27 | self.batch_size = ( 28 | cfg.TRAIN.BATCH_SIZE if is_training else cfg.TEST.BATCH_SIZE 29 | ) 30 | self.data_aug = cfg.TRAIN.DATA_AUG if is_training else cfg.TEST.DATA_AUG 31 | 32 | self.train_input_sizes = cfg.TRAIN.INPUT_SIZE 33 | self.classes = utils.read_class_names(cfg.YOLO.CLASSES) 34 | self.num_classes = len(self.classes) 35 | self.anchor_per_scale = cfg.YOLO.ANCHOR_PER_SCALE 36 | self.max_bbox_per_scale = 150 37 | 38 | self.annotations = self.load_annotations() 39 | self.num_samples = len(self.annotations) 40 | self.num_batchs = int(np.ceil(self.num_samples / self.batch_size)) 41 | self.batch_count = 0 42 | 43 | def load_annotations(self): 44 | with open(self.annot_path, "r") as f: 45 | txt = f.readlines() 46 | if self.dataset_type == "converted_coco": 47 | annotations = [ 48 | line.strip() 49 | for line in txt 50 | if len(line.strip().split()[1:]) != 0 51 | ] 52 | elif self.dataset_type == "yolo": 53 | annotations = [] 54 | for line in txt: 55 | image_path = line.strip() 56 | root, _ = os.path.splitext(image_path) 57 | with open(root + ".txt") as fd: 58 | boxes = fd.readlines() 59 | string = "" 60 | for box in boxes: 61 | box = box.strip() 62 | box = box.split() 63 | class_num = int(box[0]) 64 | center_x = float(box[1]) 65 | center_y = float(box[2]) 66 | half_width = float(box[3]) / 2 67 | half_height = float(box[4]) / 2 68 | string += " {},{},{},{},{}".format( 69 | center_x - half_width, 70 | center_y - half_height, 71 | center_x + half_width, 72 | center_y + half_height, 73 | class_num, 74 | ) 75 | annotations.append(image_path + string) 76 | 77 | np.random.shuffle(annotations) 78 | return annotations 79 | 80 | def __iter__(self): 81 | return self 82 | 83 | def __next__(self): 84 | with tf.device("/cpu:0"): 85 | # self.train_input_size = random.choice(self.train_input_sizes) 86 | self.train_input_size = cfg.TRAIN.INPUT_SIZE 87 | self.train_output_sizes = self.train_input_size // self.strides 88 | 89 | batch_image = np.zeros( 90 | ( 91 | self.batch_size, 92 | self.train_input_size, 93 | self.train_input_size, 94 | 3, 95 | ), 96 | dtype=np.float32, 97 | ) 98 | 99 | batch_label_sbbox = np.zeros( 100 | ( 101 | self.batch_size, 102 | self.train_output_sizes[0], 103 | self.train_output_sizes[0], 104 | self.anchor_per_scale, 105 | 5 + self.num_classes, 106 | ), 107 | dtype=np.float32, 108 | ) 109 | batch_label_mbbox = np.zeros( 110 | ( 111 | self.batch_size, 112 | self.train_output_sizes[1], 113 | self.train_output_sizes[1], 114 | self.anchor_per_scale, 115 | 5 + self.num_classes, 116 | ), 117 | dtype=np.float32, 118 | ) 119 | batch_label_lbbox = np.zeros( 120 | ( 121 | self.batch_size, 122 | self.train_output_sizes[2], 123 | self.train_output_sizes[2], 124 | self.anchor_per_scale, 125 | 5 + self.num_classes, 126 | ), 127 | dtype=np.float32, 128 | ) 129 | 130 | batch_sbboxes = np.zeros( 131 | (self.batch_size, self.max_bbox_per_scale, 4), dtype=np.float32 132 | ) 133 | batch_mbboxes = np.zeros( 134 | (self.batch_size, self.max_bbox_per_scale, 4), dtype=np.float32 135 | ) 136 | batch_lbboxes = np.zeros( 137 | (self.batch_size, self.max_bbox_per_scale, 4), dtype=np.float32 138 | ) 139 | 140 | num = 0 141 | if self.batch_count < self.num_batchs: 142 | while num < self.batch_size: 143 | index = self.batch_count * self.batch_size + num 144 | if index >= self.num_samples: 145 | index -= self.num_samples 146 | annotation = self.annotations[index] 147 | image, bboxes = self.parse_annotation(annotation) 148 | ( 149 | label_sbbox, 150 | label_mbbox, 151 | label_lbbox, 152 | sbboxes, 153 | mbboxes, 154 | lbboxes, 155 | ) = self.preprocess_true_boxes(bboxes) 156 | 157 | batch_image[num, :, :, :] = image 158 | batch_label_sbbox[num, :, :, :, :] = label_sbbox 159 | batch_label_mbbox[num, :, :, :, :] = label_mbbox 160 | batch_label_lbbox[num, :, :, :, :] = label_lbbox 161 | batch_sbboxes[num, :, :] = sbboxes 162 | batch_mbboxes[num, :, :] = mbboxes 163 | batch_lbboxes[num, :, :] = lbboxes 164 | num += 1 165 | self.batch_count += 1 166 | batch_smaller_target = batch_label_sbbox, batch_sbboxes 167 | batch_medium_target = batch_label_mbbox, batch_mbboxes 168 | batch_larger_target = batch_label_lbbox, batch_lbboxes 169 | 170 | return ( 171 | batch_image, 172 | ( 173 | batch_smaller_target, 174 | batch_medium_target, 175 | batch_larger_target, 176 | ), 177 | ) 178 | else: 179 | self.batch_count = 0 180 | np.random.shuffle(self.annotations) 181 | raise StopIteration 182 | 183 | def random_horizontal_flip(self, image, bboxes): 184 | if random.random() < 0.5: 185 | _, w, _ = image.shape 186 | image = image[:, ::-1, :] 187 | bboxes[:, [0, 2]] = w - bboxes[:, [2, 0]] 188 | 189 | return image, bboxes 190 | 191 | def random_crop(self, image, bboxes): 192 | if random.random() < 0.5: 193 | h, w, _ = image.shape 194 | max_bbox = np.concatenate( 195 | [ 196 | np.min(bboxes[:, 0:2], axis=0), 197 | np.max(bboxes[:, 2:4], axis=0), 198 | ], 199 | axis=-1, 200 | ) 201 | 202 | max_l_trans = max_bbox[0] 203 | max_u_trans = max_bbox[1] 204 | max_r_trans = w - max_bbox[2] 205 | max_d_trans = h - max_bbox[3] 206 | 207 | crop_xmin = max( 208 | 0, int(max_bbox[0] - random.uniform(0, max_l_trans)) 209 | ) 210 | crop_ymin = max( 211 | 0, int(max_bbox[1] - random.uniform(0, max_u_trans)) 212 | ) 213 | crop_xmax = max( 214 | w, int(max_bbox[2] + random.uniform(0, max_r_trans)) 215 | ) 216 | crop_ymax = max( 217 | h, int(max_bbox[3] + random.uniform(0, max_d_trans)) 218 | ) 219 | 220 | image = image[crop_ymin:crop_ymax, crop_xmin:crop_xmax] 221 | 222 | bboxes[:, [0, 2]] = bboxes[:, [0, 2]] - crop_xmin 223 | bboxes[:, [1, 3]] = bboxes[:, [1, 3]] - crop_ymin 224 | 225 | return image, bboxes 226 | 227 | def random_translate(self, image, bboxes): 228 | if random.random() < 0.5: 229 | h, w, _ = image.shape 230 | max_bbox = np.concatenate( 231 | [ 232 | np.min(bboxes[:, 0:2], axis=0), 233 | np.max(bboxes[:, 2:4], axis=0), 234 | ], 235 | axis=-1, 236 | ) 237 | 238 | max_l_trans = max_bbox[0] 239 | max_u_trans = max_bbox[1] 240 | max_r_trans = w - max_bbox[2] 241 | max_d_trans = h - max_bbox[3] 242 | 243 | tx = random.uniform(-(max_l_trans - 1), (max_r_trans - 1)) 244 | ty = random.uniform(-(max_u_trans - 1), (max_d_trans - 1)) 245 | 246 | M = np.array([[1, 0, tx], [0, 1, ty]]) 247 | image = cv2.warpAffine(image, M, (w, h)) 248 | 249 | bboxes[:, [0, 2]] = bboxes[:, [0, 2]] + tx 250 | bboxes[:, [1, 3]] = bboxes[:, [1, 3]] + ty 251 | 252 | return image, bboxes 253 | 254 | def parse_annotation(self, annotation): 255 | line = annotation.split() 256 | image_path = line[0] 257 | if not os.path.exists(image_path): 258 | raise KeyError("%s does not exist ... " % image_path) 259 | image = cv2.imread(image_path) 260 | if self.dataset_type == "converted_coco": 261 | bboxes = np.array( 262 | [list(map(int, box.split(","))) for box in line[1:]] 263 | ) 264 | elif self.dataset_type == "yolo": 265 | height, width, _ = image.shape 266 | bboxes = np.array( 267 | [list(map(float, box.split(","))) for box in line[1:]] 268 | ) 269 | bboxes = bboxes * np.array([width, height, width, height, 1]) 270 | bboxes = bboxes.astype(np.int64) 271 | 272 | if self.data_aug: 273 | image, bboxes = self.random_horizontal_flip( 274 | np.copy(image), np.copy(bboxes) 275 | ) 276 | image, bboxes = self.random_crop(np.copy(image), np.copy(bboxes)) 277 | image, bboxes = self.random_translate( 278 | np.copy(image), np.copy(bboxes) 279 | ) 280 | 281 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) 282 | image, bboxes = utils.image_preprocess( 283 | np.copy(image), 284 | [self.train_input_size, self.train_input_size], 285 | np.copy(bboxes), 286 | ) 287 | return image, bboxes 288 | 289 | 290 | def preprocess_true_boxes(self, bboxes): 291 | label = [ 292 | np.zeros( 293 | ( 294 | self.train_output_sizes[i], 295 | self.train_output_sizes[i], 296 | self.anchor_per_scale, 297 | 5 + self.num_classes, 298 | ) 299 | ) 300 | for i in range(3) 301 | ] 302 | bboxes_xywh = [np.zeros((self.max_bbox_per_scale, 4)) for _ in range(3)] 303 | bbox_count = np.zeros((3,)) 304 | 305 | for bbox in bboxes: 306 | bbox_coor = bbox[:4] 307 | bbox_class_ind = bbox[4] 308 | 309 | onehot = np.zeros(self.num_classes, dtype=np.float) 310 | onehot[bbox_class_ind] = 1.0 311 | uniform_distribution = np.full( 312 | self.num_classes, 1.0 / self.num_classes 313 | ) 314 | deta = 0.01 315 | smooth_onehot = onehot * (1 - deta) + deta * uniform_distribution 316 | 317 | bbox_xywh = np.concatenate( 318 | [ 319 | (bbox_coor[2:] + bbox_coor[:2]) * 0.5, 320 | bbox_coor[2:] - bbox_coor[:2], 321 | ], 322 | axis=-1, 323 | ) 324 | bbox_xywh_scaled = ( 325 | 1.0 * bbox_xywh[np.newaxis, :] / self.strides[:, np.newaxis] 326 | ) 327 | 328 | iou = [] 329 | exist_positive = False 330 | for i in range(3): 331 | anchors_xywh = np.zeros((self.anchor_per_scale, 4)) 332 | anchors_xywh[:, 0:2] = ( 333 | np.floor(bbox_xywh_scaled[i, 0:2]).astype(np.int32) + 0.5 334 | ) 335 | anchors_xywh[:, 2:4] = self.anchors[i] 336 | 337 | iou_scale = utils.bbox_iou( 338 | bbox_xywh_scaled[i][np.newaxis, :], anchors_xywh 339 | ) 340 | iou.append(iou_scale) 341 | iou_mask = iou_scale > 0.3 342 | 343 | if np.any(iou_mask): 344 | xind, yind = np.floor(bbox_xywh_scaled[i, 0:2]).astype( 345 | np.int32 346 | ) 347 | 348 | label[i][yind, xind, iou_mask, :] = 0 349 | label[i][yind, xind, iou_mask, 0:4] = bbox_xywh 350 | label[i][yind, xind, iou_mask, 4:5] = 1.0 351 | label[i][yind, xind, iou_mask, 5:] = smooth_onehot 352 | 353 | bbox_ind = int(bbox_count[i] % self.max_bbox_per_scale) 354 | bboxes_xywh[i][bbox_ind, :4] = bbox_xywh 355 | bbox_count[i] += 1 356 | 357 | exist_positive = True 358 | 359 | if not exist_positive: 360 | best_anchor_ind = np.argmax(np.array(iou).reshape(-1), axis=-1) 361 | best_detect = int(best_anchor_ind / self.anchor_per_scale) 362 | best_anchor = int(best_anchor_ind % self.anchor_per_scale) 363 | xind, yind = np.floor( 364 | bbox_xywh_scaled[best_detect, 0:2] 365 | ).astype(np.int32) 366 | 367 | label[best_detect][yind, xind, best_anchor, :] = 0 368 | label[best_detect][yind, xind, best_anchor, 0:4] = bbox_xywh 369 | label[best_detect][yind, xind, best_anchor, 4:5] = 1.0 370 | label[best_detect][yind, xind, best_anchor, 5:] = smooth_onehot 371 | 372 | bbox_ind = int( 373 | bbox_count[best_detect] % self.max_bbox_per_scale 374 | ) 375 | bboxes_xywh[best_detect][bbox_ind, :4] = bbox_xywh 376 | bbox_count[best_detect] += 1 377 | label_sbbox, label_mbbox, label_lbbox = label 378 | sbboxes, mbboxes, lbboxes = bboxes_xywh 379 | return label_sbbox, label_mbbox, label_lbbox, sbboxes, mbboxes, lbboxes 380 | 381 | def __len__(self): 382 | return self.num_batchs 383 | -------------------------------------------------------------------------------- /core/utils.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import random 3 | import colorsys 4 | import numpy as np 5 | import tensorflow as tf 6 | from core.config import cfg 7 | 8 | def load_freeze_layer(model='yolov4', tiny=False): 9 | if tiny: 10 | if model == 'yolov3': 11 | freeze_layouts = ['conv2d_9', 'conv2d_12'] 12 | else: 13 | freeze_layouts = ['conv2d_17', 'conv2d_20'] 14 | else: 15 | if model == 'yolov3': 16 | freeze_layouts = ['conv2d_58', 'conv2d_66', 'conv2d_74'] 17 | else: 18 | freeze_layouts = ['conv2d_93', 'conv2d_101', 'conv2d_109'] 19 | return freeze_layouts 20 | 21 | def load_weights(model, weights_file, model_name='yolov4', is_tiny=False): 22 | if is_tiny: 23 | if model_name == 'yolov3': 24 | layer_size = 13 25 | output_pos = [9, 12] 26 | else: 27 | layer_size = 21 28 | output_pos = [17, 20] 29 | else: 30 | if model_name == 'yolov3': 31 | layer_size = 75 32 | output_pos = [58, 66, 74] 33 | else: 34 | layer_size = 110 35 | output_pos = [93, 101, 109] 36 | wf = open(weights_file, 'rb') 37 | major, minor, revision, seen, _ = np.fromfile(wf, dtype=np.int32, count=5) 38 | 39 | j = 0 40 | for i in range(layer_size): 41 | conv_layer_name = 'conv2d_%d' %i if i > 0 else 'conv2d' 42 | bn_layer_name = 'batch_normalization_%d' %j if j > 0 else 'batch_normalization' 43 | 44 | conv_layer = model.get_layer(conv_layer_name) 45 | filters = conv_layer.filters 46 | k_size = conv_layer.kernel_size[0] 47 | in_dim = conv_layer.input_shape[-1] 48 | 49 | if i not in output_pos: 50 | # darknet weights: [beta, gamma, mean, variance] 51 | bn_weights = np.fromfile(wf, dtype=np.float32, count=4 * filters) 52 | # tf weights: [gamma, beta, mean, variance] 53 | bn_weights = bn_weights.reshape((4, filters))[[1, 0, 2, 3]] 54 | bn_layer = model.get_layer(bn_layer_name) 55 | j += 1 56 | else: 57 | conv_bias = np.fromfile(wf, dtype=np.float32, count=filters) 58 | 59 | # darknet shape (out_dim, in_dim, height, width) 60 | conv_shape = (filters, in_dim, k_size, k_size) 61 | conv_weights = np.fromfile(wf, dtype=np.float32, count=np.product(conv_shape)) 62 | # tf shape (height, width, in_dim, out_dim) 63 | conv_weights = conv_weights.reshape(conv_shape).transpose([2, 3, 1, 0]) 64 | 65 | if i not in output_pos: 66 | conv_layer.set_weights([conv_weights]) 67 | bn_layer.set_weights(bn_weights) 68 | else: 69 | conv_layer.set_weights([conv_weights, conv_bias]) 70 | 71 | # assert len(wf.read()) == 0, 'failed to read all data' 72 | wf.close() 73 | 74 | 75 | def read_class_names(class_file_name): 76 | names = {} 77 | with open(class_file_name, 'r') as data: 78 | for ID, name in enumerate(data): 79 | names[ID] = name.strip('\n') 80 | return names 81 | 82 | def load_config(FLAGS): 83 | if FLAGS.tiny: 84 | STRIDES = np.array(cfg.YOLO.STRIDES_TINY) 85 | ANCHORS = get_anchors(cfg.YOLO.ANCHORS_TINY, FLAGS.tiny) 86 | XYSCALE = cfg.YOLO.XYSCALE_TINY if FLAGS.model == 'yolov4' else [1, 1] 87 | else: 88 | STRIDES = np.array(cfg.YOLO.STRIDES) 89 | if FLAGS.model == 'yolov4': 90 | ANCHORS = get_anchors(cfg.YOLO.ANCHORS, FLAGS.tiny) 91 | elif FLAGS.model == 'yolov3': 92 | ANCHORS = get_anchors(cfg.YOLO.ANCHORS_V3, FLAGS.tiny) 93 | XYSCALE = cfg.YOLO.XYSCALE if FLAGS.model == 'yolov4' else [1, 1, 1] 94 | NUM_CLASS = len(read_class_names(cfg.YOLO.CLASSES)) 95 | 96 | return STRIDES, ANCHORS, NUM_CLASS, XYSCALE 97 | 98 | def get_anchors(anchors_path, tiny=False): 99 | anchors = np.array(anchors_path) 100 | if tiny: 101 | return anchors.reshape(2, 3, 2) 102 | else: 103 | return anchors.reshape(3, 3, 2) 104 | 105 | def image_preprocess(image, target_size, gt_boxes=None): 106 | 107 | ih, iw = target_size 108 | h, w, _ = image.shape 109 | 110 | scale = min(iw/w, ih/h) 111 | nw, nh = int(scale * w), int(scale * h) 112 | image_resized = cv2.resize(image, (nw, nh)) 113 | 114 | image_paded = np.full(shape=[ih, iw, 3], fill_value=128.0) 115 | dw, dh = (iw - nw) // 2, (ih-nh) // 2 116 | image_paded[dh:nh+dh, dw:nw+dw, :] = image_resized 117 | image_paded = image_paded / 255. 118 | 119 | if gt_boxes is None: 120 | return image_paded 121 | 122 | else: 123 | gt_boxes[:, [0, 2]] = gt_boxes[:, [0, 2]] * scale + dw 124 | gt_boxes[:, [1, 3]] = gt_boxes[:, [1, 3]] * scale + dh 125 | return image_paded, gt_boxes 126 | 127 | def draw_bbox(image, bboxes, classes=read_class_names(cfg.YOLO.CLASSES), show_label=True): 128 | num_classes = len(classes) 129 | image_h, image_w, _ = image.shape 130 | hsv_tuples = [(1.0 * x / num_classes, 1., 1.) for x in range(num_classes)] 131 | colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples)) 132 | colors = list(map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), colors)) 133 | 134 | random.seed(0) 135 | random.shuffle(colors) 136 | random.seed(None) 137 | 138 | out_boxes, out_scores, out_classes, num_boxes = bboxes 139 | for i in range(num_boxes[0]): 140 | if int(out_classes[0][i]) < 0 or int(out_classes[0][i]) > num_classes: continue 141 | coor = out_boxes[0][i] 142 | coor[0] = int(coor[0] * image_h) 143 | coor[2] = int(coor[2] * image_h) 144 | coor[1] = int(coor[1] * image_w) 145 | coor[3] = int(coor[3] * image_w) 146 | 147 | fontScale = 0.5 148 | score = out_scores[0][i] 149 | class_ind = int(out_classes[0][i]) 150 | bbox_color = colors[class_ind] 151 | bbox_thick = int(0.6 * (image_h + image_w) / 600) 152 | c1, c2 = (coor[1], coor[0]), (coor[3], coor[2]) 153 | cv2.rectangle(image, c1, c2, bbox_color, bbox_thick) 154 | 155 | if show_label: 156 | bbox_mess = '%s: %.2f' % (classes[class_ind], score) 157 | t_size = cv2.getTextSize(bbox_mess, 0, fontScale, thickness=bbox_thick // 2)[0] 158 | c3 = (c1[0] + t_size[0], c1[1] - t_size[1] - 3) 159 | cv2.rectangle(image, c1, (np.float32(c3[0]), np.float32(c3[1])), bbox_color, -1) #filled 160 | 161 | cv2.putText(image, bbox_mess, (c1[0], np.float32(c1[1] - 2)), cv2.FONT_HERSHEY_SIMPLEX, 162 | fontScale, (0, 0, 0), bbox_thick // 2, lineType=cv2.LINE_AA) 163 | return image 164 | 165 | def bbox_iou(bboxes1, bboxes2): 166 | """ 167 | @param bboxes1: (a, b, ..., 4) 168 | @param bboxes2: (A, B, ..., 4) 169 | x:X is 1:n or n:n or n:1 170 | @return (max(a,A), max(b,B), ...) 171 | ex) (4,):(3,4) -> (3,) 172 | (2,1,4):(2,3,4) -> (2,3) 173 | """ 174 | bboxes1_area = bboxes1[..., 2] * bboxes1[..., 3] 175 | bboxes2_area = bboxes2[..., 2] * bboxes2[..., 3] 176 | 177 | bboxes1_coor = tf.concat( 178 | [ 179 | bboxes1[..., :2] - bboxes1[..., 2:] * 0.5, 180 | bboxes1[..., :2] + bboxes1[..., 2:] * 0.5, 181 | ], 182 | axis=-1, 183 | ) 184 | bboxes2_coor = tf.concat( 185 | [ 186 | bboxes2[..., :2] - bboxes2[..., 2:] * 0.5, 187 | bboxes2[..., :2] + bboxes2[..., 2:] * 0.5, 188 | ], 189 | axis=-1, 190 | ) 191 | 192 | left_up = tf.maximum(bboxes1_coor[..., :2], bboxes2_coor[..., :2]) 193 | right_down = tf.minimum(bboxes1_coor[..., 2:], bboxes2_coor[..., 2:]) 194 | 195 | inter_section = tf.maximum(right_down - left_up, 0.0) 196 | inter_area = inter_section[..., 0] * inter_section[..., 1] 197 | 198 | union_area = bboxes1_area + bboxes2_area - inter_area 199 | 200 | iou = tf.math.divide_no_nan(inter_area, union_area) 201 | 202 | return iou 203 | 204 | 205 | def bbox_giou(bboxes1, bboxes2): 206 | """ 207 | Generalized IoU 208 | @param bboxes1: (a, b, ..., 4) 209 | @param bboxes2: (A, B, ..., 4) 210 | x:X is 1:n or n:n or n:1 211 | @return (max(a,A), max(b,B), ...) 212 | ex) (4,):(3,4) -> (3,) 213 | (2,1,4):(2,3,4) -> (2,3) 214 | """ 215 | bboxes1_area = bboxes1[..., 2] * bboxes1[..., 3] 216 | bboxes2_area = bboxes2[..., 2] * bboxes2[..., 3] 217 | 218 | bboxes1_coor = tf.concat( 219 | [ 220 | bboxes1[..., :2] - bboxes1[..., 2:] * 0.5, 221 | bboxes1[..., :2] + bboxes1[..., 2:] * 0.5, 222 | ], 223 | axis=-1, 224 | ) 225 | bboxes2_coor = tf.concat( 226 | [ 227 | bboxes2[..., :2] - bboxes2[..., 2:] * 0.5, 228 | bboxes2[..., :2] + bboxes2[..., 2:] * 0.5, 229 | ], 230 | axis=-1, 231 | ) 232 | 233 | left_up = tf.maximum(bboxes1_coor[..., :2], bboxes2_coor[..., :2]) 234 | right_down = tf.minimum(bboxes1_coor[..., 2:], bboxes2_coor[..., 2:]) 235 | 236 | inter_section = tf.maximum(right_down - left_up, 0.0) 237 | inter_area = inter_section[..., 0] * inter_section[..., 1] 238 | 239 | union_area = bboxes1_area + bboxes2_area - inter_area 240 | 241 | iou = tf.math.divide_no_nan(inter_area, union_area) 242 | 243 | enclose_left_up = tf.minimum(bboxes1_coor[..., :2], bboxes2_coor[..., :2]) 244 | enclose_right_down = tf.maximum( 245 | bboxes1_coor[..., 2:], bboxes2_coor[..., 2:] 246 | ) 247 | 248 | enclose_section = enclose_right_down - enclose_left_up 249 | enclose_area = enclose_section[..., 0] * enclose_section[..., 1] 250 | 251 | giou = iou - tf.math.divide_no_nan(enclose_area - union_area, enclose_area) 252 | 253 | return giou 254 | 255 | 256 | def bbox_ciou(bboxes1, bboxes2): 257 | """ 258 | Complete IoU 259 | @param bboxes1: (a, b, ..., 4) 260 | @param bboxes2: (A, B, ..., 4) 261 | x:X is 1:n or n:n or n:1 262 | @return (max(a,A), max(b,B), ...) 263 | ex) (4,):(3,4) -> (3,) 264 | (2,1,4):(2,3,4) -> (2,3) 265 | """ 266 | bboxes1_area = bboxes1[..., 2] * bboxes1[..., 3] 267 | bboxes2_area = bboxes2[..., 2] * bboxes2[..., 3] 268 | 269 | bboxes1_coor = tf.concat( 270 | [ 271 | bboxes1[..., :2] - bboxes1[..., 2:] * 0.5, 272 | bboxes1[..., :2] + bboxes1[..., 2:] * 0.5, 273 | ], 274 | axis=-1, 275 | ) 276 | bboxes2_coor = tf.concat( 277 | [ 278 | bboxes2[..., :2] - bboxes2[..., 2:] * 0.5, 279 | bboxes2[..., :2] + bboxes2[..., 2:] * 0.5, 280 | ], 281 | axis=-1, 282 | ) 283 | 284 | left_up = tf.maximum(bboxes1_coor[..., :2], bboxes2_coor[..., :2]) 285 | right_down = tf.minimum(bboxes1_coor[..., 2:], bboxes2_coor[..., 2:]) 286 | 287 | inter_section = tf.maximum(right_down - left_up, 0.0) 288 | inter_area = inter_section[..., 0] * inter_section[..., 1] 289 | 290 | union_area = bboxes1_area + bboxes2_area - inter_area 291 | 292 | iou = tf.math.divide_no_nan(inter_area, union_area) 293 | 294 | enclose_left_up = tf.minimum(bboxes1_coor[..., :2], bboxes2_coor[..., :2]) 295 | enclose_right_down = tf.maximum( 296 | bboxes1_coor[..., 2:], bboxes2_coor[..., 2:] 297 | ) 298 | 299 | enclose_section = enclose_right_down - enclose_left_up 300 | 301 | c_2 = enclose_section[..., 0] ** 2 + enclose_section[..., 1] ** 2 302 | 303 | center_diagonal = bboxes2[..., :2] - bboxes1[..., :2] 304 | 305 | rho_2 = center_diagonal[..., 0] ** 2 + center_diagonal[..., 1] ** 2 306 | 307 | diou = iou - tf.math.divide_no_nan(rho_2, c_2) 308 | 309 | v = ( 310 | ( 311 | tf.math.atan( 312 | tf.math.divide_no_nan(bboxes1[..., 2], bboxes1[..., 3]) 313 | ) 314 | - tf.math.atan( 315 | tf.math.divide_no_nan(bboxes2[..., 2], bboxes2[..., 3]) 316 | ) 317 | ) 318 | * 2 319 | / np.pi 320 | ) ** 2 321 | 322 | alpha = tf.math.divide_no_nan(v, 1 - iou + v) 323 | 324 | ciou = diou - alpha * v 325 | 326 | return ciou 327 | 328 | def nms(bboxes, iou_threshold, sigma=0.3, method='nms'): 329 | """ 330 | :param bboxes: (xmin, ymin, xmax, ymax, score, class) 331 | 332 | Note: soft-nms, https://arxiv.org/pdf/1704.04503.pdf 333 | https://github.com/bharatsingh430/soft-nms 334 | """ 335 | classes_in_img = list(set(bboxes[:, 5])) 336 | best_bboxes = [] 337 | 338 | for cls in classes_in_img: 339 | cls_mask = (bboxes[:, 5] == cls) 340 | cls_bboxes = bboxes[cls_mask] 341 | 342 | while len(cls_bboxes) > 0: 343 | max_ind = np.argmax(cls_bboxes[:, 4]) 344 | best_bbox = cls_bboxes[max_ind] 345 | best_bboxes.append(best_bbox) 346 | cls_bboxes = np.concatenate([cls_bboxes[: max_ind], cls_bboxes[max_ind + 1:]]) 347 | iou = bbox_iou(best_bbox[np.newaxis, :4], cls_bboxes[:, :4]) 348 | weight = np.ones((len(iou),), dtype=np.float32) 349 | 350 | assert method in ['nms', 'soft-nms'] 351 | 352 | if method == 'nms': 353 | iou_mask = iou > iou_threshold 354 | weight[iou_mask] = 0.0 355 | 356 | if method == 'soft-nms': 357 | weight = np.exp(-(1.0 * iou ** 2 / sigma)) 358 | 359 | cls_bboxes[:, 4] = cls_bboxes[:, 4] * weight 360 | score_mask = cls_bboxes[:, 4] > 0. 361 | cls_bboxes = cls_bboxes[score_mask] 362 | 363 | return best_bboxes 364 | 365 | def freeze_all(model, frozen=True): 366 | model.trainable = not frozen 367 | if isinstance(model, tf.keras.Model): 368 | for l in model.layers: 369 | freeze_all(l, frozen) 370 | def unfreeze_all(model, frozen=False): 371 | model.trainable = not frozen 372 | if isinstance(model, tf.keras.Model): 373 | for l in model.layers: 374 | unfreeze_all(l, frozen) 375 | 376 | -------------------------------------------------------------------------------- /core/yolov4.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # coding=utf-8 3 | 4 | import numpy as np 5 | import tensorflow as tf 6 | import core.utils as utils 7 | import core.common as common 8 | import core.backbone as backbone 9 | from core.config import cfg 10 | 11 | # NUM_CLASS = len(utils.read_class_names(cfg.YOLO.CLASSES)) 12 | # STRIDES = np.array(cfg.YOLO.STRIDES) 13 | # IOU_LOSS_THRESH = cfg.YOLO.IOU_LOSS_THRESH 14 | # XYSCALE = cfg.YOLO.XYSCALE 15 | # ANCHORS = utils.get_anchors(cfg.YOLO.ANCHORS) 16 | 17 | def YOLO(input_layer, NUM_CLASS, model='yolov4', is_tiny=False): 18 | if is_tiny: 19 | if model == 'yolov4': 20 | return YOLOv4_tiny(input_layer, NUM_CLASS) 21 | elif model == 'yolov3': 22 | return YOLOv3_tiny(input_layer, NUM_CLASS) 23 | else: 24 | if model == 'yolov4': 25 | return YOLOv4(input_layer, NUM_CLASS) 26 | elif model == 'yolov3': 27 | return YOLOv3(input_layer, NUM_CLASS) 28 | 29 | def YOLOv3(input_layer, NUM_CLASS): 30 | route_1, route_2, conv = backbone.darknet53(input_layer) 31 | 32 | conv = common.convolutional(conv, (1, 1, 1024, 512)) 33 | conv = common.convolutional(conv, (3, 3, 512, 1024)) 34 | conv = common.convolutional(conv, (1, 1, 1024, 512)) 35 | conv = common.convolutional(conv, (3, 3, 512, 1024)) 36 | conv = common.convolutional(conv, (1, 1, 1024, 512)) 37 | 38 | conv_lobj_branch = common.convolutional(conv, (3, 3, 512, 1024)) 39 | conv_lbbox = common.convolutional(conv_lobj_branch, (1, 1, 1024, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 40 | 41 | conv = common.convolutional(conv, (1, 1, 512, 256)) 42 | conv = common.upsample(conv) 43 | 44 | conv = tf.concat([conv, route_2], axis=-1) 45 | 46 | conv = common.convolutional(conv, (1, 1, 768, 256)) 47 | conv = common.convolutional(conv, (3, 3, 256, 512)) 48 | conv = common.convolutional(conv, (1, 1, 512, 256)) 49 | conv = common.convolutional(conv, (3, 3, 256, 512)) 50 | conv = common.convolutional(conv, (1, 1, 512, 256)) 51 | 52 | conv_mobj_branch = common.convolutional(conv, (3, 3, 256, 512)) 53 | conv_mbbox = common.convolutional(conv_mobj_branch, (1, 1, 512, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 54 | 55 | conv = common.convolutional(conv, (1, 1, 256, 128)) 56 | conv = common.upsample(conv) 57 | 58 | conv = tf.concat([conv, route_1], axis=-1) 59 | 60 | conv = common.convolutional(conv, (1, 1, 384, 128)) 61 | conv = common.convolutional(conv, (3, 3, 128, 256)) 62 | conv = common.convolutional(conv, (1, 1, 256, 128)) 63 | conv = common.convolutional(conv, (3, 3, 128, 256)) 64 | conv = common.convolutional(conv, (1, 1, 256, 128)) 65 | 66 | conv_sobj_branch = common.convolutional(conv, (3, 3, 128, 256)) 67 | conv_sbbox = common.convolutional(conv_sobj_branch, (1, 1, 256, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 68 | 69 | return [conv_sbbox, conv_mbbox, conv_lbbox] 70 | 71 | def YOLOv4(input_layer, NUM_CLASS): 72 | route_1, route_2, conv = backbone.cspdarknet53(input_layer) 73 | 74 | route = conv 75 | conv = common.convolutional(conv, (1, 1, 512, 256)) 76 | conv = common.upsample(conv) 77 | route_2 = common.convolutional(route_2, (1, 1, 512, 256)) 78 | conv = tf.concat([route_2, conv], axis=-1) 79 | 80 | conv = common.convolutional(conv, (1, 1, 512, 256)) 81 | conv = common.convolutional(conv, (3, 3, 256, 512)) 82 | conv = common.convolutional(conv, (1, 1, 512, 256)) 83 | conv = common.convolutional(conv, (3, 3, 256, 512)) 84 | conv = common.convolutional(conv, (1, 1, 512, 256)) 85 | 86 | route_2 = conv 87 | conv = common.convolutional(conv, (1, 1, 256, 128)) 88 | conv = common.upsample(conv) 89 | route_1 = common.convolutional(route_1, (1, 1, 256, 128)) 90 | conv = tf.concat([route_1, conv], axis=-1) 91 | 92 | conv = common.convolutional(conv, (1, 1, 256, 128)) 93 | conv = common.convolutional(conv, (3, 3, 128, 256)) 94 | conv = common.convolutional(conv, (1, 1, 256, 128)) 95 | conv = common.convolutional(conv, (3, 3, 128, 256)) 96 | conv = common.convolutional(conv, (1, 1, 256, 128)) 97 | 98 | route_1 = conv 99 | conv = common.convolutional(conv, (3, 3, 128, 256)) 100 | conv_sbbox = common.convolutional(conv, (1, 1, 256, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 101 | 102 | conv = common.convolutional(route_1, (3, 3, 128, 256), downsample=True) 103 | conv = tf.concat([conv, route_2], axis=-1) 104 | 105 | conv = common.convolutional(conv, (1, 1, 512, 256)) 106 | conv = common.convolutional(conv, (3, 3, 256, 512)) 107 | conv = common.convolutional(conv, (1, 1, 512, 256)) 108 | conv = common.convolutional(conv, (3, 3, 256, 512)) 109 | conv = common.convolutional(conv, (1, 1, 512, 256)) 110 | 111 | route_2 = conv 112 | conv = common.convolutional(conv, (3, 3, 256, 512)) 113 | conv_mbbox = common.convolutional(conv, (1, 1, 512, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 114 | 115 | conv = common.convolutional(route_2, (3, 3, 256, 512), downsample=True) 116 | conv = tf.concat([conv, route], axis=-1) 117 | 118 | conv = common.convolutional(conv, (1, 1, 1024, 512)) 119 | conv = common.convolutional(conv, (3, 3, 512, 1024)) 120 | conv = common.convolutional(conv, (1, 1, 1024, 512)) 121 | conv = common.convolutional(conv, (3, 3, 512, 1024)) 122 | conv = common.convolutional(conv, (1, 1, 1024, 512)) 123 | 124 | conv = common.convolutional(conv, (3, 3, 512, 1024)) 125 | conv_lbbox = common.convolutional(conv, (1, 1, 1024, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 126 | 127 | return [conv_sbbox, conv_mbbox, conv_lbbox] 128 | 129 | def YOLOv4_tiny(input_layer, NUM_CLASS): 130 | route_1, conv = backbone.cspdarknet53_tiny(input_layer) 131 | 132 | conv = common.convolutional(conv, (1, 1, 512, 256)) 133 | 134 | conv_lobj_branch = common.convolutional(conv, (3, 3, 256, 512)) 135 | conv_lbbox = common.convolutional(conv_lobj_branch, (1, 1, 512, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 136 | 137 | conv = common.convolutional(conv, (1, 1, 256, 128)) 138 | conv = common.upsample(conv) 139 | conv = tf.concat([conv, route_1], axis=-1) 140 | 141 | conv_mobj_branch = common.convolutional(conv, (3, 3, 128, 256)) 142 | conv_mbbox = common.convolutional(conv_mobj_branch, (1, 1, 256, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 143 | 144 | return [conv_mbbox, conv_lbbox] 145 | 146 | def YOLOv3_tiny(input_layer, NUM_CLASS): 147 | route_1, conv = backbone.darknet53_tiny(input_layer) 148 | 149 | conv = common.convolutional(conv, (1, 1, 1024, 256)) 150 | 151 | conv_lobj_branch = common.convolutional(conv, (3, 3, 256, 512)) 152 | conv_lbbox = common.convolutional(conv_lobj_branch, (1, 1, 512, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 153 | 154 | conv = common.convolutional(conv, (1, 1, 256, 128)) 155 | conv = common.upsample(conv) 156 | conv = tf.concat([conv, route_1], axis=-1) 157 | 158 | conv_mobj_branch = common.convolutional(conv, (3, 3, 128, 256)) 159 | conv_mbbox = common.convolutional(conv_mobj_branch, (1, 1, 256, 3 * (NUM_CLASS + 5)), activate=False, bn=False) 160 | 161 | return [conv_mbbox, conv_lbbox] 162 | 163 | def decode(conv_output, output_size, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE=[1,1,1], FRAMEWORK='tf'): 164 | if FRAMEWORK == 'trt': 165 | return decode_trt(conv_output, output_size, NUM_CLASS, STRIDES, ANCHORS, i=i, XYSCALE=XYSCALE) 166 | elif FRAMEWORK == 'tflite': 167 | return decode_tflite(conv_output, output_size, NUM_CLASS, STRIDES, ANCHORS, i=i, XYSCALE=XYSCALE) 168 | else: 169 | return decode_tf(conv_output, output_size, NUM_CLASS, STRIDES, ANCHORS, i=i, XYSCALE=XYSCALE) 170 | 171 | def decode_train(conv_output, output_size, NUM_CLASS, STRIDES, ANCHORS, i=0, XYSCALE=[1, 1, 1]): 172 | conv_output = tf.reshape(conv_output, 173 | (tf.shape(conv_output)[0], output_size, output_size, 3, 5 + NUM_CLASS)) 174 | 175 | conv_raw_dxdy, conv_raw_dwdh, conv_raw_conf, conv_raw_prob = tf.split(conv_output, (2, 2, 1, NUM_CLASS), 176 | axis=-1) 177 | 178 | xy_grid = tf.meshgrid(tf.range(output_size), tf.range(output_size)) 179 | xy_grid = tf.expand_dims(tf.stack(xy_grid, axis=-1), axis=2) # [gx, gy, 1, 2] 180 | xy_grid = tf.tile(tf.expand_dims(xy_grid, axis=0), [tf.shape(conv_output)[0], 1, 1, 3, 1]) 181 | 182 | xy_grid = tf.cast(xy_grid, tf.float32) 183 | 184 | pred_xy = ((tf.sigmoid(conv_raw_dxdy) * XYSCALE[i]) - 0.5 * (XYSCALE[i] - 1) + xy_grid) * \ 185 | STRIDES[i] 186 | pred_wh = (tf.exp(conv_raw_dwdh) * ANCHORS[i]) 187 | pred_xywh = tf.concat([pred_xy, pred_wh], axis=-1) 188 | 189 | pred_conf = tf.sigmoid(conv_raw_conf) 190 | pred_prob = tf.sigmoid(conv_raw_prob) 191 | 192 | return tf.concat([pred_xywh, pred_conf, pred_prob], axis=-1) 193 | 194 | def decode_tf(conv_output, output_size, NUM_CLASS, STRIDES, ANCHORS, i=0, XYSCALE=[1, 1, 1]): 195 | batch_size = tf.shape(conv_output)[0] 196 | conv_output = tf.reshape(conv_output, 197 | (batch_size, output_size, output_size, 3, 5 + NUM_CLASS)) 198 | 199 | conv_raw_dxdy, conv_raw_dwdh, conv_raw_conf, conv_raw_prob = tf.split(conv_output, (2, 2, 1, NUM_CLASS), 200 | axis=-1) 201 | 202 | xy_grid = tf.meshgrid(tf.range(output_size), tf.range(output_size)) 203 | xy_grid = tf.expand_dims(tf.stack(xy_grid, axis=-1), axis=2) # [gx, gy, 1, 2] 204 | xy_grid = tf.tile(tf.expand_dims(xy_grid, axis=0), [batch_size, 1, 1, 3, 1]) 205 | 206 | xy_grid = tf.cast(xy_grid, tf.float32) 207 | 208 | pred_xy = ((tf.sigmoid(conv_raw_dxdy) * XYSCALE[i]) - 0.5 * (XYSCALE[i] - 1) + xy_grid) * \ 209 | STRIDES[i] 210 | pred_wh = (tf.exp(conv_raw_dwdh) * ANCHORS[i]) 211 | pred_xywh = tf.concat([pred_xy, pred_wh], axis=-1) 212 | 213 | pred_conf = tf.sigmoid(conv_raw_conf) 214 | pred_prob = tf.sigmoid(conv_raw_prob) 215 | 216 | pred_prob = pred_conf * pred_prob 217 | pred_prob = tf.reshape(pred_prob, (batch_size, -1, NUM_CLASS)) 218 | pred_xywh = tf.reshape(pred_xywh, (batch_size, -1, 4)) 219 | 220 | return pred_xywh, pred_prob 221 | # return tf.concat([pred_xywh, pred_conf, pred_prob], axis=-1) 222 | 223 | def decode_tflite(conv_output, output_size, NUM_CLASS, STRIDES, ANCHORS, i=0, XYSCALE=[1,1,1]): 224 | conv_raw_dxdy_0, conv_raw_dwdh_0, conv_raw_score_0,\ 225 | conv_raw_dxdy_1, conv_raw_dwdh_1, conv_raw_score_1,\ 226 | conv_raw_dxdy_2, conv_raw_dwdh_2, conv_raw_score_2 = tf.split(conv_output, (2, 2, 1+NUM_CLASS, 2, 2, 1+NUM_CLASS, 227 | 2, 2, 1+NUM_CLASS), axis=-1) 228 | 229 | conv_raw_score = [conv_raw_score_0, conv_raw_score_1, conv_raw_score_2] 230 | for idx, score in enumerate(conv_raw_score): 231 | score = tf.sigmoid(score) 232 | score = score[:, :, :, 0:1] * score[:, :, :, 1:] 233 | conv_raw_score[idx] = tf.reshape(score, (1, -1, NUM_CLASS)) 234 | pred_prob = tf.concat(conv_raw_score, axis=1) 235 | 236 | conv_raw_dwdh = [conv_raw_dwdh_0, conv_raw_dwdh_1, conv_raw_dwdh_2] 237 | for idx, dwdh in enumerate(conv_raw_dwdh): 238 | dwdh = tf.exp(dwdh) * ANCHORS[i][idx] 239 | conv_raw_dwdh[idx] = tf.reshape(dwdh, (1, -1, 2)) 240 | pred_wh = tf.concat(conv_raw_dwdh, axis=1) 241 | 242 | xy_grid = tf.meshgrid(tf.range(output_size), tf.range(output_size)) 243 | xy_grid = tf.stack(xy_grid, axis=-1) # [gx, gy, 2] 244 | xy_grid = tf.expand_dims(xy_grid, axis=0) 245 | xy_grid = tf.cast(xy_grid, tf.float32) 246 | 247 | conv_raw_dxdy = [conv_raw_dxdy_0, conv_raw_dxdy_1, conv_raw_dxdy_2] 248 | for idx, dxdy in enumerate(conv_raw_dxdy): 249 | dxdy = ((tf.sigmoid(dxdy) * XYSCALE[i]) - 0.5 * (XYSCALE[i] - 1) + xy_grid) * \ 250 | STRIDES[i] 251 | conv_raw_dxdy[idx] = tf.reshape(dxdy, (1, -1, 2)) 252 | pred_xy = tf.concat(conv_raw_dxdy, axis=1) 253 | pred_xywh = tf.concat([pred_xy, pred_wh], axis=-1) 254 | return pred_xywh, pred_prob 255 | # return tf.concat([pred_xywh, pred_conf, pred_prob], axis=-1) 256 | 257 | def decode_trt(conv_output, output_size, NUM_CLASS, STRIDES, ANCHORS, i=0, XYSCALE=[1,1,1]): 258 | batch_size = tf.shape(conv_output)[0] 259 | conv_output = tf.reshape(conv_output, (batch_size, output_size, output_size, 3, 5 + NUM_CLASS)) 260 | 261 | conv_raw_dxdy, conv_raw_dwdh, conv_raw_conf, conv_raw_prob = tf.split(conv_output, (2, 2, 1, NUM_CLASS), axis=-1) 262 | 263 | xy_grid = tf.meshgrid(tf.range(output_size), tf.range(output_size)) 264 | xy_grid = tf.expand_dims(tf.stack(xy_grid, axis=-1), axis=2) # [gx, gy, 1, 2] 265 | xy_grid = tf.tile(tf.expand_dims(xy_grid, axis=0), [batch_size, 1, 1, 3, 1]) 266 | 267 | # x = tf.tile(tf.expand_dims(tf.range(output_size, dtype=tf.float32), axis=0), [output_size, 1]) 268 | # y = tf.tile(tf.expand_dims(tf.range(output_size, dtype=tf.float32), axis=1), [1, output_size]) 269 | # xy_grid = tf.expand_dims(tf.stack([x, y], axis=-1), axis=2) # [gx, gy, 1, 2] 270 | # xy_grid = tf.tile(tf.expand_dims(xy_grid, axis=0), [tf.shape(conv_output)[0], 1, 1, 3, 1]) 271 | 272 | xy_grid = tf.cast(xy_grid, tf.float32) 273 | 274 | # pred_xy = ((tf.sigmoid(conv_raw_dxdy) * XYSCALE[i]) - 0.5 * (XYSCALE[i] - 1) + xy_grid) * \ 275 | # STRIDES[i] 276 | pred_xy = (tf.reshape(tf.sigmoid(conv_raw_dxdy), (-1, 2)) * XYSCALE[i] - 0.5 * (XYSCALE[i] - 1) + tf.reshape(xy_grid, (-1, 2))) * STRIDES[i] 277 | pred_xy = tf.reshape(pred_xy, (batch_size, output_size, output_size, 3, 2)) 278 | pred_wh = (tf.exp(conv_raw_dwdh) * ANCHORS[i]) 279 | pred_xywh = tf.concat([pred_xy, pred_wh], axis=-1) 280 | 281 | pred_conf = tf.sigmoid(conv_raw_conf) 282 | pred_prob = tf.sigmoid(conv_raw_prob) 283 | 284 | pred_prob = pred_conf * pred_prob 285 | 286 | pred_prob = tf.reshape(pred_prob, (batch_size, -1, NUM_CLASS)) 287 | pred_xywh = tf.reshape(pred_xywh, (batch_size, -1, 4)) 288 | return pred_xywh, pred_prob 289 | # return tf.concat([pred_xywh, pred_conf, pred_prob], axis=-1) 290 | 291 | 292 | def filter_boxes(box_xywh, scores, score_threshold=0.4, input_shape = tf.constant([416,416])): 293 | scores_max = tf.math.reduce_max(scores, axis=-1) 294 | 295 | mask = scores_max >= score_threshold 296 | class_boxes = tf.boolean_mask(box_xywh, mask) 297 | pred_conf = tf.boolean_mask(scores, mask) 298 | class_boxes = tf.reshape(class_boxes, [tf.shape(scores)[0], -1, tf.shape(class_boxes)[-1]]) 299 | pred_conf = tf.reshape(pred_conf, [tf.shape(scores)[0], -1, tf.shape(pred_conf)[-1]]) 300 | 301 | box_xy, box_wh = tf.split(class_boxes, (2, 2), axis=-1) 302 | 303 | input_shape = tf.cast(input_shape, dtype=tf.float32) 304 | 305 | box_yx = box_xy[..., ::-1] 306 | box_hw = box_wh[..., ::-1] 307 | 308 | box_mins = (box_yx - (box_hw / 2.)) / input_shape 309 | box_maxes = (box_yx + (box_hw / 2.)) / input_shape 310 | boxes = tf.concat([ 311 | box_mins[..., 0:1], # y_min 312 | box_mins[..., 1:2], # x_min 313 | box_maxes[..., 0:1], # y_max 314 | box_maxes[..., 1:2] # x_max 315 | ], axis=-1) 316 | # return tf.concat([boxes, pred_conf], axis=-1) 317 | return (boxes, pred_conf) 318 | 319 | 320 | def compute_loss(pred, conv, label, bboxes, STRIDES, NUM_CLASS, IOU_LOSS_THRESH, i=0): 321 | conv_shape = tf.shape(conv) 322 | batch_size = conv_shape[0] 323 | output_size = conv_shape[1] 324 | input_size = STRIDES[i] * output_size 325 | conv = tf.reshape(conv, (batch_size, output_size, output_size, 3, 5 + NUM_CLASS)) 326 | 327 | conv_raw_conf = conv[:, :, :, :, 4:5] 328 | conv_raw_prob = conv[:, :, :, :, 5:] 329 | 330 | pred_xywh = pred[:, :, :, :, 0:4] 331 | pred_conf = pred[:, :, :, :, 4:5] 332 | 333 | label_xywh = label[:, :, :, :, 0:4] 334 | respond_bbox = label[:, :, :, :, 4:5] 335 | label_prob = label[:, :, :, :, 5:] 336 | 337 | giou = tf.expand_dims(utils.bbox_giou(pred_xywh, label_xywh), axis=-1) 338 | input_size = tf.cast(input_size, tf.float32) 339 | 340 | bbox_loss_scale = 2.0 - 1.0 * label_xywh[:, :, :, :, 2:3] * label_xywh[:, :, :, :, 3:4] / (input_size ** 2) 341 | giou_loss = respond_bbox * bbox_loss_scale * (1- giou) 342 | 343 | iou = utils.bbox_iou(pred_xywh[:, :, :, :, np.newaxis, :], bboxes[:, np.newaxis, np.newaxis, np.newaxis, :, :]) 344 | max_iou = tf.expand_dims(tf.reduce_max(iou, axis=-1), axis=-1) 345 | 346 | respond_bgd = (1.0 - respond_bbox) * tf.cast( max_iou < IOU_LOSS_THRESH, tf.float32 ) 347 | 348 | conf_focal = tf.pow(respond_bbox - pred_conf, 2) 349 | 350 | conf_loss = conf_focal * ( 351 | respond_bbox * tf.nn.sigmoid_cross_entropy_with_logits(labels=respond_bbox, logits=conv_raw_conf) 352 | + 353 | respond_bgd * tf.nn.sigmoid_cross_entropy_with_logits(labels=respond_bbox, logits=conv_raw_conf) 354 | ) 355 | 356 | prob_loss = respond_bbox * tf.nn.sigmoid_cross_entropy_with_logits(labels=label_prob, logits=conv_raw_prob) 357 | 358 | giou_loss = tf.reduce_mean(tf.reduce_sum(giou_loss, axis=[1,2,3,4])) 359 | conf_loss = tf.reduce_mean(tf.reduce_sum(conf_loss, axis=[1,2,3,4])) 360 | prob_loss = tf.reduce_mean(tf.reduce_sum(prob_loss, axis=[1,2,3,4])) 361 | 362 | return giou_loss, conf_loss, prob_loss 363 | 364 | 365 | 366 | 367 | 368 | -------------------------------------------------------------------------------- /data/anchors/basline_anchors.txt: -------------------------------------------------------------------------------- 1 | 1.25,1.625, 2.0,3.75, 4.125,2.875, 1.875,3.8125, 3.875,2.8125, 3.6875,7.4375, 3.625,2.8125, 4.875,6.1875, 11.65625,10.1875 2 | -------------------------------------------------------------------------------- /data/anchors/basline_tiny_anchors.txt: -------------------------------------------------------------------------------- 1 | 23,27, 37,58, 81,82, 81,82, 135,169, 344,319 -------------------------------------------------------------------------------- /data/anchors/yolov3_anchors.txt: -------------------------------------------------------------------------------- 1 | 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 -------------------------------------------------------------------------------- /data/anchors/yolov4_anchors.txt: -------------------------------------------------------------------------------- 1 | 12,16, 19,36, 40,28, 36,75, 76,55, 72,146, 142,110, 192,243, 459,401 2 | -------------------------------------------------------------------------------- /data/classes/coco.names: -------------------------------------------------------------------------------- 1 | person 2 | bicycle 3 | car 4 | motorbike 5 | aeroplane 6 | bus 7 | train 8 | truck 9 | boat 10 | traffic light 11 | fire hydrant 12 | stop sign 13 | parking meter 14 | bench 15 | bird 16 | cat 17 | dog 18 | horse 19 | sheep 20 | cow 21 | elephant 22 | bear 23 | zebra 24 | giraffe 25 | backpack 26 | umbrella 27 | handbag 28 | tie 29 | suitcase 30 | frisbee 31 | skis 32 | snowboard 33 | sports ball 34 | kite 35 | baseball bat 36 | baseball glove 37 | skateboard 38 | surfboard 39 | tennis racket 40 | bottle 41 | wine glass 42 | cup 43 | fork 44 | knife 45 | spoon 46 | bowl 47 | banana 48 | apple 49 | sandwich 50 | orange 51 | broccoli 52 | carrot 53 | hot dog 54 | pizza 55 | donut 56 | cake 57 | chair 58 | sofa 59 | potted plant 60 | bed 61 | dining table 62 | toilet 63 | tvmonitor 64 | laptop 65 | mouse 66 | remote 67 | keyboard 68 | cell phone 69 | microwave 70 | oven 71 | toaster 72 | sink 73 | refrigerator 74 | book 75 | clock 76 | vase 77 | scissors 78 | teddy bear 79 | hair drier 80 | toothbrush 81 | -------------------------------------------------------------------------------- /data/classes/license.names: -------------------------------------------------------------------------------- 1 | license_plate 2 | -------------------------------------------------------------------------------- /data/classes/logo.names: -------------------------------------------------------------------------------- 1 | suzuki 2 | hyundai 3 | toyota 4 | mahindra -------------------------------------------------------------------------------- /data/classes/voc.names: -------------------------------------------------------------------------------- 1 | aeroplane 2 | bicycle 3 | bird 4 | boat 5 | bottle 6 | bus 7 | car 8 | cat 9 | chair 10 | cow 11 | diningtable 12 | dog 13 | horse 14 | motorbike 15 | person 16 | pottedplant 17 | sheep 18 | sofa 19 | train 20 | tvmonitor -------------------------------------------------------------------------------- /data/classes/yymnist.names: -------------------------------------------------------------------------------- 1 | 0 2 | 1 3 | 2 4 | 3 5 | 4 6 | 5 7 | 6 8 | 7 9 | 8 10 | 9 11 | -------------------------------------------------------------------------------- /data/logo.names: -------------------------------------------------------------------------------- 1 | suzuki 2 | hyundai 3 | toyota 4 | mahindra -------------------------------------------------------------------------------- /data/ss/dataOutput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/data/ss/dataOutput.png -------------------------------------------------------------------------------- /data/ss/result14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/data/ss/result14.jpg -------------------------------------------------------------------------------- /data/ss/result15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/data/ss/result15.jpg -------------------------------------------------------------------------------- /data/ss/result16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/data/ss/result16.jpg -------------------------------------------------------------------------------- /data/ss/result5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/data/ss/result5.png -------------------------------------------------------------------------------- /data/ss/result6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/data/ss/result6.jpg -------------------------------------------------------------------------------- /data/ss/result7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/data/ss/result7.jpg -------------------------------------------------------------------------------- /data/ss/result8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/data/ss/result8.jpg -------------------------------------------------------------------------------- /detect.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | physical_devices = tf.config.experimental.list_physical_devices('GPU') 3 | if len(physical_devices) > 0: 4 | tf.config.experimental.set_memory_growth(physical_devices[0], True) 5 | from absl import app, flags, logging 6 | from absl.flags import FLAGS 7 | import core.utils as utils 8 | from core.yolov4 import filter_boxes 9 | from tensorflow.python.saved_model import tag_constants 10 | from PIL import Image 11 | import cv2 12 | import numpy as np 13 | from tensorflow.compat.v1 import ConfigProto 14 | from tensorflow.compat.v1 import InteractiveSession 15 | 16 | flags.DEFINE_string('framework', 'tf', '(tf, tflite, trt') 17 | flags.DEFINE_string('weights', './checkpoints/yolov4-416', 18 | 'path to weights file') 19 | flags.DEFINE_integer('size', 416, 'resize images to') 20 | flags.DEFINE_boolean('tiny', False, 'yolo or yolo-tiny') 21 | flags.DEFINE_string('model', 'yolov4', 'yolov3 or yolov4') 22 | flags.DEFINE_list('images', './data/images/kite.jpg', 'path to input image') 23 | flags.DEFINE_string('output', './detections/', 'path to output folder') 24 | flags.DEFINE_float('iou', 0.45, 'iou threshold') 25 | flags.DEFINE_float('score', 0.25, 'score threshold') 26 | flags.DEFINE_boolean('dont_show', False, 'dont show image output') 27 | 28 | def main(_argv): 29 | config = ConfigProto() 30 | config.gpu_options.allow_growth = True 31 | session = InteractiveSession(config=config) 32 | STRIDES, ANCHORS, NUM_CLASS, XYSCALE = utils.load_config(FLAGS) 33 | input_size = FLAGS.size 34 | images = FLAGS.images 35 | 36 | # load model 37 | if FLAGS.framework == 'tflite': 38 | interpreter = tf.lite.Interpreter(model_path=FLAGS.weights) 39 | else: 40 | saved_model_loaded = tf.saved_model.load(FLAGS.weights, tags=[tag_constants.SERVING]) 41 | 42 | # loop through images in list and run Yolov4 model on each 43 | for count, image_path in enumerate(images, 1): 44 | original_image = cv2.imread(image_path) 45 | original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB) 46 | 47 | image_data = cv2.resize(original_image, (input_size, input_size)) 48 | image_data = image_data / 255. 49 | 50 | images_data = [] 51 | for i in range(1): 52 | images_data.append(image_data) 53 | images_data = np.asarray(images_data).astype(np.float32) 54 | 55 | if FLAGS.framework == 'tflite': 56 | interpreter.allocate_tensors() 57 | input_details = interpreter.get_input_details() 58 | output_details = interpreter.get_output_details() 59 | print(input_details) 60 | print(output_details) 61 | interpreter.set_tensor(input_details[0]['index'], images_data) 62 | interpreter.invoke() 63 | pred = [interpreter.get_tensor(output_details[i]['index']) for i in range(len(output_details))] 64 | if FLAGS.model == 'yolov3' and FLAGS.tiny == True: 65 | boxes, pred_conf = filter_boxes(pred[1], pred[0], score_threshold=0.25, input_shape=tf.constant([input_size, input_size])) 66 | else: 67 | boxes, pred_conf = filter_boxes(pred[0], pred[1], score_threshold=0.25, input_shape=tf.constant([input_size, input_size])) 68 | else: 69 | infer = saved_model_loaded.signatures['serving_default'] 70 | batch_data = tf.constant(images_data) 71 | pred_bbox = infer(batch_data) 72 | for key, value in pred_bbox.items(): 73 | boxes = value[:, :, 0:4] 74 | pred_conf = value[:, :, 4:] 75 | 76 | boxes, scores, classes, valid_detections = tf.image.combined_non_max_suppression( 77 | boxes=tf.reshape(boxes, (tf.shape(boxes)[0], -1, 1, 4)), 78 | scores=tf.reshape( 79 | pred_conf, (tf.shape(pred_conf)[0], -1, tf.shape(pred_conf)[-1])), 80 | max_output_size_per_class=50, 81 | max_total_size=50, 82 | iou_threshold=FLAGS.iou, 83 | score_threshold=FLAGS.score 84 | ) 85 | pred_bbox = [boxes.numpy(), scores.numpy(), classes.numpy(), valid_detections.numpy()] 86 | image = utils.draw_bbox(original_image, pred_bbox) 87 | # image = utils.draw_bbox(image_data*255, pred_bbox) 88 | image = Image.fromarray(image.astype(np.uint8)) 89 | if not FLAGS.dont_show: 90 | image.show() 91 | image = cv2.cvtColor(np.array(image), cv2.COLOR_BGR2RGB) 92 | cv2.imwrite(FLAGS.output + 'detection' + str(count) + '.png', image) 93 | 94 | if __name__ == '__main__': 95 | try: 96 | app.run(main) 97 | except SystemExit: 98 | pass 99 | -------------------------------------------------------------------------------- /detect_flask.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import argparse 3 | import time 4 | import cv2 5 | import os 6 | from flask import Flask, request, Response, jsonify 7 | import jsonpickle 8 | #import binascii 9 | import io as StringIO 10 | import base64 11 | from io import BytesIO 12 | import io 13 | import json 14 | from PIL import Image 15 | 16 | # construct the argument parse and parse the arguments 17 | 18 | confthres = 0.3 19 | nmsthres = 0.1 20 | yolo_path = './' 21 | 22 | 23 | def get_labels(labels_path): 24 | # load the COCO class labels our YOLO model was trained on 25 | #labelsPath = os.path.sep.join([yolo_path, "yolo_v3/coco.names"]) 26 | lpath = os.path.sep.join([yolo_path, labels_path]) 27 | LABELS = open(lpath).read().strip().split("\n") 28 | return LABELS 29 | 30 | 31 | def get_colors(LABELS): 32 | # initialize a list of colors to represent each possible class label 33 | np.random.seed(42) 34 | COLORS = np.random.randint(0, 255, size=(len(LABELS), 3), dtype="uint8") 35 | return COLORS 36 | 37 | 38 | def get_weights(weights_path): 39 | # derive the paths to the YOLO weights and model configuration 40 | weightsPath = os.path.sep.join([yolo_path, weights_path]) 41 | return weightsPath 42 | 43 | 44 | def get_config(config_path): 45 | configPath = os.path.sep.join([yolo_path, config_path]) 46 | return configPath 47 | 48 | 49 | def load_model(configpath, weightspath): 50 | # load our YOLO object detector trained on COCO dataset (80 classes) 51 | print("[INFO] loading YOLO from disk...") 52 | net = cv2.dnn.readNetFromDarknet(configpath, weightspath) 53 | return net 54 | 55 | 56 | def image_to_byte_array(image: Image): 57 | imgByteArr = io.BytesIO() 58 | image.save(imgByteArr, format='PNG') 59 | imgByteArr = imgByteArr.getvalue() 60 | return imgByteArr 61 | 62 | 63 | def get_prediction(image, net, LABELS, COLORS): 64 | (H, W) = image.shape[:2] 65 | 66 | # determine only the *output* layer names that we need from YOLO 67 | ln = net.getLayerNames() 68 | ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()] 69 | 70 | # construct a blob from the input image and then perform a forward 71 | # pass of the YOLO object detector, giving us our bounding boxes and 72 | # associated probabilities 73 | blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (416, 416), 74 | swapRB=True, crop=False) 75 | net.setInput(blob) 76 | start = time.time() 77 | layerOutputs = net.forward(ln) 78 | print(layerOutputs) 79 | end = time.time() 80 | 81 | # show timing information on YOLO 82 | print("[INFO] YOLO took {:.6f} seconds".format(end - start)) 83 | 84 | # initialize our lists of detected bounding boxes, confidences, and 85 | # class IDs, respectively 86 | boxes = [] 87 | confidences = [] 88 | classIDs = [] 89 | print('******************',layerOutputs) 90 | # loop over each of the layer outputs 91 | for output in layerOutputs: 92 | # loop over each of the detections 93 | for detection in output: 94 | # extract the class ID and confidence (i.e., probability) of 95 | # the current object detection 96 | scores = detection[5:] 97 | # print(scores) 98 | classID = np.argmax(scores) 99 | # print(classID) 100 | confidence = scores[classID] 101 | 102 | # filter out weak predictions by ensuring the detected 103 | # probability is greater than the minimum probability 104 | if confidence > confthres: 105 | # scale the bounding box coordinates back relative to the 106 | # size of the image, keeping in mind that YOLO actually 107 | # returns the center (x, y)-coordinates of the bounding 108 | # box followed by the boxes' width and height 109 | box = detection[0:4] * np.array([W, H, W, H]) 110 | (centerX, centerY, width, height) = box.astype("int") 111 | 112 | # use the center (x, y)-coordinates to derive the top and 113 | # and left corner of the bounding box 114 | x = int(centerX - (width / 2)) 115 | y = int(centerY - (height / 2)) 116 | 117 | # update our list of bounding box coordinates, confidences, 118 | # and class IDs 119 | boxes.append([x, y, int(width), int(height)]) 120 | confidences.append(float(confidence)) 121 | classIDs.append(classID) 122 | 123 | # apply non-maxima suppression to suppress weak, overlapping bounding 124 | # boxes 125 | idxs = cv2.dnn.NMSBoxes(boxes, confidences, confthres, 126 | nmsthres) 127 | print(len(COLORS)) 128 | # ensure at least one detection exists 129 | if len(idxs) > 0: 130 | # loop over the indexes we are keeping 131 | for i in idxs.flatten(): 132 | # extract the bounding box coordinates 133 | (x, y) = (boxes[i][0], boxes[i][1]) 134 | (w, h) = (boxes[i][2], boxes[i][3]) 135 | 136 | # draw a bounding box rectangle and label on the image 137 | color = [int(c) for c in COLORS[classIDs[i]]] 138 | cv2.rectangle(image, (x, y), (x + w, y + h), color, 2) 139 | text = "{}: {:.4f}".format(LABELS[classIDs[i]], confidences[i]) 140 | print(boxes) 141 | print(classIDs) 142 | cv2.putText(image, text, (x, y - 5), 143 | cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) 144 | return image 145 | 146 | 147 | labelsPath = "data/classes/coco.names" 148 | cfgpath = "data/yolov4.cfg" 149 | wpath = "data/yolov4.weights" 150 | Lables = get_labels(labelsPath) 151 | CFG = get_config(cfgpath) 152 | Weights = get_weights(wpath) 153 | nets = load_model(CFG, Weights) 154 | Colors = get_colors(Lables) 155 | app = Flask(__name__) 156 | 157 | @app.route('/api/test', methods=['POST']) 158 | def main(): 159 | img = request.files["image"].read() 160 | img = Image.open(io.BytesIO(img)) 161 | npimg = np.array(img) 162 | image = npimg.copy() 163 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) 164 | res = get_prediction(image, nets, Lables, Colors) 165 | # image=cv2.cvtColor(image,cv2.COLOR_BGR2RGB) 166 | # show the output image 167 | #cv2.imshow("Image", res) 168 | # cv2.waitKey() 169 | image = cv2.cvtColor(res, cv2.COLOR_BGR2RGB) 170 | np_img = Image.fromarray(image) 171 | img_encoded = image_to_byte_array(np_img) 172 | return Response(response=img_encoded, status=200, mimetype="image/jpeg") 173 | 174 | # start flask app 175 | if __name__ == '__main__': 176 | app.run(debug=True, host='0.0.0.0') 177 | -------------------------------------------------------------------------------- /detect_object.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | physical_devices = tf.config.experimental.list_physical_devices('GPU') 3 | if len(physical_devices) > 0: 4 | tf.config.experimental.set_memory_growth(physical_devices[0], True) 5 | from absl import app, flags, logging 6 | from absl.flags import FLAGS 7 | import core.utils as utils 8 | from core.yolov4 import filter_boxes 9 | from tensorflow.python.saved_model import tag_constants 10 | from PIL import Image 11 | import cv2 12 | import numpy as np 13 | from shutil import copyfile 14 | import shutil 15 | import os, glob 16 | from tensorflow.compat.v1 import ConfigProto 17 | from tensorflow.compat.v1 import InteractiveSession 18 | 19 | 20 | framework="tf" #tf, tflite, trt 21 | model="yolov4" #yolov3 or yolov4 22 | tiny=True #yolo or yolo-tiny 23 | iou=0.45 #iou threshold 24 | score=0.25 #score threshold 25 | output='./detections/' #path to output folder 26 | 27 | #def main(): 28 | def glass_detector(image_name): 29 | image_size=416 30 | imput_image=image_name 31 | config = ConfigProto() 32 | config.gpu_options.allow_growth = True 33 | session = InteractiveSession(config=config) 34 | STRIDES, ANCHORS, NUM_CLASS, XYSCALE = utils.load_config(FLAGS) 35 | input_size = image_size 36 | images = [imput_image] 37 | 38 | # load model 39 | weights_loaded="./checkpoints/yolo-tiny-416" 40 | if framework == 'tflite': 41 | interpreter = tf.lite.Interpreter(model_path=weights_loaded) 42 | else: 43 | saved_model_loaded = tf.saved_model.load(weights_loaded, tags=[tag_constants.SERVING]) 44 | 45 | # loop through images in list and run Yolov4 model on each 46 | for count, image_path in enumerate(images, 1): 47 | original_image = cv2.imread(image_path) 48 | original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB) 49 | 50 | image_data = cv2.resize(original_image, (input_size, input_size)) 51 | image_data = image_data / 255. 52 | 53 | images_data = [] 54 | for i in range(1): 55 | images_data.append(image_data) 56 | images_data = np.asarray(images_data).astype(np.float32) 57 | 58 | if framework == 'tflite': 59 | interpreter.allocate_tensors() 60 | input_details = interpreter.get_input_details() 61 | output_details = interpreter.get_output_details() 62 | print(input_details) 63 | print(output_details) 64 | interpreter.set_tensor(input_details[0]['index'], images_data) 65 | interpreter.invoke() 66 | pred = [interpreter.get_tensor(output_details[i]['index']) for i in range(len(output_details))] 67 | if model == 'yolov3' and tiny == True: 68 | boxes, pred_conf = filter_boxes(pred[1], pred[0], score_threshold=0.25, input_shape=tf.constant([input_size, input_size])) 69 | else: 70 | boxes, pred_conf = filter_boxes(pred[0], pred[1], score_threshold=0.25, input_shape=tf.constant([input_size, input_size])) 71 | else: 72 | infer = saved_model_loaded.signatures['serving_default'] 73 | batch_data = tf.constant(images_data) 74 | pred_bbox = infer(batch_data) 75 | for key, value in pred_bbox.items(): 76 | boxes = value[:, :, 0:4] 77 | pred_conf = value[:, :, 4:] 78 | 79 | boxes, scores, classes, valid_detections = tf.image.combined_non_max_suppression( 80 | boxes=tf.reshape(boxes, (tf.shape(boxes)[0], -1, 1, 4)), 81 | scores=tf.reshape( 82 | pred_conf, (tf.shape(pred_conf)[0], -1, tf.shape(pred_conf)[-1])), 83 | max_output_size_per_class=50, 84 | max_total_size=50, 85 | iou_threshold=iou, 86 | score_threshold=score 87 | ) 88 | pred_bbox = [boxes.numpy(), scores.numpy(), classes.numpy(), valid_detections.numpy()] 89 | #image = utils.draw_bbox(original_image, pred_bbox) 90 | cropped_image = utils.draw_bbox(original_image, pred_bbox) 91 | # image = utils.draw_bbox(image_data*255, pred_bbox) 92 | image = Image.fromarray(cropped_image.astype(np.uint8)) 93 | #if not FLAGS.dont_show: 94 | #image.show() 95 | image = cv2.cvtColor(np.array(image), cv2.COLOR_BGR2RGB) 96 | 97 | cv2.imwrite(output + 'DetectedGlass' + str(count) + '.jpg', image) 98 | return image -------------------------------------------------------------------------------- /detect_video.py: -------------------------------------------------------------------------------- 1 | import time 2 | import tensorflow as tf 3 | physical_devices = tf.config.experimental.list_physical_devices('GPU') 4 | if len(physical_devices) > 0: 5 | tf.config.experimental.set_memory_growth(physical_devices[0], True) 6 | from absl import app, flags, logging 7 | from absl.flags import FLAGS 8 | import core.utils as utils 9 | from core.yolov4 import filter_boxes 10 | from tensorflow.python.saved_model import tag_constants 11 | from PIL import Image 12 | import cv2 13 | import numpy as np 14 | from tensorflow.compat.v1 import ConfigProto 15 | from tensorflow.compat.v1 import InteractiveSession 16 | 17 | flags.DEFINE_string('framework', 'tf', '(tf, tflite, trt') 18 | flags.DEFINE_string('weights', './checkpoints/yolov4-416', 19 | 'path to weights file') 20 | flags.DEFINE_integer('size', 416, 'resize images to') 21 | flags.DEFINE_boolean('tiny', False, 'yolo or yolo-tiny') 22 | flags.DEFINE_string('model', 'yolov4', 'yolov3 or yolov4') 23 | flags.DEFINE_string('video', './data/video/video.mp4', 'path to input video or set to 0 for webcam') 24 | flags.DEFINE_string('output', None, 'path to output video') 25 | flags.DEFINE_string('output_format', 'XVID', 'codec used in VideoWriter when saving video to file') 26 | flags.DEFINE_float('iou', 0.45, 'iou threshold') 27 | flags.DEFINE_float('score', 0.25, 'score threshold') 28 | flags.DEFINE_boolean('dont_show', False, 'dont show video output') 29 | 30 | def main(_argv): 31 | config = ConfigProto() 32 | config.gpu_options.allow_growth = True 33 | session = InteractiveSession(config=config) 34 | STRIDES, ANCHORS, NUM_CLASS, XYSCALE = utils.load_config(FLAGS) 35 | input_size = FLAGS.size 36 | video_path = FLAGS.video 37 | 38 | if FLAGS.framework == 'tflite': 39 | interpreter = tf.lite.Interpreter(model_path=FLAGS.weights) 40 | interpreter.allocate_tensors() 41 | input_details = interpreter.get_input_details() 42 | output_details = interpreter.get_output_details() 43 | print(input_details) 44 | print(output_details) 45 | else: 46 | saved_model_loaded = tf.saved_model.load(FLAGS.weights, tags=[tag_constants.SERVING]) 47 | infer = saved_model_loaded.signatures['serving_default'] 48 | 49 | # begin video capture 50 | try: 51 | vid = cv2.VideoCapture(int(video_path)) 52 | except: 53 | vid = cv2.VideoCapture(video_path) 54 | 55 | out = None 56 | 57 | if FLAGS.output: 58 | # by default VideoCapture returns float instead of int 59 | width = int(vid.get(cv2.CAP_PROP_FRAME_WIDTH)) 60 | height = int(vid.get(cv2.CAP_PROP_FRAME_HEIGHT)) 61 | fps = int(vid.get(cv2.CAP_PROP_FPS)) 62 | codec = cv2.VideoWriter_fourcc(*FLAGS.output_format) 63 | out = cv2.VideoWriter(FLAGS.output, codec, fps, (width, height)) 64 | 65 | while True: 66 | return_value, frame = vid.read() 67 | if return_value: 68 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 69 | image = Image.fromarray(frame) 70 | else: 71 | print('Video has ended or failed, try a different video format!') 72 | break 73 | 74 | frame_size = frame.shape[:2] 75 | image_data = cv2.resize(frame, (input_size, input_size)) 76 | image_data = image_data / 255. 77 | image_data = image_data[np.newaxis, ...].astype(np.float32) 78 | start_time = time.time() 79 | 80 | if FLAGS.framework == 'tflite': 81 | interpreter.set_tensor(input_details[0]['index'], image_data) 82 | interpreter.invoke() 83 | pred = [interpreter.get_tensor(output_details[i]['index']) for i in range(len(output_details))] 84 | if FLAGS.model == 'yolov3' and FLAGS.tiny == True: 85 | boxes, pred_conf = filter_boxes(pred[1], pred[0], score_threshold=0.25, 86 | input_shape=tf.constant([input_size, input_size])) 87 | else: 88 | boxes, pred_conf = filter_boxes(pred[0], pred[1], score_threshold=0.25, 89 | input_shape=tf.constant([input_size, input_size])) 90 | else: 91 | batch_data = tf.constant(image_data) 92 | pred_bbox = infer(batch_data) 93 | for key, value in pred_bbox.items(): 94 | boxes = value[:, :, 0:4] 95 | pred_conf = value[:, :, 4:] 96 | 97 | boxes, scores, classes, valid_detections = tf.image.combined_non_max_suppression( 98 | boxes=tf.reshape(boxes, (tf.shape(boxes)[0], -1, 1, 4)), 99 | scores=tf.reshape( 100 | pred_conf, (tf.shape(pred_conf)[0], -1, tf.shape(pred_conf)[-1])), 101 | max_output_size_per_class=50, 102 | max_total_size=50, 103 | iou_threshold=FLAGS.iou, 104 | score_threshold=FLAGS.score 105 | ) 106 | pred_bbox = [boxes.numpy(), scores.numpy(), classes.numpy(), valid_detections.numpy()] 107 | image = utils.draw_bbox(frame, pred_bbox) 108 | fps = 1.0 / (time.time() - start_time) 109 | print("FPS: %.2f" % fps) 110 | result = np.asarray(image) 111 | cv2.namedWindow("result", cv2.WINDOW_AUTOSIZE) 112 | result = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) 113 | 114 | if not FLAGS.dont_show: 115 | cv2.imshow("result", result) 116 | 117 | if FLAGS.output: 118 | out.write(result) 119 | if cv2.waitKey(1) & 0xFF == ord('q'): break 120 | cv2.destroyAllWindows() 121 | 122 | if __name__ == '__main__': 123 | try: 124 | app.run(main) 125 | except SystemExit: 126 | pass 127 | -------------------------------------------------------------------------------- /evaluate.py: -------------------------------------------------------------------------------- 1 | from absl import app, flags, logging 2 | from absl.flags import FLAGS 3 | import cv2 4 | import os 5 | import shutil 6 | import numpy as np 7 | import tensorflow as tf 8 | from core.yolov4 import filter_boxes 9 | from tensorflow.python.saved_model import tag_constants 10 | import core.utils as utils 11 | from core.config import cfg 12 | 13 | flags.DEFINE_string('weights', './checkpoints/yolov4-416', 14 | 'path to weights file') 15 | flags.DEFINE_string('framework', 'tf', 'select model type in (tf, tflite, trt)' 16 | 'path to weights file') 17 | flags.DEFINE_string('model', 'yolov4', 'yolov3 or yolov4') 18 | flags.DEFINE_boolean('tiny', False, 'yolov3 or yolov3-tiny') 19 | flags.DEFINE_integer('size', 416, 'resize images to') 20 | flags.DEFINE_string('annotation_path', "./data/dataset/val2017.txt", 'annotation path') 21 | flags.DEFINE_string('write_image_path', "./data/detection/", 'write image path') 22 | flags.DEFINE_float('iou', 0.5, 'iou threshold') 23 | flags.DEFINE_float('score', 0.25, 'score threshold') 24 | 25 | def main(_argv): 26 | INPUT_SIZE = FLAGS.size 27 | STRIDES, ANCHORS, NUM_CLASS, XYSCALE = utils.load_config(FLAGS) 28 | CLASSES = utils.read_class_names(cfg.YOLO.CLASSES) 29 | 30 | predicted_dir_path = './mAP/predicted' 31 | ground_truth_dir_path = './mAP/ground-truth' 32 | if os.path.exists(predicted_dir_path): shutil.rmtree(predicted_dir_path) 33 | if os.path.exists(ground_truth_dir_path): shutil.rmtree(ground_truth_dir_path) 34 | if os.path.exists(cfg.TEST.DECTECTED_IMAGE_PATH): shutil.rmtree(cfg.TEST.DECTECTED_IMAGE_PATH) 35 | 36 | os.mkdir(predicted_dir_path) 37 | os.mkdir(ground_truth_dir_path) 38 | os.mkdir(cfg.TEST.DECTECTED_IMAGE_PATH) 39 | 40 | # Build Model 41 | if FLAGS.framework == 'tflite': 42 | interpreter = tf.lite.Interpreter(model_path=FLAGS.weights) 43 | interpreter.allocate_tensors() 44 | input_details = interpreter.get_input_details() 45 | output_details = interpreter.get_output_details() 46 | print(input_details) 47 | print(output_details) 48 | else: 49 | saved_model_loaded = tf.saved_model.load(FLAGS.weights, tags=[tag_constants.SERVING]) 50 | infer = saved_model_loaded.signatures['serving_default'] 51 | 52 | num_lines = sum(1 for line in open(FLAGS.annotation_path)) 53 | with open(cfg.TEST.ANNOT_PATH, 'r') as annotation_file: 54 | for num, line in enumerate(annotation_file): 55 | annotation = line.strip().split() 56 | image_path = annotation[0] 57 | image_name = image_path.split('/')[-1] 58 | image = cv2.imread(image_path) 59 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) 60 | bbox_data_gt = np.array([list(map(int, box.split(','))) for box in annotation[1:]]) 61 | 62 | if len(bbox_data_gt) == 0: 63 | bboxes_gt = [] 64 | classes_gt = [] 65 | else: 66 | bboxes_gt, classes_gt = bbox_data_gt[:, :4], bbox_data_gt[:, 4] 67 | ground_truth_path = os.path.join(ground_truth_dir_path, str(num) + '.txt') 68 | 69 | print('=> ground truth of %s:' % image_name) 70 | num_bbox_gt = len(bboxes_gt) 71 | with open(ground_truth_path, 'w') as f: 72 | for i in range(num_bbox_gt): 73 | class_name = CLASSES[classes_gt[i]] 74 | xmin, ymin, xmax, ymax = list(map(str, bboxes_gt[i])) 75 | bbox_mess = ' '.join([class_name, xmin, ymin, xmax, ymax]) + '\n' 76 | f.write(bbox_mess) 77 | print('\t' + str(bbox_mess).strip()) 78 | print('=> predict result of %s:' % image_name) 79 | predict_result_path = os.path.join(predicted_dir_path, str(num) + '.txt') 80 | # Predict Process 81 | image_size = image.shape[:2] 82 | # image_data = utils.image_preprocess(np.copy(image), [INPUT_SIZE, INPUT_SIZE]) 83 | image_data = cv2.resize(np.copy(image), (INPUT_SIZE, INPUT_SIZE)) 84 | image_data = image_data / 255. 85 | image_data = image_data[np.newaxis, ...].astype(np.float32) 86 | 87 | if FLAGS.framework == 'tflite': 88 | interpreter.set_tensor(input_details[0]['index'], image_data) 89 | interpreter.invoke() 90 | pred = [interpreter.get_tensor(output_details[i]['index']) for i in range(len(output_details))] 91 | if FLAGS.model == 'yolov4' and FLAGS.tiny == True: 92 | boxes, pred_conf = filter_boxes(pred[1], pred[0], score_threshold=0.25) 93 | else: 94 | boxes, pred_conf = filter_boxes(pred[0], pred[1], score_threshold=0.25) 95 | else: 96 | batch_data = tf.constant(image_data) 97 | pred_bbox = infer(batch_data) 98 | for key, value in pred_bbox.items(): 99 | boxes = value[:, :, 0:4] 100 | pred_conf = value[:, :, 4:] 101 | 102 | boxes, scores, classes, valid_detections = tf.image.combined_non_max_suppression( 103 | boxes=tf.reshape(boxes, (tf.shape(boxes)[0], -1, 1, 4)), 104 | scores=tf.reshape( 105 | pred_conf, (tf.shape(pred_conf)[0], -1, tf.shape(pred_conf)[-1])), 106 | max_output_size_per_class=50, 107 | max_total_size=50, 108 | iou_threshold=FLAGS.iou, 109 | score_threshold=FLAGS.score 110 | ) 111 | boxes, scores, classes, valid_detections = [boxes.numpy(), scores.numpy(), classes.numpy(), valid_detections.numpy()] 112 | 113 | # if cfg.TEST.DECTECTED_IMAGE_PATH is not None: 114 | # image_result = utils.draw_bbox(np.copy(image), [boxes, scores, classes, valid_detections]) 115 | # cv2.imwrite(cfg.TEST.DECTECTED_IMAGE_PATH + image_name, image_result) 116 | 117 | with open(predict_result_path, 'w') as f: 118 | image_h, image_w, _ = image.shape 119 | for i in range(valid_detections[0]): 120 | if int(classes[0][i]) < 0 or int(classes[0][i]) > NUM_CLASS: continue 121 | coor = boxes[0][i] 122 | coor[0] = int(coor[0] * image_h) 123 | coor[2] = int(coor[2] * image_h) 124 | coor[1] = int(coor[1] * image_w) 125 | coor[3] = int(coor[3] * image_w) 126 | 127 | score = scores[0][i] 128 | class_ind = int(classes[0][i]) 129 | class_name = CLASSES[class_ind] 130 | score = '%.4f' % score 131 | ymin, xmin, ymax, xmax = list(map(str, coor)) 132 | bbox_mess = ' '.join([class_name, score, xmin, ymin, xmax, ymax]) + '\n' 133 | f.write(bbox_mess) 134 | print('\t' + str(bbox_mess).strip()) 135 | print(num, num_lines) 136 | 137 | if __name__ == '__main__': 138 | try: 139 | app.run(main) 140 | except SystemExit: 141 | pass 142 | 143 | 144 | -------------------------------------------------------------------------------- /mAP/extra/intersect-gt-and-pred.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import glob 4 | 5 | ## This script ensures same number of files in ground-truth and predicted folder. 6 | ## When you encounter file not found error, it's usually because you have 7 | ## mismatched numbers of ground-truth and predicted files. 8 | ## You can use this script to move ground-truth and predicted files that are 9 | ## not in the intersection into a backup folder (backup_no_matches_found). 10 | ## This will retain only files that have the same name in both folders. 11 | 12 | # change directory to the one with the files to be changed 13 | path_to_gt = '../ground-truth' 14 | path_to_pred = '../predicted' 15 | backup_folder = 'backup_no_matches_found' # must end without slash 16 | 17 | os.chdir(path_to_gt) 18 | gt_files = glob.glob('*.txt') 19 | if len(gt_files) == 0: 20 | print("Error: no .txt files found in", path_to_gt) 21 | sys.exit() 22 | os.chdir(path_to_pred) 23 | pred_files = glob.glob('*.txt') 24 | if len(pred_files) == 0: 25 | print("Error: no .txt files found in", path_to_pred) 26 | sys.exit() 27 | 28 | gt_files = set(gt_files) 29 | pred_files = set(pred_files) 30 | print('total ground-truth files:', len(gt_files)) 31 | print('total predicted files:', len(pred_files)) 32 | print() 33 | 34 | gt_backup = gt_files - pred_files 35 | pred_backup = pred_files - gt_files 36 | 37 | 38 | def backup(src_folder, backup_files, backup_folder): 39 | # non-intersection files (txt format) will be moved to a backup folder 40 | if not backup_files: 41 | print('No backup required for', src_folder) 42 | return 43 | os.chdir(src_folder) 44 | ## create the backup dir if it doesn't exist already 45 | if not os.path.exists(backup_folder): 46 | os.makedirs(backup_folder) 47 | for file in backup_files: 48 | os.rename(file, backup_folder + '/' + file) 49 | 50 | 51 | backup(path_to_gt, gt_backup, backup_folder) 52 | backup(path_to_pred, pred_backup, backup_folder) 53 | if gt_backup: 54 | print('total ground-truth backup files:', len(gt_backup)) 55 | if pred_backup: 56 | print('total predicted backup files:', len(pred_backup)) 57 | 58 | intersection = gt_files & pred_files 59 | print('total intersected files:', len(intersection)) 60 | print("Intersection completed!") -------------------------------------------------------------------------------- /mAP/extra/remove_space.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import glob 4 | import argparse 5 | 6 | # this script will load class_list.txt and find class names with spaces 7 | # then replace spaces with delimiters inside ground-truth/ and predicted/ 8 | 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument('-d', '--delimiter', type=str, help="delimiter to replace space (default: '-')", default='-') 11 | parser.add_argument('-y', '--yes', action='store_true', help="force yes confirmation on yes/no query (default: False)", default=False) 12 | args = parser.parse_args() 13 | 14 | def query_yes_no(question, default="yes", bypass=False): 15 | """Ask a yes/no question via raw_input() and return their answer. 16 | 17 | "question" is a string that is presented to the user. 18 | "default" is the presumed answer if the user just hits . 19 | It must be "yes" (the default), "no" or None (meaning 20 | an answer is required of the user). 21 | 22 | The "answer" return value is True for "yes" or False for "no". 23 | """ 24 | valid = {"yes": True, "y": True, "ye": True, 25 | "no": False, "n": False} 26 | if default is None: 27 | prompt = " [y/n] " 28 | elif default == "yes": 29 | prompt = " [Y/n] " 30 | elif default == "no": 31 | prompt = " [y/N] " 32 | else: 33 | raise ValueError("invalid default answer: '%s'" % default) 34 | 35 | while True: 36 | sys.stdout.write(question + prompt) 37 | if bypass: 38 | break 39 | if sys.version_info[0] == 3: 40 | choice = input().lower() # if version 3 of Python 41 | else: 42 | choice = raw_input().lower() 43 | if default is not None and choice == '': 44 | return valid[default] 45 | elif choice in valid: 46 | return valid[choice] 47 | else: 48 | sys.stdout.write("Please respond with 'yes' or 'no' " 49 | "(or 'y' or 'n').\n") 50 | 51 | 52 | def rename_class(current_class_name, new_class_name): 53 | # get list of txt files 54 | file_list = glob.glob('*.txt') 55 | file_list.sort() 56 | # iterate through the txt files 57 | for txt_file in file_list: 58 | class_found = False 59 | # open txt file lines to a list 60 | with open(txt_file) as f: 61 | content = f.readlines() 62 | # remove whitespace characters like `\n` at the end of each line 63 | content = [x.strip() for x in content] 64 | new_content = [] 65 | # go through each line of eache file 66 | for line in content: 67 | #class_name = line.split()[0] 68 | if current_class_name in line: 69 | class_found = True 70 | line = line.replace(current_class_name, new_class_name) 71 | new_content.append(line) 72 | if class_found: 73 | # rewrite file 74 | with open(txt_file, 'w') as new_f: 75 | for line in new_content: 76 | new_f.write("%s\n" % line) 77 | 78 | with open('../../data/classes/coco.names') as f: 79 | for line in f: 80 | current_class_name = line.rstrip("\n") 81 | new_class_name = line.replace(' ', args.delimiter).rstrip("\n") 82 | if current_class_name == new_class_name: 83 | continue 84 | y_n_message = ("Are you sure you want " 85 | "to rename the class " 86 | "\"" + current_class_name + "\" " 87 | "into \"" + new_class_name + "\"?" 88 | ) 89 | 90 | if query_yes_no(y_n_message, bypass=args.yes): 91 | os.chdir("../ground-truth") 92 | rename_class(current_class_name, new_class_name) 93 | os.chdir("../predicted") 94 | rename_class(current_class_name, new_class_name) 95 | 96 | print('Done!') 97 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from os.path import join 2 | import sys 3 | import tempfile 4 | from PIL import Image 5 | from werkzeug.utils import secure_filename 6 | from flask import Flask, render_template, Response, request, session, redirect, url_for, send_from_directory, flash 7 | from yolov4.tf import YOLOv4 8 | import cv2 9 | from car_colour_new import get_car_colour 10 | from speed_check_new import speed_detection 11 | # import yolov4.common.media 12 | import numpy as np 13 | import pytesseract 14 | import os 15 | import random 16 | import colorsys 17 | import re 18 | import cv2 19 | import csv 20 | 21 | UPLOAD_FOLDER = './static/uploads' 22 | output_path = './static/detections/' 23 | sec = 0 24 | frameRate = 0.1 25 | count = 0 26 | csvfile = None 27 | obj = None 28 | frameTimeStamp = [] 29 | stateLPInitial = set(["AP","AR","AS","BR","CG","GA","GJ","HR","HP","JH","KA","KL","MP","MH","MN","ML","MZ","NL","OD","PB","RJ","SK","TN","TS","TR","UP","UK","WB","AN","CH","DN","DD","DL","JK","LD","PY"]) 30 | 31 | _HSV = [(1.0 * x / 256, 1.0, 1.0) for x in range(256)] 32 | _COLORS = list(map(lambda x: colorsys.hsv_to_rgb(*x), _HSV)) 33 | _COLORS = list( 34 | map( 35 | lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), 36 | _COLORS, 37 | ) 38 | ) 39 | BBOX_COLORS = [] 40 | _OFFSET = [0, 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15] 41 | for i in range(256): 42 | BBOX_COLORS.append(_COLORS[(i * 16) % 256 + _OFFSET[(i * 16) // 256]]) 43 | 44 | 45 | def draw_bboxes1(image: np.ndarray, bboxes: np.ndarray, classes: dict): 46 | """ 47 | @parma image: Dim(height, width, channel) 48 | @param bboxes: (candidates, 4) or (candidates, 5) 49 | [[center_x, center_y, w, h, class_id], ...] 50 | [[center_x, center_y, w, h, class_id, propability], ...] 51 | @param classes: {0: 'person', 1: 'bicycle', 2: 'car', ...} 52 | 53 | @return drawn_image 54 | 55 | Usage: 56 | image = media.draw_bboxes(image, bboxes, classes) 57 | """ 58 | image = np.copy(image) 59 | height, width, _ = image.shape 60 | 61 | # Set propability 62 | if bboxes.shape[-1] == 5: 63 | bboxes = np.concatenate( 64 | [bboxes, np.full((*bboxes.shape[:-1], 1), 2.0)], axis=-1 65 | ) 66 | else: 67 | bboxes = np.copy(bboxes) 68 | 69 | # Convert ratio to length 70 | bboxes[:, [0, 2]] = bboxes[:, [0, 2]] * width 71 | bboxes[:, [1, 3]] = bboxes[:, [1, 3]] * height 72 | 73 | # Draw bboxes 74 | for bbox in bboxes: 75 | c_x = int(bbox[0]) 76 | c_y = int(bbox[1]) 77 | half_w = int(bbox[2] / 2) 78 | half_h = int(bbox[3] / 2) 79 | top_left = (c_x - half_w, c_y - half_h) 80 | bottom_right = (c_x + half_w, c_y + half_h) 81 | class_id = int(bbox[4]) 82 | bbox_color = BBOX_COLORS[class_id] 83 | font_size = 0.4 84 | font_thickness = 1 85 | 86 | # Draw box 87 | cv2.rectangle(image, top_left, bottom_right, bbox_color, 2) 88 | 89 | # Draw text box 90 | bbox_text = "{}: {:.1%}".format(classes[class_id], bbox[5]) 91 | t_size = cv2.getTextSize(bbox_text, 0, font_size, font_thickness)[0] 92 | cv2.rectangle( 93 | image, 94 | top_left, 95 | (top_left[0] + t_size[0], top_left[1] - t_size[1] - 3), 96 | bbox_color, 97 | -1, 98 | ) 99 | 100 | # Draw text 101 | cv2.putText( 102 | image, 103 | bbox_text, 104 | (top_left[0], top_left[1] - 2), 105 | cv2.FONT_HERSHEY_SIMPLEX, 106 | font_size, 107 | (255 - bbox_color[0], 255 - bbox_color[1], 255 - bbox_color[2]), 108 | font_thickness, 109 | lineType=cv2.LINE_AA, 110 | ) 111 | 112 | return image 113 | 114 | 115 | class_dict = { 116 | 0: "non-car", 117 | 1: "non-car", 118 | 2: "car", 119 | 3: "non-car", 120 | 4: "non-car", 121 | 5: "non-car", 122 | 6: "non-car", 123 | 7: "non-car", 124 | 8: "non-car", 125 | 9: "non-car", 126 | 10: "non-car", 127 | 11: "non-car", 128 | 12: "non-car", 129 | 13: "non-car", 130 | 14: "non-car", 131 | 15: "non-car", 132 | 16: "non-car", 133 | 17: "non-car", 134 | 18: "non-car", 135 | 19: "non-car", 136 | 20: "non-car", 137 | 21: "non-car", 138 | 22: "non-car", 139 | 23: "non-car", 140 | 24: "non-car", 141 | 25: "non-car", 142 | 26: "non-car", 143 | 27: "non-car", 144 | 28: "non-car", 145 | 29: "non-car", 146 | 30: "non-car", 147 | 31: "non-car", 148 | 32: "non-car", 149 | 33: "non-car", 150 | 34: "non-car", 151 | 35: "non-car", 152 | 36: "non-car", 153 | 37: "non-car", 154 | 38: "non-car", 155 | 39: "non-car", 156 | 40: "non-car", 157 | 41: "non-car", 158 | 42: "non-car", 159 | 43: "non-car", 160 | 44: "non-car", 161 | 45: "non-car", 162 | 46: "non-car", 163 | 47: "non-car", 164 | 48: "non-car", 165 | 49: "non-car", 166 | 50: "non-car", 167 | 51: "non-car", 168 | 52: "non-car", 169 | 53: "non-car", 170 | 54: "non-car", 171 | 55: "non-car", 172 | 56: "non-car", 173 | 57: "non-car", 174 | 58: "non-car", 175 | 59: "non-car", 176 | 60: "non-car", 177 | 61: "non-car", 178 | 62: "non-car", 179 | 63: "non-car", 180 | 64: "non-car", 181 | 65: "non-car", 182 | 66: "non-car", 183 | 67: "non-car", 184 | 68: "non-car", 185 | 69: "non-car", 186 | 70: "non-car", 187 | 71: "non-car", 188 | 72: "non-car", 189 | 73: "non-car", 190 | 74: "non-car", 191 | 75: "non-car", 192 | 76: "non-car", 193 | 77: "non-car", 194 | 78: "non-car", 195 | 79: "non-car" 196 | } 197 | 198 | class_dict_lp = { 199 | 0: "license_plate" 200 | } 201 | 202 | class_dict_logo = { 203 | 0: "Suzuki", 204 | 1: 'Hyundai', 205 | 2: "Toyota", 206 | 3: "Mahindra" 207 | } 208 | 209 | ###########################Loading Weights and Model############################ 210 | yolo = YOLOv4() 211 | yolo.classes = "./data/classes/coco.names" 212 | yolo.make_model() 213 | yolo.load_weights("./data/yolov4.weights", weights_type="yolo") 214 | yolo_lp = YOLOv4() 215 | yolo_lp.classes = "./data/classes/license.names" 216 | yolo_lp.make_model() 217 | yolo_lp.load_weights("./data/yolov4-license.weights", weights_type="yolo") 218 | # yolo_lp.inference("./car_video.mp4", is_image=False,score_threshold=0.8) 219 | 220 | yolo_logo = YOLOv4() 221 | yolo_logo.classes = "./data/classes/logo.names" 222 | yolo_logo.make_model() 223 | yolo_logo.load_weights("./data/yolov4-logo.weights", weights_type="yolo") 224 | 225 | # yolo.save_as_tflite("yolov4-tiny-float16.tflite") 226 | 227 | # yolo_lp.save_as_tflite("yolov4_lp-tiny-float16.tflite") 228 | 229 | # yolo_logo.save_as_tflite("yolov4_logo-tiny-float16.tflite") 230 | 231 | def validateLPText(text): 232 | if len(text)<2: 233 | return False 234 | if text[:2] not in stateLPInitial: 235 | return False 236 | if not text[-1].isnumeric: 237 | return False 238 | for letter in text: 239 | if not letter.isnumeric() and letter.islower(): 240 | return False 241 | return True 242 | 243 | def get_top_left_bottom_right(bbox): 244 | c_x = int(bbox[0]) 245 | c_y = int(bbox[1]) 246 | half_w = int(bbox[2] / 2) 247 | half_h = int(bbox[3] / 2) 248 | top_left = (c_x - half_w, c_y - half_h) 249 | bottom_right = (c_x + half_w, c_y + half_h) 250 | return(top_left, bottom_right) 251 | 252 | 253 | def detect_LP(input_img,filename): 254 | height, width, _ = input_img.shape 255 | bboxes = yolo_lp.predict(input_img) 256 | # Dim(-1, (x, y, w, h, class_id, probability)) 257 | if len(bboxes): 258 | bboxes_og = np.copy(bboxes) 259 | # Set propability 260 | if bboxes.shape[-1] == 5: 261 | bboxes = np.concatenate( 262 | [bboxes, np.full((*bboxes.shape[:-1], 1), 2.0)], axis=-1 263 | ) 264 | else: 265 | bboxes = np.copy(bboxes) 266 | 267 | # Convert ratio to length 268 | bboxes[:, [0, 2]] = bboxes[:, [0, 2]] * width 269 | bboxes[:, [1, 3]] = bboxes[:, [1, 3]] * height 270 | for bbox in bboxes: 271 | if len(bbox) and bbox[5] >= 0.9: 272 | try: 273 | top_left, bottom_right = get_top_left_bottom_right(bbox) 274 | crop_height = bottom_right[1]-top_left[1] 275 | crop_width = bottom_right[0]-top_left[0] 276 | 277 | crop_img = input_img[top_left[1]:top_left[1] + 278 | crop_height, top_left[0]:top_left[0]+crop_width] 279 | # cv2.imwrite("{}.png".format(filename), crop_img) 280 | gray = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY) 281 | gray = cv2.resize(gray, (0, 0), fx=5, fy=5) 282 | gray = cv2.GaussianBlur(gray, (3, 3), 0) 283 | gray = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] 284 | # filename = "{}.png".format(random) 285 | # cv2.imwrite(filename, gray) 286 | 287 | conf = r"--oem 1 --psm 6" 288 | text = pytesseract.image_to_string( 289 | gray, config=conf, lang='eng') 290 | # os.remove(filename) 291 | return(re.sub(r'\W+', '', text), bboxes_og) 292 | except Exception: 293 | pass 294 | 295 | 296 | def detect_logo(input_img): 297 | height, width, _ = input_img.shape 298 | bboxes = yolo_logo.predict(input_img) 299 | # Dim(-1, (x, y, w, h, class_id, probability)) 300 | if len(bboxes): 301 | bboxes_og = np.copy(bboxes) 302 | if bboxes.shape[-1] == 5: 303 | bboxes = np.concatenate( 304 | [bboxes, np.full((*bboxes.shape[:-1], 1), 2.0)], axis=-1 305 | ) 306 | else: 307 | bboxes = np.copy(bboxes) 308 | 309 | # Convert ratio to length 310 | bboxes[:, [0, 2]] = bboxes[:, [0, 2]] * width 311 | bboxes[:, [1, 3]] = bboxes[:, [1, 3]] * height 312 | for bbox in bboxes: 313 | if len(bboxes[0]) and bboxes[0][5] >= 0.9: 314 | top_left, bottom_right = get_top_left_bottom_right(bbox) 315 | return(class_dict_logo[int(bboxes[0][4])], bboxes_og) 316 | 317 | 318 | def convert_yolo_to_original_and_crop(bboxes, image, filename): 319 | height, width, _ = image.shape 320 | global csvfile,obj 321 | # Set propability 322 | if bboxes.shape[-1] == 5: 323 | bboxes = np.concatenate( 324 | [bboxes, np.full((*bboxes.shape[:-1], 1), 2.0)], axis=-1 325 | ) 326 | else: 327 | bboxes = np.copy(bboxes) 328 | 329 | # Convert ratio to length 330 | bboxes[:, [0, 2]] = bboxes[:, [0, 2]] * width 331 | bboxes[:, [1, 3]] = bboxes[:, [1, 3]] * height 332 | #Dim(-1, (x, y, w, h, class_id, probability)) 333 | # print(bboxes) 334 | # Draw bboxes 335 | for bbox in bboxes: # iterating through bboxes of first detection 336 | if bbox[4] == 2 and bbox[5] >= 0.9: 337 | try: 338 | top_left, bottom_right = get_top_left_bottom_right(bbox) 339 | crop_height = bottom_right[1]-top_left[1] 340 | crop_width = bottom_right[0]-top_left[0] 341 | 342 | car_img = image[top_left[1]:top_left[1] + 343 | crop_height, top_left[0]:top_left[0]+crop_width] 344 | lp_text, lp_bboxes = detect_LP(car_img,filename) 345 | if not validateLPText(lp_text): 346 | raise Exception("") 347 | try: 348 | temp_file = "{}.png".format(random.randint(7999, 9999)) 349 | cv2.imwrite("temp/"+temp_file, car_img) 350 | colour = get_car_colour("temp/"+temp_file) 351 | os.remove("temp/"+temp_file) 352 | except Exception: 353 | colour = "-" 354 | logo, logo_bboxes = detect_logo(car_img) 355 | car_img = draw_bboxes1(car_img, logo_bboxes, class_dict_logo) 356 | car_img = draw_bboxes1(car_img, lp_bboxes, class_dict_lp) 357 | 358 | # colour=get_car_colour() 359 | # cv2.imshow('result',car_img) 360 | # cv2.waitKey() 361 | image[top_left[1]:top_left[1] + crop_height, top_left[0]:top_left[0]+crop_width] = car_img 362 | cv2.imwrite(output_path + "data/" +'{}' .format(filename), image) 363 | print(filename, logo, lp_text, colour) 364 | frameNo = filename[5:] 365 | frameNo = int(frameNo[:-4]) 366 | obj.writerow((filename, logo, lp_text, colour,frameTimeStamp[frameNo])) 367 | return(logo, lp_text,colour) 368 | except Exception: 369 | pass 370 | # cv2.imwrite(output_path +"data/"+ '{}' .format(filename), image) 371 | return('-', '-', '-') 372 | 373 | def get_image_data(filepath, filename): 374 | global csvfile,obj 375 | # Dim(-1, (x, y, w, h, class_id, probability)) 376 | framesFolder = os.path.join(UPLOAD_FOLDER, "VidToFrame") 377 | frameFiles = os.listdir(framesFolder) 378 | logo, lp_text, colour = ("-", "-", "-") 379 | csvfile = open(output_path+'data/output.csv', 'a', newline='') 380 | obj = csv.writer(csvfile) 381 | obj.writerow(("Frame No.", "Manufacturer", "License Plate", "Colour","Time Stamp(s)")) 382 | 383 | for file in frameFiles: 384 | try: 385 | imgPath = os.path.join(framesFolder, file) 386 | input_img = cv2.imread(imgPath) 387 | ans = yolo.predict(input_img) 388 | # frame = cv2.cvtColor(input_img, cv2.COLOR_RGB2BGR) 389 | logo, lp_text, colour = convert_yolo_to_original_and_crop( 390 | ans, input_img, file) 391 | # colour = get_car_colour(imgPath) 392 | # print(file) 393 | # print(logo, lp_text, colour) 394 | # return(logo, lp_text, colour) 395 | except Exception: 396 | pass 397 | # print(Exception) 398 | logo, lp_text, colour = ("-", "-", "-") 399 | # print(logo, lp_text, colour) 400 | csvfile.close() 401 | return(logo, lp_text, colour) 402 | 403 | vidcap="" 404 | def getFrame(sec): 405 | global frameTimeStamp 406 | vidcap.set(cv2.CAP_PROP_POS_MSEC, sec*1000) 407 | hasFrames, image = vidcap.read() 408 | frameTimeStamp.append(str(sec)) 409 | if hasFrames: 410 | cv2.imwrite(os.path.join(app.config['UPLOAD_FOLDER'],"VidToFrame") + 411 | "/frame%d.jpg" % count, image) 412 | return hasFrames 413 | 414 | app = Flask(__name__) 415 | 416 | app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER 417 | 418 | 419 | @app.route("/") 420 | def index(): 421 | return render_template("index.html") 422 | 423 | 424 | # @app.route("/about") 425 | # def about(): 426 | # return render_template("about.html") 427 | 428 | 429 | @app.route('/uploader', methods=['GET', 'POST']) 430 | def upload_file(): 431 | global sec,frameRate,count,vidcap,frameTimeStamp 432 | logo, lp_text, colour, filename = ("", "", "", "") 433 | if request.method == 'POST': 434 | vidToFramePath = os.path.join(UPLOAD_FOLDER,"VidToFrame") 435 | for filename in os.listdir(vidToFramePath): 436 | os.remove(os.path.join(vidToFramePath, filename)) 437 | 438 | dataoutput = os.path.join(output_path, "data") 439 | 440 | for filename in os.listdir(dataoutput): 441 | os.remove(os.path.join(dataoutput, filename)) 442 | 443 | f = request.files['file'] 444 | 445 | filename = secure_filename(f.filename) 446 | print(filename) 447 | 448 | filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) 449 | print(filepath) 450 | f.save(filepath) 451 | 452 | vidcap = cv2.VideoCapture(os.path.join( 453 | app.config['UPLOAD_FOLDER'], filename)) 454 | 455 | success = getFrame(sec) 456 | 457 | while success: 458 | count = count + 1 459 | sec = sec + frameRate 460 | sec = round(sec, 2) 461 | success = getFrame(sec) 462 | vidcap.release() 463 | vidcap="" 464 | # os.remove(os.path.join(app.config['UPLOAD_FOLDER'], filename)) 465 | logo, lp_text, colour = get_image_data(filepath, filename) 466 | # print(logo, lp_text, colour) 467 | # logo, lp_text, colour = ("_", "_", "_") 468 | return render_template("data_done.html", fname=filename, detected_logo=logo, detected_lp_text=lp_text, detected_colour=colour) 469 | 470 | 471 | 472 | return render_template("uploaded.html", fname=filename, detected_logo=logo, detected_lp_text=lp_text, detected_colour=colour) 473 | 474 | 475 | @app.route('/speed', methods=['GET', 'POST']) 476 | def upload_file_speed(): 477 | filename="" 478 | if request.method == 'POST': 479 | speedPath = os.path.join(UPLOAD_FOLDER, "speed") 480 | for filename in os.listdir(speedPath): 481 | os.remove(os.path.join(speedPath, filename)) 482 | # print(filename) 483 | speedoutput = os.path.join(output_path, "speed") 484 | for filename in os.listdir(speedoutput): 485 | os.remove(os.path.join(speedoutput, filename)) 486 | # print(filename) 487 | f = request.files['file'] 488 | 489 | filename = secure_filename(f.filename) 490 | print(filename) 491 | 492 | filepath = os.path.join(app.config['UPLOAD_FOLDER'],"speed", filename) 493 | print(filepath) 494 | f.save(filepath) 495 | speed_detection(filepath) 496 | # logo, lp_text, colour = get_image_data(filepath, filename) 497 | 498 | 499 | # vidcap = cv2.VideoCapture(os.path.join( 500 | # app.config['UPLOAD_FOLDER'], filename)) 501 | 502 | # success = getFrame(sec) 503 | 504 | # while success: 505 | # count = count + 1 506 | # sec = sec + frameRate 507 | # sec = round(sec, 2) 508 | # success = getFrame(sec) 509 | return render_template("speed.html", fname=filename) 510 | 511 | 512 | if __name__ == '__main__': 513 | app.run(port=7000, debug=True) 514 | -------------------------------------------------------------------------------- /new_ocr.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import pytesseract 3 | import re 4 | 5 | def recognize_plate(img, coords): 6 | # separate coordinates from box 7 | xmin, ymin, xmax, ymax = coords 8 | # get the subimage that makes up the bounded region and take an additional 5 pixels on each side 9 | box = img[int(ymin)-5:int(ymax)+5, int(xmin)-5:int(xmax)+5] 10 | # grayscale region within bounding box 11 | gray = cv2.cvtColor(box, cv2.COLOR_RGB2GRAY) 12 | # resize image to three times as large as original for better readability 13 | gray = cv2.resize(gray, None, fx=3, fy=3, interpolation=cv2.INTER_CUBIC) 14 | # perform gaussian blur to smoothen image 15 | blur = cv2.GaussianBlur(gray, (5, 5), 0) 16 | #cv2.imshow("Gray", gray) 17 | #cv2.waitKey(0) 18 | # threshold the image using Otsus method to preprocess for tesseract 19 | ret, thresh = cv2.threshold( 20 | gray, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV) 21 | #cv2.imshow("Otsu Threshold", thresh) 22 | #cv2.waitKey(0) 23 | # create rectangular kernel for dilation 24 | rect_kern = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) 25 | # apply dilation to make regions more clear 26 | dilation = cv2.dilate(thresh, rect_kern, iterations=1) 27 | #cv2.imshow("Dilation", dilation) 28 | #cv2.waitKey(0) 29 | # find contours of regions of interest within license plate 30 | try: 31 | contours, hierarchy = cv2.findContours( 32 | dilation, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 33 | except: 34 | ret_img, contours, hierarchy = cv2.findContours( 35 | dilation, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 36 | # sort contours left-to-right 37 | sorted_contours = sorted( 38 | contours, key=lambda ctr: cv2.boundingRect(ctr)[0]) 39 | # create copy of gray image 40 | im2 = gray.copy() 41 | # create blank string to hold license plate number 42 | plate_num = "" 43 | # loop through contours and find individual letters and numbers in license plate 44 | for cnt in sorted_contours: 45 | x, y, w, h = cv2.boundingRect(cnt) 46 | height, width = im2.shape 47 | # if height of box is not tall enough relative to total height then skip 48 | if height / float(h) > 6: 49 | continue 50 | 51 | ratio = h / float(w) 52 | # if height to width ratio is less than 1.5 skip 53 | if ratio < 1.5: 54 | continue 55 | 56 | # if width is not wide enough relative to total width then skip 57 | if width / float(w) > 15: 58 | continue 59 | 60 | area = h * w 61 | # if area is less than 100 pixels skip 62 | if area < 100: 63 | continue 64 | 65 | # draw the rectangle 66 | rect = cv2.rectangle(im2, (x, y), (x+w, y+h), (0, 255, 0), 2) 67 | # grab character region of image 68 | roi = thresh[y-5:y+h+5, x-5:x+w+5] 69 | # perfrom bitwise not to flip image to black text on white background 70 | roi = cv2.bitwise_not(roi) 71 | # perform another blur on character region 72 | roi = cv2.medianBlur(roi, 5) 73 | try: 74 | text = pytesseract.image_to_string( 75 | roi, config='-c tessedit_char_whitelist=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ --psm 8 --oem 3') 76 | # clean tesseract text by removing any unwanted blank spaces 77 | clean_text = re.sub('[\W_]+', '', text) 78 | plate_num += clean_text 79 | except: 80 | text = None 81 | if plate_num != None: 82 | print("License Plate #: ", plate_num) 83 | #cv2.imshow("Character's Segmented", im2) 84 | #cv2.waitKey(0) 85 | return plate_num 86 | 87 | 88 | -------------------------------------------------------------------------------- /requirements-gpu.txt: -------------------------------------------------------------------------------- 1 | tensorflow-gpu==2.3.0rc0 2 | lxml 3 | tqdm 4 | absl-py 5 | matplotlib 6 | easydict 7 | pillow 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | opencv-python==4.1.1.26 2 | lxml 3 | tqdm 4 | tensorflow==2.3.0rc0 5 | absl-py 6 | easydict 7 | matplotlib 8 | pillow 9 | -------------------------------------------------------------------------------- /save_model.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from absl import app, flags, logging 3 | from absl.flags import FLAGS 4 | from core.yolov4 import YOLO, decode, filter_boxes 5 | import core.utils as utils 6 | from core.config import cfg 7 | 8 | flags.DEFINE_string('weights', './data/yolov4.weights', 'path to weights file') 9 | flags.DEFINE_string('output', './checkpoints/yolov4-416', 'path to output') 10 | flags.DEFINE_boolean('tiny', False, 'is yolo-tiny or not') 11 | flags.DEFINE_integer('input_size', 416, 'define input size of export model') 12 | flags.DEFINE_float('score_thres', 0.2, 'define score threshold') 13 | flags.DEFINE_string('framework', 'tf', 'define what framework do you want to convert (tf, trt, tflite)') 14 | flags.DEFINE_string('model', 'yolov4', 'yolov3 or yolov4') 15 | 16 | def save_tf(): 17 | STRIDES, ANCHORS, NUM_CLASS, XYSCALE = utils.load_config(FLAGS) 18 | 19 | input_layer = tf.keras.layers.Input([FLAGS.input_size, FLAGS.input_size, 3]) 20 | feature_maps = YOLO(input_layer, NUM_CLASS, FLAGS.model, FLAGS.tiny) 21 | bbox_tensors = [] 22 | prob_tensors = [] 23 | if FLAGS.tiny: 24 | for i, fm in enumerate(feature_maps): 25 | if i == 0: 26 | output_tensors = decode(fm, FLAGS.input_size // 16, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework) 27 | else: 28 | output_tensors = decode(fm, FLAGS.input_size // 32, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework) 29 | bbox_tensors.append(output_tensors[0]) 30 | prob_tensors.append(output_tensors[1]) 31 | else: 32 | for i, fm in enumerate(feature_maps): 33 | if i == 0: 34 | output_tensors = decode(fm, FLAGS.input_size // 8, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework) 35 | elif i == 1: 36 | output_tensors = decode(fm, FLAGS.input_size // 16, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework) 37 | else: 38 | output_tensors = decode(fm, FLAGS.input_size // 32, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE, FLAGS.framework) 39 | bbox_tensors.append(output_tensors[0]) 40 | prob_tensors.append(output_tensors[1]) 41 | pred_bbox = tf.concat(bbox_tensors, axis=1) 42 | pred_prob = tf.concat(prob_tensors, axis=1) 43 | if FLAGS.framework == 'tflite': 44 | pred = (pred_bbox, pred_prob) 45 | else: 46 | boxes, pred_conf = filter_boxes(pred_bbox, pred_prob, score_threshold=FLAGS.score_thres, input_shape=tf.constant([FLAGS.input_size, FLAGS.input_size])) 47 | pred = tf.concat([boxes, pred_conf], axis=-1) 48 | model = tf.keras.Model(input_layer, pred) 49 | utils.load_weights(model, FLAGS.weights, FLAGS.model, FLAGS.tiny) 50 | model.summary() 51 | model.save(FLAGS.output) 52 | 53 | def main(_argv): 54 | save_tf() 55 | 56 | if __name__ == '__main__': 57 | try: 58 | app.run(main) 59 | except SystemExit: 60 | pass 61 | -------------------------------------------------------------------------------- /scripts/coco_annotation.py: -------------------------------------------------------------------------------- 1 | from absl import app, flags, logging 2 | import os 3 | import pickle 4 | from os import listdir 5 | from os.path import isfile, join 6 | from absl.flags import FLAGS 7 | import cv2 8 | 9 | flags.DEFINE_string('coco_data', './val2017.pkl', 'path to coco data') 10 | flags.DEFINE_string('classes', '../data/classes/coco.names', 'path to classes file') 11 | flags.DEFINE_string('coco_path', "/Volumes/Elements/data/coco_dataset/coco", 'resize images to') 12 | flags.DEFINE_string('image_path', "images/val2017", 'path to image val') 13 | flags.DEFINE_string('anno_path_val', '../data/dataset/val2017.txt', 'path to classes file') 14 | 15 | def convert_annotation(output, data, data_type = "val"): 16 | class_names = [c.strip() for c in open(FLAGS.classes).readlines()] 17 | replace_dict = {"couch": "sofa", "airplane": "aeroplane", "tv": "tvmonitor", "motorcycle": "motorbike"} 18 | 19 | if os.path.exists(output): os.remove(output) 20 | directory_path = os.path.join(FLAGS.coco_path, FLAGS.image_path) 21 | # if data_type == "train": 22 | # anno_path = directory_path + "/labels/train2014" 23 | # image_path = os.path.join(directory_path, "trainvalno5k.txt") 24 | # else: 25 | # anno_path = directory_path + "/labels/val2014" 26 | # image_path = os.path.join(directory_path, "5k.txt") 27 | # with open(image_path) as f: 28 | # image_paths = f.readlines() 29 | # image_paths = [x.strip() for x in image_paths] 30 | 31 | image_paths = [f for f in listdir(directory_path) if isfile(join(directory_path, f))] 32 | 33 | check_classes = [] 34 | count = 0 35 | with open(output, 'a') as f: 36 | for image_path in image_paths: 37 | image_inds = image_path.split(".")[0] 38 | annotation = os.path.join(directory_path, image_path) 39 | # if os.path.exists(os.path.join(anno_path, image_inds + ".txt")): 40 | if image_inds in data: 41 | objects = data[image_inds]["objects"] 42 | for key, value in objects.items(): 43 | if key == 'num_obj': continue 44 | if value["name"] not in class_names: 45 | class_ind = replace_dict[value["name"]] 46 | class_ind = class_names.index(class_ind) 47 | # if value["name"] not in check_classes: 48 | # check_classes.append(value["name"]) 49 | # print(value["name"]) 50 | # continue 51 | else: 52 | class_ind = class_names.index(value["name"]) 53 | xmin = int(value["bndbox"]["xmin"]) 54 | xmax = int(value["bndbox"]["xmax"]) 55 | ymin = int(value["bndbox"]["ymin"]) 56 | ymax = int(value["bndbox"]["ymax"]) 57 | annotation += ' ' + ','.join([str(xmin), str(ymin), str(xmax), str(ymax), str(class_ind)]) 58 | else: continue 59 | f.write(annotation + "\n") 60 | count += 1 61 | # print(annotation) 62 | print(count) 63 | return 64 | 65 | def main(_argv): 66 | with open(FLAGS.coco_data, "rb") as input_file: 67 | data = pickle.load(input_file) 68 | data = data[1] 69 | convert_annotation(FLAGS.anno_path_val, data) 70 | 71 | if __name__ == '__main__': 72 | try: 73 | app.run(main) 74 | except SystemExit: 75 | pass -------------------------------------------------------------------------------- /scripts/coco_convert.py: -------------------------------------------------------------------------------- 1 | from absl import app, flags, logging 2 | from absl.flags import FLAGS 3 | import cv2 4 | import numpy as np 5 | import os 6 | import json 7 | import sys 8 | import pickle 9 | 10 | flags.DEFINE_string('input', '/Volumes/Elements/data/coco_dataset/coco/annotations/instances_val2017.json', 'path to classes file') 11 | flags.DEFINE_string('output', 'val2017.pkl', 'path to classes file') 12 | 13 | class COCO: 14 | """ 15 | Handler Class for COCO Format 16 | """ 17 | 18 | @staticmethod 19 | def parse(json_path): 20 | 21 | try: 22 | json_data = json.load(open(json_path)) 23 | 24 | images_info = json_data["images"] 25 | cls_info = json_data["categories"] 26 | 27 | data = {} 28 | 29 | progress_length = len(json_data["annotations"]) 30 | progress_cnt = 0 31 | 32 | for anno in json_data["annotations"]: 33 | 34 | image_id = anno["image_id"] 35 | cls_id = anno["category_id"] 36 | 37 | filename = None 38 | img_width = None 39 | img_height = None 40 | cls = None 41 | 42 | for info in images_info: 43 | if info["id"] == image_id: 44 | filename, img_width, img_height = \ 45 | info["file_name"].split(".")[0], info["width"], info["height"] 46 | 47 | for category in cls_info: 48 | if category["id"] == cls_id: 49 | cls = category["name"] 50 | 51 | size = { 52 | "width": img_width, 53 | "height": img_height, 54 | "depth": "3" 55 | } 56 | 57 | bndbox = { 58 | "xmin": anno["bbox"][0], 59 | "ymin": anno["bbox"][1], 60 | "xmax": anno["bbox"][2] + anno["bbox"][0], 61 | "ymax": anno["bbox"][3] + anno["bbox"][1] 62 | } 63 | 64 | obj_info = { 65 | "name": cls, 66 | "bndbox": bndbox 67 | } 68 | 69 | if filename in data: 70 | obj_idx = str(int(data[filename]["objects"]["num_obj"])) 71 | data[filename]["objects"][str(obj_idx)] = obj_info 72 | data[filename]["objects"]["num_obj"] = int(obj_idx) + 1 73 | 74 | elif filename not in data: 75 | 76 | obj = { 77 | "num_obj": "1", 78 | "0": obj_info 79 | } 80 | 81 | data[filename] = { 82 | "size": size, 83 | "objects": obj 84 | } 85 | 86 | percent = (float(progress_cnt) / float(progress_length)) * 100 87 | print(str(progress_cnt) + "/" + str(progress_length) + " total: " + str(round(percent, 2))) 88 | progress_cnt += 1 89 | 90 | #print(json.dumps(data, indent=4, sort_keys = True)) 91 | return True, data 92 | 93 | except Exception as e: 94 | 95 | exc_type, exc_obj, exc_tb = sys.exc_info() 96 | fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] 97 | 98 | msg = "ERROR : {}, moreInfo : {}\t{}\t{}".format(e, exc_type, fname, exc_tb.tb_lineno) 99 | 100 | return False, msg 101 | 102 | def main(_argv): 103 | coco = COCO() 104 | data = coco.parse(FLAGS.input) 105 | with open(FLAGS.output, 'wb') as handle: 106 | pickle.dump(data, handle, protocol=pickle.HIGHEST_PROTOCOL) 107 | 108 | if __name__ == '__main__': 109 | try: 110 | app.run(main) 111 | except SystemExit: 112 | pass 113 | -------------------------------------------------------------------------------- /scripts/get_coco_dataset_2017.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### Recommended to run 'nohup ./ &' to prevent interruption from SSH session termination. 4 | 5 | wait_to_finish() { 6 | for pid in "${download_pids[@]}"; do 7 | while kill -0 "$pid"; do 8 | sleep 30 9 | done 10 | done 11 | } 12 | 13 | 14 | # Update for default OS specific package manager. 15 | # sudo yum -y install java-1.8.0 16 | # sudo yum -y remove java-1.7.0-openjdk 17 | 18 | mkdir -p coco/images/ coco/annotations/ 19 | 20 | download_pids=() 21 | 22 | ### 2017 COCO Dataset ### 23 | 24 | echo "Downloading COCO dataset..." 25 | curl -OL "http://images.cocodataset.org/zips/val2017.zip" & 26 | download_pids+=("$!") 27 | curl -OL "http://images.cocodataset.org/annotations/annotations_trainval2017.zip" & 28 | download_pids+=("$!") 29 | 30 | wait_to_finish download_pids 31 | 32 | inflate_pids=() 33 | 34 | unzip 'val2017.zip' -d coco/images/ & 35 | inflate_pids+=("$!") 36 | unzip 'annotations_trainval2017.zip' -d coco/annotations/ & # Inflates to 'coco/annotations'. 37 | inflate_pids+=("$!") 38 | 39 | wait_to_finish inflate_pids -------------------------------------------------------------------------------- /scripts/google_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | 4 | def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): 5 | # https://gist.github.com/tanaikech/f0f2d122e05bf5f971611258c22c110f 6 | # Downloads a file from Google Drive, accepting presented query 7 | # from utils.google_utils import *; gdrive_download() 8 | t = time.time() 9 | 10 | print('Downloading https://drive.google.com/uc?export=download&id=%s as %s... ' % (id, name), end='') 11 | os.remove(name) if os.path.exists(name) else None # remove existing 12 | os.remove('cookie') if os.path.exists('cookie') else None 13 | 14 | # Attempt file download 15 | os.system("curl -c ./cookie -s -L \"https://drive.google.com/uc?export=download&id=%s\" > /dev/null" % id) 16 | if os.path.exists('cookie'): # large file 17 | s = "curl -Lb ./cookie \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( 18 | id, name) 19 | else: # small file 20 | s = "curl -s -L -o %s 'https://drive.google.com/uc?export=download&id=%s'" % (name, id) 21 | r = os.system(s) # execute, capture return values 22 | os.remove('cookie') if os.path.exists('cookie') else None 23 | 24 | # Error check 25 | if r != 0: 26 | os.remove(name) if os.path.exists(name) else None # remove partial 27 | print('Download error ') # raise Exception('Download error') 28 | return r 29 | 30 | # Unzip if archive 31 | if name.endswith('.zip'): 32 | print('unzipping... ', end='') 33 | os.system('unzip -q %s' % name) # unzip 34 | os.remove(name) # remove zip to free space 35 | 36 | print('Done (%.1fs)' % (time.time() - t)) 37 | return r 38 | 39 | # gdrive_download("1cewMfusmPjYWbrnuJRuKhPMwRe_b9PaT", name='yolov4.weights') -------------------------------------------------------------------------------- /scripts/voc/README.md: -------------------------------------------------------------------------------- 1 | # VOC Dataset 2 | 3 | ### Download 4 | 5 | ```bash 6 | $ bash get_voc2012.sh 7 | ``` 8 | 9 | ### Make names for VOC. 10 | 11 | ```bash 12 | $ python voc_make_names.py [--anno_dir {Annotation directory}] [--output {OUTPUT_NAME}] 13 | 14 | # example 15 | $ python voc_make_name.py 16 | 17 | $ python voc_make_name.py --anno_dir ../../data/voc/anno --output ../../data/classes/voc.names 18 | ``` 19 | 20 | ### Convert VOC Dataset. 21 | 22 | ```bash 23 | $ python voc_convert.py [--image_dir {Image directory}] [--anno_dir {Annotation directory}] [--train_list_txt {Path of Train list file}] [--val_list_txt {Path of Validation list file}] [--classes {Path of Classes file}] [--train_output {Path of Output file For Train}] [--val_output {Path of Output file For Val}] 24 | 25 | #example 26 | $ python voc_convert.py 27 | ``` 28 | -------------------------------------------------------------------------------- /scripts/voc/get_voc2012.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | PARENT_DIR="$( cd "$( dirname $( dirname $( dirname "${BASH_SOURCE[0]}" ) ) )" >/dev/null 2>&1 && pwd )" 5 | DATA_DIR="$PARENT_DIR/data" 6 | 7 | DATASET_NAME="VOCtrainval_11-May-2012" 8 | 9 | wget -c -P $DATA_DIR http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar 10 | 11 | if [[ -d "$DATA_DIR/$DATASET_NAME" ]]; then 12 | echo "Already '$DATA_DIR/$DATASET_NAME' path exists." 13 | exit 1 14 | fi 15 | 16 | mkdir $DATA_DIR/$DATASET_NAME 17 | 18 | tar xf $DATA_DIR/VOCtrainval_11-May-2012.tar -C $DATA_DIR/$DATASET_NAME 19 | 20 | -------------------------------------------------------------------------------- /scripts/voc/voc_convert.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | from absl import app, flags 5 | from absl.flags import FLAGS 6 | from lxml import etree 7 | 8 | 9 | flags.DEFINE_string('image_dir', '../../data/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/JPEGImages', 'path to image dir') 10 | flags.DEFINE_string('anno_dir', '../../data/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/Annotations', 'path to anno dir') 11 | flags.DEFINE_string('train_list_txt', '../../data/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/ImageSets/Main/train.txt', 'path to a set of train') 12 | flags.DEFINE_string('val_list_txt', '../../data/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/ImageSets/Main/val.txt', 'path to a set of val') 13 | flags.DEFINE_string('classes', '../../data/classes/voc2012.names', 'path to a list of class names') 14 | flags.DEFINE_string('train_output', '../../data/dataset/voc2012_train.txt', 'path to a file for train') 15 | flags.DEFINE_string('val_output', '../../data/dataset/voc2012_val.txt', 'path to a file for val') 16 | 17 | flags.DEFINE_boolean('no_val', False, 'if uses this flag, it does not convert a list of val') 18 | 19 | 20 | def convert_annotation(list_txt, output_path, image_dir, anno_dir, class_names): 21 | IMAGE_EXT = '.jpg' 22 | ANNO_EXT = '.xml' 23 | 24 | with open(list_txt, 'r') as f, open(output_path, 'w') as wf: 25 | while True: 26 | line = f.readline().strip() 27 | if line is None or not line: 28 | break 29 | im_p = os.path.join(image_dir, line + IMAGE_EXT) 30 | an_p = os.path.join(anno_dir, line + ANNO_EXT) 31 | 32 | # Get annotation. 33 | root = etree.parse(an_p).getroot() 34 | bboxes = root.xpath('//object/bndbox') 35 | names = root.xpath('//object/name') 36 | 37 | box_annotations = [] 38 | for b, n in zip(bboxes, names): 39 | name = n.text 40 | class_idx = class_names.index(name) 41 | 42 | xmin = b.find('xmin').text 43 | ymin = b.find('ymin').text 44 | xmax = b.find('xmax').text 45 | ymax = b.find('ymax').text 46 | box_annotations.append(','.join([str(xmin), str(ymin), str(xmax), str(ymax), str(class_idx)])) 47 | 48 | annotation = os.path.abspath(im_p) + ' ' + ' '.join(box_annotations) + '\n' 49 | 50 | wf.write(annotation) 51 | 52 | 53 | def convert_voc(image_dir, anno_dir, train_list_txt, val_list_txt, classes, train_output, val_output, no_val): 54 | IMAGE_EXT = '.jpg' 55 | ANNO_EXT = '.xml' 56 | 57 | class_names = [c.strip() for c in open(FLAGS.classes).readlines()] 58 | 59 | # Training set. 60 | convert_annotation(train_list_txt, train_output, image_dir, anno_dir, class_names) 61 | 62 | if no_val: 63 | return 64 | 65 | # Validation set. 66 | convert_annotation(val_list_txt, val_output, image_dir, anno_dir, class_names) 67 | 68 | 69 | def main(_argv): 70 | convert_voc(FLAGS.image_dir, FLAGS.anno_dir, FLAGS.train_list_txt, FLAGS.val_list_txt, FLAGS.classes, FLAGS.train_output, FLAGS.val_output, FLAGS.no_val) 71 | print("Complete convert voc data!") 72 | 73 | 74 | if __name__ == "__main__": 75 | try: 76 | app.run(main) 77 | except SystemExit: 78 | pass 79 | -------------------------------------------------------------------------------- /scripts/voc/voc_make_names.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | from absl import app, flags 5 | from absl.flags import FLAGS 6 | from lxml import etree 7 | 8 | 9 | flags.DEFINE_string('anno_dir', '../../data/VOCtrainval_11-May-2012/VOCdevkit/VOC2012/Annotations', 'path to anno dir') 10 | flags.DEFINE_string('output', '../../data/classes/voc2012.names', 'path to anno dir') 11 | 12 | 13 | def make_names(anno_dir, output): 14 | labels_dict = {} 15 | 16 | anno_list = os.listdir(anno_dir) 17 | 18 | for anno_file in anno_list: 19 | p = os.path.join(anno_dir, anno_file) 20 | 21 | # Get annotation. 22 | root = etree.parse(p).getroot() 23 | names = root.xpath('//object/name') 24 | 25 | for n in names: 26 | labels_dict[n.text] = 0 27 | 28 | labels = list(labels_dict.keys()) 29 | labels.sort() 30 | 31 | with open(output, 'w') as f: 32 | for l in labels: 33 | f.writelines(l + '\n') 34 | 35 | print(f"Done making a names's file ({os.path.abspath(output)})") 36 | 37 | 38 | def main(_argv): 39 | make_names(FLAGS.anno_dir, FLAGS.output) 40 | 41 | 42 | if __name__ == "__main__": 43 | try: 44 | app.run(main) 45 | except SystemExit: 46 | pass 47 | -------------------------------------------------------------------------------- /scripts/voc_annotation.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | import xml.etree.ElementTree as ET 4 | 5 | def convert_voc_annotation(data_path, data_type, anno_path, use_difficult_bbox=True): 6 | 7 | classes = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 8 | 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 9 | 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 10 | 'train', 'tvmonitor'] 11 | img_inds_file = os.path.join(data_path, 'ImageSets', 'Main', data_type + '.txt') 12 | with open(img_inds_file, 'r') as f: 13 | txt = f.readlines() 14 | image_inds = [line.strip() for line in txt] 15 | 16 | with open(anno_path, 'a') as f: 17 | for image_ind in image_inds: 18 | image_path = os.path.join(data_path, 'JPEGImages', image_ind + '.jpg') 19 | annotation = image_path 20 | label_path = os.path.join(data_path, 'Annotations', image_ind + '.xml') 21 | root = ET.parse(label_path).getroot() 22 | objects = root.findall('object') 23 | for obj in objects: 24 | difficult = obj.find('difficult').text.strip() 25 | if (not use_difficult_bbox) and(int(difficult) == 1): 26 | continue 27 | bbox = obj.find('bndbox') 28 | class_ind = classes.index(obj.find('name').text.lower().strip()) 29 | xmin = bbox.find('xmin').text.strip() 30 | xmax = bbox.find('xmax').text.strip() 31 | ymin = bbox.find('ymin').text.strip() 32 | ymax = bbox.find('ymax').text.strip() 33 | annotation += ' ' + ','.join([xmin, ymin, xmax, ymax, str(class_ind)]) 34 | print(annotation) 35 | f.write(annotation + "\n") 36 | return len(image_inds) 37 | 38 | 39 | if __name__ == '__main__': 40 | parser = argparse.ArgumentParser() 41 | parser.add_argument("--data_path", default="/home/VOC/") 42 | parser.add_argument("--train_annotation", default="./data/dataset/voc_train.txt") 43 | parser.add_argument("--test_annotation", default="./data/dataset/voc_test.txt") 44 | flags = parser.parse_args() 45 | 46 | if os.path.exists(flags.train_annotation):os.remove(flags.train_annotation) 47 | if os.path.exists(flags.test_annotation):os.remove(flags.test_annotation) 48 | 49 | num1 = convert_voc_annotation(os.path.join(flags.data_path, 'train/VOCdevkit/VOC2007'), 'trainval', flags.train_annotation, False) 50 | num2 = convert_voc_annotation(os.path.join(flags.data_path, 'train/VOCdevkit/VOC2012'), 'trainval', flags.train_annotation, False) 51 | num3 = convert_voc_annotation(os.path.join(flags.data_path, 'test/VOCdevkit/VOC2007'), 'test', flags.test_annotation, False) 52 | print('=> The number of image for train is: %d\tThe number of image for test is:%d' %(num1 + num2, num3)) 53 | -------------------------------------------------------------------------------- /speed_check.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import dlib 3 | import time 4 | import threading 5 | import math 6 | 7 | # carCascade = cv2.CascadeClassifier('C:/Users/Mukeshjain/Desktop/speed_detection/vehicle-speed-check/myhaar.xml') 8 | # video = cv2.VideoCapture('C:/Users/Mukeshjain/Desktop/speed_detection/vehicle-speed-check/i1.mp4') 9 | 10 | def upload_video(path): 11 | carCascade = cv2.CascadeClassifier('./myhaar.xml') 12 | video = cv2.VideoCapture(path) 13 | return carCascade,video 14 | 15 | def estimateSpeed(location1, location2): 16 | d_pixels = math.sqrt(math.pow(location2[0] - location1[0], 2) + math.pow(location2[1] - location1[1], 2)) 17 | # ppm = location2[2] / carWidht 18 | ppm = 16.8 19 | d_meters = d_pixels / ppm 20 | #print("d_pixels=" + str(d_pixels), "d_meters=" + str(d_meters)) 21 | fps = 20 22 | speed = d_meters * fps * 3.6 23 | return speed 24 | 25 | 26 | def trackMultipleObjects(carCascade,video): 27 | try: 28 | WIDTH = 1280 29 | HEIGHT = 720 30 | rectangleColor = (0, 255, 0) 31 | frameCounter = 0 32 | currentCarID = 0 33 | fps = 0 34 | 35 | carTracker = {} 36 | carNumbers = {} 37 | carLocation1 = {} 38 | carLocation2 = {} 39 | speed = [None] * 1000 40 | 41 | # Write output to video file 42 | #out = cv2.VideoWriter('outpy.avi',cv2.VideoWriter_fourcc('M','J','P','G'), 10, (WIDTH,HEIGHT)) 43 | 44 | 45 | while True: 46 | rc, frame = video.read() 47 | start_time = time.time() 48 | 49 | 50 | image = cv2.resize(frame, (WIDTH, HEIGHT)) 51 | resultImage = image.copy() 52 | 53 | frameCounter = frameCounter + 1 54 | 55 | carIDtoDelete = [] 56 | 57 | for carID in carTracker.keys(): 58 | trackingQuality = carTracker[carID].update(image) 59 | 60 | if trackingQuality < 7: 61 | carIDtoDelete.append(carID) 62 | 63 | for carID in carIDtoDelete: 64 | #print ('Removing carID ' + str(carID) + ' from list of trackers.') 65 | #print ('Removing carID ' + str(carID) + ' previous location.') 66 | #print ('Removing carID ' + str(carID) + ' current location.') 67 | carTracker.pop(carID, None) 68 | carLocation1.pop(carID, None) 69 | carLocation2.pop(carID, None) 70 | 71 | if not (frameCounter % 10): 72 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 73 | cars = carCascade.detectMultiScale(gray, 1.1, 13, 18, (24, 24)) 74 | 75 | for (_x, _y, _w, _h) in cars: 76 | x = int(_x) 77 | y = int(_y) 78 | w = int(_w) 79 | h = int(_h) 80 | 81 | x_bar = x + 0.5 * w 82 | y_bar = y + 0.5 * h 83 | 84 | matchCarID = None 85 | 86 | for carID in carTracker.keys(): 87 | trackedPosition = carTracker[carID].get_position() 88 | 89 | t_x = int(trackedPosition.left()) 90 | t_y = int(trackedPosition.top()) 91 | t_w = int(trackedPosition.width()) 92 | t_h = int(trackedPosition.height()) 93 | 94 | t_x_bar = t_x + 0.5 * t_w 95 | t_y_bar = t_y + 0.5 * t_h 96 | 97 | if ((t_x <= x_bar <= (t_x + t_w)) and (t_y <= y_bar <= (t_y + t_h)) and (x <= t_x_bar <= (x + w)) and (y <= t_y_bar <= (y + h))): 98 | matchCarID = carID 99 | 100 | if matchCarID is None: 101 | #print ('Creating new tracker ' + str(currentCarID)) 102 | 103 | tracker = dlib.correlation_tracker() 104 | tracker.start_track(image, dlib.rectangle(x, y, x + w, y + h)) 105 | 106 | carTracker[currentCarID] = tracker 107 | carLocation1[currentCarID] = [x, y, w, h] 108 | 109 | currentCarID = currentCarID + 1 110 | 111 | cv2.line(resultImage,(0,245),(1280,245),(0,0,0),1) 112 | cv2.line(resultImage,(0,285),(1280,285),(0,0,0),1) 113 | 114 | 115 | for carID in carTracker.keys(): 116 | trackedPosition = carTracker[carID].get_position() 117 | 118 | t_x = int(trackedPosition.left()) 119 | t_y = int(trackedPosition.top()) 120 | t_w = int(trackedPosition.width()) 121 | t_h = int(trackedPosition.height()) 122 | 123 | cv2.rectangle(resultImage, (t_x, t_y), (t_x + t_w, t_y + t_h), rectangleColor, 4) 124 | 125 | # speed estimation 126 | carLocation2[carID] = [t_x, t_y, t_w, t_h] 127 | 128 | end_time = time.time() 129 | 130 | if not (end_time == start_time): 131 | fps = 1.0/(end_time - start_time) 132 | 133 | #cv2.putText(resultImage, 'FPS: ' + str(int(fps)), (620, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2) 134 | 135 | 136 | for i in carLocation1.keys(): 137 | if frameCounter % 1 == 0: 138 | [x1, y1, w1, h1] = carLocation1[i] 139 | [x2, y2, w2, h2] = carLocation2[i] 140 | 141 | # print 'previous location: ' + str(carLocation1[i]) + ', current location: ' + str(carLocation2[i]) 142 | carLocation1[i] = [x2, y2, w2, h2] 143 | 144 | # print 'new previous location: ' + str(carLocation1[i]) 145 | if [x1, y1, w1, h1] != [x2, y2, w2, h2]: 146 | if (speed[i] == None or speed[i] == 0) and y1 >= 245 and y1 <= 285: 147 | speed[i] = estimateSpeed([x1, y1, w1, h1], [x2, y2, w2, h2]) 148 | 149 | 150 | #if y1 > 275 and y1 < 285: 151 | if speed[i] != None and y1 >= 245 : 152 | cv2.putText(resultImage, str(int(speed[i])) + " km/hr", (int(x1 + w1/2), int(y1-5)),cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 0, 0), 2) 153 | car=resultImage[y1:y1+h1+70,x1:x1+w1+70] 154 | #cv2.imwrite("output/%dcar%d.jpg" %speed[i],car) 155 | cv2.imwrite("./static/detections/speed/car-%s-%d.jpg" % 156 | (str(i), speed[i]), car) 157 | print ('CarID ' + str(i) + ': speed is ' + str("%.2f" % round(speed[i], 0)) + ' km/h.\n') 158 | 159 | #else: 160 | # cv2.putText(resultImage, "Far Object", (int(x1 + w1/2), int(y1)),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) 161 | 162 | #print ('CarID ' + str(i) + ' Location1: ' + str(carLocation1[i]) + ' Location2: ' + str(carLocation2[i]) + ' speed is ' + str("%.2f" % round(speed[i], 0)) + ' km/h.\n') 163 | imS = cv2.resize(resultImage, (640, 480)) 164 | # cv2.imshow("output", imS) 165 | cv2.imshow('Result', imS) 166 | # Write the frame into the file 'output.avi' 167 | #out.write(resultImage) 168 | 169 | if cv2.waitKey(33) == 27: 170 | break 171 | 172 | cv2.destroyAllWindows() 173 | except Exception: 174 | print("Over") 175 | 176 | def speed_detection(path): 177 | carCascade,video=upload_video(path) 178 | trackMultipleObjects(carCascade,video) 179 | 180 | # speed_detection("./i1.mp4") 181 | -------------------------------------------------------------------------------- /speed_check_new.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import dlib 3 | import time 4 | import threading 5 | import math 6 | import cv2 7 | import csv 8 | 9 | # carCascade = cv2.CascadeClassifier('C:/Users/Mukeshjain/Desktop/speed_detection/vehicle-speed-check/myhaar.xml') 10 | # video = cv2.VideoCapture('C:/Users/Mukeshjain/Desktop/speed_detection/vehicle-speed-check/i1.mp4') 11 | cars_output={} 12 | cars_output_time={} 13 | def upload_video(path): 14 | carCascade = cv2.CascadeClassifier('./myhaar.xml') 15 | video = cv2.VideoCapture(path) 16 | return carCascade,video 17 | 18 | def estimateSpeed(location1, location2): 19 | d_pixels = math.sqrt(math.pow(location2[0] - location1[0], 2) + math.pow(location2[1] - location1[1], 2)) 20 | # ppm = location2[2] / carWidht 21 | ppm = 16.8 22 | d_meters = d_pixels / ppm 23 | #print("d_pixels=" + str(d_pixels), "d_meters=" + str(d_meters)) 24 | fps = 20 25 | speed = d_meters * fps * 3.6 26 | return speed 27 | 28 | 29 | def trackMultipleObjects(carCascade,video): 30 | try: 31 | WIDTH = 1280 32 | HEIGHT = 720 33 | rectangleColor = (0, 255, 0) 34 | frameCounter = 0 35 | currentCarID = 0 36 | fps = 0 37 | 38 | carTracker = {} 39 | carNumbers = {} 40 | carLocation1 = {} 41 | carLocation2 = {} 42 | speed = [None] * 1000 43 | count=0 44 | 45 | # Write output to video file 46 | #out = cv2.VideoWriter('outpy.avi',cv2.VideoWriter_fourcc('M','J','P','G'), 10, (WIDTH,HEIGHT)) 47 | 48 | fpsx = video.get(cv2.CAP_PROP_FPS) 49 | while True: 50 | rc, frame = video.read() 51 | start_time = time.time() 52 | 53 | 54 | image = cv2.resize(frame, (WIDTH, HEIGHT)) 55 | resultImage = image.copy() 56 | 57 | frameCounter = frameCounter + 1 58 | 59 | carIDtoDelete = [] 60 | 61 | for carID in carTracker.keys(): 62 | trackingQuality = carTracker[carID].update(image) 63 | 64 | if trackingQuality < 7: 65 | carIDtoDelete.append(carID) 66 | 67 | for carID in carIDtoDelete: 68 | #print ('Removing carID ' + str(carID) + ' from list of trackers.') 69 | #print ('Removing carID ' + str(carID) + ' previous location.') 70 | #print ('Removing carID ' + str(carID) + ' current location.') 71 | carTracker.pop(carID, None) 72 | carLocation1.pop(carID, None) 73 | carLocation2.pop(carID, None) 74 | 75 | if not (frameCounter % 10): 76 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 77 | cars = carCascade.detectMultiScale(gray, 1.1, 13, 18, (24, 24)) 78 | 79 | for (_x, _y, _w, _h) in cars: 80 | x = int(_x) 81 | y = int(_y) 82 | w = int(_w) 83 | h = int(_h) 84 | 85 | x_bar = x + 0.5 * w 86 | y_bar = y + 0.5 * h 87 | 88 | matchCarID = None 89 | 90 | for carID in carTracker.keys(): 91 | trackedPosition = carTracker[carID].get_position() 92 | 93 | t_x = int(trackedPosition.left()) 94 | t_y = int(trackedPosition.top()) 95 | t_w = int(trackedPosition.width()) 96 | t_h = int(trackedPosition.height()) 97 | 98 | t_x_bar = t_x + 0.5 * t_w 99 | t_y_bar = t_y + 0.5 * t_h 100 | 101 | if ((t_x <= x_bar <= (t_x + t_w)) and (t_y <= y_bar <= (t_y + t_h)) and (x <= t_x_bar <= (x + w)) and (y <= t_y_bar <= (y + h))): 102 | matchCarID = carID 103 | 104 | if matchCarID is None: 105 | tracker = dlib.correlation_tracker() 106 | tracker.start_track(image, dlib.rectangle(x, y, x + w, y + h)) 107 | 108 | carTracker[currentCarID] = tracker 109 | carLocation1[currentCarID] = [x, y, w, h] 110 | 111 | currentCarID = currentCarID + 1 112 | 113 | cv2.line(resultImage,(0,245),(1280,245),(0,0,0),1) 114 | cv2.line(resultImage,(0,285),(1280,285),(0,0,0),1) 115 | 116 | 117 | for carID in carTracker.keys(): 118 | trackedPosition = carTracker[carID].get_position() 119 | 120 | t_x = int(trackedPosition.left()) 121 | t_y = int(trackedPosition.top()) 122 | t_w = int(trackedPosition.width()) 123 | t_h = int(trackedPosition.height()) 124 | 125 | cv2.rectangle(resultImage, (t_x, t_y), (t_x + t_w, t_y + t_h), rectangleColor, 4) 126 | 127 | # speed estimation 128 | carLocation2[carID] = [t_x, t_y, t_w, t_h] 129 | 130 | end_time = time.time() 131 | 132 | if not (end_time == start_time): 133 | fps = 1.0/(end_time - start_time) 134 | 135 | #cv2.putText(resultImage, 'FPS: ' + str(int(fps)), (620, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2) 136 | 137 | 138 | for i in carLocation1.keys(): 139 | if frameCounter % 1 == 0: 140 | [x1, y1, w1, h1] = carLocation1[i] 141 | [x2, y2, w2, h2] = carLocation2[i] 142 | 143 | # print 'previous location: ' + str(carLocation1[i]) + ', current location: ' + str(carLocation2[i]) 144 | carLocation1[i] = [x2, y2, w2, h2] 145 | 146 | # print 'new previous location: ' + str(carLocation1[i]) 147 | if [x1, y1, w1, h1] != [x2, y2, w2, h2]: 148 | if (speed[i] == None or speed[i] == 0) and y1 >= 245 and y1 <= 285: 149 | speed[i] = estimateSpeed([x1, y1, w1, h1], [x2, y2, w2, h2]) 150 | 151 | 152 | #if y1 > 275 and y1 < 285: 153 | if speed[i] != None and y1 >= 245 : 154 | cv2.putText(resultImage, str(int(speed[i])) + " km/hr", (int(x1 + w1/2), int(y1-5)),cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 0, 0), 2) 155 | car=resultImage[y1:y1+h1+70,x1:x1+w1+70] 156 | #cv2.imwrite("output/%dcar%d.jpg" %speed[i],car) 157 | cv2.imwrite("./static/detections/speed/car-%s-%d.jpg" % 158 | (str(i), speed[i]), car) 159 | cars_output[i]=int(speed[i]) 160 | cars_output_time[i]=count/fpsx 161 | print ('CarID ' + str(i) + ': speed is ' + str("%.2f" % round(speed[i], 0)) + ' km/h.\n') 162 | 163 | #else: 164 | # cv2.putText(resultImage, "Far Object", (int(x1 + w1/2), int(y1)),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) 165 | 166 | #print ('CarID ' + str(i) + ' Location1: ' + str(carLocation1[i]) + ' Location2: ' + str(carLocation2[i]) + ' speed is ' + str("%.2f" % round(speed[i], 0)) + ' km/h.\n') 167 | imS = cv2.resize(resultImage, (640, 480)) 168 | # cv2.imshow("output", imS) 169 | cv2.imshow('Result', imS) 170 | # Write the frame into the file 'output.avi' 171 | #out.write(resultImage) 172 | 173 | if cv2.waitKey(33) == 27: 174 | break 175 | count+=1 176 | 177 | cv2.destroyAllWindows() 178 | except Exception: 179 | #print(cars_output) 180 | #print(cars_output_time) 181 | csvfile = open('./static/detections/speed/speed.csv', 'a', newline='') 182 | obj = csv.writer(csvfile) 183 | obj.writerow(("Car Id.","Speed","Timestamp")) 184 | for (k1,v1),(k2,v2) in zip(cars_output.items(),cars_output_time.items()): 185 | obj.writerow([k1,v1,v2]) 186 | csvfile.close() 187 | print("Over") 188 | 189 | def speed_detection(path): 190 | carCascade,video=upload_video(path) 191 | trackMultipleObjects(carCascade,video) 192 | 193 | # speed_detection("./i1.mp4") 194 | -------------------------------------------------------------------------------- /static/css/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | * General 3 | */ 4 | 5 | 6 | 7 | body { 8 | font-family: 'Open Sans', sans-serif; 9 | } 10 | 11 | 12 | 13 | 14 | /* 15 | * Header 16 | */ 17 | 18 | 19 | 20 | .title { 21 | float: left; 22 | font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; 23 | font-size: 18px; 24 | letter-spacing: 2.5px; 25 | text-transform: uppercase; 26 | margin: 20px 20px; 27 | } 28 | 29 | .title a, .title a:visited { 30 | color: #3a3a3a; 31 | } 32 | 33 | .upload-image-thumb { 34 | max-width: 800px; 35 | margin: 10px; 36 | } 37 | .image-container { 38 | margin: 0px 20px; 39 | } 40 | 41 | .btn-primary{ 42 | border: 3px solid rgb(3, 41, 85); 43 | background-color: #3c3ed1; 44 | } 45 | 46 | .btn-primary:hover{ 47 | border: 3px solid rgb(3, 41, 85); 48 | background-color: #5658ce; 49 | } 50 | 51 | 52 | 53 | .btn-success{ 54 | border: 3px solid #005005; 55 | background-color: #2e7d32; 56 | } 57 | 58 | .btn-success:hover{ 59 | border: 3px solid #005005; 60 | background-color: #348d38; 61 | } 62 | 63 | /* div#loading { 64 | width: 445px; 65 | height: 35px; 66 | display: none; 67 | background: url(/static/img/ajax-loader.gif) no-repeat; 68 | margin-top: 200px; 69 | cursor: wait; 70 | } */ 71 | 72 | /* div#loading::after{ 73 | display: flex; 74 | justify-content: center; 75 | align-items: center; 76 | content: "Data Extraction in Progress. Please Wait."; 77 | font-weight: bold; 78 | } */ 79 | 80 | 81 | /* .content { 82 | display: flex; 83 | justify-content: center; 84 | align-items: center; 85 | width: 100%; 86 | height: 100%; 87 | } */ 88 | .loader-wrapper { 89 | width: 100%; 90 | height: 100%; 91 | position: absolute; 92 | top: 0; 93 | left: 0; 94 | background-color: #fff; 95 | display: none; 96 | 97 | } 98 | .loader { 99 | display: inline-block; 100 | width: 30px; 101 | height: 60px; 102 | position: relative; 103 | border: 5px solid #242f3f; 104 | animation: loader 2s infinite ease; 105 | } 106 | .loader-inner { 107 | vertical-align: top; 108 | display: inline-block; 109 | width: 100%; 110 | background-color: #242f3f; 111 | animation: loader-inner 2s infinite ease-in; 112 | } 113 | 114 | /* @keyframes loader { 115 | 0% { 116 | transform: rotate(0deg); 117 | } 118 | 25% { 119 | transform: rotate(180deg); 120 | } 121 | 50% { 122 | transform: rotate(180deg); 123 | } 124 | 75% { 125 | transform: rotate(360deg); 126 | } 127 | 100% { 128 | transform: rotate(360deg); 129 | } 130 | } */ 131 | 132 | @keyframes loader-inner { 133 | 0% { 134 | height: 0%; 135 | } 136 | 25% { 137 | height: 0%; 138 | } 139 | 50% { 140 | height: 100%; 141 | } 142 | 75% { 143 | height: 100%; 144 | } 145 | 100% { 146 | height: 0%; 147 | } 148 | } 149 | 150 | 151 | 152 | .loader1 { 153 | display: inline-block; 154 | width: 30px; 155 | height: 60px; 156 | position: relative; 157 | border: 5px solid #242f3f; 158 | animation: loader1 2s infinite ease; 159 | } 160 | .loader-inner1 { 161 | vertical-align: top; 162 | display: inline-block; 163 | width: 100%; 164 | background-color: #242f3f; 165 | animation: loader-inner1 2s infinite ease-in; 166 | } 167 | 168 | /* @keyframes loader1 { 169 | 100% { 170 | transform: rotate(0deg); 171 | } 172 | 75% { 173 | transform: rotate(180deg); 174 | } 175 | 50% { 176 | transform: rotate(180deg); 177 | } 178 | 25% { 179 | transform: rotate(360deg); 180 | } 181 | 0% { 182 | transform: rotate(0deg); 183 | } 184 | } */ 185 | 186 | @keyframes loader-inner1 { 187 | 0% { 188 | height: 100%; 189 | } 190 | 25% { 191 | height: 100%; 192 | } 193 | 50% { 194 | height: 0%; 195 | } 196 | 75% { 197 | height: 0%; 198 | } 199 | 100% { 200 | height: 100%; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /static/css/test.css: -------------------------------------------------------------------------------- 1 | /* test css */ 2 | -------------------------------------------------------------------------------- /static/detections/data/output.csv: -------------------------------------------------------------------------------- 1 | Frame No.,Manufacturer,License Plate,Colour,Time Stamp(s) 2 | frame29.jpg,Suzuki,MH02CB5163,White,2.9 3 | frame33.jpg,Suzuki,MH02CB5163,White,3.3 4 | frame34.jpg,Suzuki,MH02CB5163,White,3.4 5 | frame5.jpg,Hyundai,MH01BU7584,Black,0.5 6 | -------------------------------------------------------------------------------- /static/detections/speed/speed.csv: -------------------------------------------------------------------------------- 1 | Car Id.,Speed,Timestamp 2 | 5,0,1.3013000000000001 3 | 8,211,2.0353666666666665 4 | -------------------------------------------------------------------------------- /static/img/images.txt: -------------------------------------------------------------------------------- 1 | Just a placeholder file so GIT won't leave this directory off. 2 | -------------------------------------------------------------------------------- /static/img/security-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-File/Vehicle-Identification-Speed-Detection/a6f95c9f35fcb1adf81596a1dc6f08ec9564e42f/static/img/security-camera.png -------------------------------------------------------------------------------- /templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block content %} 4 | 5 |

Instructions

6 |

Add instructions here

7 | 8 | {% endblock %} -------------------------------------------------------------------------------- /templates/data_done.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} {% block content %} 2 |
3 |

4 |

Data Extraction

5 |
6 |

Data Extraction completed successfully.

7 | Download .csv 8 | 9 |
10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Vehicle Surveillance System

7 | Speed Detection 8 | Data Extraction 9 |
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Vehicle Surveillance System 12 | 13 | 14 | 17 | 18 |
19 | {% block content %} 20 | {% endblock %} 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /templates/speed.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} {% block content %} 2 |
3 |

4 |

Speed Detection

5 | Click Here for Data Extraction 6 |
7 | {% if fname %} 8 |

Speed Detection completed successfully.

9 | Download .csv 10 | {% endif %} 11 | 33 | 39 |
40 | 41 | 42 | 45 |
46 | 47 |
48 |

Upload Video

49 |
54 | 55 | 56 |
57 |
58 |
59 |
60 | {% endblock %} 61 | -------------------------------------------------------------------------------- /templates/uploaded copy.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} {% block content %} 2 |
3 |

4 |

Data Extraction

5 | Click Here for Speed Detection 6 |
7 | {% if fname %} 8 |

Data Extraction completed successfully.

9 | Download .csv 10 | {% endif %} 11 | 33 | 39 |
40 | 41 | 42 | 45 |
46 | 47 |
48 |

Upload Video

49 |
54 | 55 | 56 |
57 |
58 |
59 |
60 | {% endblock %} 61 | -------------------------------------------------------------------------------- /templates/uploaded.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} {% block content %} 2 | 8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |

22 |

Data Extraction in progress, please wait.

23 |
24 | 25 |

26 |

Data Extraction

27 | Click Here for Speed Detection 28 |
29 | {% if fname %} 30 |

Data Extraction completed successfully.

31 | Download .csv 32 | {% endif %} 33 | 34 | 35 |
36 |

Upload Video

37 |
42 | 43 | 44 |
45 |
46 |
47 |
48 | {% endblock %} 49 | -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | from absl import app, flags, logging 2 | from absl.flags import FLAGS 3 | import os 4 | import shutil 5 | import tensorflow as tf 6 | from core.yolov4 import YOLO, decode, compute_loss, decode_train 7 | from core.dataset import Dataset 8 | from core.config import cfg 9 | import numpy as np 10 | from core import utils 11 | from core.utils import freeze_all, unfreeze_all 12 | 13 | flags.DEFINE_string('model', 'yolov4', 'yolov4, yolov3') 14 | flags.DEFINE_string('weights', './scripts/yolov4.weights', 'pretrained weights') 15 | flags.DEFINE_boolean('tiny', False, 'yolo or yolo-tiny') 16 | 17 | def main(_argv): 18 | physical_devices = tf.config.experimental.list_physical_devices('GPU') 19 | if len(physical_devices) > 0: 20 | tf.config.experimental.set_memory_growth(physical_devices[0], True) 21 | 22 | trainset = Dataset(FLAGS, is_training=True) 23 | testset = Dataset(FLAGS, is_training=False) 24 | logdir = "./data/log" 25 | isfreeze = False 26 | steps_per_epoch = len(trainset) 27 | first_stage_epochs = cfg.TRAIN.FISRT_STAGE_EPOCHS 28 | second_stage_epochs = cfg.TRAIN.SECOND_STAGE_EPOCHS 29 | global_steps = tf.Variable(1, trainable=False, dtype=tf.int64) 30 | warmup_steps = cfg.TRAIN.WARMUP_EPOCHS * steps_per_epoch 31 | total_steps = (first_stage_epochs + second_stage_epochs) * steps_per_epoch 32 | # train_steps = (first_stage_epochs + second_stage_epochs) * steps_per_period 33 | 34 | input_layer = tf.keras.layers.Input([cfg.TRAIN.INPUT_SIZE, cfg.TRAIN.INPUT_SIZE, 3]) 35 | STRIDES, ANCHORS, NUM_CLASS, XYSCALE = utils.load_config(FLAGS) 36 | IOU_LOSS_THRESH = cfg.YOLO.IOU_LOSS_THRESH 37 | 38 | freeze_layers = utils.load_freeze_layer(FLAGS.model, FLAGS.tiny) 39 | 40 | feature_maps = YOLO(input_layer, NUM_CLASS, FLAGS.model, FLAGS.tiny) 41 | if FLAGS.tiny: 42 | bbox_tensors = [] 43 | for i, fm in enumerate(feature_maps): 44 | if i == 0: 45 | bbox_tensor = decode_train(fm, cfg.TRAIN.INPUT_SIZE // 16, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE) 46 | else: 47 | bbox_tensor = decode_train(fm, cfg.TRAIN.INPUT_SIZE // 32, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE) 48 | bbox_tensors.append(fm) 49 | bbox_tensors.append(bbox_tensor) 50 | else: 51 | bbox_tensors = [] 52 | for i, fm in enumerate(feature_maps): 53 | if i == 0: 54 | bbox_tensor = decode_train(fm, cfg.TRAIN.INPUT_SIZE // 8, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE) 55 | elif i == 1: 56 | bbox_tensor = decode_train(fm, cfg.TRAIN.INPUT_SIZE // 16, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE) 57 | else: 58 | bbox_tensor = decode_train(fm, cfg.TRAIN.INPUT_SIZE // 32, NUM_CLASS, STRIDES, ANCHORS, i, XYSCALE) 59 | bbox_tensors.append(fm) 60 | bbox_tensors.append(bbox_tensor) 61 | 62 | model = tf.keras.Model(input_layer, bbox_tensors) 63 | model.summary() 64 | 65 | if FLAGS.weights == None: 66 | print("Training from scratch") 67 | else: 68 | if FLAGS.weights.split(".")[len(FLAGS.weights.split(".")) - 1] == "weights": 69 | utils.load_weights(model, FLAGS.weights, FLAGS.model, FLAGS.tiny) 70 | else: 71 | model.load_weights(FLAGS.weights) 72 | print('Restoring weights from: %s ... ' % FLAGS.weights) 73 | 74 | 75 | optimizer = tf.keras.optimizers.Adam() 76 | if os.path.exists(logdir): shutil.rmtree(logdir) 77 | writer = tf.summary.create_file_writer(logdir) 78 | 79 | # define training step function 80 | # @tf.function 81 | def train_step(image_data, target): 82 | with tf.GradientTape() as tape: 83 | pred_result = model(image_data, training=True) 84 | giou_loss = conf_loss = prob_loss = 0 85 | 86 | # optimizing process 87 | for i in range(len(freeze_layers)): 88 | conv, pred = pred_result[i * 2], pred_result[i * 2 + 1] 89 | loss_items = compute_loss(pred, conv, target[i][0], target[i][1], STRIDES=STRIDES, NUM_CLASS=NUM_CLASS, IOU_LOSS_THRESH=IOU_LOSS_THRESH, i=i) 90 | giou_loss += loss_items[0] 91 | conf_loss += loss_items[1] 92 | prob_loss += loss_items[2] 93 | 94 | total_loss = giou_loss + conf_loss + prob_loss 95 | 96 | gradients = tape.gradient(total_loss, model.trainable_variables) 97 | optimizer.apply_gradients(zip(gradients, model.trainable_variables)) 98 | tf.print("=> STEP %4d/%4d lr: %.6f giou_loss: %4.2f conf_loss: %4.2f " 99 | "prob_loss: %4.2f total_loss: %4.2f" % (global_steps, total_steps, optimizer.lr.numpy(), 100 | giou_loss, conf_loss, 101 | prob_loss, total_loss)) 102 | # update learning rate 103 | global_steps.assign_add(1) 104 | if global_steps < warmup_steps: 105 | lr = global_steps / warmup_steps * cfg.TRAIN.LR_INIT 106 | else: 107 | lr = cfg.TRAIN.LR_END + 0.5 * (cfg.TRAIN.LR_INIT - cfg.TRAIN.LR_END) * ( 108 | (1 + tf.cos((global_steps - warmup_steps) / (total_steps - warmup_steps) * np.pi)) 109 | ) 110 | optimizer.lr.assign(lr.numpy()) 111 | 112 | # writing summary data 113 | with writer.as_default(): 114 | tf.summary.scalar("lr", optimizer.lr, step=global_steps) 115 | tf.summary.scalar("loss/total_loss", total_loss, step=global_steps) 116 | tf.summary.scalar("loss/giou_loss", giou_loss, step=global_steps) 117 | tf.summary.scalar("loss/conf_loss", conf_loss, step=global_steps) 118 | tf.summary.scalar("loss/prob_loss", prob_loss, step=global_steps) 119 | writer.flush() 120 | def test_step(image_data, target): 121 | with tf.GradientTape() as tape: 122 | pred_result = model(image_data, training=True) 123 | giou_loss = conf_loss = prob_loss = 0 124 | 125 | # optimizing process 126 | for i in range(len(freeze_layers)): 127 | conv, pred = pred_result[i * 2], pred_result[i * 2 + 1] 128 | loss_items = compute_loss(pred, conv, target[i][0], target[i][1], STRIDES=STRIDES, NUM_CLASS=NUM_CLASS, IOU_LOSS_THRESH=IOU_LOSS_THRESH, i=i) 129 | giou_loss += loss_items[0] 130 | conf_loss += loss_items[1] 131 | prob_loss += loss_items[2] 132 | 133 | total_loss = giou_loss + conf_loss + prob_loss 134 | 135 | tf.print("=> TEST STEP %4d giou_loss: %4.2f conf_loss: %4.2f " 136 | "prob_loss: %4.2f total_loss: %4.2f" % (global_steps, giou_loss, conf_loss, 137 | prob_loss, total_loss)) 138 | 139 | for epoch in range(first_stage_epochs + second_stage_epochs): 140 | if epoch < first_stage_epochs: 141 | if not isfreeze: 142 | isfreeze = True 143 | for name in freeze_layers: 144 | freeze = model.get_layer(name) 145 | freeze_all(freeze) 146 | elif epoch >= first_stage_epochs: 147 | if isfreeze: 148 | isfreeze = False 149 | for name in freeze_layers: 150 | freeze = model.get_layer(name) 151 | unfreeze_all(freeze) 152 | for image_data, target in trainset: 153 | train_step(image_data, target) 154 | for image_data, target in testset: 155 | test_step(image_data, target) 156 | model.save_weights("./checkpoints/yolov4") 157 | 158 | if __name__ == '__main__': 159 | try: 160 | app.run(main) 161 | except SystemExit: 162 | pass --------------------------------------------------------------------------------