개정판 08ae0d31
issue #646: MSSQL 지원(심볼 라이브러리 가져오기/내보내기)
Change-Id: I00fcef9cf40a2a77540e4239f6e989fa5495c53c
DTI_PID/DTI_PID/DetectSymbolDialog.py | ||
---|---|---|
182 | 182 |
target_cursor.execute(f"SET IDENTITY_INSERT {table} ON") |
183 | 183 |
|
184 | 184 |
try: |
185 |
# get data type |
|
186 |
data_types = {} |
|
187 |
sql = f"PRAGMA TABLE_INFO({table})" |
|
188 |
cursor.execute(sql) |
|
189 |
rows = cursor.fetchall() |
|
190 |
for row in rows: |
|
191 |
data_types[row[1]] = row[2] |
|
192 |
# up to here |
|
193 |
|
|
185 | 194 |
sql = f"select * from {table}" |
186 | 195 |
cursor.execute(sql) |
187 | 196 |
col_names = ','.join(list(map(lambda x: '[' + x[0] + ']', cursor.description))) |
... | ... | |
189 | 198 |
for row in rows: |
190 | 199 |
cols = ','.join(['?' for item in row]) |
191 | 200 |
sql = app_doc_data.project.database.to_sql(f"insert into {table}({col_names}) values({cols})") |
192 |
params = tuple(self.convert_to_params(row)) |
|
201 |
params = tuple(self.convert_to_params(data_types, row))
|
|
193 | 202 |
target_cursor.execute(sql, params) |
194 | 203 |
finally: |
195 | 204 |
if app_doc_data.project.database.db_type == 'MSSQL' and table == 'Symbol': |
... | ... | |
212 | 221 |
finally: |
213 | 222 |
QApplication.restoreOverrideCursor() |
214 | 223 |
|
215 |
def convert_to_params(self, record): |
|
224 |
def convert_to_params(self, data_types, record):
|
|
216 | 225 |
"""convert record to string""" |
217 | 226 |
from datetime import datetime |
218 | 227 |
|
219 | 228 |
res = [] |
220 |
for item in record: |
|
221 |
if isinstance(item, type(None)): |
|
229 |
for col in record.keys(): |
|
230 |
value = record[col] |
|
231 |
if isinstance(value, type(None)): |
|
222 | 232 |
res.append(None) |
223 |
elif isinstance(item, str): |
|
224 |
res.append(f"{item}") |
|
225 |
elif isinstance(item, datetime): |
|
226 |
res.append(f"{str(item)}") |
|
227 |
elif isinstance(item, bytes): # for BLOB |
|
228 |
res.append(item) |
|
233 |
elif isinstance(value, str): |
|
234 |
res.append(value.encode() if data_types and data_types[col] == 'BLOB' else value) |
|
235 |
elif isinstance(value, datetime): |
|
236 |
res.append(f"{str(value)}") |
|
237 |
elif isinstance(value, bytes): # for BLOB |
|
238 |
res.append(value) |
|
239 |
elif isinstance(value, int) or isinstance(value, float): |
|
240 |
res.append(str(value)) |
|
229 | 241 |
else: # for numeric values |
230 |
res.append(str(item))
|
|
242 |
res.append(str(value))
|
|
231 | 243 |
|
232 | 244 |
return res |
233 | 245 |
|
... | ... | |
249 | 261 |
copyfile(app_doc_data.get_template_symbol_library_path(), target) |
250 | 262 |
|
251 | 263 |
with app_doc_data.project.database.connect() as conn: |
252 |
conn.row_factory = sqlite3.Row |
|
253 |
cursor = conn.cursor() |
|
264 |
cursor = conn.cursor() if app_doc_data.project.database.db_type == 'SQLite' else conn.cursor(as_dict=True) |
|
254 | 265 |
with sqlite3.connect(target, isolation_level=None) as target_conn: |
255 | 266 |
target_conn.row_factory = sqlite3.Row |
256 | 267 |
target_cursor = target_conn.cursor() |
... | ... | |
264 | 275 |
for row in rows: |
265 | 276 |
cols = ','.join(['?' for item in row]) |
266 | 277 |
sql = f"insert into {table} values({cols})" |
267 |
params = tuple(self.convert_to_params(row)) |
|
278 |
params = tuple(self.convert_to_params(None, row))
|
|
268 | 279 |
target_cursor.execute(sql, params) |
269 | 280 |
|
270 | 281 |
target_cursor.execute('commit') |
... | ... | |
306 | 317 |
from TextDetector import TextDetector |
307 | 318 |
|
308 | 319 |
appDocData = AppDocData.instance() |
309 |
## textDetector에서 사용하기 때문에 설정
|
|
320 |
# textDetector에서 사용하기 때문에 설정 |
|
310 | 321 |
appDocData.imgName = self.imageName |
311 | 322 |
|
312 |
## 흑색 이미지로 변환
|
|
323 |
# 흑색 이미지로 변환 |
|
313 | 324 |
img = cv2.imread(self.imgPath, 1) |
314 | 325 |
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
315 | 326 |
|
316 |
## 프로젝트의 Drawing Area data
|
|
327 |
# 프로젝트의 Drawing Area data |
|
317 | 328 |
area = appDocData.getArea('Drawing') |
318 | 329 |
|
319 |
## area 영역 자른 offset
|
|
330 |
# area 영역 자른 offset |
|
320 | 331 |
offset = (area.x, area.y) if area is not None else (0, 0) |
321 | 332 |
|
322 |
## 이미지 이진화
|
|
333 |
# 이미지 이진화 |
|
323 | 334 |
thresholdImg = cv2.threshold(imgGray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] |
324 |
## 프로젝트의 Area 영역만큼만 자른 이미지
|
|
335 |
# 프로젝트의 Area 영역만큼만 자른 이미지 |
|
325 | 336 |
areaImg = thresholdImg[round(area.y):round(area.y + area.height), round(area.x):round(area.x + area.width)] |
326 | 337 |
|
327 |
## 선제거 전에 먼저 작은 영역 제거
|
|
328 |
## contours 추출을 위한 색반전
|
|
338 |
# 선제거 전에 먼저 작은 영역 제거 |
|
339 |
# contours 추출을 위한 색반전 |
|
329 | 340 |
areaImg = cv2.bitwise_not(areaImg) |
330 |
## contours 추출
|
|
341 |
# contours 추출 |
|
331 | 342 |
contours, hierarchy = cv2.findContours(areaImg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
332 | 343 |
for contour in contours: |
333 | 344 |
[x, y, w, h] = cv2.boundingRect(contour) |
334 | 345 |
|
335 | 346 |
if (w < 40 or h < 40): |
336 | 347 |
areaImg[y:y + h, x:x + w] = 0 |
337 |
## 다시 색반전
|
|
348 |
# 다시 색반전 |
|
338 | 349 |
areaImg = cv2.bitwise_not(areaImg) |
339 | 350 |
|
340 |
## find lines
|
|
351 |
# find lines |
|
341 | 352 |
verticalLineList = [] |
342 | 353 |
horizontalLineList = [] |
343 | 354 |
self.findLines(areaImg, verticalLineList, horizontalLineList) |
344 | 355 |
|
345 |
## chage color
|
|
356 |
# chage color |
|
346 | 357 |
for vLine in verticalLineList: |
347 | 358 |
p1 = vLine[0] |
348 | 359 |
p2 = vLine[1] |
349 | 360 |
x = p1[0] |
350 | 361 |
areaImg[p1[1]:p2[1], x] = 255 |
351 |
## chage color
|
|
362 |
# chage color |
|
352 | 363 |
for vLine in horizontalLineList: |
353 | 364 |
p1 = vLine[0] |
354 | 365 |
p2 = vLine[1] |
355 | 366 |
y = p1[1] |
356 | 367 |
areaImg[y, p1[0]:p2[0]] = 255 |
357 | 368 |
|
358 |
## contours 추출을 위한 색반전
|
|
369 |
# contours 추출을 위한 색반전 |
|
359 | 370 |
areaImg = cv2.bitwise_not(areaImg) |
360 |
## contours 추출
|
|
371 |
# contours 추출 |
|
361 | 372 |
recList = self.getContours(areaImg) |
362 | 373 |
|
363 |
## to xml
|
|
374 |
# to xml |
|
364 | 375 |
self.toXml(recList, offset) |
365 | 376 |
|
366 |
## table setting
|
|
377 |
# table setting |
|
367 | 378 |
self.tableSetting() |
368 | 379 |
|
369 | 380 |
self.progress.setValue(self.progress.maximum()) |
... | ... | |
376 | 387 |
|
377 | 388 |
def findLines(self, areaImg, verticalLineList, horizontalLineList): |
378 | 389 |
|
379 |
## for multiprocessing
|
|
390 |
# for multiprocessing |
|
380 | 391 |
verticalProcessList = [] |
381 | 392 |
horizontalProcessList = [] |
382 | 393 |
|
383 |
## Find VerticalLine using multiprocessing
|
|
384 |
## Set Vertical Line
|
|
394 |
# Find VerticalLine using multiprocessing |
|
395 |
# Set Vertical Line |
|
385 | 396 |
jumpValue = int(areaImg.shape[1] / os.cpu_count()) |
386 | 397 |
value = 0 |
387 | 398 |
for cpuIndex in range(os.cpu_count()): |
... | ... | |
395 | 406 |
verticalProcessList.append((_process, _queue)) |
396 | 407 |
value = value + jumpValue |
397 | 408 |
|
398 |
## Set Horizontal Line
|
|
409 |
# Set Horizontal Line |
|
399 | 410 |
jumpValue = int(areaImg.shape[0] / os.cpu_count()) |
400 | 411 |
value = 0 |
401 | 412 |
for cpuIndex in range(os.cpu_count()): |
... | ... | |
409 | 420 |
horizontalProcessList.append((_process, _queue)) |
410 | 421 |
value = value + jumpValue |
411 | 422 |
|
412 |
## set percent
|
|
423 |
# set percent |
|
413 | 424 |
progressCount = len(verticalProcessList) + len(horizontalProcessList) + 1 |
414 | 425 |
percentGage = int(100 / progressCount) |
415 | 426 |
percent = percentGage |
416 | 427 |
self.progress.setValue(percent) |
417 | 428 |
QApplication.processEvents() |
418 | 429 |
|
419 |
## process start
|
|
430 |
# process start |
|
420 | 431 |
for process in verticalProcessList: |
421 | 432 |
process[0].start() |
422 | 433 |
|
423 |
## Wait Vertical And Start Horizontal
|
|
434 |
# Wait Vertical And Start Horizontal
|
|
424 | 435 |
for index in range(len(verticalProcessList)): |
425 | 436 |
verticalLineList.extend(verticalProcessList[index][1].get()) |
426 | 437 |
verticalProcessList[index][0].join() |
... | ... | |
432 | 443 |
|
433 | 444 |
horizontalProcessList[index][0].start() |
434 | 445 |
|
435 |
## Wait Horizontal
|
|
446 |
# Wait Horizontal
|
|
436 | 447 |
for process in horizontalProcessList: |
437 | 448 |
horizontalLineList.extend(process[1].get()) |
438 | 449 |
process[0].join() |
... | ... | |
452 | 463 |
|
453 | 464 |
contours, hierarchy = cv2.findContours(areaImg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
454 | 465 |
|
455 |
## RecList 정리
|
|
466 |
# RecList 정리 |
|
456 | 467 |
lineWidth = 5 |
457 | 468 |
recList = [] |
458 | 469 |
tempRecList = [] |
... | ... | |
460 | 471 |
[x, y, w, h] = cv2.boundingRect(contour) |
461 | 472 |
tempRecList.append([x - lineWidth, y - lineWidth, x + w + lineWidth, y + h + lineWidth]) |
462 | 473 |
|
463 |
## Overlap Rec 합침
|
|
474 |
# Overlap Rec 합침 |
|
464 | 475 |
while len(tempRecList): |
465 | 476 |
rec1 = tempRecList[0] |
466 | 477 |
_temp = [] |
... | ... | |
509 | 520 |
def toXml(self, recList, offset): |
510 | 521 |
xml = Element('BOXES') |
511 | 522 |
|
512 |
## to xml
|
|
523 |
# to xml |
|
513 | 524 |
for rec in recList: |
514 | 525 |
[x1, y1, x2, y2] = rec |
515 | 526 |
w = x2 - x1 |
내보내기 Unified diff