Traffic Sign Classification with Keras and Deep Learning

Traffic Sign Classification with Keras and Deep Learning


Traffic sign recognition consists of object detection:
  • detection/localization
  • Detect and localize where in an input image/frame a traffic sign is.
  • classification
  • Take the localized ROI and actually recognize and classify the traffic sign.

The dataset we’ll be using to train our own custom traffic sign classifier is the German Traffic Sign Recognition Benchmark (GTSRB).

Notice how the traffic signs have been pre-cropped for us, implying that the dataset annotators/creators have manually labeled the signs in the images and extracted the traffic sign Region of Interest (ROI) for us.

Recognizing Traffic Signs with CNNs


Data Summary and Exploration


Data Size and Shape

  • Size of training set: 34,799 (67%)
  • Size of the validation set: 4,410 (9%)
  • Size of test set: 12,630 (24%)
  • Shape of a traffic sign image: (32, 32, 3)
  • Number of unique classes/labels: 43

Data Visualization


Determine what types of preprocessing operations should be applied to the data (if any).
  • Inspect a sample of images
  • Check: color channels
  • Check the labels
  • Is the label method correct for classification?
  • How balanced is the dataset?
  • Are there certain classes that dominate? Are there others that are under-represented?

Data Preprocessing


Contrast enhancement


Use Scikit histogram equalization function,
from tqdm import tqdm
from skimage import color, data, exposure


def normalize(image_data):
    '''Contrast Limited Adaptive Histogram Equalization (CLAHE). In addition to regular normalization, 
    this function provides local contrast enhancement -- i.e., details of the image can be 
    enhanced even in regions that are darker or lighter than most of the image.
    http://scikit-image.org/docs/dev/api/skimage.exposure.html#skimage.exposure.equalize_adapthist
    '''
    
    norm = np.array([exposure.equalize_adapthist(image, clip_limit=0.1) for image in tqdm(image_data)])
    return norm

Augmentation


  • Increase the total number of images
  • Create an equal distribution of images
  • Apply affine transformations.
  • Apply ZCA whitening to accentuate edges

Model Architecture





Steps

cd ~/anaconda3
jupyter notebook

Step 0: Load The Data


The GTSRB dataset is pre-split into training/testing splits for us.
Let’s go ahead and define a function to load our data from disk:
from skimage import exposure

def load_split(basePath, csvPath):
    # initialize the list of data and labels
    data = []
    labels = []
 
    # load the contents of the CSV file, remove the first line (since
    # it contains the CSV header), and shuffle the rows (otherwise
    # all examples of a particular class will be in sequential order)
    rows = open(csvPath).read().strip().split("\n")[1:]
    random.shuffle(rows)
    # loop over the rows of the CSV file
        for (i, row) in enumerate(rows):
            # check to see if we should show a status update
            if i > 0 and i % 1000 == 0:
                print("[INFO] processed {} total images".format(i))
 
            # split the row into components and then grab the class ID
            # and image path
            (label, imagePath) = row.strip().split(",")[-2:]
 
            # derive the full path to the image file and load it
            imagePath = os.path.sep.join([basePath, imagePath])
            image = io.imread(imagePath)
            # resize the image to be 32x32 pixels, ignoring aspect ratio,
            # and then perform Contrast Limited Adaptive Histogram
            # Equalization (CLAHE)
            image = transform.resize(image, (32, 32))
            image = exposure.equalize_adapthist(image, clip_limit=0.1)
 
            # update the list of data and labels, respectively
            data.append(image)
            labels.append(int(label))
 
            # convert the data and labels to NumPy arrays
            data = np.array(data)
            labels = np.array(labels)
 
    # return a tuple of the data and labels
    return (data, labels)
load_split() loads each training split respectively. It accepts a path to the base of the dataset as well as a .csv file path which contains the class label for each image.
You can dump the first 3 rows
print(rows[:3])
The format of the data is:
Width, Height, X1, Y1, X2, Y2, ClassID, Image Path
The image contrast can be improved by applying an algorithm called Contrast Limited Adaptive Histogram Equalization (CLAHE), the implementation of which can be found in the scikit-image library.

Original images input images can be seen on the left — notice how contrast is very low and some signs cannot be recognize. By applying CLAHE we can improve image contrast.
skimage.exposure.equalize_adapthist(image, kernel_size=None, clip_limit=0.01, nbins=256):
  • image(M, N[, C])
  • ndarray. Input image.
  • kernel_size
  • integer or list-like, optional. Defines the shape of contextual regions used in the algorithm. If iterable is passed, it must have the same number of elements as image.ndim (without color channel). If integer, it is broadcasted to each image dimension. By default, kernel_size is 1/8 of image height by 1/8 of its width.
  • clip_limit
  • float, optional. Clipping limit, normalized between 0 and 1 (higher values give more contrast).
  • nbinsint
  • optional. Number of gray bins for histogram (“data range”).

Now let’s go ahead and load + preprocess our data:
datasetPath = "/home/jerry/datasets/gtsrb"

# derive the path to the training and testing CSV files
trainPath = os.path.sep.join([datasetPath, "Train.csv"])
testPath = os.path.sep.join([datasetPath, "Test.csv"])
 
# load the training and testing data
print("[INFO] loading training and testing data...")
(trainX, trainY) = load_split(datasetPath, trainPath)
(testX, testY) = load_split(datasetPath, testPath)
 
# scale data to the range of [0, 1]
trainX = trainX.astype("float32") / 255.0
testX = testX.astype("float32") / 255.0
 
# one-hot encode the training and testing labels
numLabels = len(np.unique(trainY))
trainY = to_categorical(trainY, numLabels)
testY = to_categorical(testY, numLabels)
 
# account for skew in the labeled data
classTotals = trainY.sum(axis=0)
classWeight = classTotals.max() / classTotals

留言

熱門文章