개정판 ea56968c
복합 심볼 정보를 xml에 기재 방식 변경/ DecoDirection->ChildInfo / 심볼제작툴 작업시작
DTI_PID/DTI_PID/DTI_PID.py | ||
---|---|---|
112 | 112 |
ry = originImageWidth - x |
113 | 113 |
return (rx, ry) |
114 | 114 |
|
115 |
def getRotatedChildInfo(symbolChildInfo): |
|
116 |
childList = symbolChildInfo.split("/") |
|
117 |
tempChildInfo = "" |
|
118 |
for index in range(len(childList)): |
|
119 |
child = childList[index] |
|
120 |
direction = int(child.split(",")[0]) |
|
121 |
childName = child.split(",")[1] |
|
122 |
direction = (direction - 1) if direction > 0 else 3 |
|
123 |
if index != 0: |
|
124 |
tempChildInfo = tempChildInfo + "/" |
|
125 |
tempChildInfo = tempChildInfo + str(direction) + "," + childName |
|
126 |
return tempChildInfo |
|
127 |
|
|
115 | 128 |
|
116 | 129 |
#Check object contains pt |
117 | 130 |
#obj is item in searchedSymbolList |
... | ... | |
146 | 159 |
splitRoiList.append((roiSp, roiEp, srcPid[roiSp[1]:roiEp[1], roiSp[0]:roiEp[0]])) |
147 | 160 |
return splitRoiList |
148 | 161 |
|
149 |
def getCalculatedOriginalPoint(symbolDecoDirection, symbolOriginalPoint, symbolRotatedAngle, rotateSymbolWidth, rotateSymbolHeight, originalSymbolWidth, originalSymbolHeight):
|
|
162 |
def getCalculatedOriginalPoint(symbolChildInfo, symbolOriginalPoint, symbolRotatedAngle, rotateSymbolWidth, rotateSymbolHeight, originalSymbolWidth, originalSymbolHeight):
|
|
150 | 163 |
originalPoint = '' |
151 |
if symbolDecoDirection == -1 and symbolOriginalPoint is None:
|
|
164 |
if symbolChildInfo is None and symbolOriginalPoint is None:
|
|
152 | 165 |
originalPoint = str(rotateSymbolWidth//2)+','+str(rotateSymbolHeight//2) |
153 | 166 |
else: |
154 | 167 |
opx = int(symbolOriginalPoint.split(',')[0]) |
... | ... | |
163 | 176 |
def addSearchedSymbol(id, sCategory, sClass, sType, sItem, symbolPath |
164 | 177 |
, pt, w, h, threshold, minMatchCount, mpCount, rotatedAngle |
165 | 178 |
, isDetectOnOrigin, rotateCount, ocrOption, isContainChild |
166 |
, decoDirection, originalPoint, connectionPoint):
|
|
179 |
, childInfo, originalPoint, connectionPoint):
|
|
167 | 180 |
global searchedSymbolList |
168 | 181 |
newSym = symbol.Symbol(id, sCategory, sClass, sType, sItem, symbolPath |
169 | 182 |
, pt, w, h, threshold, minMatchCount, mpCount, rotatedAngle |
170 | 183 |
, isDetectOnOrigin, rotateCount, ocrOption, isContainChild |
171 |
, decoDirection, originalPoint, connectionPoint)
|
|
184 |
, childInfo, originalPoint, connectionPoint)
|
|
172 | 185 |
searchedSymbolList.append(newSym) |
173 | 186 |
|
174 | 187 |
|
... | ... | |
238 | 251 |
symbolRotateCount = targetSymbol.getRotationCount() |
239 | 252 |
symbolOcrOption = targetSymbol.getOcrOption() |
240 | 253 |
isContainChild = targetSymbol.getIsContainChild() |
241 |
symbolDecoDirection = targetSymbol.getDecoDirection()
|
|
254 |
symbolChildInfo = targetSymbol.getChildInfo()
|
|
242 | 255 |
symbolOriginalPoint = targetSymbol.getOriginalPoint() |
243 | 256 |
symbolConnectionPoint = targetSymbol.getConnectionPoint() |
244 | 257 |
|
... | ... | |
289 | 302 |
if roiw < sw or roih < sh: |
290 | 303 |
symGray = cv2.rotate(symGray, cv2.ROTATE_90_COUNTERCLOCKWISE) |
291 | 304 |
symbolRotatedAngle = symbolRotatedAngle + 90 |
292 |
if symbolDecoDirection > 0: |
|
293 |
symbolDecoDirection = (symbolDecoDirection + 1) % 4 |
|
305 |
|
|
306 |
if symbolChildInfo is not None: |
|
307 |
symbolChildInfo = getRotatedChildInfo(symbolChildInfo) |
|
294 | 308 |
continue |
295 | 309 |
|
296 | 310 |
## get Rotated Original Point |
297 |
originalPoint = getCalculatedOriginalPoint(symbolDecoDirection, symbolOriginalPoint, symbolRotatedAngle, sw, sh, sow, soh)
|
|
311 |
originalPoint = getCalculatedOriginalPoint(symbolChildInfo, symbolOriginalPoint, symbolRotatedAngle, sw, sh, sow, soh)
|
|
298 | 312 |
|
299 | 313 |
|
300 | 314 |
## Template Matching |
... | ... | |
330 | 344 |
addSearchedSymbol(symId, symbolName, symbolClass, symbolType, symbolItem |
331 | 345 |
, symbolPath, searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount |
332 | 346 |
, mpCount, symbolRotatedAngle, isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild |
333 |
, symbolDecoDirection, originalPoint, symbolConnectionPoint)
|
|
347 |
, symbolChildInfo, originalPoint, symbolConnectionPoint)
|
|
334 | 348 |
threadLock.release() |
335 | 349 |
## 겹치는 영역이 기준값보다 클 경우 |
336 | 350 |
else: |
... | ... | |
345 | 359 |
searchedSymbolList[symbolIndex] = symbol.Symbol(symId, symbolName, symbolClass, symbolType, symbolItem |
346 | 360 |
, symbolPath, searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount |
347 | 361 |
, mpCount, symbolRotatedAngle, isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild |
348 |
, symbolDecoDirection, originalPoint, symbolConnectionPoint)
|
|
362 |
, symbolChildInfo, originalPoint, symbolConnectionPoint)
|
|
349 | 363 |
threadLock.release() |
350 | 364 |
## 현재 심볼과 검출된 심볼이 같지 않을 경우 (포함) |
351 | 365 |
else: |
... | ... | |
362 | 376 |
searchedSymbolList[searchedSymbolList.index(s)] = symbol.Symbol(symId, symbolName, symbolClass, symbolType, symbolItem |
363 | 377 |
, symbolPath, searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount |
364 | 378 |
, mpCount, symbolRotatedAngle, isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild |
365 |
, symbolDecoDirection, originalPoint, symbolConnectionPoint)
|
|
379 |
, symbolChildInfo, originalPoint, symbolConnectionPoint)
|
|
366 | 380 |
threadLock.release() |
367 | 381 |
else: |
368 | 382 |
if mpCount >= symbolMinMatchCount: |
... | ... | |
377 | 391 |
addSearchedSymbol(symId, symbolName, symbolClass, symbolType, symbolItem |
378 | 392 |
, symbolPath, searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount |
379 | 393 |
, mpCount, symbolRotatedAngle, isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild |
380 |
, symbolDecoDirection, originalPoint, symbolConnectionPoint)
|
|
394 |
, symbolChildInfo, originalPoint, symbolConnectionPoint)
|
|
381 | 395 |
threadLock.release() |
382 | 396 |
|
383 | 397 |
## Rotate Symbol |
384 | 398 |
symGray = cv2.rotate(symGray, cv2.ROTATE_90_COUNTERCLOCKWISE) |
385 | 399 |
symbolRotatedAngle = symbolRotatedAngle + 90 |
386 |
if symbolDecoDirection >= 0: |
|
387 |
symbolDecoDirection = (symbolDecoDirection + 1) % 4 |
|
400 |
|
|
401 |
if symbolChildInfo is not None: |
|
402 |
symbolChildInfo = getRotatedChildInfo(symbolChildInfo) |
|
388 | 403 |
|
389 | 404 |
splitCount = splitCount // 2 |
390 | 405 |
|
... | ... | |
616 | 631 |
if connectionPointList is not None and len(connectionPointList) > 0: |
617 | 632 |
symOpStr = sym.getOriginalPoint() |
618 | 633 |
symOp = (int(symOpStr.split(',')[0]), int(symOpStr.split(',')[1])) |
619 |
#symOp = getCoordOnRotatedImage(rotatedAngle, symOp[0], symOp[1], sow, soh) |
|
634 |
|
|
620 | 635 |
blank = np.zeros((symWidth, symHeight, 3), np.uint8) |
621 | 636 |
blank[::] = (255, 255, 255) |
622 | 637 |
blank = cvtGrayImage(blank) |
623 | 638 |
bw, bh = blank.shape[::-1] |
624 | 639 |
srcGray[symSp[1]:symSp[1]+bh, symSp[0]:symSp[0]+bw] = blank |
625 |
#getCoordOnRotatedImage(rotatedAngle, opx, opy, sow, soh) |
|
640 |
|
|
626 | 641 |
for cp in connectionPointList: |
627 | 642 |
pt = cp.split(",") |
628 | 643 |
cpx = int(pt[0]) |
... | ... | |
681 | 696 |
srcGray = cvtGrayImage(src) |
682 | 697 |
else: |
683 | 698 |
srcGray = src.copy() |
684 |
#srcGray = src |
|
699 |
|
|
685 | 700 |
(ocrCompletedSrc, textInfoList) = OCR.removeTextFromNpArray(srcGray) |
686 | 701 |
for textInfo in textInfoList: |
687 | 702 |
removeText(ocrCompletedSrc, textInfo.getText(), textInfo.getX(), textInfo.getY(), textInfo.getW(), textInfo.getH()) |
688 |
#ocrCompletedSrc = srcGray.copy() |
|
689 |
#ocrCompletedSrc = TOCR.removeTextFromNpArray(srcGray, TOCR.FLAG_IMAGE_TO_DATA) |
|
690 | 703 |
|
691 | 704 |
|
692 | 705 |
#Main function |
DTI_PID/DTI_PID/DTI_PID.pyproj | ||
---|---|---|
39 | 39 |
</Compile> |
40 | 40 |
<Compile Include="DTI_PID.py" /> |
41 | 41 |
<Compile Include="potrace.py" /> |
42 |
<Compile Include="QcImageViewer.py"> |
|
43 |
<SubType>Code</SubType> |
|
44 |
</Compile> |
|
45 |
<Compile Include="QtImageViewer.py"> |
|
46 |
<SubType>Code</SubType> |
|
47 |
</Compile> |
|
42 | 48 |
<Compile Include="symbol.py"> |
43 | 49 |
<SubType>Code</SubType> |
44 | 50 |
</Compile> |
45 | 51 |
<Compile Include="SymbolBase.py"> |
46 | 52 |
<SubType>Code</SubType> |
47 | 53 |
</Compile> |
54 |
<Compile Include="SymbolGenerator.py"> |
|
55 |
<SubType>Code</SubType> |
|
56 |
</Compile> |
|
48 | 57 |
<Compile Include="tesseract_ocr_module.py"> |
49 | 58 |
<SubType>Code</SubType> |
50 | 59 |
</Compile> |
DTI_PID/DTI_PID/QcImageViewer.py | ||
---|---|---|
1 |
import sys |
|
2 |
from PyQt5.QtCore import Qt |
|
3 |
from PyQt5.QtWidgets import QWidget, QApplication, QGridLayout, QLabel |
|
4 |
from PyQt5 import QtCore, QtGui, QtWidgets |
|
5 |
from PyQt5.QtWidgets import * |
|
6 |
from PyQt5.QtGui import * |
|
7 |
|
|
8 |
CROP_AREA_MIN_SIZE = 10 |
|
9 |
|
|
10 |
class QcImageViewer(QGraphicsView): |
|
11 |
def __init__(self, filePath, imgW, imgH): |
|
12 |
super().__init__() |
|
13 |
print("__init__") |
|
14 |
self.filePath = filePath |
|
15 |
self.selectedArea = [(0, 0),(imgW, imgH)] |
|
16 |
self.imgW = imgW |
|
17 |
self.imgH = imgH |
|
18 |
self.zoom = 1.0 |
|
19 |
self.isPressCtrl = False |
|
20 |
#PyQt5.QtCore.QRectF(3740.953125, 1164.765625, 1479.9375, 1891.03125) |
|
21 |
self.initImage() |
|
22 |
self.setMouseTracking(True) |
|
23 |
#self.mousePressEvent = self.mousePressEvent |
|
24 |
#self.mouseReleaseEvent = self.mouseReleaseEvent |
|
25 |
#self.mouseDoubleClickEvent = self.mouseDoubleClickEvent |
|
26 |
#self.wheelEvent = self.wheelEvent |
|
27 |
#self.keyPressEvent = self.keyPressEvent |
|
28 |
#self.keyReleaseEvent = self.keyReleaseEvent |
|
29 |
|
|
30 |
def mousePressEvent(self, event): |
|
31 |
if event.button() == QtCore.Qt.LeftButton: |
|
32 |
print("Pressed : " + str(event.x()) + ", " + str(event.y())) |
|
33 |
self.originPoint = event.pos() |
|
34 |
self.currentRect = QtCore.QRect() |
|
35 |
self.currentRect.setTopLeft(QtCore.QPoint(event.x(), event.y())) |
|
36 |
|
|
37 |
def mouseReleaseEvent(self, event): |
|
38 |
if event.button() == QtCore.Qt.LeftButton: |
|
39 |
print("Released : " + str(event.x()) + ", " + str(event.y())) |
|
40 |
self.currentRect.setBottomRight(QtCore.QPoint(event.x(), event.y())) |
|
41 |
|
|
42 |
if self.currentRect.width() > CROP_AREA_MIN_SIZE and self.currentRect.height() > CROP_AREA_MIN_SIZE: |
|
43 |
pixmap = self.pixmap().copy(self.currentRect) |
|
44 |
pixmap.scaled(self.currentRect.width(), self.currentRect.height()) |
|
45 |
print("New Size : " + str(self.currentRect.width()) + "/" + str(self.currentRect.height())) |
|
46 |
self.setPixmap(pixmap) |
|
47 |
self.resize(self.currentRect.width(), self.currentRect.height()) |
|
48 |
self.parentWidget().resize(self.currentRect.width(), self.currentRect.height()) |
|
49 |
|
|
50 |
def mouseDoubleClickEvent(self, event): |
|
51 |
if event.button() == QtCore.Qt.RightButton: |
|
52 |
self.initImage() |
|
53 |
|
|
54 |
def keyPressEvent(self, event): |
|
55 |
if event.key() == QtCore.Qt.Key_Control: |
|
56 |
self.isPressCtrl = True |
|
57 |
print("Pressed Ctrl") |
|
58 |
|
|
59 |
def keyReleaseEvent(self, event): |
|
60 |
if event.key() == QtCore.Qt.Key_Control: |
|
61 |
self.isPressCtrl = False |
|
62 |
print("Released Ctrl") |
|
63 |
|
|
64 |
def wheelEvent(self, event): |
|
65 |
if self.isPressCtrl == True: |
|
66 |
event.modifiers() |
|
67 |
print("Pressed Ctrl and Mouse Wheel") |
|
68 |
|
|
69 |
def initImage(self): |
|
70 |
self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) |
|
71 |
self.setScaledContents(True) |
|
72 |
pixmap = QPixmap(self.filePath) |
|
73 |
pixmap = pixmap.scaled(self.imgW, self.imgH, QtCore.Qt.KeepAspectRatioByExpanding) |
|
74 |
self.setPixmap(pixmap) |
|
75 |
self.resize(self.imgW, self.imgH) |
|
76 |
if self.parentWidget() is not None: |
|
77 |
self.parentWidget().resize(self.imgW, self.imgH) |
DTI_PID/DTI_PID/QtImageViewer.py | ||
---|---|---|
1 |
import os.path |
|
2 |
try: |
|
3 |
from PyQt5.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR |
|
4 |
from PyQt5.QtGui import QImage, QPixmap, QPainterPath |
|
5 |
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog |
|
6 |
except ImportError: |
|
7 |
try: |
|
8 |
from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR |
|
9 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog |
|
10 |
except ImportError: |
|
11 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
|
12 |
|
|
13 |
|
|
14 |
__author__ = "Marcel Goldschen-Ohm <marcel.goldschen@gmail.com>" |
|
15 |
__version__ = '0.9.0' |
|
16 |
|
|
17 |
|
|
18 |
class QtImageViewer(QGraphicsView): |
|
19 |
""" PyQt image viewer widget for a QPixmap in a QGraphicsView scene with mouse zooming and panning. |
|
20 |
Displays a QImage or QPixmap (QImage is internally converted to a QPixmap). |
|
21 |
To display any other image format, you must first convert it to a QImage or QPixmap. |
|
22 |
Some useful image format conversion utilities: |
|
23 |
qimage2ndarray: NumPy ndarray <==> QImage (https://github.com/hmeine/qimage2ndarray) |
|
24 |
ImageQt: PIL Image <==> QImage (https://github.com/python-pillow/Pillow/blob/master/PIL/ImageQt.py) |
|
25 |
Mouse interaction: |
|
26 |
Left mouse button drag: Pan image. |
|
27 |
Right mouse button drag: Zoom box. |
|
28 |
Right mouse button doubleclick: Zoom to show entire image. |
|
29 |
""" |
|
30 |
|
|
31 |
MENU_HAND_TOOL = 0 |
|
32 |
MENU_CROP_TOOL = 1 |
|
33 |
MENU_ERASER_TOOL = 2 |
|
34 |
MENU_PEN_TOOL = 3 |
|
35 |
|
|
36 |
# Mouse button signals emit image scene (x, y) coordinates. |
|
37 |
# !!! For image (row, column) matrix indexing, row = y and column = x. |
|
38 |
leftMouseButtonPressed = pyqtSignal(float, float) |
|
39 |
rightMouseButtonPressed = pyqtSignal(float, float) |
|
40 |
leftMouseButtonReleased = pyqtSignal(float, float) |
|
41 |
rightMouseButtonReleased = pyqtSignal(float, float) |
|
42 |
leftMouseButtonDoubleClicked = pyqtSignal(float, float) |
|
43 |
rightMouseButtonDoubleClicked = pyqtSignal(float, float) |
|
44 |
|
|
45 |
def __init__(self): |
|
46 |
QGraphicsView.__init__(self) |
|
47 |
|
|
48 |
# Image is displayed as a QPixmap in a QGraphicsScene attached to this QGraphicsView. |
|
49 |
self.scene = QGraphicsScene() |
|
50 |
self.setScene(self.scene) |
|
51 |
self.scene.setBackgroundBrush(Qt.gray) |
|
52 |
|
|
53 |
self.isPressCtrl = False |
|
54 |
self.factor = 1.0 |
|
55 |
self.numScheduledScalings = 0 |
|
56 |
self.currentMenuTool = self.MENU_HAND_TOOL |
|
57 |
|
|
58 |
# Store a local handle to the scene's current image pixmap. |
|
59 |
self._pixmapHandle = None |
|
60 |
|
|
61 |
# Image aspect ratio mode. |
|
62 |
# !!! ONLY applies to full image. Aspect ratio is always ignored when zooming. |
|
63 |
# Qt.IgnoreAspectRatio: Scale image to fit viewport. |
|
64 |
# Qt.KeepAspectRatio: Scale image to fit inside viewport, preserving aspect ratio. |
|
65 |
# Qt.KeepAspectRatioByExpanding: Scale image to fill the viewport, preserving aspect ratio. |
|
66 |
self.aspectRatioMode = Qt.KeepAspectRatio |
|
67 |
|
|
68 |
# Scroll bar behaviour. |
|
69 |
# Qt.ScrollBarAlwaysOff: Never shows a scroll bar. |
|
70 |
# Qt.ScrollBarAlwaysOn: Always shows a scroll bar. |
|
71 |
# Qt.ScrollBarAsNeeded: Shows a scroll bar only when zoomed. |
|
72 |
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) |
|
73 |
self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) |
|
74 |
|
|
75 |
# Stack of QRectF zoom boxes in scene coordinates. |
|
76 |
self.zoomStack = [] |
|
77 |
|
|
78 |
# Flags for enabling/disabling mouse interaction. |
|
79 |
self.canZoom = True |
|
80 |
self.canPan = True |
|
81 |
|
|
82 |
def hasImage(self): |
|
83 |
""" Returns whether or not the scene contains an image pixmap. |
|
84 |
""" |
|
85 |
return self._pixmapHandle is not None |
|
86 |
|
|
87 |
def clearImage(self): |
|
88 |
""" Removes the current image pixmap from the scene if it exists. |
|
89 |
""" |
|
90 |
if self.hasImage(): |
|
91 |
self.scene.removeItem(self._pixmapHandle) |
|
92 |
self._pixmapHandle = None |
|
93 |
|
|
94 |
def pixmap(self): |
|
95 |
""" Returns the scene's current image pixmap as a QPixmap, or else None if no image exists. |
|
96 |
:rtype: QPixmap | None |
|
97 |
""" |
|
98 |
if self.hasImage(): |
|
99 |
return self._pixmapHandle.pixmap() |
|
100 |
return None |
|
101 |
|
|
102 |
def image(self): |
|
103 |
""" Returns the scene's current image pixmap as a QImage, or else None if no image exists. |
|
104 |
:rtype: QImage | None |
|
105 |
""" |
|
106 |
if self.hasImage(): |
|
107 |
return self._pixmapHandle.pixmap().toImage() |
|
108 |
return None |
|
109 |
|
|
110 |
def setImage(self, image): |
|
111 |
""" Set the scene's current image pixmap to the input QImage or QPixmap. |
|
112 |
Raises a RuntimeError if the input image has type other than QImage or QPixmap. |
|
113 |
:type image: QImage | QPixmap |
|
114 |
""" |
|
115 |
if type(image) is QPixmap: |
|
116 |
pixmap = image |
|
117 |
elif type(image) is QImage: |
|
118 |
pixmap = QPixmap.fromImage(image) |
|
119 |
else: |
|
120 |
raise RuntimeError("ImageViewer.setImage: Argument must be a QImage or QPixmap.") |
|
121 |
if self.hasImage(): |
|
122 |
self._pixmapHandle.setPixmap(pixmap) |
|
123 |
else: |
|
124 |
self._pixmapHandle = self.scene.addPixmap(pixmap) |
|
125 |
|
|
126 |
self.setSceneRect(QRectF(pixmap.rect())) # Set scene size to image size. |
|
127 |
self.updateViewer() |
|
128 |
|
|
129 |
def loadImageFromFile(self, fileName=""): |
|
130 |
""" Load an image from file. |
|
131 |
Without any arguments, loadImageFromFile() will popup a file dialog to choose the image file. |
|
132 |
With a fileName argument, loadImageFromFile(fileName) will attempt to load the specified image file directly. |
|
133 |
""" |
|
134 |
if len(fileName) == 0: |
|
135 |
if QT_VERSION_STR[0] == '4': |
|
136 |
fileName = QFileDialog.getOpenFileName(self, "Open image file.") |
|
137 |
elif QT_VERSION_STR[0] == '5': |
|
138 |
fileName, dummy = QFileDialog.getOpenFileName(self, "Open image file.") |
|
139 |
if len(fileName) and os.path.isfile(fileName): |
|
140 |
image = QImage(fileName) |
|
141 |
self.setImage(image) |
|
142 |
|
|
143 |
def updateViewer(self): |
|
144 |
""" Show current zoom (if showing entire image, apply current aspect ratio mode). |
|
145 |
""" |
|
146 |
if not self.hasImage(): |
|
147 |
return |
|
148 |
if len(self.zoomStack) and self.sceneRect().contains(self.zoomStack[-1]): |
|
149 |
self.fitInView(self.zoomStack[-1], Qt.KeepAspectRatioByExpanding) # Show zoomed rect (ignore aspect ratio). |
|
150 |
else: |
|
151 |
self.zoomStack = [] # Clear the zoom stack (in case we got here because of an invalid zoom). |
|
152 |
self.fitInView(self.sceneRect(), self.aspectRatioMode) # Show entire image (use current aspect ratio mode). |
|
153 |
#self.setFocusPolicy(Qt.StrongFocus) |
|
154 |
#self.setFocus(True) |
|
155 |
|
|
156 |
def resizeEvent(self, event): |
|
157 |
""" Maintain current zoom on resize. |
|
158 |
""" |
|
159 |
self.updateViewer() |
|
160 |
|
|
161 |
def mousePressEvent(self, event): |
|
162 |
""" Start mouse pan or zoom mode. |
|
163 |
""" |
|
164 |
scenePos = self.mapToScene(event.pos()) |
|
165 |
if event.button() == Qt.LeftButton: |
|
166 |
if self.canPan and self.currentMenuTool == self.MENU_HAND_TOOL: |
|
167 |
self.setDragMode(QGraphicsView.ScrollHandDrag) |
|
168 |
elif self.currentMenuTool == self.MENU_CROP_TOOL: |
|
169 |
self.setDragMode(QGraphicsView.RubberBandDrag) |
|
170 |
self.leftMouseButtonPressed.emit(scenePos.x(), scenePos.y()) |
|
171 |
elif event.button() == Qt.RightButton: |
|
172 |
if self.canZoom: |
|
173 |
self.setDragMode(QGraphicsView.RubberBandDrag) |
|
174 |
self.rightMouseButtonPressed.emit(scenePos.x(), scenePos.y()) |
|
175 |
QGraphicsView.mousePressEvent(self, event) |
|
176 |
|
|
177 |
def mouseReleaseEvent(self, event): |
|
178 |
""" Stop mouse pan or zoom mode (apply zoom if valid). |
|
179 |
""" |
|
180 |
QGraphicsView.mouseReleaseEvent(self, event) |
|
181 |
scenePos = self.mapToScene(event.pos()) |
|
182 |
if event.button() == Qt.LeftButton: |
|
183 |
if self.currentMenuTool == self.MENU_CROP_TOOL: |
|
184 |
viewBBox = self.zoomStack[-1] if len(self.zoomStack) else self.sceneRect() |
|
185 |
selectionBBox = self.scene.selectionArea().boundingRect().intersected(viewBBox) |
|
186 |
|
|
187 |
croppedImage = self.image().copy(selectionBBox.toAlignedRect()) |
|
188 |
self.setImage(croppedImage) |
|
189 |
self.setDragMode(QGraphicsView.NoDrag) |
|
190 |
self.leftMouseButtonReleased.emit(scenePos.x(), scenePos.y()) |
|
191 |
elif event.button() == Qt.RightButton: |
|
192 |
if self.canZoom: |
|
193 |
viewBBox = self.zoomStack[-1] if len(self.zoomStack) else self.sceneRect() |
|
194 |
selectionBBox = self.scene.selectionArea().boundingRect().intersected(viewBBox) |
|
195 |
self.scene.setSelectionArea(QPainterPath()) # Clear current selection area. |
|
196 |
if selectionBBox.isValid() and (selectionBBox != viewBBox): |
|
197 |
self.zoomStack.append(selectionBBox) |
|
198 |
self.updateViewer() |
|
199 |
self.setDragMode(QGraphicsView.NoDrag) |
|
200 |
self.rightMouseButtonReleased.emit(scenePos.x(), scenePos.y()) |
|
201 |
|
|
202 |
def mouseDoubleClickEvent(self, event): |
|
203 |
""" Show entire image. |
|
204 |
""" |
|
205 |
scenePos = self.mapToScene(event.pos()) |
|
206 |
if event.button() == Qt.LeftButton: |
|
207 |
self.leftMouseButtonDoubleClicked.emit(scenePos.x(), scenePos.y()) |
|
208 |
elif event.button() == Qt.RightButton: |
|
209 |
if self.canZoom: |
|
210 |
self.zoomStack = [] # Clear zoom stack. |
|
211 |
self.updateViewer() |
|
212 |
self.rightMouseButtonDoubleClicked.emit(scenePos.x(), scenePos.y()) |
|
213 |
QGraphicsView.mouseDoubleClickEvent(self, event) |
|
214 |
|
|
215 |
def keyPressEvent(self, event): |
|
216 |
if event.key() == Qt.Key_Control: |
|
217 |
self.isPressCtrl = True |
|
218 |
print("Pressed Ctrl") |
|
219 |
|
|
220 |
def keyReleaseEvent(self, event): |
|
221 |
if event.key() == Qt.Key_Control: |
|
222 |
self.isPressCtrl = False |
|
223 |
print("Released Ctrl") |
|
224 |
|
|
225 |
def wheelEvent(self, event): |
|
226 |
if self.isPressCtrl == True: |
|
227 |
print("Pressed Ctrl and Mouse Wheel") |
|
228 |
if self.canZoom: |
|
229 |
print("Zoomable") |
|
230 |
numDegrees = event.angleDelta().y() // 8 |
|
231 |
numSteps = numDegrees // 15 |
|
232 |
self.numScheduledScalings = self.numScheduledScalings + numSteps |
|
233 |
if self.numScheduledScalings * numSteps < 0: |
|
234 |
self.numScheduledScalings = numSteps |
|
235 |
self.factor = 1.0 + (self.numScheduledScalings / 300.0) |
|
236 |
print("Factor : " + str(self.factor)) |
|
237 |
self.scale(self.factor, self.factor) |
|
238 |
|
|
239 |
#viewBBox = self.zoomStack[-1] if len(self.zoomStack) else self.sceneRect() |
|
240 |
#selectionBBox = self.scene.selectionArea().boundingRect().intersected(viewBBox) |
|
241 |
#self.scene.setSelectionArea(QPainterPath()) # Clear current selection area. |
|
242 |
#if selectionBBox.isValid() and (selectionBBox != viewBBox): |
|
243 |
# self.zoomStack.append(selectionBBox) |
|
244 |
# self.updateViewer() |
|
245 |
else: |
|
246 |
super().wheelEvent(event) |
|
247 |
|
|
248 |
|
|
249 |
|
|
250 |
if __name__ == '__main__': |
|
251 |
import sys |
|
252 |
try: |
|
253 |
from PyQt5.QtWidgets import QApplication |
|
254 |
except ImportError: |
|
255 |
try: |
|
256 |
from PyQt4.QtGui import QApplication |
|
257 |
except ImportError: |
|
258 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
|
259 |
print('Using Qt ' + QT_VERSION_STR) |
|
260 |
|
|
261 |
def handleLeftClick(x, y): |
|
262 |
row = int(y) |
|
263 |
column = int(x) |
|
264 |
print("Clicked on image pixel (row="+str(row)+", column="+str(column)+")") |
|
265 |
|
|
266 |
# Create the application. |
|
267 |
app = QApplication(sys.argv) |
|
268 |
|
|
269 |
# Create image viewer and load an image file to display. |
|
270 |
viewer = QtImageViewer() |
|
271 |
viewer.loadImageFromFile() # Pops up file dialog. |
|
272 |
|
|
273 |
# Handle left mouse clicks with custom slot. |
|
274 |
viewer.leftMouseButtonPressed.connect(handleLeftClick) |
|
275 |
|
|
276 |
# Show viewer and run application. |
|
277 |
viewer.show() |
|
278 |
sys.exit(app.exec_()) |
DTI_PID/DTI_PID/SymbolBase.py | ||
---|---|---|
4 | 4 |
class SymbolBase(): |
5 | 5 |
def __init__(self, id, sName, sClass, sType, sItem, path = None, threshold = None, minMatchCount = 0 |
6 | 6 |
, isDetectOnOrigin = False, rotationCount = 4, ocrOption = OCR_OPTION_NOT_EXEC, isContainChild = 0 |
7 |
, decoDirection = -1, originalPoint = None, connectionPoint = None):
|
|
7 |
, childInfo = None, originalPoint = None, connectionPoint = None):
|
|
8 | 8 |
self.id = id |
9 | 9 |
self.sName = sName |
10 | 10 |
self.sClass = sClass |
... | ... | |
17 | 17 |
self.rotationCount = rotationCount |
18 | 18 |
self.ocrOption = ocrOption |
19 | 19 |
self.isContainChild = isContainChild |
20 |
self.decoDirection = decoDirection
|
|
20 |
self.childInfo = childInfo
|
|
21 | 21 |
self.originalPoint = originalPoint |
22 | 22 |
self.connectionPoint = connectionPoint |
23 | 23 |
|
... | ... | |
93 | 93 |
def getIsContainChild(self): |
94 | 94 |
return self.isContainChild |
95 | 95 |
|
96 |
def setDecoDirection(self, decoDirection):
|
|
97 |
self.decoDirection = decoDirection
|
|
96 |
def setChildInfo(self, childInfo):
|
|
97 |
self.childInfo = childInfo
|
|
98 | 98 |
|
99 |
def getDecoDirection(self):
|
|
100 |
return self.decoDirection
|
|
99 |
def getChildInfo(self):
|
|
100 |
return self.childInfo
|
|
101 | 101 |
|
102 | 102 |
def setOriginalPoint(self, originalPoint): |
103 | 103 |
self.originalPoint = originalPoint |
DTI_PID/DTI_PID/SymbolGenerator.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
|
|
3 |
# Form implementation generated from reading ui file 'D:\Anaconda3\output\SymbolGenerator.ui' |
|
4 |
# |
|
5 |
# Created by: PyQt5 UI code generator 5.6 |
|
6 |
# |
|
7 |
# WARNING! All changes made in this file will be lost! |
|
8 |
|
|
9 |
from PyQt5 import QtCore, QtGui, QtWidgets |
|
10 |
from PyQt5.QtWidgets import * |
|
11 |
from PyQt5.QtGui import * |
|
12 |
from QcImageViewer import QcImageViewer |
|
13 |
import cv2 |
|
14 |
from QtImageViewer import QtImageViewer |
|
15 |
|
|
16 |
class Ui_MainWindow(object): |
|
17 |
def setupUi(self, MainWindow): |
|
18 |
defaultFilePath = "D:\\Visual Studio Project\\DTIPID\\DTIPID\\DTI_PID\\DTI_PID\\res\\UY1-K-2000_P1_300dpi.png" |
|
19 |
defaultImg = cv2.imread("D:\\Visual Studio Project\\DTIPID\\DTIPID\\DTI_PID\\DTI_PID\\res\\UY1-K-2000_P1_300dpi.png", 1) |
|
20 |
_chan, imgW, imgH = defaultImg.shape[::-1] |
|
21 |
|
|
22 |
MainWindow.setObjectName("MainWindow") |
|
23 |
MainWindow.showFullScreen() |
|
24 |
|
|
25 |
mainWindowWidth = MainWindow.frameGeometry().width() |
|
26 |
mainWindowHeight = MainWindow.frameGeometry().height() |
|
27 |
|
|
28 |
self.centralwidget = QtWidgets.QWidget(MainWindow) |
|
29 |
self.centralwidget.setObjectName("centralwidget") |
|
30 |
self.centralwidget.setGeometry(QtCore.QRect(0, 0, mainWindowWidth, mainWindowHeight - 50)) |
|
31 |
|
|
32 |
centralWidth = self.centralwidget.frameGeometry().width() |
|
33 |
centralHeight = self.centralwidget.frameGeometry().height() |
|
34 |
|
|
35 |
self.topWidget = QtWidgets.QWidget(self.centralwidget) |
|
36 |
self.topWidget.setObjectName("topWidget") |
|
37 |
self.topWidget.setGeometry(QtCore.QRect(0, 0, mainWindowWidth, 40)) |
|
38 |
self.topWidget.setLayout(QHBoxLayout()) |
|
39 |
self.initToolMenu(self.topWidget) |
|
40 |
|
|
41 |
self.imageWidget = QtWidgets.QWidget(self.centralwidget) |
|
42 |
self.imageWidget.setObjectName("imageWidget") |
|
43 |
self.imageWidget.setGeometry(QtCore.QRect(0, self.topWidget.y()+self.topWidget.height(), mainWindowWidth, centralHeight - 40)) |
|
44 |
|
|
45 |
#self.scrollArea = QtWidgets.QScrollArea(self.centralwidget) |
|
46 |
#self.scrollArea.setGeometry(QtCore.QRect(0, 0, centralWidth, centralHeight)) |
|
47 |
#self.scrollArea.setWidgetResizable(False) |
|
48 |
#self.scrollArea.setObjectName("scrollArea") |
|
49 |
#self.scrollArea.horizontalScrollBar().setEnabled(True) |
|
50 |
#self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) |
|
51 |
#self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) |
|
52 |
#self.scrollAreaWidgetContents = QtWidgets.QWidget() |
|
53 |
#self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, imgW, imgH)) |
|
54 |
#self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") |
|
55 |
|
|
56 |
centralWidth = self.centralwidget.frameGeometry().width() |
|
57 |
centralHeight = self.centralwidget.frameGeometry().height() |
|
58 |
|
|
59 |
#self.mainView = QcImageViewer(defaultFilePath, imgW, imgH) |
|
60 |
#self.mainView.setParent(self.scrollAreaWidgetContents) |
|
61 |
#self.mainView.setFocusPolicy(QtCore.Qt.StrongFocus) |
|
62 |
#self.centralwidget.setFocusProxy(self.mainView) |
|
63 |
#self.mainView.setFocus(True) |
|
64 |
|
|
65 |
self.mainView = QtImageViewer() |
|
66 |
#self.mainView.resize(imgW, imgH) |
|
67 |
self.mainView.resize(centralWidth, centralHeight) |
|
68 |
self.mainView.aspectRatioMode = QtCore.Qt.KeepAspectRatio |
|
69 |
self.mainView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) |
|
70 |
self.mainView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) |
|
71 |
self.mainView.canZoom = True |
|
72 |
self.mainView.canPan = True |
|
73 |
|
|
74 |
image = QImage(defaultFilePath) |
|
75 |
image = image.scaled(imgW, imgH) |
|
76 |
self.mainView.setImage(image) |
|
77 |
self.mainView.setParent(self.imageWidget) |
|
78 |
|
|
79 |
#self.imageWidget.setParent(self.centralwidget) |
|
80 |
#self.topWidget.setParent(self.centralwidget) |
|
81 |
|
|
82 |
|
|
83 |
#self.scrollArea.setWidget(self.scrollAreaWidgetContents) |
|
84 |
MainWindow.setCentralWidget(self.centralwidget) |
|
85 |
|
|
86 |
|
|
87 |
self.menubar = QtWidgets.QMenuBar(MainWindow) |
|
88 |
self.menubar.setGeometry(QtCore.QRect(0, 0, mainWindowWidth, 21)) |
|
89 |
self.menubar.setObjectName("menubar") |
|
90 |
self.menuFile = QtWidgets.QMenu(self.menubar) |
|
91 |
self.menuFile.setObjectName("menuFile") |
|
92 |
MainWindow.setMenuBar(self.menubar) |
|
93 |
self.statusbar = QtWidgets.QStatusBar(MainWindow) |
|
94 |
self.statusbar.setObjectName("statusbar") |
|
95 |
MainWindow.setStatusBar(self.statusbar) |
|
96 |
self.actionOpen = QtWidgets.QAction(MainWindow) |
|
97 |
self.actionOpen.setObjectName("actionOpen") |
|
98 |
self.actionSave = QtWidgets.QAction(MainWindow) |
|
99 |
self.actionSave.setObjectName("actionSave") |
|
100 |
self.actionExit = QtWidgets.QAction(MainWindow) |
|
101 |
self.actionExit.setObjectName("actionExit") |
|
102 |
self.menuFile.addAction(self.actionOpen) |
|
103 |
self.menuFile.addAction(self.actionSave) |
|
104 |
self.menuFile.addAction(self.actionExit) |
|
105 |
self.menubar.addAction(self.menuFile.menuAction()) |
|
106 |
|
|
107 |
self.retranslateUi(MainWindow) |
|
108 |
QtCore.QMetaObject.connectSlotsByName(MainWindow) |
|
109 |
|
|
110 |
#self.centralwidget.setFocus(True) |
|
111 |
#self.centralwidget.setFocusPolicy(QtCore.Qt.StrongFocus) |
|
112 |
|
|
113 |
#self.centralwidget.keyPressEvent = self.centralKeyPressEvent |
|
114 |
|
|
115 |
def retranslateUi(self, MainWindow): |
|
116 |
_translate = QtCore.QCoreApplication.translate |
|
117 |
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) |
|
118 |
self.menuFile.setTitle(_translate("MainWindow", "File")) |
|
119 |
self.actionOpen.setText(_translate("MainWindow", "Open")) |
|
120 |
self.actionSave.setText(_translate("MainWindow", "Save")) |
|
121 |
self.actionExit.setText(_translate("MainWindow", "Exit")) |
|
122 |
|
|
123 |
#def centralKeyPressEvent(self, event): |
|
124 |
# print("Central Widget Key Pressed") |
|
125 |
|
|
126 |
def initToolMenu(self, topWidget): |
|
127 |
layout = topWidget.layout() |
|
128 |
saveTool = QPushButton() |
|
129 |
saveTool.setText("Save Tool") |
|
130 |
saveTool.mousePressEvent = self.saveToolClickEvent |
|
131 |
layout.addWidget(saveTool) |
|
132 |
|
|
133 |
layout = topWidget.layout() |
|
134 |
handTool = QPushButton() |
|
135 |
handTool.setText("Hand Tool") |
|
136 |
handTool.mousePressEvent = self.handToolClickEvent |
|
137 |
layout.addWidget(handTool) |
|
138 |
|
|
139 |
cropTool = QPushButton() |
|
140 |
cropTool.setText("Crop Tool") |
|
141 |
cropTool.mousePressEvent = self.cropToolClickEvent |
|
142 |
layout.addWidget(cropTool) |
|
143 |
|
|
144 |
eraserTool = QPushButton() |
|
145 |
eraserTool.setText("Eraser Tool") |
|
146 |
eraserTool.mousePressEvent = self.eraserToolClickEvent |
|
147 |
layout.addWidget(eraserTool) |
|
148 |
|
|
149 |
penTool = QPushButton() |
|
150 |
penTool.setText("Pen Tool") |
|
151 |
penTool.mousePressEvent = self.penToolClickEvent |
|
152 |
layout.addWidget(penTool) |
|
153 |
|
|
154 |
def handToolClickEvent(self, event): |
|
155 |
print("hand tool clicked") |
|
156 |
self.mainView.currentMenuTool = QtImageViewer.MENU_HAND_TOOL |
|
157 |
|
|
158 |
def cropToolClickEvent(self, event): |
|
159 |
print("crop tool clicked") |
|
160 |
self.mainView.currentMenuTool = QtImageViewer.MENU_CROP_TOOL |
|
161 |
|
|
162 |
def eraserToolClickEvent(self, event): |
|
163 |
print("eraser tool clicked") |
|
164 |
self.mainView.currentMenuTool = QtImageViewer.MENU_ERASER_TOOL |
|
165 |
|
|
166 |
def penToolClickEvent(self, event): |
|
167 |
print("pen tool clicked") |
|
168 |
self.mainView.currentMenuTool = QtImageViewer.MENU_PEN_TOOL |
|
169 |
|
|
170 |
|
|
171 |
if __name__ == "__main__": |
|
172 |
import sys |
|
173 |
app = QtWidgets.QApplication(sys.argv) |
|
174 |
MainWindow = QtWidgets.QMainWindow() |
|
175 |
ui = Ui_MainWindow() |
|
176 |
ui.setupUi(MainWindow) |
|
177 |
MainWindow.show() |
|
178 |
sys.exit(app.exec_()) |
|
179 |
|
DTI_PID/DTI_PID/XmlGenerator.py | ||
---|---|---|
26 | 26 |
|
27 | 27 |
SSUB_TEXT = "TEXT" |
28 | 28 |
SSUB_ORIGINAL_POINT = "ORIGINALPOINT" |
29 |
SSUB_DECO_DIRECTION = "DECODIRECTION"
|
|
29 |
SSUB_CHILD = "CHILD"
|
|
30 | 30 |
SSUB_ANGLE = "ANGLE" |
31 | 31 |
SSUB_START_POINT = "STARTPOINT" |
32 | 32 |
SSUB_SIZE = "SIZE" |
... | ... | |
80 | 80 |
|
81 | 81 |
return xml |
82 | 82 |
|
83 |
def getDirection(decoDirection):
|
|
83 |
def getConvertedChildInfo(childInfo):
|
|
84 | 84 |
ret = '' |
85 |
if decoDirection == 0: |
|
86 |
ret = "UP" |
|
87 |
elif decoDirection == 1: |
|
88 |
ret = "RIGHT" |
|
89 |
elif decoDirection == 2: |
|
90 |
ret = "DOWN" |
|
85 |
childList = childInfo.split("/") |
|
86 |
for index in range(len(childList)): |
|
87 |
child = childList[index] |
|
88 |
direction = int(child.split(",")[0]) |
|
89 |
childName = child.split(",")[1] |
|
90 |
if index != 0: |
|
91 |
ret = ret + "/" |
|
92 |
directionCode = getDirectionCode(direction) |
|
93 |
ret = ret + directionCode + "," + childName |
|
94 |
return ret |
|
95 |
|
|
96 |
def getDirectionCode(direction): |
|
97 |
ret = "" |
|
98 |
if direction == 0: |
|
99 |
ret = "U" |
|
100 |
elif direction == 1: |
|
101 |
ret = "R" |
|
102 |
elif direction == 2: |
|
103 |
ret = "D" |
|
91 | 104 |
else : |
92 |
ret = "LEFT"
|
|
105 |
ret = "L" |
|
93 | 106 |
return ret |
94 | 107 |
|
95 | 108 |
def getSymbolInfoNode(symbol): |
... | ... | |
102 | 115 |
sAngle = symbol.getRotatedAngle() |
103 | 116 |
sText = symbol.getText() |
104 | 117 |
sOriginalPoint = symbol.getOriginalPoint() |
105 |
sDecoDirection = symbol.getDecoDirection()
|
|
118 |
sChildInfo = symbol.getChildInfo()
|
|
106 | 119 |
sWidth = symbol.getWidth() |
107 | 120 |
sHeight = symbol.getHeight() |
108 | 121 |
|
... | ... | |
134 | 147 |
sOpY = sSp[1] + int(sOriginalPoint.split(',')[1]) |
135 | 148 |
sOriginalPointNode.text = str(sOpX) + "," + str(sOpY) |
136 | 149 |
|
137 |
if sDecoDirection >= 0:
|
|
138 |
sDecoDirectionNode = Element(SSUB_DECO_DIRECTION)
|
|
139 |
sDecoDirectionNode.text = getDirection(sDecoDirection)
|
|
140 |
sCategoryNode.append(sDecoDirectionNode)
|
|
150 |
if sChildInfo is not None:
|
|
151 |
sChildInfoNode = Element(SSUB_CHILD)
|
|
152 |
sChildInfoNode.text = getConvertedChildInfo(sChildInfo)
|
|
153 |
sCategoryNode.append(sChildInfoNode)
|
|
141 | 154 |
|
142 | 155 |
sAngleNode = Element(SSUB_ANGLE) |
143 | 156 |
sAngleNode.text = str(round(math.radians(sAngle), 2)) |
DTI_PID/DTI_PID/symbol.py | ||
---|---|---|
3 | 3 |
class Symbol(SymbolBase): |
4 | 4 |
def __init__(self, id, sName, sClass, sType, sItem, path, sp, width, height, threshold, minMatchCount, mpCount, rotatedAngle |
5 | 5 |
, isDetectOnOrigin, rotationCount, ocrOption, isContainChild = 0 |
6 |
, decoDirection = -1, originalPoint = None, connectionPoint = None):
|
|
6 |
, childInfo = None, originalPoint = None, connectionPoint = None):
|
|
7 | 7 |
SymbolBase.__init__(self, id, sName, sClass, sType, sItem, path, threshold, minMatchCount |
8 | 8 |
, isDetectOnOrigin, rotationCount, ocrOption, isContainChild |
9 |
, decoDirection, originalPoint, connectionPoint)
|
|
9 |
, childInfo, originalPoint, connectionPoint)
|
|
10 | 10 |
self.sp = sp |
11 | 11 |
self.width = width |
12 | 12 |
self.height = height |
내보내기 Unified diff