{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Number Detection using OpenCV and Decision Trees \n*MNIST dataset*\nYou can access the dataset here: [Kaggle MNIST dataset](https://www.kaggle.com/competitions/digit-recognizer/data)","metadata":{"id":"8VSMSdsxavx2"}},{"cell_type":"markdown","source":"> This notebook uses the MNIST number classification dataset to recognizer numbers with the help of OpenCV and Random Forest Classifier. \n","metadata":{}},{"cell_type":"code","source":"from sklearn.datasets import load_digits\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn import metrics\n%matplotlib inline","metadata":{"id":"WV1DJZSgatge","execution":{"iopub.status.busy":"2022-09-28T18:59:11.594179Z","iopub.execute_input":"2022-09-28T18:59:11.594689Z","iopub.status.idle":"2022-09-28T18:59:12.833747Z","shell.execute_reply.started":"2022-09-28T18:59:11.594585Z","shell.execute_reply":"2022-09-28T18:59:12.832480Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Reading the data","metadata":{"id":"78ukqewsqxpj"}},{"cell_type":"code","source":"train = pd.read_csv(\"../input/digit-recognizer/train.csv\")\ntrain.shape","metadata":{"id":"SuvozQCw8TLY","outputId":"9e2a32cd-a12c-4566-81b1-598a71f3f4a5","execution":{"iopub.status.busy":"2022-09-28T18:59:12.836017Z","iopub.execute_input":"2022-09-28T18:59:12.836566Z","iopub.status.idle":"2022-09-28T18:59:16.973944Z","shell.execute_reply.started":"2022-09-28T18:59:12.836519Z","shell.execute_reply":"2022-09-28T18:59:16.972645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Explaination of the MNIST dataset\n> - MNIST is a famous dataset that consists of handwritten numbers for classification. \n-It consists of 785 columns in total where 1 of it is the `label` (the number that represents the specific row) and the rest 784 columns are `pixels` of the image. \n<br></br>\n- **Why 784 pixels of the image?** \n- The images that we are using for classification of numbers are of 28x28 pixels. Something like this: \n<br></br>\n<img src=\"http://i.imgur.com/rwMpFVu.png\" height=\"200\"></img>\n\n> - To represent this 28x28 matrix in a dataset will be incovenient. Hence we turn this into a `single row` of 784 (28*28) containing all the digits shown in the image above. Like this- \n<br></br>\n<img src=\"https://static.wixstatic.com/media/34bab5_2bf56349ff884c49bfe06edfb33eb1e9~mv2.png/v1/fill/w_910,h_267,al_c/34bab5_2bf56349ff884c49bfe06edfb33eb1e9~mv2.png\" height=\"200\"  width=\"500\"></img>\n\n\n> -Hence we turn the 2D matrix to a 1D matrix. This is called `Row Flattening`\n- This 1D matrix is then added as a single row in our MNIST dataset widht 784 columns. \n- The **785th** column depicts the number that is represented by those 784 pixels.\n","metadata":{"id":"7aO1hBHqq1PB"}},{"cell_type":"markdown","source":"### Entire model: \n<br></br>\n<img src=\"http://gpucomputing.shef.ac.uk/static/img/intro_dl_sharc_dgx1/mnist_simple.png\" height=\"200\" ></img>","metadata":{"id":"w63oo-ZAuZTI"}},{"cell_type":"code","source":"y=train['label']\nX=train.drop('label',axis=1)\ntrain.head()","metadata":{"id":"MNE2evf-9gaL","outputId":"2f03fbef-bd75-46ce-8372-008215466b98","execution":{"iopub.status.busy":"2022-09-28T18:59:16.975151Z","iopub.execute_input":"2022-09-28T18:59:16.975500Z","iopub.status.idle":"2022-09-28T18:59:17.118607Z","shell.execute_reply.started":"2022-09-28T18:59:16.975456Z","shell.execute_reply":"2022-09-28T18:59:17.117430Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- In the MNIST dataset shown above, column `label` is the number that we have to predict while the rest of the columns are the pixels of that number. ","metadata":{"id":"rJrAqP0YuvDC"}},{"cell_type":"markdown","source":"### Training the model","metadata":{"id":"O3df5OvnvF63"}},{"cell_type":"markdown","source":"> We will be splitting our training data, 80% for training our model and 20% for testing it's accuracy","metadata":{"id":"SWe3A8aNvKQr"}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nX_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2)","metadata":{"id":"IChtnP8ArwS3","execution":{"iopub.status.busy":"2022-09-28T18:59:17.121368Z","iopub.execute_input":"2022-09-28T18:59:17.122172Z","iopub.status.idle":"2022-09-28T18:59:17.443407Z","shell.execute_reply.started":"2022-09-28T18:59:17.122130Z","shell.execute_reply":"2022-09-28T18:59:17.441915Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> The model input X requires a `Float` value while the output Y needs to be in the integer form (since integer values are predicted).","metadata":{"id":"aICktzOCvb8Z"}},{"cell_type":"code","source":"X_train = np.asarray(X_train).astype(np.float32)\ny_train= np.asarray(y_train).astype(np.int64)\nX_test = np.asarray(X_test).astype(np.float32)","metadata":{"id":"Mjzz3qquM1lJ","execution":{"iopub.status.busy":"2022-09-28T18:59:17.445000Z","iopub.execute_input":"2022-09-28T18:59:17.445720Z","iopub.status.idle":"2022-09-28T18:59:17.520225Z","shell.execute_reply.started":"2022-09-28T18:59:17.445675Z","shell.execute_reply":"2022-09-28T18:59:17.518775Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> `Rtrees` is a class of OpenCV that helps us to implement Random Forest algorithm","metadata":{"id":"xshnxnDZwWNj"}},{"cell_type":"code","source":"import cv2\nrtree = cv2.ml.RTrees_create()","metadata":{"id":"fDQAG4U_NHq-","execution":{"iopub.status.busy":"2022-09-28T18:59:17.521830Z","iopub.execute_input":"2022-09-28T18:59:17.522300Z","iopub.status.idle":"2022-09-28T18:59:17.752142Z","shell.execute_reply.started":"2022-09-28T18:59:17.522255Z","shell.execute_reply":"2022-09-28T18:59:17.751019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Hyperparameter tuning for our model","metadata":{"id":"nyJ_QGf510GN"}},{"cell_type":"code","source":"num_trees = 100 ## No. of trees for training our model\neps = 0.01 ## Stops the algorithm if this accuracy is reached (error rate=0.01)\ncriteria = (cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS,\n            num_trees, eps)\nrtree.setTermCriteria(criteria) ## defines these criterias for the model rtree","metadata":{"id":"X1PCuWWbNL6-","execution":{"iopub.status.busy":"2022-09-28T18:59:17.753427Z","iopub.execute_input":"2022-09-28T18:59:17.754555Z","iopub.status.idle":"2022-09-28T18:59:17.761510Z","shell.execute_reply.started":"2022-09-28T18:59:17.754515Z","shell.execute_reply":"2022-09-28T18:59:17.760157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Sample tree for reference \n<br></br>\n<img src=\"https://forum.huawei.com/enterprise/en/data/attachment/forum/202103/24/190400o09x7rhnnhy2yon7.png?1.png\" height=\"300\"><img>","metadata":{"id":"9a6V2vG83XGK"}},{"cell_type":"code","source":"rtree.setMaxCategories(len(np.unique(y_train))) ## max categories in our case: 10 (since numbers from 0 to 9 can be predicted)","metadata":{"id":"FuQQ7iTRnJeo","execution":{"iopub.status.busy":"2022-09-28T18:59:17.763162Z","iopub.execute_input":"2022-09-28T18:59:17.764055Z","iopub.status.idle":"2022-09-28T18:59:17.775671Z","shell.execute_reply.started":"2022-09-28T18:59:17.764017Z","shell.execute_reply":"2022-09-28T18:59:17.774484Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rtree.setMinSampleCount(2) ## If the number of samples in a node is less than this parameter then the node will not be split.\n## As shown in the image above, minimum number of samples required to split a node is 2. ","metadata":{"id":"D7yQsGoFNQ0B","execution":{"iopub.status.busy":"2022-09-28T18:59:17.777088Z","iopub.execute_input":"2022-09-28T18:59:17.777547Z","iopub.status.idle":"2022-09-28T18:59:17.785319Z","shell.execute_reply.started":"2022-09-28T18:59:17.777505Z","shell.execute_reply":"2022-09-28T18:59:17.784023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rtree.setMaxDepth(1000) ## Setting a maximum depth above which the tree won't be split. (Levels of the decision tree)","metadata":{"id":"ZtwA3Ct1NSj3","execution":{"iopub.status.busy":"2022-09-28T18:59:17.789600Z","iopub.execute_input":"2022-09-28T18:59:17.789996Z","iopub.status.idle":"2022-09-28T18:59:17.794846Z","shell.execute_reply.started":"2022-09-28T18:59:17.789960Z","shell.execute_reply":"2022-09-28T18:59:17.793720Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> After our hyperparameter tuning, we will be training our model.","metadata":{"id":"g0uPE3kZ4eCK"}},{"cell_type":"code","source":"rtree.train(X_train, cv2.ml.ROW_SAMPLE, y_train)","metadata":{"id":"V0TAmYjnNWZD","outputId":"09dc0310-5934-4135-f3e4-73f17d5208ee","execution":{"iopub.status.busy":"2022-09-28T18:59:17.796744Z","iopub.execute_input":"2022-09-28T18:59:17.797090Z","iopub.status.idle":"2022-09-28T19:00:30.300030Z","shell.execute_reply.started":"2022-09-28T18:59:17.797058Z","shell.execute_reply":"2022-09-28T19:00:30.298815Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rtree.getMaxDepth() ## Max depth of our tree after training our model is 25","metadata":{"id":"ZKQbM_cOUQTZ","outputId":"cdd97346-7198-41ac-bc86-f7e9b326256b","execution":{"iopub.status.busy":"2022-09-28T19:00:30.301379Z","iopub.execute_input":"2022-09-28T19:00:30.301776Z","iopub.status.idle":"2022-09-28T19:00:30.308815Z","shell.execute_reply.started":"2022-09-28T19:00:30.301742Z","shell.execute_reply":"2022-09-28T19:00:30.307783Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a , y_hat = rtree.predict(X_test) ## Predicting the 20% of the data that we took for testing","metadata":{"id":"n8xTbajvV1VD","execution":{"iopub.status.busy":"2022-09-28T19:00:30.310947Z","iopub.execute_input":"2022-09-28T19:00:30.311278Z","iopub.status.idle":"2022-09-28T19:00:30.902989Z","shell.execute_reply.started":"2022-09-28T19:00:30.311248Z","shell.execute_reply":"2022-09-28T19:00:30.901680Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(a)","metadata":{"id":"auOwmubpA0yE","outputId":"ee0a7987-ef8d-44e8-f1f4-b61ac1666ad8","execution":{"iopub.status.busy":"2022-09-28T19:00:30.904270Z","iopub.execute_input":"2022-09-28T19:00:30.904657Z","iopub.status.idle":"2022-09-28T19:00:30.912018Z","shell.execute_reply.started":"2022-09-28T19:00:30.904623Z","shell.execute_reply":"2022-09-28T19:00:30.910649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import accuracy_score\naccuracy_score(y_test, y_hat) ","metadata":{"id":"_DazLmLRV3k-","outputId":"02a71b56-9376-443e-a8e8-168eb8511563","execution":{"iopub.status.busy":"2022-09-28T19:00:30.913844Z","iopub.execute_input":"2022-09-28T19:00:30.914304Z","iopub.status.idle":"2022-09-28T19:00:30.925351Z","shell.execute_reply.started":"2022-09-28T19:00:30.914260Z","shell.execute_reply":"2022-09-28T19:00:30.924040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Hence we got an accuracy of 96%, we can improve this by tuning the number of trees, depth, sample count etc. ","metadata":{"id":"8wvUk8rZ4wcu"}},{"cell_type":"markdown","source":"## Testing with actual images","metadata":{"id":"-NsSt1Mq5AQZ"}},{"cell_type":"markdown","source":"> - Now we will be using an actual image for testing our model, to see how well it predicts. \n> - Since our dataset is for 28x28 pixel images, we resize our image to 28x28","metadata":{"id":"hTSuireV5GAn"}},{"cell_type":"code","source":"file = r'../input/mnistasjpg/testSample/testSample/img_142.jpg'\ntest_image = cv2.imread(file, cv2.IMREAD_GRAYSCALE)\n\n# Format Image\nimg_resized = cv2.resize(test_image, (28,28), interpolation=cv2.INTER_LINEAR)\nplt.imshow(img_resized, cmap='gray') ## Displaying the image that we have to predict ","metadata":{"id":"s4t47pXy-tLS","outputId":"65e010e1-d81b-4c01-8a9e-6fe08f43dabf","execution":{"iopub.status.busy":"2022-09-28T19:01:29.254464Z","iopub.execute_input":"2022-09-28T19:01:29.254897Z","iopub.status.idle":"2022-09-28T19:01:29.421275Z","shell.execute_reply.started":"2022-09-28T19:01:29.254862Z","shell.execute_reply":"2022-09-28T19:01:29.420367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> - Now we flatten our image of 28x28 to convert it to a single vector of size 784 so that it fits our model. \n- Our model only accepts a single row of 784 features.","metadata":{"id":"LtA-M2y57DRU"}},{"cell_type":"code","source":"img_resized=img_resized.astype('float32')\nimg_resized -= img_resized.mean(axis=0)\nimg_resized = img_resized.flatten().reshape(1,784)","metadata":{"id":"idyQF2kX_voR","execution":{"iopub.status.busy":"2022-09-28T19:01:31.426456Z","iopub.execute_input":"2022-09-28T19:01:31.427427Z","iopub.status.idle":"2022-09-28T19:01:31.432413Z","shell.execute_reply.started":"2022-09-28T19:01:31.427388Z","shell.execute_reply":"2022-09-28T19:01:31.431568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> - Predicting our image ","metadata":{"id":"4FMHMGMl7sOe"}},{"cell_type":"code","source":"_, pred = rtree.predict(img_resized)","metadata":{"id":"ykaJKVzrHKYD","execution":{"iopub.status.busy":"2022-09-28T19:01:32.971628Z","iopub.execute_input":"2022-09-28T19:01:32.972318Z","iopub.status.idle":"2022-09-28T19:01:32.978645Z","shell.execute_reply.started":"2022-09-28T19:01:32.972269Z","shell.execute_reply":"2022-09-28T19:01:32.977386Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred","metadata":{"id":"ukKgdpw7HeUR","outputId":"2fa3ad42-27dd-4a86-e9b2-a8a62e63e351","execution":{"iopub.status.busy":"2022-09-28T19:01:34.942927Z","iopub.execute_input":"2022-09-28T19:01:34.943326Z","iopub.status.idle":"2022-09-28T19:01:34.950448Z","shell.execute_reply.started":"2022-09-28T19:01:34.943293Z","shell.execute_reply":"2022-09-28T19:01:34.949552Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"id":"zQUBi2F3zt-b"},"execution_count":null,"outputs":[]}]}