<jupyter_start><jupyter_text>Autonomous driving - Car detectionIntegration of (https://arxiv.org/abs/1506.02640) and <NAME>, 2016 (https://arxiv.org/abs/1612.08242).<jupyter_code>import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow
import numpy as np
import tensorflow as tf
from keras import backend as K
from keras.models import load_model
from yad2k.utils.yolo_utils import read_classes, read_anchors, generate_colors, preprocess_image, draw_boxes, scale_boxes
from yad2k.keras_yolo import yolo_head, yolo_boxes_to_corners
from lane_utils import *
import time
%matplotlib inline<jupyter_output>C:\Users\Kiko-PC\Anaconda3\envs\tensorflow\lib\site-packages\h5py\__init__.py:34: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
Using TensorFlow backend.<jupyter_text>IntroductionBounding box exmple :In this prject, I use pretrained weights, where we have 80 trained yolo classes, for recognition.  The class label is represented as $c$ and it's integer from 1 to 80, each number represent the class label accordingly.  If $c=3$, then the classified object is a $car$  2 - YOLO YOLO stands for You Only Look Once. It's an object detector that uses features learned by a deep convolutional neural network to detect an object. Before we get out hands dirty with code, we must understand how YOLO works. 2.1 - Architercutre detailsNeural network io:-  **input** : (m, 608, 608, 3)-  **output** : confidece of an object being present in the rectangle, list of rectangles position and sizes and classes of the objects begin detected. Each bounding box is represented by 6 numbers $(Pc, Rx, Ry, Rh, Rw, C1..Cn)$ as explained above. In this case n=80, which means we have $c$ as 80-dimensional vector, and the final size of representing the bounding box is 85 Let us consider an input, where the input image is 608 x 608, and stride of the network is 32. As pointed earlier, the dimensions of the feature map will be 13 x 13. We then divide the input image into 19 x 19 cells. For keeping the things simple we will flatten the last two dimensions, from (19, 19, 5, 85) the output of our CNN is flatten to (19, 19, 425). Now, for each box (of each cell) we will compute the following elementwise product and extract a probability that the box contains a certain class.**Find the class detected by each box** Here's one example visualizing what YOLO can predict on an image:- For each of the $SxS$ grid cells, find the maximum of the confidence scores (taking a max across both the 5 anchor boxes and across different classes).  A confidence score is: probability(containing an object) x IoU(pred, truth).If the cell contains an object, it predicts a probability of this object belonging to one class Ci, i=1,2,…, K: probability(the object belongs to the class Ci | containing an object). At this stage, the model only predicts one set of class probabilities per cell, regardless of the number of boxes B. - Color that grid cell according to what object that grid cell considers the most likely.- Draw rectangle  Each of the $SxS$ grid cells colored according the class that has the largest predicted probability in specified cell.  Part 1 - Filtering with a threshold on class scoresThe output result may contain several rectangles that are false positives or overlap, so we need to find a way to reduce them.The first attempt to reduce these rectangles is to filter them by threshold.**Input arguments**: - `box_confidence`: tensor of shape $(19 \times 19, 5, 1)$ containing $p_c$ (confidence probability that there's some object) for each of the 5 boxes predicted in each of the 19x19 cells.- `boxes`: tensor of shape $(19 \times 19, 5, 4)$ containing $(b_x, b_y, b_h, b_w)$ for each of the 5 boxes per cell.- `box_class_probs`: tensor of shape $(19 \times 19, 5, 80)$ containing the detection probabilities $(c_1, c_2, ... c_{80})$ for each of the 80 classes for each of the 5 boxes per cell.<jupyter_code>def yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = .6):
    """Filters YOLO boxes by thresholding on object and class confidence.
    
    Arguments:
    box_confidence -- tensor of shape (19, 19, 5, 1)
    boxes -- tensor of shape (19, 19, 5, 4)
    box_class_probs -- tensor of shape (19, 19, 5, 80)
    threshold -- real value, if [ highest class probability score < threshold], then get rid of the corresponding box
    
    Returns:
    scores -- tensor of shape (None,), containing the class probability score for selected boxes
    boxes -- tensor of shape (None, 4), containing (b_x, b_y, b_h, b_w) coordinates of selected boxes
    classes -- tensor of shape (None,), containing the index of the class detected by the selected boxes
    
    Note: "None" is here because you don't know the exact number of selected boxes, as it depends on the threshold. 
    For example, the actual output size of scores would be (10,) if there are 10 boxes.
    """
    
    # Step 1: Compute box scores
    box_scores = box_confidence * box_class_probs #multiply box probability(p) with class probability
    
    # Step 2: Find the box_classes thanks to the max box_scores, keep track of the corresponding score
    box_classes = K.argmax(box_scores, axis=-1) #max class index
    box_class_scores = K.max(box_scores, axis=-1) #max class probability
    
    # Step 3: Create a filtering mask based on "box_class_scores" by using "threshold". The mask should have the
    # same dimension as box_class_scores, and be True for the boxes you want to keep (with probability >= threshold)
    filtering_mask = box_class_scores>=threshold
    
    # Step 4: Apply the mask to scores, boxes and classes
    scores = tf.boolean_mask(tensor=box_class_scores, mask=filtering_mask, name='score_mask')
    boxes  = tf.boolean_mask(tensor=boxes, mask=filtering_mask, name='box_mask')
    classes = tf.boolean_mask(tensor=box_classes, mask=filtering_mask, name='classes_mask')
    
    return scores, boxes, classes<jupyter_output><empty_output><jupyter_text>Part 2 : Non-max suppression Even after yolo filtering by thresholding over, we still have a lot of overlapping boxes. Second approach and filtering is Non-Max suppression algorithm.* Discard all boxes with $Pc <= 0.6$  * While tehre are any remaining boxes :     * Pick the box with the largest $Pc$    * Output that as a prediction    * Discard any remaining boxes with $IOU>=0.5$ with the box output in the previous step Example of non max suppression algorithm, on input the aglorithm receive 4 overlapping bounding boxes, and the output returns only one Non-max suppression uses the very important function called **"Intersection over Union"**, or IoU.**Below is implementation of iou**:<jupyter_code>def iou(box1, box2):
    """Implement the intersection over union (IoU) between box1 and box2
    
    Arguments:
    box1 -- first box, list object with coordinates (x1, y1, x2, y2)
    box2 -- second box, list object with coordinates (x1, y1, x2, y2)
    """

    # Calculate the (y1, x1, y2, x2) coordinates of the intersection of box1 and box2. Calculate its Area.
    xi1 = max(box1[0],box2[0])
    yi1 = max(box1[1],box2[1])
    xi2 = min(box1[2], box2[2])
    yi2 = min(box1[3], box2[3])
    inter_area = abs(xi1-xi2) * abs(yi1-yi2)

    # Calculate the Union area by using Formula: Union(A,B) = A + B - Inter(A,B)
    box1_area = abs(box1[0]-box1[2]) * abs(box1[1]-box1[3])
    box2_area = abs(box2[0]-box2[2]) * abs(box2[1]-box2[3])
    union_area = box1_area + box2_area -inter_area
    
    # compute the IoU
    iou = inter_area/union_area

    return iou
