Skip to content

Instantly share code, notes, and snippets.

@rakshith48
Created December 21, 2019 11:53
Show Gist options
  • Save rakshith48/922d2b1182918c94a89635803ab6e237 to your computer and use it in GitHub Desktop.
Save rakshith48/922d2b1182918c94a89635803ab6e237 to your computer and use it in GitHub Desktop.
Created on Cognitive Class Labs
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a href=\"https://cognitiveclass.ai/\">\n",
" <img src=\"https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/CV0101/Logo/SNLogo.png\" width=\"200\" align=\"center\">\n",
"</a>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h1>Lab - Detecting text in images with OpenCV and Tesseract OCR</h1>\n",
"\n",
"<b>Welcome!</b> In this lab you will learn about about Automatic number-plate recognition. We will use the Tesseract OCR An Optical Character Recognition Engine (OCR Engine) to automatically recognize text in vehicle registration plates. Pretty cool, right? \n",
"\n",
"After completing this lab you will:\n",
"<h5> 1. Learn to download, read and display images using Python, OpenCV and Matplotlib </h5>\n",
"<h5> 2. Learn to use Tesseract OCR for detetcing text in images</h5>\n",
"<h5> 3. Learn about image processing techniques </h5>\n",
"<h5> 4. Compress images using a technique called K Means Clustering</h5>\n",
"<h5> 5. Compress images by upto 90% ! </h5>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div class=\"alert alert-block alert-info\" style=\"margin-top: 20px\">\n",
" <br>\n",
" <br>\n",
" <h2>Table of Contents</h2>\n",
" <ul>\n",
" <li><a href=\"#ref0\">Tesseract</a></li>\n",
" <li><a href=\"#ref1\">Perform OCR using the Tesseract Engine on license plates</a></li>\n",
" <li><a href=\"#ref2\">Image Processing Techniques</a></li>\n",
" <li><a href=\"#ref4\">Exercises</a></li>\n",
" </ul>\n",
" <br>\n",
" <p>Estimated Time Needed: <strong>1 hr</strong></p>\n",
" </div>\n",
"<hr>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id=\"ref0\"></a>\n",
"<h2 align=\"center\">Tesseract<a href=\"http://opensource.google.com/projects/tesseract\"> Homepage</a></h2>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Tesseract is an Optical Character Recognition (OCR) Engine open-sourced and supported by Google\n",
"- Has ability to recognize more than 100 languages out of the box"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### We will use Tesseract for recognizing images of License Plates. These images were clicked under different lighting conditions and have a variety of variations in them. Pretty cool, right?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To view the license plates, you could click on the `license_plates` folder which is listed in the files directory in the left-sidebar of the JupyterLab environment. If this sidemenu is hidden, you can go to `View`>`View Left-Sidebar`. Once you click on the folder, you could click on each file name to view the image of the license plate"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Install the Pytesseract package for using the Tesseract Engine with Python"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting pytesseract\n",
" Downloading https://files.pythonhosted.org/packages/a9/7c/9ed191f009dac30682c320d925d50dbc39ae621310218a95f970ee4ff5e5/pytesseract-0.3.1.tar.gz\n",
"Collecting wget\n",
" Downloading https://files.pythonhosted.org/packages/47/6a/62e288da7bcda82b935ff0c6cfe542970f04e29c756b0e147251b2fb251f/wget-3.2.zip\n",
"Requirement already satisfied, skipping upgrade: Pillow in /home/jupyterlab/conda/envs/python/lib/python3.6/site-packages (from pytesseract) (6.2.1)\n",
"Building wheels for collected packages: pytesseract, wget\n",
" Building wheel for pytesseract (setup.py) ... \u001b[?25ldone\n",
"\u001b[?25h Stored in directory: /home/jupyterlab/.cache/pip/wheels/01/84/d2/10729e740ad8f5c5d3b02d10c7f15afeaa390f7723bd59dbd7\n",
" Building wheel for wget (setup.py) ... \u001b[?25ldone\n",
"\u001b[?25h Stored in directory: /home/jupyterlab/.cache/pip/wheels/40/15/30/7d8f7cea2902b4db79e3fea550d7d7b85ecb27ef992b618f3f\n",
"Successfully built pytesseract wget\n",
"Installing collected packages: pytesseract, wget\n",
"Successfully installed pytesseract-0.3.1 wget-3.2\n"
]
}
],
"source": [
"!pip install --upgrade pytesseract wget"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Loading the required python modules\n",
"import pytesseract\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"import glob\n",
"import os"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id=\"ref1\"></a>\n",
"<h2 align=\"center\">Perform OCR using the Tesseract Engine on license plates</h2>"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import wget, zipfile, os\n",
"\n",
"filename='license-plates'\n",
"\n",
"if not os.path.isfile(filename):\n",
" filename = wget.download('https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/CV0101/Dataset/license-plates.zip')\n",
" with zipfile.ZipFile(\"license-plates.zip\",\"r\") as zip_ref:\n",
" zip_ref.extractall()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"path_for_license_plates = os.getcwd() + \"/license-plates/**/*.jpg\"\n",
"list_license_plates = []\n",
"predicted_license_plates = []\n",
"\n",
"for path_to_license_plate in glob.glob(path_for_license_plates, recursive=True):\n",
" \n",
" license_plate_file = path_to_license_plate.split(\"/\")[-1]\n",
" license_plate, _ = os.path.splitext(license_plate_file)\n",
" '''\n",
" Here we append the actual license plate to a list\n",
" '''\n",
" list_license_plates.append(license_plate)\n",
" \n",
" '''\n",
" Read each license plate image file using openCV\n",
" '''\n",
" img = cv2.imread(path_to_license_plate)\n",
" \n",
" '''\n",
" We then pass each license plate image file to the Tesseract OCR engine using \n",
" the Python library wrapper for it. We get back a predicted_result for the license plate.\n",
" We append the predicted_result in a list and compare it with the original the license plate\n",
" '''\n",
" predicted_result = pytesseract.image_to_string(img, lang='eng',\n",
" config='--oem 3 --psm 6 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')\n",
" \n",
" filter_predicted_result = \"\".join(predicted_result.split()).replace(\":\", \"\").replace(\"-\", \"\")\n",
" predicted_license_plates.append(filter_predicted_result)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Actual License Plate \t Predicted License Plate \t Accuracy\n",
"-------------------- \t ----------------------- \t --------\n",
" OCX4764 \t\t\t OCX4764 \t\t 100%\n",
" PJB7392 \t\t\t PJB7392 \t\t 100%\n",
" NYY1710 \t\t\t NYY1710 \t\t 100%\n",
" PJG0783 \t\t\t PJG0783 \t\t 100%\n",
" OYJ9557 \t\t\t OYJ9557 \t\t 100%\n",
" OUP9563 \t\t\t OUP9563 \t\t 100%\n",
" OLC4728 \t\t\t OLC4728 \t\t 100%\n",
" OKV8004 \t\t\t QKV8004 \t\t 86.0%\n",
" ODJ1599 \t\t\t ODJ1599 \t\t 100%\n",
" PJB2414 \t\t\t PJB2414 \t\t 100%\n",
" OLA1208 \t\t\t OLA1208 \t\t 100%\n",
" AYO9034 \t\t\t AYO9034 \t\t 100%\n",
" GWT2180 \t\t\t GWT2120 \t\t 86.0%\n",
" JSQ1413 \t\t\t JSQ|413 \t\t 86.0%\n",
" OKS0078 \t\t\t OKS0078 \t\t 100%\n",
" NTK5785 \t\t\t NTK5785 \t\t 100%\n",
" PJD2685 \t\t\t PJD2685 \t\t 100%\n",
" NZW2197 \t\t\t NZW2197 \t\t 100%\n"
]
}
],
"source": [
"print(\"Actual License Plate\", \"\\t\", \"Predicted License Plate\", \"\\t\", \"Accuracy\")\n",
"print(\"--------------------\", \"\\t\", \"-----------------------\", \"\\t\", \"--------\")\n",
"\n",
"def calculate_predicted_accuracy(actual_list, predicted_list):\n",
" for actual_plate, predict_plate in zip(actual_list, predicted_list):\n",
" accuracy = \"0%\"\n",
" num_matches = 0\n",
" if actual_plate == predict_plate:\n",
" accuracy = \"100%\"\n",
" else:\n",
" if len(actual_plate) == len(predict_plate):\n",
" for a, p in zip(actual_plate, predict_plate):\n",
" if a == p:\n",
" num_matches += 1\n",
" accuracy = str(round((num_matches/len(actual_plate)), 2) * 100)\n",
" accuracy += \"%\"\n",
" print(\" \", actual_plate, \"\\t\\t\\t\", predict_plate, \"\\t\\t \", accuracy)\n",
"\n",
" \n",
"calculate_predicted_accuracy(list_license_plates, predicted_license_plates)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3>Woah! We see that the Tesseract OCR engine mostly predicts all of the license plates correctly with 100% accuracy! </h3>\n",
"\n",
"\n",
"<h3>For the license plates the Tesseract OCR Engine predicted incorrectly (i.e. GWT2180, OKV8004, JSQ1413), we will apply image processing techniques on those license plate files and pass them to the Tesseract OCR again. Applying the image processing techniques would increase the accuracy of the Tesseract Engine for the license plates of GWT2180, OKV8004, JSQ1413</h3>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id=\"ref2\"></a>\n",
"<h2 align=\"center\"> Image Processing Techniques </h2>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Image resizing is a technique in which we scale the image either horizontally, or vertically or both. \n",
"Further documentation on image resizing: [here](https://www.tutorialkart.com/opencv/python/opencv-python-resize-image/)\n",
"\n",
"For our use case, we will read the license plate file of ```GWT2180``` using ```cv2.imread``` and then resize the image file by a factor of 2x in both the horizontal and vertical directions using ```cv2.resize```"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Text(0.5, 1.0, 'GWT2180 license plate')"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Read the license plate file and display it\n",
"test_license_plate = cv2.imread(os.getcwd() + \"/license-plates/GWT2180.jpg\")\n",
"plt.imshow(test_license_plate)\n",
"plt.axis('off')\n",
"plt.title('GWT2180 license plate')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 1. Image resizing"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"resize_test_license_plate = cv2.resize(test_license_plate, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 2. Converting to Grayscale"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we convert our resized image file to gray scale. We learnt about this technique in the image processing lab"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"grayscale_resize_test_license_plate = cv2.cvtColor(resize_test_license_plate, cv2.COLOR_BGR2GRAY)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 3. Denoising the Image"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Gaussian Blur is a technique for denoising images. Full OpenCV documentation on Gaussian Blur: [here](https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_filtering/py_filtering.html#gaussian-filtering)\n",
"\n",
"We apply a gaussian blur to the greyscale image"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"gaussian_blur_license_plate = cv2.GaussianBlur(grayscale_resize_test_license_plate, (5, 5), 0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Pass the transformed license plate file to the Tesseract OCR engine and see the predicted result\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"new_predicted_result_GWT2180 = pytesseract.image_to_string(gaussian_blur_license_plate, lang='eng',\n",
"config='--oem 3 -l eng --psm 6 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')\n",
"filter_new_predicted_result_GWT2180 = \"\".join(new_predicted_result_GWT2180.split()).replace(\":\", \"\").replace(\"-\", \"\")\n",
"print(filter_new_predicted_result_GWT2180)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" #### Voila We see that the Tesseract OCR correctly recognises all characters in the GWT2180 license plate after we passed in the transformed license plate"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id=\"ref4\"></a>\n",
"<h2 align=\"center\"> Exercises </h2>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Exercise 1:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 1.1 Read in the license plate file of JSQ1413\n",
"# Write your code below:\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 1.2 Apply the image processing techniques to the license plate of JSQ1413 described above \n",
"# Write your code below:\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 1.3 Pass the modified license plate file to the Tesseract Engine. Report your findings \n",
"# Write your code below:\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Click *here* to view the solution\n",
"\n",
"<!---\n",
"\n",
"# 1.1 Read the license plate file and display it\n",
"\n",
"test_license_plate_JSQ1413 = cv2.imread(os.getcwd() + \"/license-plates/JSQ1413.jpg\")\n",
"plt.imshow(test_license_plate_OKV8004)\n",
"plt.axis('off')\n",
"plt.title('OKV8004 license plate')\n",
"\n",
"# 1.2 Apply the image processing techniques to the license plate of JSQ1413 described above\n",
"\n",
"resize_test_license_plate_JSQ1413 = cv2.resize(test_license_plate_JSQ1413, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)\n",
"grayscale_resize_test_license_plate_JSQ1413 = cv2.cvtColor(resize_test_license_plate_JSQ1413, cv2.COLOR_BGR2GRAY)\n",
"gaussian_blur_license_plate_JSQ1413 = cv2.GaussianBlur(grayscale_resize_test_license_plate_JSQ1413, (5, 5), 0)\n",
"\n",
"# 1.3 Pass the modified license plate file to the Tesseract Engine. Report your findings\n",
"\n",
"new_predicted_result_JSQ1413 = pytesseract.image_to_string(gaussian_blur_license_plate_JSQ1413, lang='eng',\n",
"config='--oem 3 -l eng --psm 6 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')\n",
"filter_new_predicted_result_JSQ1413 = \"\".join(new_predicted_result_JSQ1413.split()).replace(\":\", \"\").replace(\"-\", \"\")\n",
"print(filter_new_predicted_result_JSQ1413)\n",
"--->"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h1>Thank you for completing this lab!</h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div class=\"alert alert-block alert-info\" style=\"margin-top: 20px\">\n",
"<h2>Get IBM Watson Studio free of charge!</h2>\n",
" <p><a href=\"https://cocl.us/NotebooksPython101bottom\"><img src=\"https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/CV0101/Logo/BottomAd.png\" width=\"750\" align=\"center\"></a></p>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3>About the Author:</h3>\n",
"This lab was written by <a href=\"https://www.linkedin.com/in/sacchitchadha/\" target=\"_blank\" >Sacchit Chadha</a>.\n",
"<p><a href=\"https://www.linkedin.com/in/sacchitchadha/\" target=\"_blank\">Sacchit Chadha</a> is a Software Engineer at IBM, and is currently pursuing a Bachelors Degree in Computer Science from the University of Waterloo. His work at IBM focused on Computer Vision, Cloud Computing and Blockchain.</p>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<hr>\n",
"<p>Copyright &copy; 2019 IBM Developer Skills Network. This notebook and its source code are released under the terms of the <a href=\"https://cognitiveclass.ai/mit-license/\">MIT License</a>.</p>"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python",
"language": "python",
"name": "conda-env-python-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment