├── README.md ├── digital_display_ocr.py ├── letsgodigital ├── letsgodigital.charset ├── letsgodigital.inttemp ├── letsgodigital.normproto ├── letsgodigital.pffmtable ├── letsgodigital.shapetable ├── letsgodigital.traineddata └── letsgodigital.unicharset └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | # Digital display Segmentation + OCR using openCV and Tesseract 2 | -------------------------------------------------------------------------------- /digital_display_ocr.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import imutils 4 | from skimage import exposure 5 | from pytesseract import image_to_string 6 | import PIL 7 | 8 | def take_picture(should_save=False, d_id=0): 9 | cam = cv2.VideoCapture(d_id) 10 | s, img = cam.read() 11 | if s: 12 | if should_save: 13 | cv2.imwrite('ocr.jpg',img) 14 | print "picture taken" 15 | return img 16 | 17 | def cnvt_edged_image(img_arr, should_save=False): 18 | # ratio = img_arr.shape[0] / 300.0 19 | image = imutils.resize(img_arr,height=300) 20 | gray_image = cv2.bilateralFilter(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY),11, 17, 17) 21 | edged_image = cv2.Canny(gray_image, 30, 200) 22 | 23 | if should_save: 24 | cv2.imwrite('cntr_ocr.jpg') 25 | 26 | return edged_image 27 | 28 | '''image passed in must be ran through the cnv_edge_image first''' 29 | def find_display_contour(edge_img_arr): 30 | display_contour = None 31 | edge_copy = edge_img_arr.copy() 32 | contours,hierarchy = cv2.findContours(edge_copy, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 33 | top_cntrs = sorted(contours, key = cv2.contourArea, reverse = True)[:10] 34 | 35 | for cntr in top_cntrs: 36 | peri = cv2.arcLength(cntr,True) 37 | approx = cv2.approxPolyDP(cntr, 0.02 * peri, True) 38 | 39 | if len(approx) == 4: 40 | display_contour = approx 41 | break 42 | 43 | return display_contour 44 | 45 | def crop_display(image_arr): 46 | edge_image = cnvt_edged_image(image_arr) 47 | display_contour = find_display_contour(edge_image) 48 | cntr_pts = display_contour.reshape(4,2) 49 | return cntr_pts 50 | 51 | 52 | def normalize_contrs(img,cntr_pts): 53 | ratio = img.shape[0] / 300.0 54 | norm_pts = np.zeros((4,2), dtype="float32") 55 | 56 | s = cntr_pts.sum(axis=1) 57 | norm_pts[0] = cntr_pts[np.argmin(s)] 58 | norm_pts[2] = cntr_pts[np.argmax(s)] 59 | 60 | d = np.diff(cntr_pts,axis=1) 61 | norm_pts[1] = cntr_pts[np.argmin(d)] 62 | norm_pts[3] = cntr_pts[np.argmax(d)] 63 | 64 | norm_pts *= ratio 65 | 66 | (top_left, top_right, bottom_right, bottom_left) = norm_pts 67 | 68 | width1 = np.sqrt(((bottom_right[0] - bottom_left[0]) ** 2) + ((bottom_right[1] - bottom_left[1]) ** 2)) 69 | width2 = np.sqrt(((top_right[0] - top_left[0]) ** 2) + ((top_right[1] - top_left[1]) ** 2)) 70 | height1 = np.sqrt(((top_right[0] - bottom_right[0]) ** 2) + ((top_right[1] - bottom_right[1]) ** 2)) 71 | height2 = np.sqrt(((top_left[0] - bottom_left[0]) ** 2) + ((top_left[1] - bottom_left[1]) ** 2)) 72 | 73 | max_width = max(int(width1), int(width2)) 74 | max_height = max(int(height1), int(height2)) 75 | 76 | dst = np.array([[0,0], [max_width -1, 0],[max_width -1, max_height -1],[0, max_height-1]], dtype="float32") 77 | persp_matrix = cv2.getPerspectiveTransform(norm_pts,dst) 78 | return cv2.warpPerspective(img,persp_matrix,(max_width,max_height)) 79 | 80 | def process_image(orig_image_arr): 81 | ratio = orig_image_arr.shape[0] / 300.0 82 | 83 | display_image_arr = normalize_contrs(orig_image_arr,crop_display(orig_image_arr)) 84 | #display image is now segmented. 85 | gry_disp_arr = cv2.cvtColor(display_image_arr, cv2.COLOR_BGR2GRAY) 86 | gry_disp_arr = exposure.rescale_intensity(gry_disp_arr, out_range= (0,255)) 87 | 88 | #thresholding 89 | ret, thresh = cv2.threshold(gry_disp_arr,127,255,cv2.THRESH_BINARY) 90 | return thresh 91 | 92 | def ocr_image(orig_image_arr): 93 | otsu_thresh_image = PIL.Image.fromarray(process_image(orig_image_arr)) 94 | return image_to_string(otsu_thresh_image, lang="letsgodigital", config="-psm 100 -c tessedit_char_whitelist=.0123456789") 95 | 96 | 97 | -------------------------------------------------------------------------------- /letsgodigital/letsgodigital.charset: -------------------------------------------------------------------------------- 1 | 16 2 | NULL 0 NULL 0 3 | - 10 0,255,0,255,0,32767,0,32767,0,32767 NULL 1 0 0 # # - [2d ]p 4 | + 10 0,255,0,255,0,32767,0,32767,0,32767 NULL 2 0 0 # # + [2b ]p 5 | 1 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 3 0 0 # # 1 [31 ]0 6 | 2 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 4 0 0 # # 2 [32 ]0 7 | . 10 0,255,0,255,0,32767,0,32767,0,32767 NULL 5 0 0 # # . [2e ]p 8 | 3 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 6 0 0 # # 3 [33 ]0 9 | 4 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 7 0 0 # # 4 [34 ]0 10 | 5 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 8 0 0 # # 5 [35 ]0 11 | 6 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 9 0 0 # # 6 [36 ]0 12 | 7 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 10 0 0 # # 7 [37 ]0 13 | , 10 0,255,0,255,0,32767,0,32767,0,32767 NULL 11 0 0 # # , [2c ]p 14 | 8 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 12 0 0 # # 8 [38 ]0 15 | 9 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 13 0 0 # # 9 [39 ]0 16 | 0 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 14 0 0 # # 0 [30 ]0 17 | E 5 0,255,0,255,0,32767,0,32767,0,32767 NULL -1 0 0 # # E [45 ]A 18 | -------------------------------------------------------------------------------- /letsgodigital/letsgodigital.inttemp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upupnaway/digital-display-character-rec/b5d7cc3d50fb2d88f812c3d8fbdf67f7f5ab0f92/letsgodigital/letsgodigital.inttemp -------------------------------------------------------------------------------- /letsgodigital/letsgodigital.normproto: -------------------------------------------------------------------------------- 1 | 4 2 | linear essential -0.250000 0.750000 3 | linear non-essential 0.000000 1.000000 4 | linear essential 0.000000 1.000000 5 | linear essential 0.000000 1.000000 6 | 7 | - 1 8 | significant elliptical 12 9 | 0.314453 0.108561 0.068034 0.142578 10 | 0.000587 0.000400 0.000400 0.000400 11 | 12 | + 1 13 | significant elliptical 50 14 | 0.313750 0.148625 0.129922 0.128828 15 | 0.000422 0.000400 0.000400 0.000400 16 | 17 | 1 1 18 | significant elliptical 50 19 | 0.322656 0.155914 0.200312 0.065781 20 | 0.000400 0.000400 0.000400 0.000400 21 | 22 | 2 1 23 | significant elliptical 50 24 | 0.363594 0.323375 0.247110 0.154375 25 | 0.000400 0.000400 0.000400 0.000400 26 | 27 | . 1 28 | significant elliptical 50 29 | 0.087266 0.059086 0.058281 0.058203 30 | 0.000400 0.000400 0.000400 0.000400 31 | 32 | 3 1 33 | significant elliptical 50 34 | 0.365703 0.317937 0.247266 0.149219 35 | 0.000400 0.000400 0.000400 0.000400 36 | 37 | 4 1 38 | significant elliptical 50 39 | 0.398281 0.247992 0.191719 0.166640 40 | 0.000400 0.000400 0.000400 0.000400 41 | 42 | 5 1 43 | significant elliptical 50 44 | 0.366875 0.323805 0.246875 0.151407 45 | 0.000400 0.000400 0.000400 0.000400 46 | 47 | 6 1 48 | significant elliptical 50 49 | 0.365938 0.336211 0.243281 0.158672 50 | 0.000400 0.000400 0.000400 0.000400 51 | 52 | 7 1 53 | significant elliptical 50 54 | 0.437031 0.217930 0.227812 0.126797 55 | 0.000400 0.000400 0.000400 0.000400 56 | 57 | , 1 58 | significant elliptical 50 59 | 0.012500 0.069078 0.077344 0.058906 60 | 0.000649 0.000400 0.000400 0.000400 61 | 62 | 8 1 63 | significant elliptical 50 64 | 0.375313 0.347445 0.240859 0.167969 65 | 0.000400 0.000400 0.000400 0.000400 66 | 67 | 9 1 68 | significant elliptical 50 69 | 0.384141 0.336922 0.243594 0.159531 70 | 0.000400 0.000400 0.000400 0.000400 71 | 72 | 0 1 73 | significant elliptical 48 74 | 0.381999 0.357625 0.236247 0.169352 75 | 0.000400 0.000400 0.000400 0.000400 76 | 77 | E 1 78 | significant elliptical 50 79 | 0.379687 0.326164 0.248984 0.152891 80 | 0.000400 0.000400 0.000400 0.000400 81 | -------------------------------------------------------------------------------- /letsgodigital/letsgodigital.pffmtable: -------------------------------------------------------------------------------- 1 | %+-@E1DD1%AH?CNULL 0 2 | - 37 3 | + 43 4 | 1 45 5 | 2 64 6 | . 37 7 | 3 69 8 | 4 49 9 | 5 68 10 | 6 68 11 | 7 49 12 | , 37 13 | 8 65 14 | 9 72 15 | 0 63 16 | E 67 17 | -------------------------------------------------------------------------------- /letsgodigital/letsgodigital.shapetable: -------------------------------------------------------------------------------- 1 |   2 |     -------------------------------------------------------------------------------- /letsgodigital/letsgodigital.traineddata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/upupnaway/digital-display-character-rec/b5d7cc3d50fb2d88f812c3d8fbdf67f7f5ab0f92/letsgodigital/letsgodigital.traineddata -------------------------------------------------------------------------------- /letsgodigital/letsgodigital.unicharset: -------------------------------------------------------------------------------- 1 | 16 2 | NULL 0 NULL 0 3 | - 10 0,255,0,255,0,32767,0,32767,0,32767 NULL 1 0 0 # - [2d ]p 4 | + 10 0,255,0,255,0,32767,0,32767,0,32767 NULL 2 0 0 # + [2b ]p 5 | 1 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 3 0 0 # 1 [31 ]0 6 | 2 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 4 0 0 # 2 [32 ]0 7 | . 10 0,255,0,255,0,32767,0,32767,0,32767 NULL 5 0 0 # . [2e ]p 8 | 3 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 6 0 0 # 3 [33 ]0 9 | 4 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 7 0 0 # 4 [34 ]0 10 | 5 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 8 0 0 # 5 [35 ]0 11 | 6 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 9 0 0 # 6 [36 ]0 12 | 7 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 10 0 0 # 7 [37 ]0 13 | , 10 0,255,0,255,0,32767,0,32767,0,32767 NULL 11 0 0 # , [2c ]p 14 | 8 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 12 0 0 # 8 [38 ]0 15 | 9 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 13 0 0 # 9 [39 ]0 16 | 0 8 0,255,0,255,0,32767,0,32767,0,32767 NULL 14 0 0 # 0 [30 ]0 17 | E 5 0,255,0,255,0,32767,0,32767,0,32767 NULL -1 0 0 # E [45 ]A 18 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | dask==0.10.2 2 | decorator==4.0.10 3 | Django==1.9.8 4 | image==1.5.3 5 | imutils==0.3.6 6 | networkx==1.11 7 | numpy==1.11.1 8 | Pillow==3.3.0 9 | pytesseract==0.1.6 10 | scikit-image==0.12.3 11 | scipy==0.18.0 12 | six==1.10.0 13 | tesseract==0.1.3 14 | toolz==0.8.0 15 | --------------------------------------------------------------------------------