diff --git a/classification/Figure_1.png b/classification/Figure_1.png new file mode 100644 index 0000000..333dc53 Binary files /dev/null and b/classification/Figure_1.png differ diff --git a/classification/README.md b/classification/README.md new file mode 100644 index 0000000..1e4457b --- /dev/null +++ b/classification/README.md @@ -0,0 +1,44 @@ +# Census Image Classfication + +### Methodology + +* Preprocess image : crop edges to alter frame to form +* Resize image to (430, 250) +* Training on a Convolutional Neural Netowrk model with a learning rate of 1e-6 owing to low dataset +* Obtained accuracy = 95.6% + +### Image preprocessing + +Raw dataset image before preprocessing: + +![dataset image](https://github.com/salonirk11/census_image_classfication/blob/master/img_raw.jpg) + + +The raw image was thresholded to ```binary``` colours. Thereafter, using a combination of ```findContours``` and ```boundingRect``` methods of ```OpenCV```, the form was brought into focus remvoing all the extra portions of the image. +Following this, image was resized to (430, 250) to retain sufficient features and to maintain the proportion of the form. + +The image obtained afer preprocessing on the above image : + +![processed image](https://github.com/salonirk11/census_image_classfication/blob/master/img_proc.jpg) + + +### Training + +The processed dataset was trained on a convolutional neural model. ```BatchNormalisation```, ```MaxPooling``` were used in this model with ```relu``` as activation. + + +To run the model use the following command: +``` +python train.py +``` + +For example: +``` +python train.py images/freecen data/gold/combined_classifications_20180227.csv +``` + +### Optimization + +Following is the learning curve for a learing rate of 1e-6 + +![learning_rate](https://github.com/salonirk11/census_image_classfication/blob/master/Figure_1.png) diff --git a/classification/__pycache__/pre_process.cpython-35.pyc b/classification/__pycache__/pre_process.cpython-35.pyc new file mode 100644 index 0000000..30b295d Binary files /dev/null and b/classification/__pycache__/pre_process.cpython-35.pyc differ diff --git a/classification/img.jpg b/classification/img.jpg new file mode 100644 index 0000000..11e669a Binary files /dev/null and b/classification/img.jpg differ diff --git a/classification/img_proc.jpg b/classification/img_proc.jpg new file mode 100644 index 0000000..fd30d44 Binary files /dev/null and b/classification/img_proc.jpg differ diff --git a/classification/img_raw.jpg b/classification/img_raw.jpg new file mode 100644 index 0000000..b43b810 Binary files /dev/null and b/classification/img_raw.jpg differ diff --git a/classification/pre_process.py b/classification/pre_process.py new file mode 100644 index 0000000..4c535da --- /dev/null +++ b/classification/pre_process.py @@ -0,0 +1,41 @@ +import cv2 +from matplotlib import pyplot as plt +import csv +import os +import numpy as np +from tqdm import tqdm + +def proc(img): + img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) + ret,img = cv2.threshold(img,200,255,cv2.THRESH_BINARY) + (_,cnts, _) = cv2.findContours(img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + x_, y_, w_, h_ = 0, 0, 0, 0 + for c in cnts: + x,y,w,h = cv2.boundingRect(c) + if w>500 and h>500 and w*h > w_*h_: + w_=w + h_=h + x_=x + y_=y + new_img = img[y_:y_+h_,x_:x_+w_] + new_img = cv2.cvtColor(new_img, cv2.COLOR_GRAY2BGR) + img = cv2.resize(new_img,(430,250)) + img=np.array(img) + return img + + +def read_im(path): + img = cv2.imread(path) + img = proc(img) + return img + +def train_data(im_dir, src_file): + img_list= [] + labels_list= [] + with open(src_file, 'r') as f: + reader = csv.reader(f) + for line in tqdm(reader): + img_list.append(read_im(os.path.join(im_dir,line[0]))) + labels_list.append(line[1]) + img_list=np.array(img_list) + return img_list, labels_list diff --git a/classification/train.py b/classification/train.py new file mode 100644 index 0000000..4fb7dfc --- /dev/null +++ b/classification/train.py @@ -0,0 +1,82 @@ +import pre_process +import cv2 +import sys +import numpy as np +from matplotlib import pyplot as plt + +import keras +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense, Dropout, Flatten, Activation +from keras.layers import Conv2D, MaxPooling2D, BatchNormalization +from keras.preprocessing.image import ImageDataGenerator +from keras.losses import categorical_crossentropy +from keras.optimizers import Adam + +def plot_rate(history): + plt.subplot(211) + plt.plot(history.history['acc']) + plt.plot(history.history['val_acc']) + plt.title('model accuracy') + plt.ylabel('accuracy') + plt.xlabel('epoch') + plt.legend(['train', 'test'], loc='upper left') + + plt.subplot(212) + plt.plot(history.history['loss']) + plt.plot(history.history['val_loss']) + plt.title('model loss') + plt.ylabel('loss') + plt.xlabel('epoch') + plt.legend(['train', 'test'], loc='upper left') + + plt.show() + + +def getSimpleCNN(input_shape, num_classes): + inputs = Input(shape=input_shape) + x = Conv2D(64, (3, 3), activation='relu')(inputs) + x = BatchNormalization()(x) + x = MaxPooling2D(pool_size=(2, 2)) (x) + x = Conv2D(32, (3, 3), activation='relu')(x) + x = BatchNormalization()(x) + x = MaxPooling2D(pool_size=(2, 2)) (x) + x = Conv2D(16, (3, 3), activation='relu')(x) + x = BatchNormalization()(x) + x = MaxPooling2D(pool_size=(2, 2)) (x) + x = Dropout(0.25)(x) + x = Flatten()(x) + x = Dense(64)(x) + x = BatchNormalization()(x) + x = Activation('relu')(x) + x = Dropout(0.5)(x) + out = Dense(num_classes, activation='softmax')(x) + model = Model(inputs, out) + model.compile(loss=categorical_crossentropy, + optimizer=Adam(lr=1e-4), + metrics=['accuracy']) + return model + + +if __name__=="__main__": + x_train, y_train = pre_process.train_data(sys.argv[1], sys.argv[2]) + labels_set = list(set(y_train)) + labels_dict = {labels_set[i]:i for i in range(len(labels_set))} + + x_train = x_train.reshape(x_train.shape[0], 430, 250, 3) + input_shape = (430,250,3) + num_classes = len(labels_dict.keys()) + + model = getSimpleCNN(input_shape, num_classes) + y_train = np.array([labels_dict[x] for x in y_train]) + y_train = keras.utils.to_categorical(y_train, num_classes) + + batch_size = 4 + epochs = 18 + history = model.fit( + x_train, y_train, + batch_size=batch_size, + epochs=epochs, + validation_split=0.2 + ) + plot_rate(history)