<jupyter_start><jupyter_text>Create pre-processing pipeline images and distributions, included shifted distributions, for report Clone code and prepare data<jupyter_code>!git clone https://github.com/dsikar/sdsandbox
%cd  sdsandbox/src/
!tar xvf examples/logs_Wed_Nov_25_23_39_22_2020.tar.gz
def GetJSONSteeringAngles(filemask):
    """
    Get steering angles stored as 'user/angle' attributes in .json files
    Inputs:
        filemask: string, path and mask
    Outputs
        svals: list, steering values
    """
    filemask = os.path.expanduser(filemask)
    path, mask = os.path.split(filemask)

    matches = []
    for root, dirnames, filenames in os.walk(path):
        for filename in fnmatch.filter(filenames, mask):
            matches.append(os.path.join(root, filename))
    # sort by create date
    # matches = sorted(matches, key=os.path.getmtime)
    # sort by filename prefix
    matches = sort_sdsandbox_files(matches)
    # steering values
    svals = []
    for fullpath in matches:
      # print(fullpath)
      frame_number = os.path.basename(fullpath).split("_")[0]
      json_filename = os.path.join(os.path.dirname(fullpath), "record_" + frame_number + ".json")
      jobj = load_json(json_filename)
      svals.append(jobj['user/angle'])
    return svals

def load_json(filepath):
    """
    Load a json file
    Inputs
        filepath: string, path to file
    Outputs
        data: dictionary, json key, value pairs
    Example
    path = "~/git/msc-data/unity/roboRacingLeague/log/logs_Sat_Nov_14_12_36_16_2020/record_11640.json"
    js = load_json(path)
    """
    with open(filepath, "rt") as fp:
        data = json.load(fp)
    return data 

def sort_sdsandbox_files(matches):
  """
  Sort sdsandbox files in format e.g. 'logs_Wed_Nov_25_23_39_22_2020/1339_cam-image_array_.jpg'
  This is to emulate a sort-by-date feature, once files have been copied and datetime stamp is lost

  Parameters
  -------
  matches: list of strings, image filepaths

  Output
  -------
  sorted_matches: list of strings, sorted list

  Example
  -------
  matches = sort_sdsandbox_files(matches)
  for match in matches:
    print(match)
  """
  filenums = {}
  sorted_matches = []
  for match in matches:
    # match ~ 'logs_Wed_Nov_25_23_39_22_2020/1339_cam-image_array_.jpg'
    # match.split('/')[-1].split('_')[0] ~ 1339
    filenums[int(match.split('/')[-1].split('_')[0])] = match

  filenums = sorted(filenums.items(), key=lambda filenums: filenums[0])
  for key in filenums:
    sorted_matches.append(key[1]) 

  return sorted_matches        

def GetPredictions(filemask, modelpath, datashift = 0, modelname = 'nvidia2'):
    """
    Get predictions of a given model
    
    Parameters
    -------
        filemask: string, path of the images to generate steering angle predictions
        modelpath: string, path of the trained model 
        datashift: integer, RGB intensity mean shift to left (negative) or right (positive) or 
        input image RGB intensity mean
        modelname: string, model name refering to input geometry to use
    
    Output
    -------
        predictions: numpy array of floats, steering angle predictons
        
    Example:
    filemask = '../../../../Downloads/dataset/unity/genTrack/genTrackOneLap/logs_Wed_Nov_25_23_39_22_2020/*.jpg'
    modelpath = '../../../../Downloads/trained_models/nvidia2/20201207192948_nvidia2.h5'
    datashift = -10
    filename = 'nvidia2'
    
    p = GetPredictions(filemask, modelpath, datashift)
    
    """
    import os
    from tensorflow.python.keras.models import load_model
    import cv2
    import Augment_cls    
    import fnmatch
    from PIL import Image
    import numpy as np
    import sys # for exception handling

    ag = Augment_cls.Augment_cls(modelname)

    model = load_model(modelpath)
    model.compile("sgd", "mse")
    
    filemask = os.path.expanduser(filemask)
    path, mask = os.path.split(filemask)

    matches = []
    for root, dirnames, filenames in os.walk(path):
        for filename in fnmatch.filter(filenames, mask):
            matches.append(os.path.join(root, filename))
    # sort by create date
    matches = sorted(matches, key=os.path.getmtime)
    # sort by filename prefix
    matches = sort_sdsandbox_files(matches)

    # steering values
    svals = []
    for fullpath in matches: 
      try:
        image = Image.open(fullpath)
        #PIL Image as a numpy array
        image = np.array(image, dtype=np.float32)
        # shift distribution
        image, rgbmean, rgbstd, rgbvar = shiftRGBValues(image, datashift, datashift, datashift)   
        # keep data type for prediction model
        image = np.array(image, dtype=np.float32)   
        image = ag.preprocess(image)
        image = image.reshape((1,) + image.shape)

        mod_pred = model.predict(image)   
        svals.append(mod_pred)

      except:
        print("Error ", sys.exc_info()[0], " occurred processing image ", fullpath, ", skipping") 
        pass

    preds = []
    # only return steering angles
    for i in range(0, len(svals)):
      preds.append(svals[i][0][0])      
    return preds  


