개정판 3d2440f0
Contour로 텍스트 영역 검출 함수 생성 및 환경설정에서 지정한 TypeA/B 값에 따라, Azure 혹은 Contour로 텍스트 영역 획득하도록 수정
DTI_PID/DTI_PID/Configuration_UI.py | ||
---|---|---|
11 | 11 |
class Ui_ConfigurationDialog(object): |
12 | 12 |
def setupUi(self, ConfigurationDialog): |
13 | 13 |
ConfigurationDialog.setObjectName("ConfigurationDialog") |
14 |
ConfigurationDialog.resize(550, 474)
|
|
14 |
ConfigurationDialog.resize(550, 502)
|
|
15 | 15 |
font = QtGui.QFont() |
16 | 16 |
font.setFamily("맑은 고딕") |
17 | 17 |
ConfigurationDialog.setFont(font) |
... | ... | |
139 | 139 |
self.gridLayout_14.setObjectName("gridLayout_14") |
140 | 140 |
self.verticalLayout_5 = QtWidgets.QVBoxLayout() |
141 | 141 |
self.verticalLayout_5.setObjectName("verticalLayout_5") |
142 |
self.horizontalLayout_14 = QtWidgets.QHBoxLayout() |
|
143 |
self.horizontalLayout_14.setObjectName("horizontalLayout_14") |
|
144 |
self.label_19 = QtWidgets.QLabel(self.groupBoxText) |
|
145 |
self.label_19.setObjectName("label_19") |
|
146 |
self.horizontalLayout_14.addWidget(self.label_19) |
|
147 |
self.textAreaTypeARadioButton = QtWidgets.QRadioButton(self.groupBoxText) |
|
148 |
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) |
|
149 |
sizePolicy.setHorizontalStretch(0) |
|
150 |
sizePolicy.setVerticalStretch(0) |
|
151 |
sizePolicy.setHeightForWidth(self.textAreaTypeARadioButton.sizePolicy().hasHeightForWidth()) |
|
152 |
self.textAreaTypeARadioButton.setSizePolicy(sizePolicy) |
|
153 |
self.textAreaTypeARadioButton.setChecked(True) |
|
154 |
self.textAreaTypeARadioButton.setObjectName("textAreaTypeARadioButton") |
|
155 |
self.buttonGroup = QtWidgets.QButtonGroup(ConfigurationDialog) |
|
156 |
self.buttonGroup.setObjectName("buttonGroup") |
|
157 |
self.buttonGroup.addButton(self.textAreaTypeARadioButton) |
|
158 |
self.horizontalLayout_14.addWidget(self.textAreaTypeARadioButton) |
|
159 |
self.textAreaTypeBRadioButton = QtWidgets.QRadioButton(self.groupBoxText) |
|
160 |
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) |
|
161 |
sizePolicy.setHorizontalStretch(0) |
|
162 |
sizePolicy.setVerticalStretch(0) |
|
163 |
sizePolicy.setHeightForWidth(self.textAreaTypeBRadioButton.sizePolicy().hasHeightForWidth()) |
|
164 |
self.textAreaTypeBRadioButton.setSizePolicy(sizePolicy) |
|
165 |
self.textAreaTypeBRadioButton.setObjectName("textAreaTypeBRadioButton") |
|
166 |
self.buttonGroup.addButton(self.textAreaTypeBRadioButton) |
|
167 |
self.horizontalLayout_14.addWidget(self.textAreaTypeBRadioButton) |
|
168 |
self.textAreaHelpLabel = QtWidgets.QLabel(self.groupBoxText) |
|
169 |
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) |
|
170 |
sizePolicy.setHorizontalStretch(0) |
|
171 |
sizePolicy.setVerticalStretch(0) |
|
172 |
sizePolicy.setHeightForWidth(self.textAreaHelpLabel.sizePolicy().hasHeightForWidth()) |
|
173 |
self.textAreaHelpLabel.setSizePolicy(sizePolicy) |
|
174 |
self.textAreaHelpLabel.setMinimumSize(QtCore.QSize(20, 20)) |
|
175 |
self.textAreaHelpLabel.setMaximumSize(QtCore.QSize(20, 20)) |
|
176 |
self.textAreaHelpLabel.setText("") |
|
177 |
self.textAreaHelpLabel.setTextFormat(QtCore.Qt.AutoText) |
|
178 |
self.textAreaHelpLabel.setPixmap(QtGui.QPixmap("../res/info.png")) |
|
179 |
self.textAreaHelpLabel.setScaledContents(True) |
|
180 |
self.textAreaHelpLabel.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) |
|
181 |
self.textAreaHelpLabel.setObjectName("textAreaHelpLabel") |
|
182 |
self.horizontalLayout_14.addWidget(self.textAreaHelpLabel) |
|
183 |
self.verticalLayout_5.addLayout(self.horizontalLayout_14) |
|
142 | 184 |
self.horizontalLayout_13 = QtWidgets.QHBoxLayout() |
143 | 185 |
self.horizontalLayout_13.setObjectName("horizontalLayout_13") |
144 | 186 |
self.label_17 = QtWidgets.QLabel(self.groupBoxText) |
... | ... | |
328 | 370 |
self.label_2.setText(_translate("ConfigurationDialog", "Delimiter : ")) |
329 | 371 |
self.pushButtonAddProperty.setText(_translate("ConfigurationDialog", "추가")) |
330 | 372 |
self.groupBoxText.setTitle(_translate("ConfigurationDialog", "텍스트 검출")) |
373 |
self.label_19.setText(_translate("ConfigurationDialog", "텍스트 영역 검출 방식 : ")) |
|
374 |
self.textAreaTypeARadioButton.setText(_translate("ConfigurationDialog", "Type A")) |
|
375 |
self.textAreaTypeBRadioButton.setText(_translate("ConfigurationDialog", "Type B")) |
|
331 | 376 |
self.label_17.setText(_translate("ConfigurationDialog", "Minimum Text Size : ")) |
332 | 377 |
self.label_18.setText(_translate("ConfigurationDialog", "Maximum Text Size : ")) |
333 | 378 |
self.tabWidget.setTabText(self.tabWidget.indexOf(self.Recognition), _translate("ConfigurationDialog", "인식")) |
DTI_PID/DTI_PID/DTI_PID.py | ||
---|---|---|
705 | 705 |
@date |
706 | 706 |
@history humkyung 2018.04.06 check if file exists |
707 | 707 |
Jeongwoo 2018.05.09 Use Tesseract OCR after Azure OCR (Azure OCR : Getting text area) |
708 |
Jeongwoo 2018.05.25 Add condition on if-statemen |
|
708 |
Jeongwoo 2018.05.25 Add condition on if-statement |
|
709 |
Jeongwoo 2018.06.05 Get text area data list by config.type |
|
709 | 710 |
''' |
710 | 711 |
def initMainSrc(mainRes): |
711 | 712 |
global srcGray |
... | ... | |
718 | 719 |
ocrCompletedSrc = srcGray.copy() |
719 | 720 |
|
720 | 721 |
area = AppDocData.instance().getArea('Drawing') |
721 |
|
|
722 |
configs = AppDocData.instance().getConfigs('Text Area', 'Text Area') |
|
723 |
type = int(configs[0].value) if 1 == len(configs) else 0 |
|
722 | 724 |
#(_tempOcrSrc, textInfoList) = OCR.removeTextFromNpArray(area.img if area is not None else srcGray, area.x if area is not None else 0, area.y if area is not None else 0) |
723 |
(_tempOcrSrc, tInfoList) = OCR.removeTextFromNpArray(area.img if area is not None else srcGray, area.x if area is not None else 0, area.y if area is not None else 0) |
|
725 |
tInfoList = [] |
|
726 |
if type == 0: |
|
727 |
(_tempOcrSrc, tInfoList) = OCR.removeTextFromNpArray(area.img if area is not None else srcGray, area.x if area is not None else 0, area.y if area is not None else 0) |
|
728 |
else: |
|
729 |
tInfoList = getTextAreaInfo(area.img if area is not None else srcGray, area.x if area is not None else 0, area.y if area is not None else 0) |
|
724 | 730 |
|
725 | 731 |
global MIN_TEXT_SIZE |
726 | 732 |
for tInfo in tInfoList: |
... | ... | |
983 | 989 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
984 | 990 |
|
985 | 991 |
#return res |
992 |
|
|
993 |
''' |
|
994 |
@brief Get Text Area info by contour |
|
995 |
@author Jeongwoo |
|
996 |
@date 2018.06.05 |
|
997 |
''' |
|
998 |
def getTextAreaInfo(imgGray, offsetX, offsetY): |
|
999 |
contourImg = np.ones(imgGray.shape, np.uint8) * 255 |
|
1000 |
contourOcrImg = contourImg.copy() |
|
1001 |
binaryImg,mask = cv2.threshold(imgGray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) |
|
1002 |
|
|
1003 |
image, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) |
|
1004 |
for contour in contours: |
|
1005 |
area = cv2.contourArea(contour, True) |
|
1006 |
if area >= 0: |
|
1007 |
[x, y, w, h] = cv2.boundingRect(contour) |
|
1008 |
|
|
1009 |
# remove too big or small one |
|
1010 |
if (w > 100 or h > 100) or (w < 5 or h < 5): continue |
|
1011 |
|
|
1012 |
cv2.drawContours(contourImg, [contour], -1, (0,0,0), 1) |
|
1013 |
cv2.drawContours(contourOcrImg, [contour], -1, (0,0,0), -1) |
|
1014 |
else: |
|
1015 |
cv2.drawContours(contourOcrImg, [contour], -1, (255,255,255), -1) |
|
1016 |
|
|
1017 |
rects = [] |
|
1018 |
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (8, 8)) |
|
1019 |
eroded = cv2.erode(contourImg, kernel) |
|
1020 |
image, contours, hierarchy = cv2.findContours(eroded, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE) |
|
1021 |
for contour in contours: |
|
1022 |
area = cv2.contourArea(contour, True) |
|
1023 |
if area >= 0: |
|
1024 |
[x, y, w, h] = cv2.boundingRect(contour) |
|
1025 |
# remove small one less than character size |
|
1026 |
if (w < 20 or h < 20): continue |
|
1027 |
rects.append(QRect(x, y, w, h)) # expand rect |
|
1028 |
|
|
1029 |
intersected = True |
|
1030 |
while intersected: |
|
1031 |
intersected = False |
|
1032 |
for rect in rects[:]: |
|
1033 |
matches = [x for x in rects if rect.intersects(x)] |
|
1034 |
if len(matches) > 1: |
|
1035 |
united = matches[0] |
|
1036 |
for _rect in matches: |
|
1037 |
united = united.united(_rect) |
|
1038 |
if _rect in rects: rects.remove(_rect) |
|
1039 |
rects.append(united) |
|
1040 |
intersected = True |
|
1041 |
break |
|
1042 |
|
|
1043 |
list = [] |
|
1044 |
for rect in rects: |
|
1045 |
list.append(ti.TextInfo('', int(offsetX) + rect.x(), int(offsetY) + rect.y(), rect.width(), rect.height(), 0)) |
|
1046 |
return list |
|
986 | 1047 |
|
987 | 1048 |
if __name__ == '__main__': |
988 | 1049 |
import DTI_PID_UI |
... | ... | |
993 | 1054 |
|
994 | 1055 |
start = timeit.default_timer() |
995 | 1056 |
img = cv2.imread('D:/Visual Studio Project/DTIPID/DTIPID/DTI_PID/DTI_PID/res/Result/PC-K/PC-K-2203_P1_800DPI.png', 1) |
996 |
ocrImg = img.copy() |
|
997 | 1057 |
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
998 | 1058 |
contourImg = np.ones(imgGray.shape, np.uint8)*255 |
999 | 1059 |
contourOcrImg = contourImg.copy() |
DTI_PID/DTI_PID/QConfigurationDialog.py | ||
---|---|---|
45 | 45 |
humkyung 2018.05.09 read line no tag rule configuration |
46 | 46 |
Jeongwoo 2018.05.18 read Small Line Minimum Length |
47 | 47 |
Jeongwoo 2018.06.04 read Min/Max Text Size |
48 |
Jeongwoo 2018.06.05 read Text Area Detection Method |
|
48 | 49 |
''' |
49 | 50 |
def __init__(self, parent): |
50 | 51 |
QDialog.__init__(self, parent) |
... | ... | |
58 | 59 |
self.itemModel = QStandardItemModel() |
59 | 60 |
|
60 | 61 |
docData = AppDocData.instance() |
62 |
configs = docData.getConfigs('Text Area', 'Text Area') |
|
63 |
value = int(configs[0].value) if 1 == len(configs) else 0 |
|
64 |
if value == 0: |
|
65 |
self.ui.textAreaTypeARadioButton.setChecked(True) |
|
66 |
else: |
|
67 |
self.ui.textAreaTypeBRadioButton.setChecked(True) |
|
68 |
|
|
61 | 69 |
configs = docData.getConfigs('Text Size', 'Min Text Size') |
62 | 70 |
self.ui.minTextSizeSpinBox.setValue(int(configs[0].value)) if 1 == len(configs) else self.ui.minTextSizeSpinBox.setValue(30) |
63 | 71 |
configs = docData.getConfigs('Text Size', 'Max Text Size') |
... | ... | |
156 | 164 |
humkyung 2018.05.09 save line no tag rule |
157 | 165 |
Jeongwoo 2018.05.18 save Small Line Minimum Length |
158 | 166 |
Jeongwoo 2018.06.04 save Min/Max Text Size |
167 |
Jeongwoo 2018.06.05 save Text Area Detection Method |
|
159 | 168 |
''' |
160 | 169 |
def accept(self): |
161 | 170 |
try: |
162 | 171 |
self.isAccepted = True |
163 | 172 |
|
164 | 173 |
configs = [] |
174 |
configs.append(Config('Text Area', 'Text Area', 0 if self.ui.textAreaTypeARadioButton.isChecked() else 1)) |
|
165 | 175 |
configs.append(Config('Text Size', 'Min Text Size', self.ui.minTextSizeSpinBox.value())) |
166 | 176 |
configs.append(Config('Text Size', 'Max Text Size', self.ui.maxTextSizeSpinBox.value())) |
167 | 177 |
configs.append(Config('Size', 'Delimiter', self.ui.lineEditSizeDelimiter.text())) |
DTI_PID/DTI_PID/UI/Configuration.ui | ||
---|---|---|
7 | 7 |
<x>0</x> |
8 | 8 |
<y>0</y> |
9 | 9 |
<width>550</width> |
10 |
<height>474</height>
|
|
10 |
<height>502</height>
|
|
11 | 11 |
</rect> |
12 | 12 |
</property> |
13 | 13 |
<property name="font"> |
... | ... | |
228 | 228 |
<item row="0" column="0"> |
229 | 229 |
<layout class="QVBoxLayout" name="verticalLayout_5"> |
230 | 230 |
<item> |
231 |
<layout class="QHBoxLayout" name="horizontalLayout_14"> |
|
232 |
<item> |
|
233 |
<widget class="QLabel" name="label_19"> |
|
234 |
<property name="text"> |
|
235 |
<string>텍스트 영역 검출 방식 : </string> |
|
236 |
</property> |
|
237 |
</widget> |
|
238 |
</item> |
|
239 |
<item> |
|
240 |
<widget class="QRadioButton" name="textAreaTypeARadioButton"> |
|
241 |
<property name="sizePolicy"> |
|
242 |
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> |
|
243 |
<horstretch>0</horstretch> |
|
244 |
<verstretch>0</verstretch> |
|
245 |
</sizepolicy> |
|
246 |
</property> |
|
247 |
<property name="text"> |
|
248 |
<string>Type A</string> |
|
249 |
</property> |
|
250 |
<property name="checked"> |
|
251 |
<bool>true</bool> |
|
252 |
</property> |
|
253 |
<attribute name="buttonGroup"> |
|
254 |
<string notr="true">buttonGroup</string> |
|
255 |
</attribute> |
|
256 |
</widget> |
|
257 |
</item> |
|
258 |
<item> |
|
259 |
<widget class="QRadioButton" name="textAreaTypeBRadioButton"> |
|
260 |
<property name="sizePolicy"> |
|
261 |
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> |
|
262 |
<horstretch>0</horstretch> |
|
263 |
<verstretch>0</verstretch> |
|
264 |
</sizepolicy> |
|
265 |
</property> |
|
266 |
<property name="text"> |
|
267 |
<string>Type B</string> |
|
268 |
</property> |
|
269 |
<attribute name="buttonGroup"> |
|
270 |
<string notr="true">buttonGroup</string> |
|
271 |
</attribute> |
|
272 |
</widget> |
|
273 |
</item> |
|
274 |
<item> |
|
275 |
<widget class="QLabel" name="textAreaHelpLabel"> |
|
276 |
<property name="sizePolicy"> |
|
277 |
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> |
|
278 |
<horstretch>0</horstretch> |
|
279 |
<verstretch>0</verstretch> |
|
280 |
</sizepolicy> |
|
281 |
</property> |
|
282 |
<property name="minimumSize"> |
|
283 |
<size> |
|
284 |
<width>20</width> |
|
285 |
<height>20</height> |
|
286 |
</size> |
|
287 |
</property> |
|
288 |
<property name="maximumSize"> |
|
289 |
<size> |
|
290 |
<width>20</width> |
|
291 |
<height>20</height> |
|
292 |
</size> |
|
293 |
</property> |
|
294 |
<property name="text"> |
|
295 |
<string/> |
|
296 |
</property> |
|
297 |
<property name="textFormat"> |
|
298 |
<enum>Qt::AutoText</enum> |
|
299 |
</property> |
|
300 |
<property name="pixmap"> |
|
301 |
<pixmap>../res/info.png</pixmap> |
|
302 |
</property> |
|
303 |
<property name="scaledContents"> |
|
304 |
<bool>true</bool> |
|
305 |
</property> |
|
306 |
<property name="alignment"> |
|
307 |
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> |
|
308 |
</property> |
|
309 |
</widget> |
|
310 |
</item> |
|
311 |
</layout> |
|
312 |
</item> |
|
313 |
<item> |
|
231 | 314 |
<layout class="QHBoxLayout" name="horizontalLayout_13"> |
232 | 315 |
<item alignment="Qt::AlignLeft"> |
233 | 316 |
<widget class="QLabel" name="label_17"> |
... | ... | |
542 | 625 |
</hints> |
543 | 626 |
</connection> |
544 | 627 |
</connections> |
628 |
<buttongroups> |
|
629 |
<buttongroup name="buttonGroup"/> |
|
630 |
</buttongroups> |
|
545 | 631 |
</ui> |
내보내기 Unified diff