├── Data.zip
├── README.md
├── images
├── .gitkeep
├── 2018.png
├── ger1.png
├── ger2.png
├── ger3.png
├── ger4.png
├── pro1.png
├── pro2.png
└── pro3.png
├── picture_from_webcam.py
├── read_from_disk.py
└── video_from_webam.py
/Data.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Embossed-Text-Reader/87888c1f2a74ac72c33b3895f1f15b30293e0067/Data.zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Embossed-Text-Reader
2 | This is a tesseract based OCR to read Embossed text on metals. It can also be use as a general OCR.
3 |
4 | This is not generalized solution. The satements and parameters of some funtions will changed according to the texture,
5 | color, lighting effect and visibility of text of image.
6 |
7 | Tesseract is an open-sourced OCR which is capable of reading text from papers, pdfs and other clean formats. Tesseract fails when
8 | tried to perform OCR on noisy and dirty images (for eg. Embossed or Engraved text). The code uses opencv image filtering techniques
9 | to filter the images as clean as possible and then feeds it to Tesseract.
10 |
11 | ## Dependencies
12 | Python
13 | OpenCV
14 | Tesseract
15 | Numpy
16 | imutils
17 |
18 | ### There are three files -
19 | 1. picture_from_webcam.py clicks a single picture from webcam and performs OCR on it
20 | 2. read_from_disk.py loads a picture from an image file
21 | 3. video_from_webcam.py feeds the realtime video from the webcam (doesn't perform as expected)
22 |
23 | ## Example
24 | #### Edged image (canny) with dialation
25 |
26 |
27 | #### Finding and deleting unessesary contours
28 |
29 |
30 |
31 | #### Inverted threshold image
32 |
33 |
34 |
35 | #### Results
36 |
37 |
38 |
39 | ## Sample results -
40 |
41 |
42 |
43 |
44 |
45 |
46 | The code may fail sometimes but tuning parameters of canny and appropriate dialation will improve results
47 |
48 | ### Data.zip contains all data I have used during implementation of this project
49 |
--------------------------------------------------------------------------------
/images/.gitkeep:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/images/2018.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Embossed-Text-Reader/87888c1f2a74ac72c33b3895f1f15b30293e0067/images/2018.png
--------------------------------------------------------------------------------
/images/ger1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Embossed-Text-Reader/87888c1f2a74ac72c33b3895f1f15b30293e0067/images/ger1.png
--------------------------------------------------------------------------------
/images/ger2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Embossed-Text-Reader/87888c1f2a74ac72c33b3895f1f15b30293e0067/images/ger2.png
--------------------------------------------------------------------------------
/images/ger3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Embossed-Text-Reader/87888c1f2a74ac72c33b3895f1f15b30293e0067/images/ger3.png
--------------------------------------------------------------------------------
/images/ger4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Embossed-Text-Reader/87888c1f2a74ac72c33b3895f1f15b30293e0067/images/ger4.png
--------------------------------------------------------------------------------
/images/pro1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Embossed-Text-Reader/87888c1f2a74ac72c33b3895f1f15b30293e0067/images/pro1.png
--------------------------------------------------------------------------------
/images/pro2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Embossed-Text-Reader/87888c1f2a74ac72c33b3895f1f15b30293e0067/images/pro2.png
--------------------------------------------------------------------------------
/images/pro3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Embossed-Text-Reader/87888c1f2a74ac72c33b3895f1f15b30293e0067/images/pro3.png
--------------------------------------------------------------------------------
/picture_from_webcam.py:
--------------------------------------------------------------------------------
1 | import cv2 as cv2
2 | import numpy as np
3 | import imutils
4 | import pytesseract
5 |
6 | # Capture from web cam
7 | cap = cv2.VideoCapture(0)
8 |
9 | _,image = cap.read()
10 | # You can load a saved file from disk
11 | # image = cv2.imread('test13.jpg')
12 | img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
13 | img = cv2.GaussianBlur(img, (7,7), 0)
14 |
15 | # perform edge detection, then perform a dilation + erosion to
16 | # close gaps in between object edges
17 | edged = cv2.Canny(img, 20, 50)# Adjust these parameters according to your image
18 | dilate = cv2.dilate(edged, None, iterations=1)
19 | # We don't perform erosion, it completely depends on the image and need
20 | # erode = cv2.erode(dilate, None, iterations=1)
21 |
22 | # make an empty mask
23 | mask = np.ones(img.shape[:2], dtype="uint8") * 255
24 |
25 | # find contours
26 | cnts,hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
27 | cnts = cnts[0] if imutils.is_cv2() else cnts[1]
28 |
29 | orig = img.copy()
30 | for c in cnts:
31 | # if the contour is not sufficiently large, ignore it
32 | if cv2.contourArea(c) < 200:
33 | cv2.drawContours(mask, [c], -1, 0, -1)
34 |
35 | x,y,w,h = cv2.boundingRect(c)
36 |
37 | # Filter and remove more contours according to your need
38 | if(w>h):
39 | cv2.drawContours(mask, [c], -1, 0, -1)
40 |
41 | # Remove those ignored contours
42 | newimage = cv2.bitwise_and(dilate.copy(), dilate.copy(), mask=mask)
43 | # Dilate again if necessary
44 | img2 = cv2.dilate(newimage, None, iterations=1)
45 | ret2,th1 = cv2.threshold(newimage,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
46 |
47 | # tesseract on the filtered image
48 | temp = pytesseract.image_to_string(th1)
49 | # Write output on the image
50 | cv2.putText(image,temp,(50,100),cv2.FONT_HERSHEY_SIMPLEX,1.0,(0,255,255),3)
51 |
52 | # Show the results
53 | cv2.imshow('Original image', cv2.resize(image,(640,480)))
54 | cv2.imshow('Dilated', cv2.resize(dilate,(640,480)))
55 | cv2.imshow('New Image', cv2.resize(newimage,(640,480)))
56 | cv2.imshow('Inverted Threshold', cv2.resize(th1,(640,480)))
57 |
58 | cv2.waitKey(0)
59 | cv2.destroyAllWindows()
60 |
61 |
--------------------------------------------------------------------------------
/read_from_disk.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import numpy as np
3 | import imutils
4 | import pytesseract
5 |
6 | # read image from disk
7 | image = cv2.imread('test13.jpg')
8 | # make it gray
9 | img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
10 | # blur it to remove noise
11 | img = cv2.GaussianBlur(img, (7,7), 0)
12 |
13 | # perform edge detection, then perform a dilation + erosion to
14 | # close gaps in between object edges
15 | edged = cv2.Canny(img, 40, 90)
16 | dilate = cv2.dilate(edged, None, iterations=2)
17 | # perform erosion if necessay, it completely depends on the image
18 | # erode = cv2.erode(dilate, None, iterations=1)
19 |
20 | # create an empty masks
21 | mask = np.ones(img.shape[:2], dtype="uint8") * 255
22 |
23 | # find contours
24 | cnts = cv2.findContours(dilate.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
25 | cnts = cnts[0] if imutils.is_cv2() else cnts[1]
26 |
27 | orig = img.copy()
28 | for c in cnts:
29 | # if the contour is not sufficiently large, ignore it
30 | if cv2.contourArea(c) < 300:
31 | cv2.drawContours(mask, [c], -1, 0, -1)
32 |
33 | x,y,w,h = cv2.boundingRect(c)
34 |
35 | # filter more contours if nessesary
36 | if(w>h):
37 | cv2.drawContours(mask, [c], -1, 0, -1)
38 |
39 | newimage = cv2.bitwise_and(dilate.copy(), dilate.copy(), mask=mask)
40 | img2 = cv2.dilate(newimage, None, iterations=3)
41 | ret2,th1 = cv2.threshold(img2 ,0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
42 |
43 | # Tesseract OCR on the image
44 | temp = pytesseract.image_to_string(th1)
45 | # Write results on the image
46 | cv2.putText(image, temp, (100,100), cv2.FONT_HERSHEY_SIMPLEX, 1.8, (0,255,255), 3)
47 |
48 | # show the outputs
49 | cv2.imshow('Original image', cv2.resize(image,(640,480)))
50 | cv2.imshow('Dilated', cv2.resize(dilate,(640,480)))
51 | cv2.imshow('New Image', cv2.resize(newimage,(640,480)))
52 | cv2.imshow('Inverted Threshold', cv2.resize(th1,(640,480)))
53 |
54 | cv2.waitKey(0)
55 | cv2.destroyAllWindows()
56 |
57 |
--------------------------------------------------------------------------------
/video_from_webam.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import numpy as np
3 | import imutils
4 | import pytesseract
5 |
6 | # read from web camera
7 | cap = cv2.VideoCapture(1)
8 |
9 | while True:
10 | # Read a frame
11 | _,image = cap.read()
12 | img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
13 | img = cv2.GaussianBlur(img, (7,7), 0)
14 |
15 | # perform edge detection, then perform a dilation + erosion to
16 | # close gaps in between object edges
17 | edged = cv2.Canny(img, 40, 90)
18 | dilate = cv2.dilate(edged, None, iterations=2)
19 | # erode = cv2.erode(dilate, None, iterations=1)
20 |
21 | # create ann empty mask
22 | mask = np.ones(img.shape[:2], dtype="uint8") * 255
23 |
24 | # find the contours
25 | cnts,hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
26 | cnts = cnts[0] if imutils.is_cv2() else cnts[1]
27 |
28 | orig = img.copy()
29 | for c in cnts:
30 | # if the contour is not sufficiently large, ignore it
31 | if cv2.contourArea(c) < 200:
32 | cv2.drawContours(mask, [c], -1, 0, -1)
33 |
34 | x,y,w,h = cv2.boundingRect(c)
35 |
36 | # Filter and remove more contours according to your need
37 | if(w>h):
38 | cv2.drawContours(mask, [c], -1, 0, -1)
39 |
40 | # Remove ignored contours
41 | newimage = cv2.bitwise_and(dilate.copy(), dilate.copy(), mask=mask)
42 | # Dialte agin if necessay
43 | img2 = cv2.dilate(newimage, None, iterations=1)
44 | # Invert threshold for better results
45 | ret2,th1 = cv2.threshold(img2 ,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
46 |
47 | # Tesseract on the filtered image
48 | temp = pytesseract.image_to_string(th1)
49 | # Write text on the image
50 | cv2.putText(image,temp,(50,100),cv2.FONT_HERSHEY_SIMPLEX,1.0,(0,255,255),3)
51 |
52 | # Show the results
53 | cv2.imshow('Original image', cv2.resize(image,(640,480)))
54 | cv2.imshow('Dilated', cv2.resize(dilate,(640,480)))
55 | cv2.imshow('New Image', cv2.resize(newimage,(640,480)))
56 | cv2.imshow('Inverted Threshold', cv2.resize(th1,(640,480)))
57 |
58 | # Exit condition
59 | if cv2.waitKey(1) == ord('q'):
60 | break
61 |
62 | cv2.destroyAllWindows()
63 |
64 |
--------------------------------------------------------------------------------