box1 = (2, 1, 4, 3)
box2 = (1, 2, 3, 4) 
print("iou = " + str(iou(box1, box2)))<jupyter_output>iou = 0.14285714285714285<jupyter_text>With computing iou, we co mposed the third part of non max supression algorithm, now, lets combine everything into one :<jupyter_code>def yolo_non_max_suppression(scores, boxes, classes, max_boxes = 10, iou_threshold = 0.5):
    """
    Applies Non-max suppression (NMS) to set of boxes
    
    Arguments:
    scores -- tensor of shape (None,), output of yolo_filter_boxes()
    boxes -- tensor of shape (None, 4), output of yolo_filter_boxes() that have been scaled to the image size (see later)
    classes -- tensor of shape (None,), output of yolo_filter_boxes()
    max_boxes -- integer, maximum number of predicted boxes you'd like
    iou_threshold -- real value, "intersection over union" threshold used for NMS filtering
    
    Returns:
    scores -- tensor of shape (, None), predicted score for each box
    boxes -- tensor of shape (4, None), predicted box coordinates
    classes -- tensor of shape (, None), predicted class for each box
    
    Note: The "None" dimension of the output tensors has obviously to be less than max_boxes. Note also that this
    function will transpose the shapes of scores, boxes, classes. This is made for convenience.
    """
    
    max_boxes_tensor = K.variable(max_boxes, dtype='int32')     # tensor to be used in tf.image.non_max_suppression()
    K.get_session().run(tf.variables_initializer([max_boxes_tensor])) # initialize variable max_boxes_tensor
    
    # Use tf.image.non_max_suppression() to get the list of indices corresponding to boxes you keep
    nms_indices = tf.image.non_max_suppression(boxes=boxes, 
                                               scores=scores,
                                               max_output_size=max_boxes, 
                                               iou_threshold=iou_threshold, name='nms_indices')
    
    scores = K.gather(scores, nms_indices)
    boxes = K.gather(boxes, nms_indices)
    classes = K.gather(classes, nms_indices)
    
    return scores, boxes, classes<jupyter_output><empty_output><jupyter_text>2.4 Wrapping up the filteringLet's calculate the whole algorithm : * Get Yolo CNN output* Discard all boxes with $Pc <= 0.6$  * While tehre are any remaining boxes :     * Pick the box with the largest $Pc$    * Output that as a prediction    * Discard any remaining boxes with $IOU>=0.5$ with the box output in the previous step<jupyter_code>def yolo_eval(yolo_outputs, image_shape = (720., 1280.), max_boxes=10, score_threshold=.6, iou_threshold=.5):
    """
    Converts the output of YOLO encoding (a lot of boxes) to your predicted boxes along with their scores, box coordinates and classes.
    
    Arguments:
    yolo_outputs -- output of the encoding model (for image_shape of (608, 608, 3)), contains 4 tensors:
                    box_confidence: tensor of shape (None, 19, 19, 5, 1)
                    box_xy: tensor of shape (None, 19, 19, 5, 2)
                    box_wh: tensor of shape (None, 19, 19, 5, 2)
                    box_class_probs: tensor of shape (None, 19, 19, 5, 80)
    image_shape -- tensor of shape (2,) containing the input shape, in this notebook we use (608., 608.) (has to be float32 dtype)
    max_boxes -- integer, maximum number of predicted boxes you'd like
    score_threshold -- real value, if [ highest class probability score < threshold], then get rid of the corresponding box
    iou_threshold -- real value, "intersection over union" threshold used for NMS filtering
    
    Returns:
    scores -- tensor of shape (None, ), predicted score for each box
    boxes -- tensor of shape (None, 4), predicted box coordinates
    classes -- tensor of shape (None,), predicted class for each box
    """
    
    
    # Retrieve outputs of the YOLO model (≈1 line)
    box_confidence, box_xy, box_wh, box_class_probs = yolo_outputs

    # Convert boxes to be ready for filtering functions 
    boxes = yolo_boxes_to_corners(box_xy, box_wh)

    # Use one of the functions you've implemented to perform Score-filtering with a threshold of score_threshold (≈1 line)
    scores, boxes, classes = yolo_filter_boxes(box_confidence, boxes, box_class_probs, score_threshold)
    
    # Scale boxes back to original image shape.
    boxes = scale_boxes(boxes, image_shape)

    # Use one of the functions you've implemented to perform Non-max suppression with a threshold of iou_threshold (≈1 line)
    scores, boxes, classes = yolo_non_max_suppression(scores, boxes, classes, max_boxes, iou_threshold)
        
    return scores, boxes, classes<jupyter_output><empty_output><jupyter_text>Part 3 :  YOLO V2. Model For the purpose of this project, I'm using a pretrained weights for Yolo V2.You can download the weights  here<jupyter_code>sess = K.get_session()<jupyter_output><empty_output><jupyter_text>3.1 - Defining classes, anchors and image shape. We have gathered the information about the 80 classes and 5 boxes in two files "coco_classes.txt" and "yolo_anchors.txt". Let's load these quantities into the model by running the next cell. The car detection dataset has 720x1280 images, which we've pre-processed into 608x608 images.   Anchor BoxesGenerating anchor boxes using K-means clusteringThere are many ways to compute bounding boxes for detection tasks. One approach is to directly predict the bounding box values, however this approach is susceptible to errors as it tends to favor bounding boxes with large dimensions. Further, the training process is unstable because the range of values to predict can vary significantly.In YOLOv2, the first step is to compute good candidate anchor boxes. This is achieved using K-means clustering. However, using direct Euler distance metric for K-means minizers error for larger bounding boxes, but not for smaller boxes. Therefore, in YOLOv2, intersection over union (IOU) is used as a distance metric. The IOU calculations are made assuming all the bounding boxes are located at one point, i.e. only width and height are used as features. Figure below shows the height and width plotted against each other. Fixed slopes indicate that most bounding boxes have specific predefined aspect ratios, and size. This is not surprising given the fact that a person and vehicle are expected to have certain fixed dimensions.In Yolo V2, this specialization is ‘assisted’ with predefined anchors as in Faster-RCNN. The predefined anchors are chosen to be as representative as possible of the ground truth boxes, with the following K-means clustering algorithm to define them:* all ground-truth bounding boxes are centered on (0,0)* the algorithm initiates 5 centroïds by drawing randomly 5 of the ground-truth bounding boxes* then, the following two steps are alternated:    * each ground truth box is assigned to one of the centroïd, using as distance measure the IOU, in order to get 5 clusters or groups of ground-truth bouding boxes    * new centroïds are computed by taking the box inside each cluster that minimizes the mean IOU with all other boxes inside the cluster  Reading class/anchors dataBellow we are reading the class labels and pre-computed anchors points with K-means algorithm<jupyter_code>class_names = read_classes("model_data/coco_classes.txt")