# change rgb values
# https://stackoverflow.com/questions/59320564/how-to-access-and-change-color-channels-using-pil
def shiftRGBValues(img, rv=0, gv=0, bv=0):
  """
  Shift RGB values using PIL, and return mean and standard deviations

  Parameters
  -------
    img: uint8 numpy image array
    rv: integer, value to be added to red channel
    gv: integer, value to be added to green channel
    bv, integer, value to be added to blue channel

  Output
  -------
    myimg: uint8 numpy image array
    rgbmean: float, rgb mean
    rgbstd: float, rgb standard deviation
    rgbvar: float, rgb variance

  Example
  -------
  import matplotlib.pyplot as plt
  import matplotlib.image as mpimg
  img = mpimg.imread('steph.jpeg')
  myimg, rgbmean, rgbstd, rgbvar = changeRGB(img, 60, 0, 0)
  plt.imshow(myimg)
  """
  from PIL import Image
  import numpy as np

  im = Image.fromarray(np.uint8(img))

  # Split into 3 channels
  r, g, b = im.split()

  # Red
  r = r.point(lambda i: i + rv)

  # Green
  g = g.point(lambda i: i + gv)

  # Blue
  b = b.point(lambda i: i + bv)

  # Recombine back to RGB image
  result = Image.merge('RGB', (r, g, b))

  rgbmean = np.mean(result) 
  rgbstd = np.std(result) 
  rgbvar = np.var(result) 
  # Convert to uint8 numpy array
  myimg = np.asarray(result)

  return myimg, rgbmean, rgbstd, rgbvar    

# TODO Rename gos steer_error, Steering Error, average error over a set of predictions in degrees
def gos(p, g, n):
    """
    Calculate the goodness-of-steer between a prediction and a ground truth array.
    Inputs
        p: array of floats, steering angle prediction
        g: array of floats, steering angle ground truth.
        n: float, normalization constant
    Output
        gos: float, average of absolute difference between ground truth and prediction arrays
    """
    # todo add type assertion
    assert len(p) == len(g), "Arrays must be of equal length"
    return sum(abs(p - g)) / len(p) * n
    # print("Goodness of steer: {:.2f}".format(steer))<jupyter_output><empty_output><jupyter_text>Generate data<jupyter_code>from datetime import datetime
now = datetime.now()
date_time = now.strftime("%m/%d/%Y, %H:%M:%S")
print("******************")
print("Start time:",date_time)	

filemask = 'logs_Wed_Nov_25_23_39_22_2020/*.jpg'
modelpath = 'examples/20201207192948_nvidia2.h5'
modelname = 'nvidia2'

# datashift values to test
pMinus120 = 0
pMinus80 = 1
pMinus40 = 2
pMinus0 = 3
pPlus40 = 4
pPlus80 = 5
pPlus120 = 6

datashifts = [-120,-80,-40,0,40,80,120]
results = []
for val in datashifts:
  print("Processing shift: {}".format(str(val)))
  res = GetPredictions(filemask, modelpath, val, modelname)
  results.append(res)
