{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Kuzushiji Recognition with the concept of Hand-Written digit recognition"},{"metadata":{},"cell_type":"markdown","source":"This kernel is created with respect to the competition [Kuzushiji Recognition](https://www.kaggle.com/c/kuzushiji-recognition/data)<br> and also it is forked from a previous kernel [Kuzushiji Visualisation](https://www.kaggle.com/anokas/kuzushiji-visualisation)\n\n**Saa.. Hajimeruu...<br>(eng sub: so.. Lets Begin..)**"},{"metadata":{},"cell_type":"markdown","source":"This kernel demostrates my approach to Kuzushiji recognition with the simplest Hand-written Digit recognition technique, which is the most basic thing  that we learn for understanding optical character recognition.<br>My Article on Hand-Written Digit recognition.Link - [Handwritten Digits Recognition](https://medium.com/@basu369victor/handwritten-digits-recognition-d3d383431845). I have written this article with respect to my very first experience in optical character recognition. \n## **What is Kuzushiji ?**\nKuzushiji is a Japanese cursive script. Many of pre-modern documents are, whether they were handwritten or print, written in kuzushiji. It is extremely important to get familiar with kuzushiji in order to read pre-modern Japanese texts. Understanding 変体仮名 (hentaigana), the variant (and obsolute) form of modern hiragana, is another essential skill to read pre-modern Japanese texts. Hiragana is one of the components of the Japanese phonetic lettering system, and with a few exceptions, each sound in the Japanese language is represented by one hiragana character. However, until the Japanese script reform of 1900, each syllable had been written using a variety of hiragana, originated in manʼyōgana, an ancient writing system that employs Chinese kanji characters to represent the Japanese language. The variant form is now called 変体仮名( hentaigana).\n\nSource - [Crane(Competition Discussion)](https://www.kaggle.com/c/kuzushiji-recognition/discussion/100951)\n![Kuzushiji](https://miro.medium.com/max/1400/1*Y-JaqNDSQMvklXn39KOrkg.jpeg)"},{"metadata":{},"cell_type":"markdown","source":"Vast portions of Japanese historical documents now cannot be read by most Japanese people. By helping to automate the transcription of kuzushiji we would contribute to unlocking a priceless trove of books and records.\n\nThe specific task is to locate and classify each kuzushiji character on a page. While complete bounding boxes are provided for the training set, only a single point within the ground truth bounding box is needed for submissions."},{"metadata":{},"cell_type":"markdown","source":"## The most difficult part of this Problem.....\n![konosuba](https://i.ytimg.com/vi/rTztN4OYSOk/maxresdefault.jpg)\n<br>According to me the most difficult part of this problem was not recognition of Kuzushiji, rather it was the detection of Kazushiji. <br>Training a machine learning or deep learning model to recognize Kuzushiji would never be big deal. At the end of the road, for recognition of Kuzushiji, the only thing that matters is accuracy. And there are so many machine learning algorithms and deep neural networks, we could approach this recognition problem with any of them to reach the desired accuracy.<br>But what about the detection of Kuzushiji. To detect Kuzushiji simply from a sheet of paper, it requires a big brain. It is not about the detection of a single character, there are multiple characters on a single sheet of paper and you have to detect all of them. Choosing an algorithm or technique to detect characters on a sheet of paper requires time, patient and understanding."},{"metadata":{},"cell_type":"markdown","source":"## Why did I choose the most basic approch for Kuzushiji Detection?\n<br>\nIt might sound awkward, but I am going, to tell the truth.<br><br>\nFirst of all, in both the problem hand-written digit recognition and Kuzushiji recognition, the recognition word was common. After that in both the problem, you need to detect something which is written with very bad handwriting. I both the case I struggled most of the time for detection of characters from a sheet of paper, I mean when I learned handwritten digit recognition for the first time, the detection part costs me a lot of time. No matter how many times I tried it always resulted in either not detecting anything or detection of wrong objects instead of digits. It might sound like I did not have any valid logic to approach this problem but that's the truth.\n![](https://i.kym-cdn.com/photos/images/original/000/898/121/784.jpg)\n<br>\nHere I have applied the same detection technique which I used to solve simple problems like handwritten digit recognition and I hope you would also be familiar with this technique.\n![](https://i.ytimg.com/vi/ur6JY2Hl-MM/hqdefault.jpg)"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"from PIL import Image, ImageDraw, ImageFont\nfrom os import listdir\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport cv2\nfrom skimage.feature import hog\nimport os\nfrom tqdm import tqdm\nfrom sklearn.preprocessing import LabelEncoder\nfrom keras.utils import np_utils\nfrom keras import backend as K\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import classification_report\nfrom tensorflow.python import keras\nfrom keras.layers import Dense, Flatten, Conv2D, Dropout, MaxPooling2D, BatchNormalization,Input\nfrom keras.models import Model,load_model\nfrom IPython.display import SVG\nfrom keras.callbacks import EarlyStopping,ModelCheckpoint\nfrom keras.utils.vis_utils import model_to_dot\nfrom keras.utils import plot_model\n#%matplotlib inline\nprint(os.listdir(\"../input/\"))\nInputPath = \"../input/artificial-lunar-rocky-landscape-dataset/images/\"\n# Any results you write to the current direct","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"First, in order to visualise the dataset, we need a font that can display the full range of Japanese characters. We're using [Noto Sans](https://en.wikipedia.org/wiki/Noto_fonts), an open source font by Google which can display very almost all the characters used within this competition."},{"metadata":{"trusted":true},"cell_type":"code","source":"fontsize = 50\n\n# From https://www.google.com/get/noto/\n!wget -q --show-progress https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip\n!unzip -p NotoSansCJKjp-hinted.zip NotoSansCJKjp-Regular.otf > NotoSansCJKjp-Regular.otf\n!rm NotoSansCJKjp-hinted.zip\n\nfont = ImageFont.truetype('./NotoSansCJKjp-Regular.otf', fontsize, encoding='utf-8')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Visualising the training data\nYou'll notice that some of the characters \"off to the side\" of columns in the text aren't annotated in the training set. These characters are annotations and not part of the main text of the books, so they shouldn't be transcribed by your model."},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"df_train = pd.read_csv('../input/train.csv')\nunicode_map = {codepoint: char for codepoint, char in pd.read_csv('../input/unicode_translation.csv').values}\nunicode_map","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# This function takes in a filename of an image, and the labels in the string format given in train.csv, and returns an image containing the bounding boxes and characters annotated\ndef visualize_training_data(image_fn, labels):\n    # Convert annotation string to array\n    labels = np.array(labels.split(' ')).reshape(-1, 5)\n    #print(labels)\n    \n    # Read image\n    imsource = Image.open(image_fn).convert('RGBA')\n    bbox_canvas = Image.new('RGBA', imsource.size)\n    char_canvas = Image.new('RGBA', imsource.size)\n    bbox_draw = ImageDraw.Draw(bbox_canvas) # Separate canvases for boxes and chars so a box doesn't cut off a character\n    char_draw = ImageDraw.Draw(char_canvas)\n\n    for codepoint, x, y, w, h in labels:\n        x, y, w, h = int(x), int(y), int(w), int(h)\n        char = unicode_map[codepoint] # Convert codepoint to actual unicode character\n\n        # Draw bounding box around character, and unicode character next to it\n        bbox_draw.rectangle((x, y, x+w, y+h), fill=(255, 255, 255, 0), outline=(255, 0, 0, 255))\n        char_draw.text((x + w + fontsize/4, y + h/2 - fontsize), char, fill=(0, 0, 255, 255), font=font)\n        Croped_image = imsource.crop((x, y, x+w, y+h))\n        plt.figure()\n        print(str(unicode_map[codepoint]))\n        plt.imshow(Croped_image)\n        plt.show()\n\n    imsource = Image.alpha_composite(Image.alpha_composite(imsource, bbox_canvas), char_canvas)\n    imsource = imsource.convert(\"RGB\") # Remove alpha for saving in jpg format.\n    return np.asarray(imsource)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"np.random.seed(1337)\n\nfor i in range(1):\n    img, labels = df_train.values[np.random.randint(len(df_train))]\n    viz = visualize_training_data('../input/train_images/{}.jpg'.format(img), labels)\n    \n    plt.figure(figsize=(15, 15))\n    plt.title(img)\n    plt.imshow(viz, interpolation='lanczos')\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def preProcessImage(image):\n    #image = np.asarray(image)\n    #image = image.resize((300,300))\n    #image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n    ret,th1 = cv2.threshold(image,155,255,cv2.THRESH_BINARY)\n    return th1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Extract Data** - It is a function that crops out the kuzushiji from the image, resize it to a fixed size, covert it to grayscale and then does a Binary Threshold. <br>\n**Simple Thresholding** -  If pixel value is greater than a threshold value, it is assigned one value (may be white), else it is assigned another value (may be black). The function used is cv2.threshold. First argument is the source image, which should be a grayscale image. Second argument is the threshold value which is used to classify the pixel values. Third argument is the maxVal which represents the value to be given if pixel value is more than (sometimes less than) the threshold value. OpenCV provides different styles of thresholding and it is decided by the fourth parameter of the function"},{"metadata":{"trusted":true},"cell_type":"code","source":"# This function takes in a filename of an image, and the labels in the string format given in a submission csv, and returns an image with the characters and predictions annotated.\ndef Extract_Data():\n    X_=[]\n    y_=[]\n    # Convert annotation string to array #300\n    for img, labels in tqdm(df_train[:420].values):\n        try:\n            image_fn = '../input/train_images/{}.jpg'.format(img)\n            labels = np.array(labels.split(' ')).reshape(-1, 5)\n            # Read image\n            imsource = Image.open(image_fn).convert('RGBA')\n            bbox_canvas = Image.new('RGBA', imsource.size)\n            char_canvas = Image.new('RGBA', imsource.size)\n            bbox_draw = ImageDraw.Draw(bbox_canvas) # Separate canvases for boxes and chars so a box doesn't cut off a character\n            char_draw = ImageDraw.Draw(char_canvas)\n\n            for codepoint, x, y, w, h in labels:\n                x, y, w, h = int(x), int(y), int(w), int(h)\n                char = unicode_map[codepoint] # Convert codepoint to actual unicode character\n\n                # Draw bounding box around character, and unicode character next to it\n                #bbox_draw.rectangle((x-10, y-10, x+10, y+10), fill=(255, 0, 0, 255))\n                #char_draw.text((x+25, y-fontsize*(3/4)), char, fill=(255, 0, 0, 255), font=font)\n                Croped_image = imsource.crop((x, y, x+w, y+h))\n                image = Croped_image.resize((300,300))\n                image = np.asarray(image)\n                image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)\n                ret,th1 = cv2.threshold(image,155,255,cv2.THRESH_BINARY_INV)\n                X_.append(th1)\n                y_.append(str(unicode_map[codepoint]))\n        except:\n            pass\n    X_ = np.array(X_)\n    y_ = np.array(y_)\n\n    '''imsource = Image.alpha_composite(Image.alpha_composite(imsource, bbox_canvas), char_canvas)\n    imsource = imsource.convert(\"RGB\") '''# Remove alpha for saving in jpg format.\n    return X_,y_","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"XX_,yy_ = Extract_Data()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure()\nplt.imshow(XX_[99])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"XX_.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"unique, counts = np.unique(yy_, return_counts=True)\nprint(unique, counts )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"NoOfClasses = len(unique)\nNoOfClasses","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_ROWS=300\nIMG_COLS=300\ndef PreProcessData(X,y):\n    lb = LabelEncoder()\n    y_integer = lb.fit_transform(y)\n    out_y = np_utils.to_categorical(y_integer)\n    num_images = X.shape[0]\n    out_x = X.reshape(num_images, IMG_ROWS, IMG_COLS, 1)\n    #out_x = x_shaped_array / 255\n    return out_x, out_y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"lb = LabelEncoder()\ny_integer = lb.fit_transform(yy_)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X,y = PreProcessData(XX_,yy_)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(X, y, random_state=42)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"K.clear_session()\ndef Kuzushiji_Classifier(in_):\n    model_ = Conv2D(32,(3,3),activation='relu', padding=\"same\")(in_)\n    model_ = BatchNormalization()(model_)\n    model_ =  Conv2D(32,(3, 3), activation='relu')(model_)\n    model_ = BatchNormalization()(model_)\n    model_ = Conv2D(32,5,strides=2,padding='same',activation='relu')(model_)\n    model_ = MaxPooling2D((2, 2))(model_)\n    model_ = BatchNormalization()(model_)\n    model_ = Dropout(0.4)(model_)\n    model_ = Conv2D(64,(3, 3), strides=2,padding='same', activation='relu')(model_)\n    model_ = MaxPooling2D(pool_size=(2, 2))(model_)\n    model_ = BatchNormalization()(model_)\n    model_ = Conv2D(64, kernel_size=(3, 3), strides=2,padding='same', activation='relu')(model_)\n    model_ = Dropout(0.4)(model_)\n    model_ = Flatten()(model_)\n    model_ = Dense(128, activation='relu')(model_)\n    model_ = Dropout(0.4)(model_)\n    model_ = Dense(NoOfClasses, activation='softmax')(model_)\n    return model_","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"Input_Sample = Input(shape=(300, 300,1))\nOutput_ = Kuzushiji_Classifier(Input_Sample)\nModel_Enhancer = Model(inputs=Input_Sample, outputs=Output_)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"Model_Enhancer.compile(loss = \"categorical_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\nModel_Enhancer.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"checkpointer = ModelCheckpoint('model_Kuzushiji.h5', verbose=0,mode='auto', monitor='val_acc',save_best_only=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"ModelHistory = Model_Enhancer.fit(X_train, y_train,\n          batch_size=100,\n          epochs=32,\n          verbose=1,callbacks=[checkpointer],\n          validation_data=(X_val, y_val))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Loss Curves\nplt.figure(figsize=[20,9])\nplt.plot(ModelHistory.history['loss'], 'r')\nplt.plot(ModelHistory.history['val_loss'], 'b')\nplt.legend(['Training Loss','Validation Loss'])\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.title('Loss Curves')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Accuracy Curves\nplt.figure(figsize=[20,9])\nplt.plot(ModelHistory.history['acc'], 'r')\nplt.plot(ModelHistory.history['val_acc'], 'b')\nplt.legend(['Training Accuracy','Validation Accuracy'])\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.title('Accuracy Curves')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"According to the the Accuracy and Loss curve my model might look overfitted, but to overcome this overfitting you could do a slight change in the processing technique. In **the Extract_Data** function where I have used the code \n> <br>ret,th1 = cv2.threshold(image,155,255,cv2.THRESH_BINARY_INV)<br>\n\nyou could use *THRESH_BINARY* instead of *THRESH_BINARY_INV* and this would regularize the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"Model_ = load_model('model_Kuzushiji.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Visualising predictions\nFor the test set, you're only required to predict a single point within each bounding box instead of the entire bounding box (ideally, the centre of the bounding box). It may also be useful to visualise the box centres on the image:"},{"metadata":{},"cell_type":"markdown","source":"## About the Detection technique\n<br>First of all we have used OpenCV library for this purpose. At first the image is gray scaled,  thenit is passed through inverse binary threshold, which one of the type of sample thresholding technique. We then use **findContours** to detect the location of ink spots over the image. <br>**Contours** can be explained simply as a curve joining all the continuous points (along the boundary), having same color or intensity. The contours are a useful tool for shape analysis and object detection and recognition.<br> We do not need to detect every ink spots because some of them indicates boundary line or just simple unnecessary spot on the sheet of paper. Therefore we have fixed a size which is 7000 in this case to exclude those unnecessary spots and lines from being detected and only the Kuzushiji could be detected properly.\n![](https://res.cloudinary.com/teepublic/image/private/s---JKs_-9D--/t_Preview/b_rgb:ffffff,c_limit,f_jpg,h_630,q_90,w_630/v1555995870/production/designs/4697372_2.jpg)"},{"metadata":{"trusted":true},"cell_type":"code","source":"def VisualizeKuzushiji(imagePath):\n    img = cv2.imread(imagePath)\n    imsource = Image.open(imagePath)#fromarray(img)\n    char_draw = ImageDraw.Draw(imsource)\n    im_grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    ret, im_th = cv2.threshold(im_grey, 130, 255, cv2.THRESH_BINARY_INV)\n    ctrs,_ = cv2.findContours(im_th.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n    rects = [cv2.boundingRect(ctr) for ctr in ctrs]\n    Kuzushijis = []\n    for rect in rects:\n        leng = int(rect[3] * 1.6)\n        pt1 = int(rect[1] + rect[3]//2 - leng// 2)\n        pt2 = int(rect[0] + rect[2]//2 - leng// 2)\n        roi = im_th[pt1:pt1+leng, pt2:pt2+leng]\n        #bbox_draw.rectangle((rect[0], rect[1], rect[0] + rect[2],rect[1] + rect[3]), fill=(0, 225, 0, 0))\n        #print(roi.size)\n        if roi.size>7000:\n            cv2.rectangle(img, (rect[0], rect[1]), (rect[0] + rect[2], rect[1] + rect[3]), (225, 0, 0), 6)\n            roi = cv2.resize(roi, (300,300))\n            #roi = cv2.dilate(roi, (3, 3))\n            ret,th1 = cv2.threshold(roi,155,255,cv2.THRESH_BINARY)\n            ProcessImage = th1.reshape(1,IMG_ROWS, IMG_COLS, 1)\n            y_pred = Model_.predict(ProcessImage)\n            y_true = np.argmax(y_pred,axis=1)\n            Kuzushiji = lb.inverse_transform(y_true)\n            #print(Kuzushiji[0])\n            Kuzushijis.append(str(Kuzushiji[0]))\n            char_draw.text((rect[0]+10, rect[1]),str(Kuzushiji[0]), fill=(0,22,225,0), font=font)\n            #cv2.putText(img, str(Kuzushiji[0]), (rect[0], rect[1]),font, 2, (0, 255, 255), 3)\n    return img,imsource","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img1, imsource1 = VisualizeKuzushiji('../input/train_images/100241706_00014_2.jpg')\nplt.figure(figsize=(30,30))\nplt.subplot(1,4,1)\nplt.title(\"Detection of Kuzushiji\",fontsize=20)\nplt.imshow(img1)\nplt.subplot(1,4,2)\nplt.title(\"Recognition of Kuzushiji\",fontsize=20)\nplt.imshow(imsource1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(30,30))\nplt.title(\"Recognition of Kuzushiji\",fontsize=20)\nplt.imshow(imsource1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img2, imsource2 = VisualizeKuzushiji('../input/test_images/test_001c37e2.jpg')\nplt.figure(figsize=(30,30))\nplt.subplot(1,4,1)\nplt.title(\"Detection of Kuzushiji\",fontsize=20)\nplt.imshow(img2)\nplt.subplot(1,4,2)\nplt.title(\"Recognition of Kuzushiji\",fontsize=20)\nplt.imshow(imsource2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(30,30))\nplt.title(\"Recognition of Kuzushiji\",fontsize=20)\nplt.imshow(imsource2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img3, imsource3 = VisualizeKuzushiji('../input/test_images/test_009f58c8.jpg')\nplt.figure(figsize=(30,30))\nplt.subplot(1,4,1)\nplt.title(\"Detection of Kuzushiji\",fontsize=20)\nplt.imshow(img3)\nplt.subplot(1,4,2)\nplt.title(\"Recognition of Kuzushiji\",fontsize=20)\nplt.imshow(imsource3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(30,30))\nplt.title(\"Recognition of Kuzushiji\",fontsize=20)\nplt.imshow(imsource3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img4, imsource4 = VisualizeKuzushiji('../input/test_images/test_1abdbbfe.jpg')\nplt.figure(figsize=(30,30))\nplt.subplot(1,4,1)\nplt.title(\"Detection of Kuzushiji\",fontsize=20)\nplt.imshow(img4)\nplt.subplot(1,4,2)\nplt.title(\"Recognition of Kuzushiji\",fontsize=20)\nplt.imshow(imsource4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(30,30))\nplt.title(\"Recognition of Kuzushiji\",fontsize=20)\nplt.imshow(imsource4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## About the recognition model\n![](https://i.imgur.com/Gz0pm57.jpg)\n<br>\nThe model that is created is a Deep neural network model. this model is highly inspired by the kernel - [Classifying Cursive hiragana(崩し字) KMNIST using CNN](https://www.kaggle.com/gpreda/classifying-cursive-hiragana-kmnist-using-cnn). We have used Conv2D, Dense, Maxpooling2D and BatchNormalization layers to construct our model. For more detail, about each of the layers, you could google them out or visit the above-mentioned kernel.<br>\nThis model is taking too much time to train. For only 32 epochs it is taking almost 2 hours. But, once I tested it for 40 epochs and surprisingly its accuracy kept increasing till then.<br>\nBut the fact is I am a very lazy guy, waiting for just 32 epochs my condition is like this..\n![](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRxfyK9-L_xuJyHy3L9rgET1P0KnrYyS79EgQYHhmew9bemE9b7)\nSo don't expect me to wait for another 10 epochs...\n<br>If you have patience then go for it."},{"metadata":{},"cell_type":"markdown","source":"## Future Scopes\n* As I mentioned before, the higher number of epochs would give you higher accuracy.\n* The parameters or the neural network architecture could be tuned or different neural network architectures could be implemented for better accuracy.\n* I found this kernel very interesting for both detection and recognition of Kuzushiji recognition.\n[CenterNet -Keypoint Detector-](https://www.kaggle.com/kmat2019/centernet-keypoint-detector)"},{"metadata":{"trusted":true},"cell_type":"markdown","source":"## Conclusion\n* I have tried out my way in solving this problem and also this is not the best way. So you could try out your way while solving this problem.\n* I tried out the basic way of optical character recognition to solve this problem and it worked pretty well and satisfying.\n* To approach any problem please do not forget the basics, basic concepts could be the solution to Giant and tough problems."},{"metadata":{},"cell_type":"markdown","source":"### I hope this Kernel was helpful to you (ﾉ^_^)ﾉ...\n### Please Upvote this Kernel if you like it....\n![Thank you](https://memestatic.fjcdn.com/pictures/Konosuba+wallpapers+megumin+edition+some+of+these+are+probably_6f11f9_6344521.jpg)"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}