개정판 9ecba041
initial commit
.gitattributes | ||
---|---|---|
1 |
############################################################################### |
|
2 |
# Set default behavior to automatically normalize line endings. |
|
3 |
############################################################################### |
|
4 |
* text=auto |
|
5 |
|
|
6 |
############################################################################### |
|
7 |
# Set default behavior for command prompt diff. |
|
8 |
# |
|
9 |
# This is need for earlier builds of msysgit that does not have it on by |
|
10 |
# default for csharp files. |
|
11 |
# Note: This is only used by command line |
|
12 |
############################################################################### |
|
13 |
#*.cs diff=csharp |
|
14 |
|
|
15 |
############################################################################### |
|
16 |
# Set the merge driver for project and solution files |
|
17 |
# |
|
18 |
# Merging from the command prompt will add diff markers to the files if there |
|
19 |
# are conflicts (Merging from VS is not affected by the settings below, in VS |
|
20 |
# the diff markers are never inserted). Diff markers may cause the following |
|
21 |
# file extensions to fail to load in VS. An alternative would be to treat |
|
22 |
# these files as binary and thus will always conflict and require user |
|
23 |
# intervention with every merge. To do so, just uncomment the entries below |
|
24 |
############################################################################### |
|
25 |
#*.sln merge=binary |
|
26 |
#*.csproj merge=binary |
|
27 |
#*.vbproj merge=binary |
|
28 |
#*.vcxproj merge=binary |
|
29 |
#*.vcproj merge=binary |
|
30 |
#*.dbproj merge=binary |
|
31 |
#*.fsproj merge=binary |
|
32 |
#*.lsproj merge=binary |
|
33 |
#*.wixproj merge=binary |
|
34 |
#*.modelproj merge=binary |
|
35 |
#*.sqlproj merge=binary |
|
36 |
#*.wwaproj merge=binary |
|
37 |
|
|
38 |
############################################################################### |
|
39 |
# behavior for image files |
|
40 |
# |
|
41 |
# image files are treated as binary by default. |
|
42 |
############################################################################### |
|
43 |
#*.jpg binary |
|
44 |
#*.png binary |
|
45 |
#*.gif binary |
|
46 |
|
|
47 |
############################################################################### |
|
48 |
# diff behavior for common document formats |
|
49 |
# |
|
50 |
# Convert binary document formats to text before diffing them. This feature |
|
51 |
# is only available from the command line. Turn it on by uncommenting the |
|
52 |
# entries below. |
|
53 |
############################################################################### |
|
54 |
#*.doc diff=astextplain |
|
55 |
#*.DOC diff=astextplain |
|
56 |
#*.docx diff=astextplain |
|
57 |
#*.DOCX diff=astextplain |
|
58 |
#*.dot diff=astextplain |
|
59 |
#*.DOT diff=astextplain |
|
60 |
#*.pdf diff=astextplain |
|
61 |
#*.PDF diff=astextplain |
|
62 |
#*.rtf diff=astextplain |
|
63 |
#*.RTF diff=astextplain |
.gitignore | ||
---|---|---|
1 |
## Ignore Visual Studio temporary files, build results, and |
|
2 |
## files generated by popular Visual Studio add-ons. |
|
3 |
|
|
4 |
# User-specific files |
|
5 |
*.suo |
|
6 |
*.user |
|
7 |
*.userosscache |
|
8 |
*.sln.docstates |
|
9 |
|
|
10 |
# User-specific files (MonoDevelop/Xamarin Studio) |
|
11 |
*.userprefs |
|
12 |
|
|
13 |
# Build results |
|
14 |
[Dd]ebug/ |
|
15 |
[Dd]ebugPublic/ |
|
16 |
[Rr]elease/ |
|
17 |
[Rr]eleases/ |
|
18 |
x64/ |
|
19 |
x86/ |
|
20 |
bld/ |
|
21 |
[Bb]in/ |
|
22 |
[Oo]bj/ |
|
23 |
[Ll]og/ |
|
24 |
|
|
25 |
# Visual Studio 2015 cache/options directory |
|
26 |
.vs/ |
|
27 |
# Uncomment if you have tasks that create the project's static files in wwwroot |
|
28 |
#wwwroot/ |
|
29 |
|
|
30 |
# MSTest test Results |
|
31 |
[Tt]est[Rr]esult*/ |
|
32 |
[Bb]uild[Ll]og.* |
|
33 |
|
|
34 |
# NUNIT |
|
35 |
*.VisualState.xml |
|
36 |
TestResult.xml |
|
37 |
|
|
38 |
# Build Results of an ATL Project |
|
39 |
[Dd]ebugPS/ |
|
40 |
[Rr]eleasePS/ |
|
41 |
dlldata.c |
|
42 |
|
|
43 |
# DNX |
|
44 |
project.lock.json |
|
45 |
project.fragment.lock.json |
|
46 |
artifacts/ |
|
47 |
|
|
48 |
*_i.c |
|
49 |
*_p.c |
|
50 |
*_i.h |
|
51 |
*.ilk |
|
52 |
*.meta |
|
53 |
*.obj |
|
54 |
*.pch |
|
55 |
*.pdb |
|
56 |
*.pgc |
|
57 |
*.pgd |
|
58 |
*.rsp |
|
59 |
*.sbr |
|
60 |
*.tlb |
|
61 |
*.tli |
|
62 |
*.tlh |
|
63 |
*.tmp |
|
64 |
*.tmp_proj |
|
65 |
*.log |
|
66 |
*.vspscc |
|
67 |
*.vssscc |
|
68 |
.builds |
|
69 |
*.pidb |
|
70 |
*.svclog |
|
71 |
*.scc |
|
72 |
|
|
73 |
# Chutzpah Test files |
|
74 |
_Chutzpah* |
|
75 |
|
|
76 |
# Visual C++ cache files |
|
77 |
ipch/ |
|
78 |
*.aps |
|
79 |
*.ncb |
|
80 |
*.opendb |
|
81 |
*.opensdf |
|
82 |
*.sdf |
|
83 |
*.cachefile |
|
84 |
*.VC.db |
|
85 |
*.VC.VC.opendb |
|
86 |
|
|
87 |
# Visual Studio profiler |
|
88 |
*.psess |
|
89 |
*.vsp |
|
90 |
*.vspx |
|
91 |
*.sap |
|
92 |
|
|
93 |
# TFS 2012 Local Workspace |
|
94 |
$tf/ |
|
95 |
|
|
96 |
# Guidance Automation Toolkit |
|
97 |
*.gpState |
|
98 |
|
|
99 |
# ReSharper is a .NET coding add-in |
|
100 |
_ReSharper*/ |
|
101 |
*.[Rr]e[Ss]harper |
|
102 |
*.DotSettings.user |
|
103 |
|
|
104 |
# JustCode is a .NET coding add-in |
|
105 |
.JustCode |
|
106 |
|
|
107 |
# TeamCity is a build add-in |
|
108 |
_TeamCity* |
|
109 |
|
|
110 |
# DotCover is a Code Coverage Tool |
|
111 |
*.dotCover |
|
112 |
|
|
113 |
# NCrunch |
|
114 |
_NCrunch_* |
|
115 |
.*crunch*.local.xml |
|
116 |
nCrunchTemp_* |
|
117 |
|
|
118 |
# MightyMoose |
|
119 |
*.mm.* |
|
120 |
AutoTest.Net/ |
|
121 |
|
|
122 |
# Web workbench (sass) |
|
123 |
.sass-cache/ |
|
124 |
|
|
125 |
# Installshield output folder |
|
126 |
[Ee]xpress/ |
|
127 |
|
|
128 |
# DocProject is a documentation generator add-in |
|
129 |
DocProject/buildhelp/ |
|
130 |
DocProject/Help/*.HxT |
|
131 |
DocProject/Help/*.HxC |
|
132 |
DocProject/Help/*.hhc |
|
133 |
DocProject/Help/*.hhk |
|
134 |
DocProject/Help/*.hhp |
|
135 |
DocProject/Help/Html2 |
|
136 |
DocProject/Help/html |
|
137 |
|
|
138 |
# Click-Once directory |
|
139 |
publish/ |
|
140 |
|
|
141 |
# Publish Web Output |
|
142 |
*.[Pp]ublish.xml |
|
143 |
*.azurePubxml |
|
144 |
# TODO: Comment the next line if you want to checkin your web deploy settings |
|
145 |
# but database connection strings (with potential passwords) will be unencrypted |
|
146 |
#*.pubxml |
|
147 |
*.publishproj |
|
148 |
|
|
149 |
# Microsoft Azure Web App publish settings. Comment the next line if you want to |
|
150 |
# checkin your Azure Web App publish settings, but sensitive information contained |
|
151 |
# in these scripts will be unencrypted |
|
152 |
PublishScripts/ |
|
153 |
|
|
154 |
# NuGet Packages |
|
155 |
*.nupkg |
|
156 |
# The packages folder can be ignored because of Package Restore |
|
157 |
**/packages/* |
|
158 |
# except build/, which is used as an MSBuild target. |
|
159 |
!**/packages/build/ |
|
160 |
# Uncomment if necessary however generally it will be regenerated when needed |
|
161 |
#!**/packages/repositories.config |
|
162 |
# NuGet v3's project.json files produces more ignoreable files |
|
163 |
*.nuget.props |
|
164 |
*.nuget.targets |
|
165 |
|
|
166 |
# Microsoft Azure Build Output |
|
167 |
csx/ |
|
168 |
*.build.csdef |
|
169 |
|
|
170 |
# Microsoft Azure Emulator |
|
171 |
ecf/ |
|
172 |
rcf/ |
|
173 |
|
|
174 |
# Windows Store app package directories and files |
|
175 |
AppPackages/ |
|
176 |
BundleArtifacts/ |
|
177 |
Package.StoreAssociation.xml |
|
178 |
_pkginfo.txt |
|
179 |
|
|
180 |
# Visual Studio cache files |
|
181 |
# files ending in .cache can be ignored |
|
182 |
*.[Cc]ache |
|
183 |
# but keep track of directories ending in .cache |
|
184 |
!*.[Cc]ache/ |
|
185 |
|
|
186 |
# Others |
|
187 |
ClientBin/ |
|
188 |
~$* |
|
189 |
*~ |
|
190 |
*.dbmdl |
|
191 |
*.dbproj.schemaview |
|
192 |
*.jfm |
|
193 |
*.pfx |
|
194 |
*.publishsettings |
|
195 |
node_modules/ |
|
196 |
orleans.codegen.cs |
|
197 |
|
|
198 |
# Since there are multiple workflows, uncomment next line to ignore bower_components |
|
199 |
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) |
|
200 |
#bower_components/ |
|
201 |
|
|
202 |
# RIA/Silverlight projects |
|
203 |
Generated_Code/ |
|
204 |
|
|
205 |
# Backup & report files from converting an old project file |
|
206 |
# to a newer Visual Studio version. Backup files are not needed, |
|
207 |
# because we have git ;-) |
|
208 |
_UpgradeReport_Files/ |
|
209 |
Backup*/ |
|
210 |
UpgradeLog*.XML |
|
211 |
UpgradeLog*.htm |
|
212 |
|
|
213 |
# SQL Server files |
|
214 |
*.mdf |
|
215 |
*.ldf |
|
216 |
|
|
217 |
# Business Intelligence projects |
|
218 |
*.rdl.data |
|
219 |
*.bim.layout |
|
220 |
*.bim_*.settings |
|
221 |
|
|
222 |
# Microsoft Fakes |
|
223 |
FakesAssemblies/ |
|
224 |
|
|
225 |
# GhostDoc plugin setting file |
|
226 |
*.GhostDoc.xml |
|
227 |
|
|
228 |
# Node.js Tools for Visual Studio |
|
229 |
.ntvs_analysis.dat |
|
230 |
|
|
231 |
# Visual Studio 6 build log |
|
232 |
*.plg |
|
233 |
|
|
234 |
# Visual Studio 6 workspace options file |
|
235 |
*.opt |
|
236 |
|
|
237 |
# Visual Studio LightSwitch build output |
|
238 |
**/*.HTMLClient/GeneratedArtifacts |
|
239 |
**/*.DesktopClient/GeneratedArtifacts |
|
240 |
**/*.DesktopClient/ModelManifest.xml |
|
241 |
**/*.Server/GeneratedArtifacts |
|
242 |
**/*.Server/ModelManifest.xml |
|
243 |
_Pvt_Extensions |
|
244 |
|
|
245 |
# Paket dependency manager |
|
246 |
.paket/paket.exe |
|
247 |
paket-files/ |
|
248 |
|
|
249 |
# FAKE - F# Make |
|
250 |
.fake/ |
|
251 |
|
|
252 |
# JetBrains Rider |
|
253 |
.idea/ |
|
254 |
*.sln.iml |
|
255 |
|
|
256 |
# CodeRush |
|
257 |
.cr/ |
|
258 |
|
|
259 |
# Python Tools for Visual Studio (PTVS) |
|
260 |
__pycache__/ |
|
261 |
*.pyc |
DTI_PID/DTI_PID.sln | ||
---|---|---|
1 |
|
|
2 |
Microsoft Visual Studio Solution File, Format Version 12.00 |
|
3 |
# Visual Studio 15 |
|
4 |
VisualStudioVersion = 15.0.26730.3 |
|
5 |
MinimumVisualStudioVersion = 10.0.40219.1 |
|
6 |
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "DTI_PID", "DTI_PID\DTI_PID.pyproj", "{7C2E55A3-2B16-4B4F-867F-F16E2EF6F2F0}" |
|
7 |
EndProject |
|
8 |
Global |
|
9 |
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
|
10 |
Debug|Any CPU = Debug|Any CPU |
|
11 |
Release|Any CPU = Release|Any CPU |
|
12 |
EndGlobalSection |
|
13 |
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
|
14 |
{7C2E55A3-2B16-4B4F-867F-F16E2EF6F2F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|
15 |
{7C2E55A3-2B16-4B4F-867F-F16E2EF6F2F0}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|
16 |
EndGlobalSection |
|
17 |
GlobalSection(SolutionProperties) = preSolution |
|
18 |
HideSolutionNode = FALSE |
|
19 |
EndGlobalSection |
|
20 |
GlobalSection(ExtensibilityGlobals) = postSolution |
|
21 |
SolutionGuid = {3D496EC3-A232-40B5-BD20-1EA3CFECD450} |
|
22 |
EndGlobalSection |
|
23 |
EndGlobal |
DTI_PID/DTI_PID/AreaOcrTestmodule.py | ||
---|---|---|
1 |
import http.client |
|
2 |
import urllib |
|
3 |
import base64 |
|
4 |
import json |
|
5 |
import cv2 |
|
6 |
import numpy as np |
|
7 |
import matplotlib.pyplot as plt |
|
8 |
import matplotlib.image as mpimg |
|
9 |
from PIL import Image |
|
10 |
from io import BytesIO |
|
11 |
import pytesseract |
|
12 |
|
|
13 |
|
|
14 |
CONST_IMG_PID_UY1_K_300DPI = "res/UY1-K-2000_P1_300dpi.png" |
|
15 |
src = [] |
|
16 |
resized = [] |
|
17 |
croppedSrc = [] |
|
18 |
eventSp = (-1, -1) |
|
19 |
eventEp = (-1, -1) |
|
20 |
cropping = False |
|
21 |
|
|
22 |
resizeFactor = 0.15 |
|
23 |
|
|
24 |
|
|
25 |
def cropSrc(event, x, y, flags, param): |
|
26 |
global src |
|
27 |
global resized, croppedSrc |
|
28 |
global eventSp, cropping |
|
29 |
global resizeFactor |
|
30 |
|
|
31 |
if event == cv2.EVENT_LBUTTONDOWN: |
|
32 |
eventSp = (-1, -1) |
|
33 |
eventEp = (-1, -1) |
|
34 |
|
|
35 |
eventSp = (x, y) |
|
36 |
cropping = True |
|
37 |
elif event == cv2.EVENT_LBUTTONUP: |
|
38 |
eventEp = (x, y) |
|
39 |
cropping = False |
|
40 |
|
|
41 |
realSrcEventSp = (int(eventSp[0]/resizeFactor), int(eventSp[1]/resizeFactor)) |
|
42 |
realSrcEventEp = (int(eventEp[0]/resizeFactor), int(eventEp[1]/resizeFactor)) |
|
43 |
croppedSrc = src[realSrcEventSp[1]:realSrcEventEp[1], realSrcEventSp[0]:realSrcEventEp[0]] |
|
44 |
kernel = np.ones((2, 2), np.uint8) |
|
45 |
croppedSrc = cv2.dilate(croppedSrc, kernel) |
|
46 |
im = Image.fromarray(croppedSrc) |
|
47 |
#ocrData = pytesseract.image_to_data(im, config='-psm 10') |
|
48 |
#ocrData = pytesseract.image_to_string(im, config='-psm 10') |
|
49 |
ocrData = pytesseract.image_to_boxes(im, config='-c tessedit_char_whitelist="-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" -psm 6') |
|
50 |
#ocrData = pytesseract.image_to_data(im, config='-c tessedit_char_whitelist=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz -psm 6') |
|
51 |
#ocrData = pytesseract.image_to_string(im, config = "hocr") |
|
52 |
print("tesseract result : \n" + ocrData) |
|
53 |
|
|
54 |
#### For image_to_data() |
|
55 |
#if ocrData: |
|
56 |
# splitOcrData = ocrData.split('\n') |
|
57 |
# size = len(splitOcrData) |
|
58 |
# i = 1 |
|
59 |
# while i < size: |
|
60 |
# data = splitOcrData[i] |
|
61 |
# sData = data.split('\t') |
|
62 |
# if len(sData) == 12: |
|
63 |
# text = sData[11] |
|
64 |
# tx = int(sData[6]) // 2 |
|
65 |
# ty = int(sData[7]) // 2 |
|
66 |
# tw = int(sData[8]) // 2 |
|
67 |
# th = int(sData[9]) // 2 |
|
68 |
# #realSp = (symbolSp[0]+tx, symbolSp[1]+ty) |
|
69 |
# #cv2.putText(canvas, text, (realSp[0], realSp[1]+th), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 3) |
|
70 |
# i = i+1 |
|
71 |
|
|
72 |
|
|
73 |
## For image_to_boxes() |
|
74 |
if ocrData: |
|
75 |
splitOcrData = ocrData.split('\n') |
|
76 |
for data in splitOcrData: |
|
77 |
sData = data.split(' ') |
|
78 |
text = sData[0] |
|
79 |
tx = int(sData[1]) |
|
80 |
ty = int(sData[2]) |
|
81 |
tex = int(sData[3]) |
|
82 |
tey = int(sData[4]) |
|
83 |
tw = tex - tx |
|
84 |
th = tey - ty |
|
85 |
#realSp = (symbolSp[0]+tx, symbolSp[1]+ty) |
|
86 |
#cv2.putText(canvas, text, (realSp[0], realSp[1]+th), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 3) |
|
87 |
|
|
88 |
cv2.imshow('cropped', croppedSrc) |
|
89 |
cv2.waitKey(0) |
|
90 |
|
|
91 |
|
|
92 |
def main(): |
|
93 |
global src |
|
94 |
global resized, resizeFactor |
|
95 |
print('main') |
|
96 |
src = cv2.imread(CONST_IMG_PID_UY1_K_300DPI) |
|
97 |
|
|
98 |
resized = cv2.resize(src, None, fx=resizeFactor, fy=resizeFactor) |
|
99 |
cv2.namedWindow('main') |
|
100 |
cv2.setMouseCallback('main', cropSrc) |
|
101 |
cv2.imshow('main', resized) |
|
102 |
cv2.waitKey(0) |
|
103 |
|
|
104 |
|
|
105 |
main() |
DTI_PID/DTI_PID/DTI_PID.py | ||
---|---|---|
1 |
#region import libs |
|
2 |
##import httplib |
|
3 |
import http.client |
|
4 |
import urllib, base64, json |
|
5 |
import cv2 |
|
6 |
import numpy as np |
|
7 |
import matplotlib.pyplot as plt |
|
8 |
import matplotlib.image as mpimg |
|
9 |
import SymbolBase |
|
10 |
import symbol |
|
11 |
import azure_ocr_module as OCR |
|
12 |
import azure_handwrite_ocr_module as HOCR |
|
13 |
import imutils |
|
14 |
from PIL import Image |
|
15 |
from PIL import ImageTk |
|
16 |
from PIL import ImageChops |
|
17 |
from io import BytesIO |
|
18 |
from functools import partial |
|
19 |
from functools import reduce |
|
20 |
import gc |
|
21 |
import os |
|
22 |
import glob |
|
23 |
import timeit |
|
24 |
import scipy |
|
25 |
import math, operator |
|
26 |
import threading |
|
27 |
import concurrent.futures as futures |
|
28 |
import XmlGenerator as xg |
|
29 |
import sqlite3 |
|
30 |
import pytesseract |
|
31 |
#endregion |
|
32 |
|
|
33 |
## Tesseract path |
|
34 |
pytesseract.pytesseract.tesseract_cmd = 'D:\\Program Files\\Tesseract-OCR\\tesseract.exe' |
|
35 |
tesseract_cmd = 'D:\\Program Files\\Tesseract-OCR\\tesseract.exe' |
|
36 |
|
|
37 |
#region Image path for test |
|
38 |
CONST_IMG_PID_UY1_K_300DPI = "res/UY1-K-2000_P1_300dpi.png" |
|
39 |
CONST_IMG_PID_UY1_K_2005G_300DPI = "res/UY1-K-2005G_P1_300dpi_black.png" |
|
40 |
CONST_IMG_PID_UY1_K_2006_300DPI = "res/UY1-K-2006_P1_300dpi_black.png" |
|
41 |
CONST_IMG_PID_UY1_K_2007_300DPI = "res/UY1-K-2007_P1_300dpi_black.png" |
|
42 |
#endregion |
|
43 |
|
|
44 |
#region Image path List for test |
|
45 |
targetSymbolList = [] |
|
46 |
#endregion |
|
47 |
|
|
48 |
#region Global variables |
|
49 |
searchedSymbolList = [] |
|
50 |
src = [] |
|
51 |
srcGray = [] |
|
52 |
ocrCompletedSrc = [] |
|
53 |
afterDenoising = [] |
|
54 |
canvas = [] |
|
55 |
WHITE_LIST_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-" |
|
56 |
|
|
57 |
#DB_NAME = "db/DTI_PID_test.db" |
|
58 |
DB_NAME = "db/DTI_PID.db" |
|
59 |
|
|
60 |
THREAD_MAX_WORKER = 4 |
|
61 |
threadLock = threading.Lock() |
|
62 |
|
|
63 |
ACCEPT_OVERLAY_AREA = 10 |
|
64 |
#endregion |
|
65 |
|
|
66 |
|
|
67 |
#Convert into Grayscale image |
|
68 |
def cvtGrayImage(img): |
|
69 |
return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
|
70 |
|
|
71 |
|
|
72 |
#Check object contains pt |
|
73 |
#obj is item in searchedSymbolList |
|
74 |
def contains(obj, pt, tw, th): |
|
75 |
sp = obj.getSp() |
|
76 |
width = obj.getWidth() |
|
77 |
height = obj.getHeight() |
|
78 |
|
|
79 |
if sp[0] > pt[0]+tw: |
|
80 |
return 0 |
|
81 |
if sp[0]+width < pt[0]: |
|
82 |
return 0 |
|
83 |
if sp[1] > pt[1]+th: |
|
84 |
return 0 |
|
85 |
if sp[1]+height < pt[1]: |
|
86 |
return 0 |
|
87 |
|
|
88 |
#shared area |
|
89 |
x = max(sp[0], pt[0]); |
|
90 |
y = max(sp[1], pt[1]); |
|
91 |
w = min(sp[0] + width, pt[0] + tw) - x; |
|
92 |
h = min(sp[1] + height, pt[1] + th) - y; |
|
93 |
|
|
94 |
return float((w * h)) / float((tw * th)) * 100 |
|
95 |
|
|
96 |
|
|
97 |
#Add symbols |
|
98 |
def addSearchedSymbol(id, sCategory, sClass, sType, sItem, symbolPath, pt, w, h, threshold, minMatchCount, mpCount, rotatedAngle, isDetectOnOrigin, rotateCount, ocrOption): |
|
99 |
global searchedSymbolList |
|
100 |
newSym = symbol.Symbol(id, sCategory, sClass, sType, sItem, symbolPath, pt, w, h, threshold, minMatchCount, mpCount, rotatedAngle, isDetectOnOrigin, rotateCount, ocrOption) |
|
101 |
searchedSymbolList.append(newSym) |
|
102 |
|
|
103 |
|
|
104 |
#Calculate count of keypoint match result |
|
105 |
def getMatchPointCount(src, cmp): |
|
106 |
orb = cv2.ORB_create(1000, 2.0, 2, 1) |
|
107 |
|
|
108 |
kp1, des1 = orb.detectAndCompute(src, None) |
|
109 |
kp2, des2 = orb.detectAndCompute(cmp, None) |
|
110 |
|
|
111 |
FLANN_INDEX_LSH = 6 |
|
112 |
# table_number : The number of hash tables use |
|
113 |
# key_size : The length of the key in the hash tables |
|
114 |
# multi_probe_level : Number of levels to use in multi-probe (0 for standard LSH) |
|
115 |
# It controls how neighboring buckets are searched |
|
116 |
# Recommended value is 2 |
|
117 |
# checks : specifies the maximum leafs to visit when searching for neighbours. |
|
118 |
# LSH : Locality-Sensitive Hashing |
|
119 |
# ref : https://www.cs.ubc.ca/research/flann/uploads/FLANN/flann_manual-1.8.4.pdf |
|
120 |
index_params = dict(algorithm = FLANN_INDEX_LSH, table_number = 20, key_size = 10, multi_probe_level = 4) |
|
121 |
search_params = dict(checks = 100) |
|
122 |
|
|
123 |
flann = cv2.FlannBasedMatcher(index_params,search_params) |
|
124 |
|
|
125 |
matches = flann.knnMatch(des1, des2, k = 2) |
|
126 |
#matchesMask = [[0, 0] for i in xrange(len(matches))] #Python 2.x |
|
127 |
matchesMask = [[0, 0] for i in range(len(matches))] #Python 3.x |
|
128 |
|
|
129 |
count = 0 |
|
130 |
# ratio test as per Lowe's paper |
|
131 |
for i in range(len(matches)): |
|
132 |
if len(matches[i]) == 2: |
|
133 |
m = matches[i][0] |
|
134 |
n = matches[i][1] |
|
135 |
if m.distance < 0.85 * n.distance: |
|
136 |
count = count + 1 |
|
137 |
|
|
138 |
matchCount = count |
|
139 |
|
|
140 |
print("match Count : " + str(matchCount)) |
|
141 |
return matchCount |
|
142 |
|
|
143 |
|
|
144 |
#detect symbols on PID |
|
145 |
def detectSymbolsOnPid(mainRes, targetSymbols): |
|
146 |
for detailTarget in targetSymbols: |
|
147 |
detectSymbolOnPid(mainRes, detailTarget) |
|
148 |
|
|
149 |
|
|
150 |
#detect symbol on PID |
|
151 |
def detectSymbolOnPid(mainRes, targetSymbol): |
|
152 |
global src |
|
153 |
global srcGray |
|
154 |
global ocrCompletedSrc |
|
155 |
global afterDenoising |
|
156 |
global threadLock |
|
157 |
|
|
158 |
symId = targetSymbol.getId() |
|
159 |
symbolName = targetSymbol.getName() |
|
160 |
symbolClass = targetSymbol.getClass() |
|
161 |
symbolType = targetSymbol.getType() |
|
162 |
symbolItem = targetSymbol.getItem() |
|
163 |
symbolPath = targetSymbol.getPath() |
|
164 |
symbolThreshold = targetSymbol.getThreshold() |
|
165 |
symbolMinMatchCount = targetSymbol.getMinMatchCount() |
|
166 |
isDetectOnOrigin = targetSymbol.getIsDetectOnOrigin() |
|
167 |
symbolRotateCount = targetSymbol.getRotationCount() |
|
168 |
symbolOcrOption = targetSymbol.getOcrOption() |
|
169 |
|
|
170 |
print('current symbol : ' + symbolPath) |
|
171 |
|
|
172 |
foundSymbolCount = 0 |
|
173 |
|
|
174 |
sym = cv2.imread(symbolPath, 1) |
|
175 |
symGray = cvtGrayImage(sym) |
|
176 |
|
|
177 |
if isDetectOnOrigin == True: |
|
178 |
copiedBasePid = srcGray.copy() |
|
179 |
else: |
|
180 |
copiedBasePid = ocrCompletedSrc.copy() |
|
181 |
|
|
182 |
|
|
183 |
srcWidth, srcHeight = copiedBasePid.shape[::-1] |
|
184 |
|
|
185 |
|
|
186 |
if srcWidth > 10000 or srcHeight > 10000: |
|
187 |
splitCount = 2 ## splitCount = 2^n |
|
188 |
else: |
|
189 |
splitCount = 1 |
|
190 |
|
|
191 |
|
|
192 |
roiSp = (0, 0) |
|
193 |
roiEp = (0, 0) |
|
194 |
totalMpCount = 0 |
|
195 |
while splitCount >= 1: |
|
196 |
splitWidth = srcWidth // splitCount |
|
197 |
splitHeight = srcHeight // splitCount |
|
198 |
|
|
199 |
##Setting ROI List - [splitCount * splitCount] size |
|
200 |
splitRoiList = [] |
|
201 |
for hi in range(splitCount): |
|
202 |
for wi in range(splitCount): |
|
203 |
roiSp = (srcWidth*wi//splitCount, srcHeight*hi//splitCount) |
|
204 |
roiEp = (srcWidth*(wi+1)//splitCount, srcHeight*(hi+1)//splitCount) |
|
205 |
splitRoiList.append((roiSp, roiEp, copiedBasePid[roiSp[1]:roiEp[1], roiSp[0]:roiEp[0]])) |
|
206 |
|
|
207 |
for roiIndex in range(len(splitRoiList)): |
|
208 |
roiItemSp = splitRoiList[roiIndex][0] |
|
209 |
roiItemEp = splitRoiList[roiIndex][1] |
|
210 |
roiItem = splitRoiList[roiIndex][2] |
|
211 |
rotatedAngle = 0 |
|
212 |
|
|
213 |
for rc in range(symbolRotateCount): |
|
214 |
##Template Matching |
|
215 |
sw, sh = symGray.shape[::-1] |
|
216 |
roiw = (roiItemEp[0] - roiItemSp[0]) |
|
217 |
roih = (roiItemEp[1] - roiItemSp[1]) |
|
218 |
|
|
219 |
## Case : Bigger Symbol than Split ROI |
|
220 |
if roiw < sw or roih < sh: |
|
221 |
symGray = cv2.rotate(symGray, cv2.ROTATE_90_CLOCKWISE) |
|
222 |
rotatedAngle = rotatedAngle + 90 |
|
223 |
continue |
|
224 |
|
|
225 |
## Template Matching |
|
226 |
tmRes = cv2.matchTemplate(roiItem, symGray, cv2.TM_CCOEFF_NORMED) |
|
227 |
loc = np.where(tmRes >= symbolThreshold) |
|
228 |
|
|
229 |
for pt in zip(*loc[::-1]): |
|
230 |
overlapArea = 0 |
|
231 |
mpCount = 0 # Match Point Count |
|
232 |
symbolIndex = -1 |
|
233 |
|
|
234 |
searchedItemSp = (roiItemSp[0]+pt[0], roiItemSp[1]+pt[1]) |
|
235 |
|
|
236 |
for i in range(len(searchedSymbolList)): |
|
237 |
overlapArea = contains(searchedSymbolList[i], searchedItemSp, sw, sh) |
|
238 |
#print("OverlapArea : " + str(overlapArea)) |
|
239 |
if overlapArea > ACCEPT_OVERLAY_AREA: |
|
240 |
symbolIndex = i |
|
241 |
break |
|
242 |
|
|
243 |
|
|
244 |
roi = roiItem[pt[1]:pt[1]+sh, pt[0]:pt[0]+sw] |
|
245 |
mpCount = getMatchPointCount(roi, symGray) |
|
246 |
if overlapArea <= ACCEPT_OVERLAY_AREA: |
|
247 |
if mpCount >= symbolMinMatchCount: |
|
248 |
foundSymbolCount = foundSymbolCount + 1 |
|
249 |
totalMpCount = totalMpCount + mpCount |
|
250 |
threadLock.acquire() |
|
251 |
addSearchedSymbol(symId, symbolName, symbolClass, symbolType, symbolItem |
|
252 |
, symbolPath, searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount |
|
253 |
, mpCount, rotatedAngle, isDetectOnOrigin, symbolRotateCount, symbolOcrOption) |
|
254 |
#print('symbol added') |
|
255 |
threadLock.release() |
|
256 |
else: |
|
257 |
if symbolIndex != -1 and symbolIndex < len(searchedSymbolList): |
|
258 |
symbolMpCount = searchedSymbolList[symbolIndex].getMpCount() |
|
259 |
if symbolMpCount < mpCount: |
|
260 |
threadLock.acquire() |
|
261 |
totalMpCount = totalMpCount - symbolMpCount + mpCount |
|
262 |
searchedSymbolList[symbolIndex] = symbol.Symbol(symId, symbolName, symbolClass, symbolType, symbolItem |
|
263 |
, symbolPath, searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount |
|
264 |
, mpCount, rotatedAngle, isDetectOnOrigin, symbolRotateCount, symbolOcrOption) |
|
265 |
#print('symbol changed') |
|
266 |
threadLock.release() |
|
267 |
|
|
268 |
## Rotate Symbol |
|
269 |
symGray = cv2.rotate(symGray, cv2.ROTATE_90_CLOCKWISE) |
|
270 |
rotatedAngle = rotatedAngle + 90 |
|
271 |
|
|
272 |
splitCount = splitCount // 2 |
|
273 |
|
|
274 |
avgMpCount = 0 |
|
275 |
if foundSymbolCount != 0: |
|
276 |
avgMpCount = totalMpCount / foundSymbolCount |
|
277 |
|
|
278 |
|
|
279 |
threadLock.acquire() |
|
280 |
srcName = mainRes.split("/")[-1] |
|
281 |
srcName = srcName.replace(".png", "") |
|
282 |
print('finish symbol(count) / AvgMpCount : ' + symbolPath + '(' + str(foundSymbolCount) + ') / avgMpCount : ' + str(avgMpCount)) |
|
283 |
f = open("res/Result/result_"+srcName+"_600dpi.txt", 'a+') |
|
284 |
data = 'symbolName - (count) : ' + symbolPath + ' - (' + str(foundSymbolCount) + ') / avgMpCount : '+str(avgMpCount)+'\n' |
|
285 |
f.write(data) |
|
286 |
f.close() |
|
287 |
threadLock.release() |
|
288 |
|
|
289 |
|
|
290 |
def drawRectOnSrc(sym): |
|
291 |
path = sym.getPath() |
|
292 |
sp = sym.getSp() |
|
293 |
sw = sym.getWidth() |
|
294 |
sh = sym.getHeight() |
|
295 |
sAngle = sym.getRotatedAngle() |
|
296 |
symImg = cv2.imread(path) |
|
297 |
symImg = cvtGrayImage(symImg) |
|
298 |
|
|
299 |
for i in range(sAngle//90): |
|
300 |
symImg = cv2.rotate(symImg, cv2.ROTATE_90_CLOCKWISE) |
|
301 |
|
|
302 |
temp = [] |
|
303 |
temp = srcGray[sp[1]:sp[1]+sh, sp[0]:sp[0]+sw] |
|
304 |
tempBin = cv2.bitwise_not(temp) |
|
305 |
result = cv2.bitwise_xor(symImg, tempBin) |
|
306 |
name = sym.getPath() |
|
307 |
#if "L01" in name: |
|
308 |
# cv2.imshow('symImg', symImg) |
|
309 |
# cv2.imshow('srcGrayRoi', srcGray[sp[1]:sp[1]+sh, sp[0]:sp[0]+sw]) |
|
310 |
# cv2.imshow('temp', temp) |
|
311 |
# cv2.imshow('tempBin', tempBin) |
|
312 |
# cv2.imshow('result', result) |
|
313 |
# cv2.waitKey(0) |
|
314 |
srcGray[sp[1]:sp[1]+sh, sp[0]:sp[0]+sw] = result |
|
315 |
ocrCompletedSrc[sp[1]:sp[1]+sh, sp[0]:sp[0]+sw] = result |
|
316 |
|
|
317 |
cv2.rectangle(src, sp, (sp[0]+sw, sp[1]+sh), (0, 0, 255), 2) |
|
318 |
|
|
319 |
def drawFoundSymbols(symbol): |
|
320 |
global src |
|
321 |
global canvas |
|
322 |
global WHITE_LIST_CHARS |
|
323 |
|
|
324 |
symbolPath = symbol.getPath() |
|
325 |
symbolSp = symbol.getSp() |
|
326 |
symbolWidth = symbol.getWidth() |
|
327 |
symbolHeight = symbol.getHeight() |
|
328 |
symbolRotatedAngle = symbol.getRotatedAngle() |
|
329 |
symbolOcrOption = symbol.getOcrOption() |
|
330 |
|
|
331 |
symImg = cv2.imread(symbolPath, 1) |
|
332 |
for i in range(symbolRotatedAngle//90): |
|
333 |
symImg = cv2.rotate(symImg, cv2.ROTATE_90_CLOCKWISE) |
|
334 |
|
|
335 |
|
|
336 |
chan, w, h = symImg.shape[::-1] |
|
337 |
canvas[symbolSp[1]:symbolSp[1]+h, symbolSp[0]:symbolSp[0]+w] = cv2.bitwise_and(canvas[symbolSp[1]:symbolSp[1]+h, symbolSp[0]:symbolSp[0]+w], symImg) |
|
338 |
|
|
339 |
|
|
340 |
if symbolOcrOption == SymbolBase.OCR_OPTION_ALL_FIND or symbolOcrOption == SymbolBase.OCR_OPTION_HALF_AND_HALF: |
|
341 |
if symbolOcrOption == SymbolBase.OCR_OPTION_HALF_AND_HALF: |
|
342 |
inSqWidth = int(((w//2) * math.cos(round(math.radians(45), 2)))) * 2 |
|
343 |
inSqHeight = int(((h//2) * math.sin(round(math.radians(45), 2)))) * 2 |
|
344 |
inSqX = w//2 - (inSqWidth//2) |
|
345 |
inSqY = h//2 - (inSqHeight//2) |
|
346 |
else: |
|
347 |
inSqWidth = w |
|
348 |
inSqHeight = h |
|
349 |
inSqX = 0 |
|
350 |
inSqY = 0 |
|
351 |
|
|
352 |
roi = src[symbolSp[1]:symbolSp[1]+h, symbolSp[0]:symbolSp[0]+w] |
|
353 |
srcRoi = roi[inSqY:inSqY+inSqHeight, inSqX:inSqX+inSqWidth] |
|
354 |
symRev = cv2.bitwise_not(symImg[inSqY:inSqY+inSqHeight, inSqX:inSqX+inSqWidth]) |
|
355 |
bitImg = cv2.bitwise_or(srcRoi, symRev) |
|
356 |
|
|
357 |
kernel1 = np.ones((2, 2), np.uint8) |
|
358 |
bitImg = cv2.dilate(bitImg, kernel1) |
|
359 |
#kernel2 = np.ones((1, 1), np.uint8) |
|
360 |
#bitImg = cv2.erode(bitImg, kernel2) |
|
361 |
|
|
362 |
bitImg = cv2.resize(bitImg, None, fx = 2.0, fy = 2.0) |
|
363 |
|
|
364 |
im = Image.fromarray(bitImg) |
|
365 |
|
|
366 |
#im = Image.fromarray(src[symbolSp[1]:symbolSp[1]+h, symbolSp[0]:symbolSp[0]+w]) |
|
367 |
ocrData = pytesseract.image_to_boxes(im, config='-c tessedit_char_whitelist="-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" -psm 6') |
|
368 |
#ocrData = pytesseract.image_to_data(im) |
|
369 |
#ocrData = pytesseract.image_to_string(im, config = "hocr") |
|
370 |
print("tesseract result : \n" + ocrData) |
|
371 |
|
|
372 |
### For image_to_data() |
|
373 |
#if ocrData: |
|
374 |
# splitOcrData = ocrData.split('\n') |
|
375 |
# size = len(splitOcrData) |
|
376 |
# i = 1 |
|
377 |
# while i < size: |
|
378 |
# data = splitOcrData[i] |
|
379 |
# threadLock.acquire() |
|
380 |
# sData = data.split('\t') |
|
381 |
# if len(sData) == 12: |
|
382 |
# text = sData[11] |
|
383 |
# tx = int(sData[6]) // 2 |
|
384 |
# ty = int(sData[7]) // 2 |
|
385 |
# tw = int(sData[8]) // 2 |
|
386 |
# th = int(sData[9]) // 2 |
|
387 |
# realSp = (symbolSp[0]+tx, symbolSp[1]+ty) |
|
388 |
# cv2.putText(canvas, text, (realSp[0], realSp[1]+th), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 3) |
|
389 |
# threadLock.release() |
|
390 |
# i = i+1 |
|
391 |
|
|
392 |
### For image_to_boxes() |
|
393 |
if ocrData: |
|
394 |
splitOcrData = ocrData.split('\n') |
|
395 |
tList = [] |
|
396 |
lastCoord = (-1, -1) # Top-Right Coord |
|
397 |
tText = [] |
|
398 |
ftSp = (-1, -1) |
|
399 |
threadLock.acquire() |
|
400 |
for data in splitOcrData: |
|
401 |
sData = data.split(' ') |
|
402 |
text = sData[0] |
|
403 |
tsx = int(sData[1]) // 2 |
|
404 |
tsy = int(sData[2]) // 2 |
|
405 |
tex = int(sData[3]) // 2 |
|
406 |
tey = int(sData[4]) // 2 |
|
407 |
tw = tex - tsx |
|
408 |
th = tey - tsy |
|
409 |
|
|
410 |
MIN_TEXT_SIZE = 10 |
|
411 |
if WHITE_LIST_CHARS.find(text) >= 0: |
|
412 |
if tw >= MIN_TEXT_SIZE or th >= MIN_TEXT_SIZE: |
|
413 |
if lastCoord == (-1, -1): |
|
414 |
tText.append(text) |
|
415 |
ftSp = (tsx, tsy) |
|
416 |
else: |
|
417 |
COORD_ADJUSTMENT = 15 |
|
418 |
if (abs(lastCoord[1] - tsy) <= COORD_ADJUSTMENT and lastCoord[0] >= tsx - COORD_ADJUSTMENT and lastCoord[0] <= tsx + COORD_ADJUSTMENT) or (abs(lastCoord[0] - tsx) <= COORD_ADJUSTMENT and lastCoord[1] >= tsy - COORD_ADJUSTMENT and lastCoord[1] <= tsy + COORD_ADJUSTMENT): |
|
419 |
tText.append(text) |
|
420 |
else: |
|
421 |
if symbolOcrOption == SymbolBase.OCR_OPTION_ALL_FIND: |
|
422 |
tText.append(',') |
|
423 |
tText.append(text) |
|
424 |
|
|
425 |
lastCoord = (tex, tsy) # Top-Right Coord |
|
426 |
|
|
427 |
realSp = (symbolSp[0]+inSqX+ftSp[0], symbolSp[1]+inSqY+ftSp[1]) |
|
428 |
resultText = ''.join(tText) |
|
429 |
cv2.putText(canvas, resultText, (realSp[0], realSp[1]+th), 2, 1.0, (0, 0, 0)) # cv2.FONT_HERSHEY_SIMPLEX |
|
430 |
|
|
431 |
# text value in symbol object update |
|
432 |
index = [i for i, item in enumerate(searchedSymbolList) if item.getSp() == symbolSp] |
|
433 |
if len(index) > 0: |
|
434 |
searchedSymbolList[index[0]].setText(resultText) |
|
435 |
threadLock.release() |
|
436 |
|
|
437 |
|
|
438 |
def drawFoundSymbolsOnCanvas(mainRes, width, height): |
|
439 |
global src |
|
440 |
global srcGray |
|
441 |
global ocrCompletedSrc |
|
442 |
global searchedSymbolList |
|
443 |
global canvas |
|
444 |
canvas = np.zeros((height, width, 3), np.uint8) |
|
445 |
canvas[::] = (255, 255, 255) |
|
446 |
|
|
447 |
|
|
448 |
#pool = futures.ThreadPoolExecutor(max_workers = THREAD_MAX_WORKER) |
|
449 |
for symbol in searchedSymbolList: |
|
450 |
#pool.submit(drawFoundSymbols, symbol) |
|
451 |
drawFoundSymbols(symbol) |
|
452 |
#pool.shutdown(wait = True) |
|
453 |
|
|
454 |
|
|
455 |
srcName = mainRes.split("/")[-1] |
|
456 |
srcName = srcName.replace(".png", "") |
|
457 |
cv2.imwrite('res/Result/result_moved_'+srcName+'_600dpi.png', canvas) |
|
458 |
|
|
459 |
|
|
460 |
|
|
461 |
|
|
462 |
|
|
463 |
#Generate target symbol data list |
|
464 |
def initTargetSymbolDataList(): |
|
465 |
############ region SQLite |
|
466 |
conn = sqlite3.connect(DB_NAME) |
|
467 |
cursor = conn.cursor() |
|
468 |
sql = 'SELECT * FROM Symbol' |
|
469 |
cursor.execute(sql) |
|
470 |
rows = cursor.fetchall() |
|
471 |
dict = {} |
|
472 |
|
|
473 |
## Init Symbol Data from SQLite |
|
474 |
for row in rows: |
|
475 |
symId = row[0] // 100 # symId |
|
476 |
if symId in dict: |
|
477 |
dict[symId].append(symbol.SymbolBase(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10])) |
|
478 |
else: |
|
479 |
symGroup = [] |
|
480 |
symGroup.append(symbol.SymbolBase(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10])) |
|
481 |
dict[symId] = symGroup |
|
482 |
conn.close() |
|
483 |
|
|
484 |
## Sort each symbol list by symbol id |
|
485 |
for k, v in dict.items(): |
|
486 |
dict[k] = sorted(v, key=lambda symbol:symbol.id) |
|
487 |
|
|
488 |
## Insert each symbol list into targetSymbolList |
|
489 |
for sym in list(dict.values()): |
|
490 |
targetSymbolList.append(sym) |
|
491 |
############ endregion SQLite |
|
492 |
|
|
493 |
return targetSymbolList |
|
494 |
|
|
495 |
|
|
496 |
def initMainSrc(mainRes): |
|
497 |
global src |
|
498 |
global srcGray |
|
499 |
global ocrCompletedSrc |
|
500 |
|
|
501 |
#load original src & symbol |
|
502 |
src = cv2.imread(mainRes, 1) |
|
503 |
|
|
504 |
#gray scale |
|
505 |
if len(src.shape) == 3: |
|
506 |
srcGray = cvtGrayImage(src) |
|
507 |
else: |
|
508 |
srcGray = src.copy() |
|
509 |
#srcGray = src |
|
510 |
ocrCompletedSrc = OCR.removeTextFromNpArray(srcGray) |
|
511 |
|
|
512 |
|
|
513 |
#Main function |
|
514 |
def main(): |
|
515 |
global src |
|
516 |
global srcGray |
|
517 |
global ocrCompletedSrc |
|
518 |
global searchedSymbolList |
|
519 |
global threadLock |
|
520 |
|
|
521 |
#srcList = [CONST_IMG_PID_UY1_K_2006_300DPI] |
|
522 |
srcList = [CONST_IMG_PID_UY1_K_300DPI] |
|
523 |
#srcList = [CONST_IMG_PID_UY1_K_2005G_300DPI, CONST_IMG_PID_UY1_K_2007_300DPI] |
|
524 |
#srcList = [CONST_IMG_PID_UY1_K_300DPI, CONST_IMG_PID_UY1_K_2005G_300DPI, CONST_IMG_PID_UY1_K_2006_300DPI, CONST_IMG_PID_UY1_K_2007_300DPI] |
|
525 |
|
|
526 |
initTargetSymbolDataList() |
|
527 |
|
|
528 |
for mainRes in srcList: |
|
529 |
#Init src |
|
530 |
src = [] |
|
531 |
srcGray = [] |
|
532 |
ocrCompletedSrc = [] |
|
533 |
searchedSymbolList = [] |
|
534 |
|
|
535 |
start = timeit.default_timer() |
|
536 |
|
|
537 |
initMainSrc(mainRes) |
|
538 |
|
|
539 |
print("######### Ready : " + mainRes) |
|
540 |
|
|
541 |
#threadLock = threading.Lock() |
|
542 |
pool = futures.ThreadPoolExecutor(max_workers = THREAD_MAX_WORKER) |
|
543 |
for targetItem in targetSymbolList: |
|
544 |
if type(targetItem).__name__ == 'list': |
|
545 |
#detectSymbolsOnPid(mainRes, target) |
|
546 |
pool.submit(detectSymbolsOnPid, mainRes, targetItem) |
|
547 |
else: |
|
548 |
#detectSymbolOnPid(mainRes, target) |
|
549 |
pool.submit(detectSymbolOnPid, mainRes, targetItem) |
|
550 |
|
|
551 |
pool.shutdown(wait = True) |
|
552 |
|
|
553 |
|
|
554 |
chan, srcWidth, srcHeight = src.shape[::-1] |
|
555 |
drawFoundSymbolsOnCanvas(mainRes, srcWidth, srcHeight) |
|
556 |
|
|
557 |
srcGray = OCR.removeTextFromNpArray(srcGray) |
|
558 |
|
|
559 |
srcName = mainRes.split("/")[-1] |
|
560 |
srcName = srcName.replace(".png", "") |
|
561 |
|
|
562 |
stop = timeit.default_timer() |
|
563 |
seconds = stop - start |
|
564 |
f = open("res/Result/result_"+srcName+"_600dpi.txt", 'a+') |
|
565 |
data = "Running Time : " + str(seconds / 60) + "min\n" |
|
566 |
f.write(data) |
|
567 |
f.close() |
|
568 |
print("\nRunning Time : " + str(seconds / 60) + "min\n") |
|
569 |
|
|
570 |
|
|
571 |
pool = futures.ThreadPoolExecutor(max_workers = THREAD_MAX_WORKER) |
|
572 |
for sym in searchedSymbolList: |
|
573 |
threadLock.acquire() |
|
574 |
pool.submit(drawRectOnSrc, sym) |
|
575 |
#drawRectOnSrc() |
|
576 |
threadLock.release() |
|
577 |
pool.shutdown(wait = True) |
|
578 |
|
|
579 |
print("Searched symbol count : " + str(len(searchedSymbolList))) |
|
580 |
|
|
581 |
cv2.imwrite("res/Result/result_fslo_"+srcName+"_600dpi.png", srcGray) |
|
582 |
cv2.imwrite("res/Result/result_fslo_rect_"+srcName+"_600dpi.png", src) |
|
583 |
|
|
584 |
xg.writeXml(srcName, srcWidth, srcHeight, searchedSymbolList) |
|
585 |
|
|
586 |
b, g, r = cv2.split(src) |
|
587 |
pltSrc = cv2.merge([r, g, b]) |
|
588 |
|
|
589 |
plt.imshow(pltSrc) |
|
590 |
plt.imshow(cv2.cvtColor(srcGray, cv2.COLOR_GRAY2RGB)) |
|
591 |
plt.show() |
|
592 |
|
|
593 |
while True: |
|
594 |
k = cv2.waitKey(0) |
|
595 |
if k == 27: |
|
596 |
cv2.destroyAllWindows() |
|
597 |
break |
|
598 |
elif k == 'r': |
|
599 |
print('result') |
|
600 |
break; |
|
601 |
|
|
602 |
|
|
603 |
#region Program start |
|
604 |
main() |
|
605 |
#endregion |
DTI_PID/DTI_PID/DTI_PID.pyproj | ||
---|---|---|
1 |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> |
|
2 |
<PropertyGroup> |
|
3 |
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|
4 |
<SchemaVersion>2.0</SchemaVersion> |
|
5 |
<ProjectGuid>7c2e55a3-2b16-4b4f-867f-f16e2ef6f2f0</ProjectGuid> |
|
6 |
<ProjectHome>.</ProjectHome> |
|
7 |
<StartupFile>DTI_PID.py</StartupFile> |
|
8 |
<SearchPath> |
|
9 |
</SearchPath> |
|
10 |
<WorkingDirectory>.</WorkingDirectory> |
|
11 |
<OutputPath>.</OutputPath> |
|
12 |
<Name>DTI_PID</Name> |
|
13 |
<RootNamespace>DTI_PID</RootNamespace> |
|
14 |
</PropertyGroup> |
|
15 |
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> |
|
16 |
<DebugSymbols>true</DebugSymbols> |
|
17 |
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging> |
|
18 |
</PropertyGroup> |
|
19 |
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> |
|
20 |
<DebugSymbols>true</DebugSymbols> |
|
21 |
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging> |
|
22 |
</PropertyGroup> |
|
23 |
<ItemGroup> |
|
24 |
<Compile Include="AreaOcrTestmodule.py"> |
|
25 |
<SubType>Code</SubType> |
|
26 |
</Compile> |
|
27 |
<Compile Include="azure_handwrite_ocr_module.py"> |
|
28 |
<SubType>Code</SubType> |
|
29 |
</Compile> |
|
30 |
<Compile Include="azure_ocr_module.py"> |
|
31 |
<SubType>Code</SubType> |
|
32 |
</Compile> |
|
33 |
<Compile Include="DTI_PID.py" /> |
|
34 |
<Compile Include="symbol.py"> |
|
35 |
<SubType>Code</SubType> |
|
36 |
</Compile> |
|
37 |
<Compile Include="SymbolBase.py"> |
|
38 |
<SubType>Code</SubType> |
|
39 |
</Compile> |
|
40 |
<Compile Include="XmlGenerator.py"> |
|
41 |
<SubType>Code</SubType> |
|
42 |
</Compile> |
|
43 |
</ItemGroup> |
|
44 |
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets" /> |
|
45 |
<!-- Uncomment the CoreCompile target to enable the Build command in |
|
46 |
Visual Studio and specify your pre- and post-build commands in |
|
47 |
the BeforeBuild and AfterBuild targets below. --> |
|
48 |
<!--<Target Name="CoreCompile" />--> |
|
49 |
<Target Name="BeforeBuild"> |
|
50 |
</Target> |
|
51 |
<Target Name="AfterBuild"> |
|
52 |
</Target> |
|
53 |
</Project> |
DTI_PID/DTI_PID/SymbolBase.py | ||
---|---|---|
1 |
OCR_OPTION_NOT_EXEC = 0 |
|
2 |
OCR_OPTION_ALL_FIND = 1 |
|
3 |
OCR_OPTION_HALF_AND_HALF = 2 |
|
4 |
class SymbolBase(): |
|
5 |
def __init__(self, id, sName, sClass, sType, sItem, path = None, threshold = None, minMatchCount = 0, isDetectOnOrigin = False, rotationCount = 4, ocrOption = OCR_OPTION_NOT_EXEC): |
|
6 |
self.id = id |
|
7 |
self.sName = sName |
|
8 |
self.sClass = sClass |
|
9 |
self.sType = sType |
|
10 |
self.sItem = sItem |
|
11 |
self.path = path |
|
12 |
self.threshold = threshold |
|
13 |
self.minMatchCount = minMatchCount |
|
14 |
self.isDetectOnOrigin = isDetectOnOrigin |
|
15 |
self.rotationCount = rotationCount |
|
16 |
self.ocrOption = ocrOption |
|
17 |
|
|
18 |
def setId(self, id): |
|
19 |
self.id = id |
|
20 |
|
|
21 |
def getId(self): |
|
22 |
return self.id |
|
23 |
|
|
24 |
def setName(self, sName): |
|
25 |
self.sName = sName |
|
26 |
|
|
27 |
def getName(self): |
|
28 |
return self.sName |
|
29 |
|
|
30 |
def setClass(self, sClass): |
|
31 |
self.sClass = sClass |
|
32 |
|
|
33 |
def getClass(self): |
|
34 |
return self.sClass |
|
35 |
|
|
36 |
def setType(self, type): |
|
37 |
self.sType = type |
|
38 |
|
|
39 |
def getType(self): |
|
40 |
return self.sType |
|
41 |
|
|
42 |
def setItem(self, item): |
|
43 |
self.sItem = item |
|
44 |
|
|
45 |
def getItem(self): |
|
46 |
return self.sItem |
|
47 |
|
|
48 |
def setPath(self, path): |
|
49 |
self.path = path |
|
50 |
|
|
51 |
def getPath(self): |
|
52 |
return self.path |
|
53 |
|
|
54 |
def setThreshold(self, threshold): |
|
55 |
self.threshold = threshold |
|
56 |
|
|
57 |
def getThreshold(self): |
|
58 |
return self.threshold |
|
59 |
|
|
60 |
def setMinMatchCount(self, minMatchCount): |
|
61 |
self.minMatchCount = minMatchCount |
|
62 |
|
|
63 |
def getMinMatchCount(self): |
|
64 |
return self.minMatchCount |
|
65 |
|
|
66 |
def setIsDetectOnOrigin(self, isDetectOnOrigin): |
|
67 |
self.isDetectOnOrigin = isDetectOnOrigin |
|
68 |
|
|
69 |
def getIsDetectOnOrigin(self): |
|
70 |
return self.isDetectOnOrigin |
|
71 |
|
|
72 |
def setRotationCount(self, rotationCount): |
|
73 |
self.rotationCount = rotationCount |
|
74 |
|
|
75 |
def getRotationCount(self): |
|
76 |
return self.rotationCount |
|
77 |
|
|
78 |
def setOcrOption(self, ocrOption): |
|
79 |
self.ocrOption = ocrOption |
|
80 |
|
|
81 |
def getOcrOption(self): |
|
82 |
return self.ocrOption |
DTI_PID/DTI_PID/XmlGenerator.py | ||
---|---|---|
1 |
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree |
|
2 |
import symbol |
|
3 |
import math |
|
4 |
|
|
5 |
ROOT_NODE_NAME = "DWG" |
|
6 |
ROOT_DWGNAME_NODE_NAME = "DWGNAME" |
|
7 |
ROOT_SIZE_NODE_NAME = "SIZE" |
|
8 |
|
|
9 |
SCATEGORY_NODE_NAME = "SYMBOL" |
|
10 |
|
|
11 |
SSYSTEM_PATH_NODE_NAME = "SYSTEMPATH" |
|
12 |
|
|
13 |
SNAME_NODE_NAME = "NAME" |
|
14 |
SNAME_PIPING = "PIPING" |
|
15 |
SNAME_EQUIPMENT = "EQUIPMENT" |
|
16 |
SNAME_INSTRUMENT = "INSTRUMENT" |
|
17 |
|
|
18 |
SCLASS_NODE_NAME = "CLASS" |
|
19 |
SCLASS_ROUTING = "ROUTING" |
|
20 |
SCLASS_VALVES = "VALVES" |
|
21 |
SCLASS_REDUCERS = "REDUCERS" |
|
22 |
SCLASS_VESSELS = "VESSELS" |
|
23 |
SCLASS_OFF_LINE = "OFF-LINE" |
|
24 |
SCLASS_SYSTEM_FUNCTIONS = "SYSTEM FUNCTIONS" |
|
25 |
|
|
26 |
STYPE_NODE_NAME = "TYPE" |
|
27 |
STYPE_PROCESS_LINES = "PROCESS LINES" |
|
28 |
STYPE_2_WAY_COMMON = "2 WAY COMMON" |
|
29 |
STYPE_ANGLE_VALVES = "ANGLE VALVES" |
|
30 |
STYPE_DIAMETER_CHANGE = "DIAMETER CHANGE" |
|
31 |
STYPE_TANKS = "TANKS" |
|
32 |
STYPE_SINGLE_FUNC = "SINGLE FUNC" |
|
33 |
STYPE_DCS = "D C S" |
|
34 |
STYPE_PIPING_CONNECTORS = "PIPING CONNECTORS" |
|
35 |
|
|
36 |
SITEM_NODE_NAME = "ITEM" |
|
37 |
SITEM_PRIMARY_PIPING = "PRIMARY PIPING" |
|
38 |
SITEM_GATE_VALVE = "GATE VALVE" |
|
39 |
SITEM_GATE_VALVE_CLOSED = "GATE VALVE (CLOSED)" |
|
40 |
SITEM_GLOBE_VALVE = "GLOBE VALVE" |
|
41 |
SITEM_CHECK_VALVE = "CHECK VALVE" |
|
42 |
SITEM_ANGLE_VALVE = "ANGLE VALVE" |
|
43 |
SITEM_CONCENTRIC_REDUCER = "CONCENTRIC REDUCER" |
|
44 |
SITEM_CONE_ROOF_TANK = "CONE ROOF TANK" |
|
45 |
SITEM_DISC_SINGLE_FUNC_FIELD_MOUNTED = "DISC SINGLE-FUNC FIELD MOUNTED" |
|
46 |
SITEM_DISC_SINGLE_FUNC_ACCESS_IN_PRIME_LOC = "DISC SINGLE-FUNC ACCESS IN PRIME LOC" |
|
47 |
SITEM_DCS_FUNC_ACCESS_IN_PRIME_LOC = "DCS FUNC ACCESS IN PRIME LOC" |
|
48 |
SITEM_CONTINUATION_ARROW = "CONTINUATION ARROW" |
|
49 |
|
|
50 |
SSUB_TEXT = "TEXT" |
|
51 |
SSUB_ORIGINAL_POINT = "ORIGINALPOINT" |
|
52 |
SSUB_ANGLE = "ANGLE" |
|
53 |
|
|
54 |
def writeXml(pidName, pidWidth, pidHeight, searchedSymbolList): |
|
55 |
xmlData = generateXml(pidName, pidWidth, pidHeight, searchedSymbolList) |
|
56 |
#xmlData = indent(xmlData) |
|
57 |
ElementTree(xmlData).write("res/Result/"+pidName+".xml") |
|
58 |
|
|
59 |
def generateXml(pidName, pidWidth, pidHeight, searchedSymbolList): |
|
60 |
xml = Element(ROOT_NODE_NAME) # Root Node |
|
61 |
SubElement(xml, ROOT_DWGNAME_NODE_NAME).text = pidName |
|
62 |
SubElement(xml, ROOT_SIZE_NODE_NAME).text = str(pidWidth) + "," + str(pidHeight) |
|
63 |
for symbol in searchedSymbolList: |
|
64 |
node = getSymbolInfoNode(symbol) |
|
65 |
xml.append(node) |
|
66 |
return xml |
|
67 |
|
|
68 |
def getSymbolInfoNode(symbol): |
|
69 |
sName = symbol.getName() |
|
70 |
sClass = symbol.getClass() |
|
71 |
sType = symbol.getType() |
|
72 |
sItem = symbol.getItem() |
|
73 |
sName = symbol.getName() |
|
74 |
sSp = symbol.getSp() |
|
75 |
sAngle = symbol.getRotatedAngle() |
|
76 |
sText = symbol.getText() |
|
77 |
|
|
78 |
sCategoryNode = Element(SCATEGORY_NODE_NAME) |
|
79 |
|
|
80 |
sSystemPathNode = Element(SSYSTEM_PATH_NODE_NAME) |
|
81 |
if sType is None or not sType: |
|
82 |
sSystemPathNode.text = "\\" + sName + "\\" + sClass + "\\" + sItem |
|
83 |
else: |
|
84 |
sSystemPathNode.text = "\\" + sName + "\\" + sClass + "\\" + sType + "\\" + sItem |
|
85 |
|
|
86 |
sNameNode = Element(SNAME_NODE_NAME) |
|
87 |
sNameNode.text = sName |
|
88 |
|
|
89 |
sClassNode = Element(SCLASS_NODE_NAME) |
|
90 |
sClassNode.text = sClass |
|
91 |
|
|
92 |
sTypeNode = Element(STYPE_NODE_NAME) |
|
93 |
sTypeNode.text = sType |
|
94 |
|
|
95 |
sItemNode = Element(SITEM_NODE_NAME) |
|
96 |
sItemNode.text = sItem |
|
97 |
|
|
98 |
sOriginalPointNode = Element(SSUB_ORIGINAL_POINT) |
|
99 |
sOriginalPointNode.text = str(sSp[0]) + "," + str(sSp[1]) |
|
100 |
|
|
101 |
sAngleNode = Element(SSUB_ANGLE) |
|
102 |
sAngleNode.text = str(round(math.radians(sAngle), 2)) |
|
103 |
|
|
104 |
sTextNode = Element(SSUB_TEXT) |
|
105 |
sTextNode.text = sText |
|
106 |
|
|
107 |
sCategoryNode.append(sSystemPathNode) |
|
108 |
sCategoryNode.append(sNameNode) |
|
109 |
sCategoryNode.append(sClassNode) |
|
110 |
sCategoryNode.append(sTypeNode) |
|
111 |
sCategoryNode.append(sItemNode) |
|
112 |
sCategoryNode.append(sOriginalPointNode) |
|
113 |
sCategoryNode.append(sAngleNode) |
|
114 |
sCategoryNode.append(sTextNode) |
|
115 |
|
|
116 |
return sCategoryNode |
|
117 |
|
|
118 |
def indent(elem, level=0): |
|
119 |
i = "\n" + level*" " |
|
120 |
if len(elem): |
|
121 |
if not elem.text or not elem.text.strip(): |
|
122 |
elem.text = i + " " |
|
123 |
if not elem.tail or not elem.tail.strip(): |
|
124 |
elem.tail = i |
|
125 |
for elem in elem: |
|
126 |
indent(elem, level+1) |
|
127 |
if not elem.tail or not elem.tail.strip(): |
|
128 |
elem.tail = i |
|
129 |
else: |
|
130 |
if level and (not elem.tail or not elem.tail.strip()): |
|
131 |
elem.tail = i |
|
132 |
|
|
133 |
return elem |
DTI_PID/DTI_PID/azure_handwrite_ocr_module.py | ||
---|---|---|
1 |
#import httplib |
|
2 |
import http.client |
|
3 |
import urllib |
|
4 |
import base64 |
|
5 |
import json |
|
6 |
import cv2 |
|
7 |
import numpy as np |
|
8 |
import matplotlib.pyplot as plt |
|
9 |
import matplotlib.image as mpimg |
|
10 |
from PIL import Image |
|
11 |
from io import BytesIO |
|
12 |
|
|
13 |
|
|
14 |
def url_to_image(url): |
|
15 |
# download the image, convert it to a NumPy array, and then read |
|
16 |
# it into OpenCV format |
|
17 |
resp = urllib.request.urlopen(url) |
|
18 |
#resp = urllib.urlopen(url) |
|
19 |
image = np.asarray(bytearray(resp.read()), dtype="uint8") |
|
20 |
image = cv2.imdecode(image, cv2.IMREAD_COLOR) |
|
21 |
# return the image |
|
22 |
return image |
|
23 |
|
|
24 |
def getRollbackRotateCodeByOrientation(orientation): |
|
25 |
rotatedAngle = None |
|
26 |
if orientation == "Left": |
|
27 |
rotatedAngle = cv2.ROTATE_90_COUNTERCLOCKWISE |
|
28 |
elif orientation == "Right": |
|
29 |
rotatedAngle = cv2.ROTATE_90_CLOCKWISE |
|
30 |
else: |
|
31 |
rotatedAngle = cv2.ROTATE_180 |
|
32 |
return rotatedAngle |
|
33 |
|
|
34 |
def getRotateCodeByOrientation(orientation): |
|
35 |
rotatedAngle = None |
|
36 |
if orientation == "Left": |
|
37 |
rotatedAngle = cv2.ROTATE_90_CLOCKWISE |
|
38 |
elif orientation == "Right": |
|
39 |
rotatedAngle = cv2.ROTATE_90_COUNTERCLOCKWISE |
|
40 |
else: |
|
41 |
rotatedAngle = cv2.ROTATE_180 |
|
42 |
return rotatedAngle |
|
43 |
|
|
44 |
|
|
45 |
#################################### |
|
46 |
|
|
47 |
############################################### |
|
48 |
#### Update or verify the following values. ### |
|
49 |
############################################### |
|
50 |
|
|
51 |
# Replace the subscription_key string value with your valid subscription key. |
|
52 |
#subscription_key = '4774f949a51e4728b436d05a0d0415c2' # zombie612 |
|
53 |
#subscription_key = 'ef94d01a99854539a72b5696118b4ac9' # kyusu99 |
|
54 |
subscription_key = '828669ef78ae40959882ff4a897fb1a4' # master |
|
55 |
|
|
56 |
# Replace or verify the region. |
|
57 |
# |
|
58 |
# You must use the same region in your REST API call as you used to obtain your |
|
59 |
# subscription keys. |
|
60 |
# For example, if you obtained your subscription keys from the westus region, |
|
61 |
# replace |
|
62 |
# "westcentralus" in the URI below with "westus". |
|
63 |
# |
|
64 |
# NOTE: Free trial subscription keys are generated in the westcentralus region, |
|
65 |
# so if you are using |
|
66 |
# a free trial subscription key, you should not need to change this region. |
|
67 |
#uri_base = 'westcentralus.api.cognitive.microsoft.com' # USA |
|
68 |
#uri_base = 'eastasia.api.cognitive.microsoft.com' # east asia for master |
|
69 |
uri_base = 'southeastasia.api.cognitive.microsoft.com' # southeast asia for master |
|
70 |
headers = { |
|
71 |
# Request headers. |
|
72 |
#'Content-Type': 'application/json', |
|
73 |
'Content-Type': 'application/octet-stream', |
|
74 |
'Ocp-Apim-Subscription-Key': subscription_key, |
|
75 |
} |
|
76 |
|
|
77 |
#params = urllib.urlencode({ |
|
78 |
params = urllib.parse.urlencode({ |
|
79 |
# Request parameters. The language setting "unk" means automatically |
|
80 |
'handwriting': 'false' |
|
81 |
}) |
|
82 |
|
|
83 |
# The URL of a JPEG image containing text. |
|
84 |
#body = "{'url':'D:/Visual Studio Project/PyOpenCv/PyOpenCv/res/symbol1.png'}" |
|
85 |
#body = |
|
86 |
#"{'url':'https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Atomist_quote_from_Democritus.png/338px-Atomist_quote_from_Democritus.png'}" |
|
87 |
#body = "{'url':'http://cfile9.uf.tistory.com/image/99AFE1505A322DBD114994'}" |
|
88 |
|
|
89 |
def detectAndRemoveText(image): |
|
90 |
tmp = image.copy() |
|
91 |
img = np.array(tmp) |
|
92 |
try: |
|
93 |
tmp = image.copy() |
|
94 |
bin_img = BytesIO() |
|
95 |
tmp.save(bin_img, format='PNG') |
|
96 |
tmp.close() |
|
97 |
|
|
98 |
img_data = bin_img.getvalue() |
|
99 |
bin_img.close() |
|
100 |
|
|
101 |
#region REST API with raw file |
|
102 |
# Execute the REST API call and get the response. |
|
103 |
conn = http.client.HTTPSConnection(uri_base) |
|
104 |
#conn = httplib.HTTPSConnection(uri_base) |
|
105 |
conn.request("POST", "/vision/v1.0/recognizeText?%s" % params, img_data, headers) |
|
106 |
response = conn.getresponse() |
|
107 |
data = response.read() |
|
108 |
#endregion |
|
109 |
operationLocation = response.info().get('Operation-Location') |
|
110 |
operationId = operationLocation.split("/")[-1] |
내보내기 Unified diff