now = datetime.now()
date_time = now.strftime("%m/%d/%Y, %H:%M:%S")
print("******************")
print("End time:",date_time)<jupyter_output>******************
Start time: 05/15/2022, 15:14:32
Processing shift: -120<jupyter_text>CleanupTo avoid error when computing steering errors<jupyter_code>!rm logs_Wed_Nov_25_23_39_22_2020/0_cam-image_array_.jpg<jupyter_output>rm: cannot remove 'logs_Wed_Nov_25_23_39_22_2020/0_cam-image_array_.jpg': No such file or directory<jupyter_text>Convert to Numpy arrays<jupyter_code>import numpy as np
for i in range (0, len(results)):
  results[i] = np.array(results[i])<jupyter_output><empty_output><jupyter_text>Data shift steering error average<jupyter_code>sterr = []
for i in range (0, len(results)):
  steer_err = gos(results[i],g,nc)
  sterr.append(steer_err)
  strline = "Steering error average for data shift = {}: {}".format(str(datashifts[i]), str(steer_err))
  print(strline)<jupyter_output>Steering error average for data shift = -120: 1.8432540957430164
Steering error average for data shift = -80: 1.7000205273693305
Steering error average for data shift = -40: 1.694793940333196
Steering error average for data shift = 0: 1.6829038607492623
Steering error average for data shift = 40: 1.9145348848815178
Steering error average for data shift = 80: 2.6942793829939564
Steering error average for data shift = 120: 3.6825313317011763<jupyter_text>Plot graphs Negative 120, 80, 40 and 0<jupyter_code>import os
import fnmatch
import json
import matplotlib.pyplot as plt
# plot ground truth steering angles for
# filemask = 'logs_Wed_Nov_25_23_39_22_2020/*.jpg'
nc = 25 # norm. constant, maximum steering angle in degrees

g = GetJSONSteeringAngles(filemask)
g = np.asarray(g)

plt.rcParams["figure.figsize"] = (18,3)

plt.plot(g*nc, label='Ground truth')
res = "{:.2f}".format(sterr[pMinus0])
plt.plot(results[pMinus0]*nc, label='RGB shift | st. err: 0 | ' + res)
res = "{:.2f}".format(sterr[pMinus40])
plt.plot(results[pMinus40]*nc, label='RGB shift | st. err: -40 | ' + res)
res = "{:.2f}".format(sterr[pMinus80])
plt.plot(results[pMinus80]*nc, label='RGB shift | st. err: -80 | ' + res)
res = "{:.2f}".format(sterr[pMinus120])
plt.plot(results[pMinus120]*nc, label='RGB shift | st. err: -120 | ' + res)

plt.ylabel('Steering angle')
plt.xlabel('Frame number')    
# Set a title of the current axes.
modelstr = modelname + ' (' + modelpath + ')'

#pMinus120 = 0
#pMinus80 = 1
#pMinus40 = 2
#pMinus0 = 3
#pPlus40 = 4
#pPlus80 = 5
#pPlus120 = 6
#datashifts = [-120,-80,-40,0,40,80,120]
#results

mytitle = 'Ground truth and steering predictions for shifted data, from model ' + modelstr + ', ' + 'for logs_Wed_Nov_25_23_39_22_2020'
plt.title(mytitle)
plt.grid(axis='y')
# set limit
plt.xlim([-5,len(g)+5])
plt.gca().invert_yaxis()
plt.legend(loc='lower right')
plt.show()<jupyter_output><empty_output><jupyter_text>Positive 40, 80, 120<jupyter_code>plt.rcParams["figure.figsize"] = (18,3)

plt.plot(g*nc, label='Ground truth')
#plt.plot(results[pMinus0]*nc, label='RGB shift: 0')
res = "{:.2f}".format(sterr[pPlus40])
plt.plot(results[pPlus40]*nc, label='RGB shift | st. err: 40 | ' + res)
res = "{:.2f}".format(sterr[pPlus80])
plt.plot(results[pPlus80]*nc, label='RGB shift | st. err: 80 | ' + res)
res = "{:.2f}".format(sterr[pPlus120])
plt.plot(results[pPlus120]*nc, label='RGB shift | st. err: 120 | ' + res)

plt.ylabel('Steering angle')
plt.xlabel('Frame number')    
# Set a title of the current axes.
modelstr = modelname + ' (' + modelpath + ')'

#pMinus120 = 0
#pMinus80 = 1
#pMinus40 = 2
#pMinus0 = 3
#pPlus40 = 4
#pPlus80 = 5
#pPlus120 = 6
#datashifts = [-120,-80,-40,0,40,80,120]
#results

mytitle = 'Ground truth and steering predictions for shifted data, from model ' + modelstr + ', ' + 'for logs_Wed_Nov_25_23_39_22_2020'
plt.title(mytitle)
plt.grid(axis='y')
# set limit
plt.xlim([-5,len(g)+5])
plt.gca().invert_yaxis()
plt.legend(loc='lower right')
plt.show()<jupyter_output><empty_output><jupyter_text>Data shift steering error average<jupyter_code>sterr = []
for i in range (0, len(results)):
  steer_err = gos(results[i],g,nc)
  sterr.append(steer_err)
  strline = "Steering error average for data shift = {}: {}".format(str(datashifts[i]), str(steer_err))
  print(strline)
def listSteeringBins(svals, pname="output", save=True, nc=25, rmout=0):
    """
    Plot a steering values' histogram
    Inputs
        svals: list, array of normalized steering values
        pname: string, output plot name
        save: boolean, save plot to disk
        nc: int, normalization constant, used in the simulator to put angles in range
        -1, 1. Default is 25.
        rmout: integer, outlier range to remove
    Outputs
        none
    """
    svalscp = [element * nc for element in svals]
    values = len(svals)
    
    # remove outliers
    if(rmout>0):
        #my_iterator = filter(lambda svalscp: svalscp <= rmout and svalscp >= (-1 * rmout), svalscp)
        #svalsrmout = list(my_iterator)
        #svalscp = svalsrmout
        #values = len(svalsrmout)
        #print("Removed {} records".format(len(svals) - len(svalsrmout)))
        #svals = svalsrmout
        svals = removeOutliers(svalscp, rmout, nc)
        values = len(svals)
    mean = ("%.2f" % statistics.mean(svalscp))
    std = ("%.2f" % statistics.stdev(svalscp))
    plt.title=(pname)
    # NB Plotted as normalized histogram
    sns.distplot(svalscp, bins=nc*2, kde=False, norm_hist=True, 
    axlabel= pname + ' steer. degs. norm. hist. ' + str(values) + ' values, mean = ' + mean + ' std = ' + std)
    #if(save):
    #    sns.save("output.png")
    if(save):
        plt.savefig(pname + '.png')
    plt.show()

listSteeringBins(preds)
listSteeringBins(preds)<jupyter_output>/usr/local/lib/python3.7/dist-packages/seaborn/distributions.py:2619: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).
  warnings.warn(msg, FutureWarning)<jupyter_text>Positive steering angle example, labelled dataset<jupyter_code># 1105_cam-image_array_.jpg
#!ls logs_Wed_Nov_25_23_39_22_2020/1105_cam-image_array_.jpg
# !ls logs_Wed_Nov_25_23_39_22_2020/*1105*
!cat logs_Wed_Nov_25_23_39_22_2020/record_1105.json
# {"cam/image_array":"1105_cam-image_array_.jpg","user/throttle":0.0,"user/angle":0.31525176763534548,"user/mode":"user","track/lap":0,"track/loc":21}
# 0.31525176763534548 * 25 = 7.88129419088 ~ 7.9 degrees
from utils.utils import plot_img_hist # need utils.py
from PIL import Image
import matplotlib.image as mpimg
import cv2
from google.colab.patches import cv2_imshow
imgpath = 'logs_Wed_Nov_25_23_39_22_2020/1105_cam-image_array_.jpg'
image = Image.open(imgpath)
plt.imshow(image)
myfig = plot_img_hist(image)
myplot = mpimg.imread('temp_plot.jpg')
# correct channels
b,g,r = cv2.split(myplot)
myplot = cv2.merge([r,g,b])
cv2_imshow(myplot)<jupyter_output><empty_output><jupyter_text>Shift and plot<jupyter_code># image = Image.open(imgpath)
datashift = 120
imageshifted, rgbmean, rgbstd, rgbvar = shiftRGBValues(image, datashift, datashift, datashift)
plt.imshow(imageshifted)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12909863268286206, 'fraction_numerical': 0.0483207221558476, 'mean_word_length': 3.755997474747475, 'pattern_counts': {'":': 6, '<': 38, '<?xml version=': 0, '>': 39, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '484278', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 5866, 'n_tokens_neox': 5247, 'n_words': 1316, 'path': 'src/notebooks/RGBShiftPredict_PreProcessingAndDistributionPlots.ipynb', 'repo_name': 'dsikar/sdsandbox', 'size': '15066'}