anchors = read_anchors("model_data/yolo_anchors.txt")
print(anchors)
image_shape = (720., 1280.)<jupyter_output>model_data/yolo_anchors.txt
[[0.57273  0.677385]
 [1.87446  2.06253 ]
 [3.33843  5.47434 ]
 [7.88282  3.52778 ]
 [9.77052  9.16828 ]]<jupyter_text>3.2 - Loading a pretrained modelFor the purpose of this project, I'm using a pretrained weights for Yolo V2.You can download the weights  hereThese weights are generated with using pure numpy arrays, but luckily the authors of Yolo provided configuration files containing the full model information, which means we can convert the weights in any high level program language.<NAME> wrote a function for weights conversion, which works well for Yolo V2, and I provided small modifications for Yolo V3 References are at the end of this notebook.<jupyter_code>yolo_model = load_model("yolo.h5")<jupyter_output>C:\Users\Kiko-PC\Anaconda3\envs\tensorflow\lib\site-packages\keras\models.py:255: UserWarning: No training configuration found in save file: the model was *not* compiled. Compile it manually.
  warnings.warn('No training configuration found in save file: '<jupyter_text>This loads the weights of a trained YOLO model. Here's a summary of the layers your model contains.<jupyter_code>yolo_model.summary()<jupyter_output>__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_1 (InputLayer)            (None, 608, 608, 3)  0                                            
__________________________________________________________________________________________________
conv2d_1 (Conv2D)               (None, 608, 608, 32) 864         input_1[0][0]                    
__________________________________________________________________________________________________
batch_normalization_1 (BatchNor (None, 608, 608, 32) 128         conv2d_1[0][0]                   
__________________________________________________________________________________________________
leaky_re_lu_1 (LeakyReLU)       (None, 608, 608, 32) 0           batch_normalization_1[0][0]      
__________[...]<jupyter_text>**Note**: On some computers, you may see a warning message from Keras. Don't worry about it if you do--it is fine.**Reminder**: this model converts a preprocessed batch of input images (shape: (m, 608, 608, 3)) into a tensor of shape (m, 19, 19, 5, 85) as explained in Figure (2).  3.3 - Convert output of the model to usable bounding box tensorsThe output of `yolo_model` is a (m, 19, 19, 5, 85) tensor that needs to pass through non-trivial processing and conversion. The following cell does that for you.<jupyter_code>yolo_outputs = yolo_head(yolo_model.output, anchors, len(class_names))
print(yolo_outputs)<jupyter_output>(<tf.Tensor 'Sigmoid:0' shape=(?, ?, ?, 5, 1) dtype=float32>, <tf.Tensor 'truediv:0' shape=(?, ?, ?, 5, 2) dtype=float32>, <tf.Tensor 'truediv_1:0' shape=(?, ?, ?, 5, 2) dtype=float32>, <tf.Tensor 'Reshape_6:0' shape=(?, ?, ?, 5, 80) dtype=float32>)<jupyter_text>You added `yolo_outputs` to your graph. This set of 4 tensors is ready to be used as input by your `yolo_eval` function.  3.4 - Filtering boxes`yolo_outputs` gave you all the predicted boxes of `yolo_model` in the correct format. You're now ready to perform filtering and select only the best boxes. Lets now call `yolo_eval`, which you had previously implemented, to do this.<jupyter_code>scores, boxes, classes = yolo_eval(yolo_outputs, image_shape)
print(scores)
print(boxes)
print(classes)<jupyter_output>Tensor("Gather:0", shape=(?,), dtype=float32)
Tensor("Gather_1:0", shape=(?, 4), dtype=float32)
Tensor("Gather_2:0", shape=(?,), dtype=int64)<jupyter_text>3.5 - Run the graph on an imageLet the fun begin. You have created a (`sess`) graph that can be summarized as follows:1.  yolo_model.input  is given to `yolo_model`. The model is used to compute the output  yolo_model.output 2.  yolo_model.output  is processed by `yolo_head`. It gives you  yolo_outputs 3.  yolo_outputs  goes through a filtering function, `yolo_eval`. It outputs your predictions:  scores, boxes, classes **Exercise**: Implement predict() which runs the graph to test YOLO on an image.You will need to run a TensorFlow session, to have it compute `scores, boxes, classes`.The code below also uses the following function:```pythonimage, image_data = preprocess_image("images/" + image_file, model_image_size = (608, 608))```which outputs:- image: a python (PIL) representation of your image used for drawing boxes. You won't need to use it.- image_data: a numpy-array representing the image. This will be the input to the CNN.**Important note**: when a model uses BatchNorm (as is the case in YOLO), you will need to pass an additional placeholder in the feed_dict {K.learning_phase(): 0}.<jupyter_code>from PIL import Image

def predict(sess, image_file):
    """
    Runs the graph stored in "sess" to predict boxes for "image_file". Prints and plots the preditions.
    
    Arguments:
    sess -- your tensorflow/Keras session containing the YOLO graph
    image_file -- name of an image stored in the "images" folder.
    
    Returns:
    out_scores -- tensor of shape (None, ), scores of the predicted boxes
    out_boxes -- tensor of shape (None, 4), coordinates of the predicted boxes
    out_classes -- tensor of shape (None, ), class index of the predicted boxes
    
    Note: "None" actually represents the number of predicted boxes, it varies between 0 and max_boxes. 
    """
    # Preprocess your image
    image, image_data = preprocess_image(image_file, model_image_size = (608, 608))
    
    image = Image.fromarray(image.astype('uint8'), 'RGB')

    # Run the session with the correct tensors and choose the correct placeholders in the feed_dict.
    # You'll need to use feed_dict={yolo_model.input: ... , K.learning_phase(): 0})
    out_scores, out_boxes, out_classes = sess.run([scores,boxes,classes], 
                                                  feed_dict = {yolo_model.input:image_data, K.learning_phase():0})


    # Generate colors for drawing bounding boxes.
    colors = generate_colors(class_names)
    # Draw bounding boxes on the image file
    drawer=draw_boxes(image, out_scores, out_boxes, out_classes, class_names, colors)


    return out_scores, out_boxes, out_classes, drawer<jupyter_output><empty_output><jupyter_text>Run the following cell on the "test.jpg" image to verify that your function is correct.<jupyter_code>def pipeline_final(img):

    start_cars = time.time()
    out_scores, out_boxes, out_classes, image = predict(sess, img)
    end_cars = time.time()
    
    start_lanes = time.time()
    initial_lane,left_fit, right_fit, left_fitx, right_fitx, ploty, filtered_image, warped, deep_search, out_img = pipeline_lanes(np.copy(img))
    result=cv2.addWeighted(image, 1, initial_lane, 0.3, 1)
    
    
    result  = add_diagnostic_image(result, filtered_image, 0)
    result  = add_diagnostic_image(result, warped, 1)
    result  = add_diagnostic_image(result, deep_search, 2)
    result  = add_diagnostic_image(result, out_img, 3)
    
    end_lanes = time.time()
    fps_lanes = 1/(end_lanes-start_lanes)
    fps_cars = 1/(end_cars - start_cars)
    fps_text_cars = "FPS cars : %.2f" % fps_cars
    fps_text_lanes = "FPS lanes : %.2f" % fps_lanes

    result  = add_diagnostic_text(result, fps_text_lanes, 4, offset=50)
    result  = add_diagnostic_text(result, fps_text_cars, 4, offset=90)


    return result



def pipeline_lanes(img):

    global caches 
    
    is_blind = False
    left_fit, right_fit = None, None

    if caches:
        left_fit, right_fit, is_blind  = caches
        
    filtered_image = filter_image(img, is_blind)
       
    warped, filled = perspective_transform_with_filled_area(img, filtered_image)
    
    #The line below is added only for the first initial frame and for diagnostic purposes 
    ploty, left_fitx, right_fitx, left_fit, right_fit, deep_search = get_lane_rectangles(warped, left_fit, right_fit, is_blind)
    if not caches : 
        caches = [left_fit, right_fit, is_blind]

    if caches : 
        left_fit, right_fit, is_blind  = caches
        out_img, ploty, left_fitx, right_fitx, left_fit, right_fit, is_blind = get_next_frame_lines(warped, left_fit, right_fit, is_blind)
        caches = [left_fit, right_fit, is_blind]

            

    result = inverse_perspective_transform(img, warped, left_fitx, right_fitx, ploty)
    

    return result, left_fit, right_fit, left_fitx, right_fitx, ploty, filtered_image, warped, deep_search,out_img
from moviepy.editor import VideoFileClip

# Reinitialize some global variables.
caches = [] 

output = 'custom_output.mp4'
clip1 = VideoFileClip("../project_video.mp4")
white_clip = clip1.fl_image(pipeline_final) 
%time white_clip.write_videofile(output, audio=False)<jupyter_output>[MoviePy] >>>> Building video custom_output.mp4
[MoviePy] Writing video custom_output.mp4
{'fraction_non_alphanumeric': 0.08288504510469254, 'fraction_numerical': 0.024579988413473475, 'mean_word_length': 3.981859410430839, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 59, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 13, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '373222', 'license': 'MIT', 'n_tokens_mistral': 7397, 'n_tokens_neox': 6839, 'n_words': 2845, 'path': 'YoloV2/Notebook.ipynb', 'repo_name': 'kirilcvetkov92/Vehicle-Detection', 'size': '24185'}