프로젝트

일반

사용자정보

개정판 f5b9097a

IDf5b9097a5cf2663df4c790f2b6847735cbcb1eb6
상위 0b04ae07
하위 aff546dc

백흠경이(가) 약 5년 전에 추가함

issue #478: 텍스트 인식 시 패딩 크기 증가(10)
- 다른 텍스트 영역에 포함되는 텍스트 영역 제거

Change-Id: I157577f0f98c8f362ac68854fb304de58a37ebcf

차이점 보기:

DTI_PID/DTI_PID/RecognitionDialog.py
135 135
                    selectedContours.append(contour)
136 136

  
137 137
            # draw contour with white color
138
            contourImage = cv2.drawContours(image, selectedContours, -1, (255, 255, 255), -1)
138
            cv2.drawContours(image, selectedContours, -1, (255, 255, 255), -1)
139 139
        except Exception as ex:
140 140
            from App import App
141 141

  
......
143 143
                                                           sys.exc_info()[-1].tb_lineno)
144 144
            App.mainWnd().addMessage.emit(MessageType.Error, message)
145 145

  
146
        return contourImage
146
        return image
147 147

  
148 148
    '''
149 149
        @brief  arrange line's position
......
453 453
                        maxProgressValue = int(maxProgressValue * 0.5) + len(textAreas)
454 454

  
455 455
                    worker.displayTitle.emit(worker.tr('Detecting texts...'))
456
                    textDetector.recognizeText(ocr_image, offset, textAreas, searchedSymbolList, worker,
456
                    textDetector.recognizeText(area.img, offset, textAreas, searchedSymbolList, worker,
457 457
                                               listWidget, maxProgressValue)
458 458
                    textInfoList = textDetector.textInfoList.copy() if textDetector.textInfoList is not None else None
459 459
                    otherTextInfoList = textDetector.otherTextInfoList.copy() if textDetector.otherTextInfoList is not None else None
......
518 518

  
519 519
                # remove text from image
520 520
                Worker.drawFoundSymbolsOnCanvas(mainRes, textInfoList, listWidget)
521
                textDetector.removeTextFromImage(app_doc_data.imgSrc, offset)
521
                textDetector.remove_text_from_image(area.img, offset)
522 522
                if not worker.isTextChecked:
523 523
                    textInfoList.clear()
524 524
                # up to here
DTI_PID/DTI_PID/TextDetector.py
57 57
    def getTextAreaInfo(self, imgGray, offsetX, offsetY):
58 58
        from AppDocData import AppDocData
59 59

  
60
        app_doc_data = AppDocData.instance()
61
        project = app_doc_data.getCurrentProject()
62

  
63
        configs = app_doc_data.getConfigs('Text Size', 'Max Text Size')
64
        maxTextSize = int(configs[0].value) if 1 == len(configs) else 100
65
        minSize = 5
66

  
67
        ocr_image = np.ones(imgGray.shape, np.uint8) * 255
68
        binaryImg, mask = cv2.threshold(imgGray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
69

  
70
        contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
71
        for contour in contours:
72
            # remove too big one or horizontal/vertical line
73
            [x, y, w, h] = cv2.boundingRect(contour)
74
            area = cv2.contourArea(contour, True)
75

  
76
            # skip one which size is greater than max size or less then minimum size
77
            if area >= 0:
78
                if (w > maxTextSize or h > maxTextSize) or (w <= minSize and h <= minSize):
79
                    continue
80

  
81
            if area >= 0:
82
                cv2.drawContours(ocr_image, [contour], -1, (0, 0, 0), -1)
83
                cv2.drawContours(ocr_image, [contour], -1, (255, 255, 255), 1)
84
            else:
85
                cv2.drawContours(ocr_image, [contour], -1, (255, 255, 255), -1)
86

  
87
        path = os.path.join(project.getTempPath(), 'OCR_{}.png'.format(app_doc_data.imgName))
88
        cv2.imwrite(path, ocr_image)
89

  
90
        rects = []
91
        configs = app_doc_data.getConfigs('Text Recognition', 'Expand Size')
92
        expandSize = int(configs[0].value) if 1 == len(configs) else 10
93
        configs = app_doc_data.getConfigs('Text Recognition', 'Shrink Size')
94
        shrinkSize = int(configs[0].value) if 1 == len(configs) else 0
95

  
96
        eroded = cv2.erode(ocr_image, np.ones((expandSize, expandSize), np.uint8))
97
        eroded = cv2.bitwise_not(eroded)
98

  
99
        bboxes = []
100
        contours, hierarchy = cv2.findContours(eroded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
101
        for contour in contours:
102
            area = cv2.contourArea(contour, True)
103
            if area < 0:
104
                [x, y, w, h] = cv2.boundingRect(contour)
105
                bboxes.append(QRect(x, y, w, h))
106

  
107
        # exclude bounding boxes contains child bounding box
108
        not_containing_bbox = []
109
        for bbox in bboxes:
110
            matches = [_bbox for _bbox in bboxes if bbox != _bbox and bbox.contains(_bbox)]
111
            if not matches:
112
                not_containing_bbox.append(bbox)
113
        # up to here
60
        list = []
61
        ocr_image = None
62
        try:
63
            app_doc_data = AppDocData.instance()
64
            project = app_doc_data.getCurrentProject()
65

  
66
            configs = app_doc_data.getConfigs('Text Size', 'Max Text Size')
67
            maxTextSize = int(configs[0].value) if 1 == len(configs) else 100
68
            minSize = 5
114 69

  
115
        for bbox in not_containing_bbox:
116
            x, y = bbox.left(), bbox.top()
117
            w, h = bbox.width(), bbox.height()
118
            img = ocr_image[bbox.top():bbox.bottom(), bbox.left():bbox.right()]
119
            img = cv2.bitwise_not(img)
70
            ocr_image = np.ones(imgGray.shape, np.uint8) * 255
71
            # binaryImg, mask = cv2.threshold(imgGray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
72
            binaryImg, mask = cv2.threshold(imgGray, 200, 255, cv2.THRESH_BINARY)
120 73

  
121
            horizontal, max_width = 0, 0
122
            vertical, max_height = 0, 0
123
            _contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
124
            for xx in _contours:
125
                [_x, _y, _w, _h] = cv2.boundingRect(xx)
74
            contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
75
            for contour in contours:
76
                # remove too big one or horizontal/vertical line
77
                [x, y, w, h] = cv2.boundingRect(contour)
78
                area = cv2.contourArea(contour, True)
126 79

  
127
                max_width = _x if _x > max_width else max_width
128
                max_height = _y if _y > max_height else max_height
80
                # skip one which size is greater than max size or less then minimum size
81
                if area >= 0:
82
                    if (w > maxTextSize or h > maxTextSize) or (w <= minSize and h <= minSize):
83
                        continue
129 84

  
130
                if (_w < _h) or (_w > maxTextSize > _h):  # width is greater than height
131
                    horizontal += 1 + (_w * _h) / (w * h)
85
                if area >= 0:
86
                    cv2.drawContours(ocr_image, [contour], -1, (0, 0, 0), -1)
87
                    cv2.drawContours(ocr_image, [contour], -1, (255, 255, 255), 1)
132 88
                else:
133
                    vertical += 1 + (_w * _h) / (w * h)
134

  
135
            if (w < minSize and h < minSize) or (max_width > maxTextSize and max_height > maxTextSize):
136
                continue  # skip too small or big one
137

  
138
            rects.append([0 if horizontal > vertical else 90, QRect(x, y, w, h)])
139

  
140
        configs = app_doc_data.getConfigs('Text Recognition', 'Merge Size')
141
        mergeSize = int(configs[0].value) if 1 == len(configs) else 10
142
        # merge rectangles
143
        interestings = []
144
        while rects:
145
            rect = rects.pop()
146

  
147
            if 0 == rect[0]:    # x-direction text
148
                rectExpand = rect[1].adjusted(-mergeSize, 0, mergeSize, 0)
149
                matches = [x for x in rects if (x[0] == rect[0]) and
150
                           abs(x[1].height() - rect[1].height()) < (x[1].height() + rect[1].height())*0.5 and
151
                           abs(x[1].center().y() - rect[1].center().y()) < rect[1].height()*0.5 and
152
                           rectExpand.intersects(x[1])]
153
            else:               # y -direction text
154
                rectExpand = rect[1].adjusted(0, -mergeSize, 0, mergeSize)
155
                matches = [x for x in rects if (x[0] == rect[0]) and
156
                           abs(x[1].width() - rect[1].width()) < (x[1].width() + rect[1].width())*0.5 and
157
                           abs(x[1].center().x() - rect[1].center().x()) < rect[1].width()*0.5 and
158
                           rectExpand.intersects(x[1])]
159

  
160
            if matches:
161
                for _rect in matches:
162
                    rect[1] = rect[1].united(_rect[1])
163
                    if _rect in rects:
164
                        rects.remove(_rect)
165
                rects.append(rect)
166
            else:
167
                interestings.append(rect)
89
                    cv2.drawContours(ocr_image, [contour], -1, (255, 255, 255), -1)
90

  
91
            path = os.path.join(project.getTempPath(), 'OCR_{}.png'.format(app_doc_data.imgName))
92
            cv2.imwrite(path, ocr_image)
93

  
94
            rects = []
95
            configs = app_doc_data.getConfigs('Text Recognition', 'Expand Size')
96
            expandSize = int(configs[0].value) if 1 == len(configs) else 10
97
            configs = app_doc_data.getConfigs('Text Recognition', 'Shrink Size')
98
            shrinkSize = int(configs[0].value) if 1 == len(configs) else 0
99

  
100
            eroded = cv2.erode(ocr_image, np.ones((expandSize, expandSize), np.uint8))
101
            eroded = cv2.bitwise_not(eroded)
102

  
103
            bboxes = []
104
            contours, hierarchy = cv2.findContours(eroded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
105
            for contour in contours:
106
                area = cv2.contourArea(contour, True)
107
                if area < 0:
108
                    [x, y, w, h] = cv2.boundingRect(contour)
109
                    bboxes.append(QRect(x, y, w, h))
110

  
111
            # exclude bounding boxes contains child bounding box
112
            not_containing_bbox = []
113
            for bbox in bboxes:
114
                matches = [_bbox for _bbox in bboxes if bbox != _bbox and bbox.contains(_bbox)]
115
                if not matches:
116
                    not_containing_bbox.append(bbox)
117
            # up to here
168 118

  
169
        list = []
170
        for rect in interestings:
171
            angle = rect[0]
172
            list.append(ti.TextInfo('', round(offsetX) + rect[1].x(), round(offsetY) + rect[1].y(), rect[1].width(),
173
                                    rect[1].height(), angle))
119
            for bbox in not_containing_bbox:
120
                x, y = bbox.left(), bbox.top()
121
                w, h = bbox.width(), bbox.height()
122
                img = ocr_image[bbox.top():bbox.bottom(), bbox.left():bbox.right()]
123
                img = cv2.bitwise_not(img)
124

  
125
                horizontal, max_width = 0, 0
126
                vertical, max_height = 0, 0
127
                _contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
128
                for xx in _contours:
129
                    [_x, _y, _w, _h] = cv2.boundingRect(xx)
130

  
131
                    max_width = _x if _x > max_width else max_width
132
                    max_height = _y if _y > max_height else max_height
133

  
134
                    if (_w < _h) or (_w > maxTextSize > _h):  # width is greater than height
135
                        horizontal += 1 + (_w * _h) / (w * h)
136
                    else:
137
                        vertical += 1 + (_w * _h) / (w * h)
138

  
139
                if (w < minSize and h < minSize) or (max_width > maxTextSize and max_height > maxTextSize):
140
                    continue  # skip too small or big one
141

  
142
                rects.append([0 if horizontal > vertical else 90, QRect(x, y, w, h)])
143

  
144
            configs = app_doc_data.getConfigs('Text Recognition', 'Merge Size')
145
            mergeSize = int(configs[0].value) if 1 == len(configs) else 10
146
            # merge rectangles
147
            interestings = []
148
            while rects:
149
                rect = rects.pop()
150

  
151
                if 0 == rect[0]:    # x-direction text
152
                    rectExpand = rect[1].adjusted(-mergeSize, 0, mergeSize, 0)
153
                    matches = [x for x in rects if (x[0] == rect[0]) and
154
                               abs(x[1].height() - rect[1].height()) < (x[1].height() + rect[1].height())*0.5 and
155
                               abs(x[1].center().y() - rect[1].center().y()) < rect[1].height()*0.5 and
156
                               rectExpand.intersects(x[1])]
157
                else:               # y -direction text
158
                    rectExpand = rect[1].adjusted(0, -mergeSize, 0, mergeSize)
159
                    matches = [x for x in rects if (x[0] == rect[0]) and
160
                               abs(x[1].width() - rect[1].width()) < (x[1].width() + rect[1].width())*0.5 and
161
                               abs(x[1].center().x() - rect[1].center().x()) < rect[1].width()*0.5 and
162
                               rectExpand.intersects(x[1])]
163

  
164
                if matches:
165
                    for _rect in matches:
166
                        rect[1] = rect[1].united(_rect[1])
167
                        if _rect in rects:
168
                            rects.remove(_rect)
169
                    rects.append(rect)
170
                else:
171
                    interestings.append(rect)
172

  
173
            for rect in interestings:
174
                matches = [_rect for _rect in interestings if rect != _rect and _rect[1].contains(rect[1])]
175
                # if there is no boxes which contains
176
                if not matches:
177
                    angle = rect[0]
178
                    list.append(ti.TextInfo('', round(offsetX) + rect[1].x(), round(offsetY) + rect[1].y(), rect[1].width(),
179
                                            rect[1].height(), angle))
180
        except Exception as ex:
181
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
182
                                                           sys.exc_info()[-1].tb_lineno)
183
            print(message)
174 184

  
175 185
        return list, ocr_image
176 186

  
......
272 282
            app_doc_data = AppDocData.instance()
273 283
            project = app_doc_data.getCurrentProject()
274 284

  
275
            text_info_array = np.array_split(tInfoList, THREAD_MAX_WORKER)
285
            text_info_array = np.array_split(tInfoList, THREAD_MAX_WORKER if len(tInfoList) > THREAD_MAX_WORKER else \
286
                len(tInfoList))
276 287
            with futures.ThreadPoolExecutor(max_workers=THREAD_MAX_WORKER) as pool:
277 288
                future_text = {pool.submit(TextDetector.recognizeTextFromImage, tInfo, imgSrc, offset,
278 289
                                       searchedSymbolList, worker, listWidget, maxProgressValue):
279 290
                               tInfo for tInfo in text_info_array}
280
                """
281
                future = pool.submit(TextDetector.recognizeTextFromImage, tInfo, imgSrc, offset,
282
                                     searchedSymbolList, worker, listWidget, maxProgressValue)
283
                """
291

  
284 292
                for future in futures.as_completed(future_text):
285 293
                    try:
286 294
                        data = future.result()
......
340 348

  
341 349
            if worker is not None: worker.updateProgress.emit(maxProgressValue, None)
342 350

  
343
            """
351
            """"
344 352
            for text_box in tInfoList:
345 353
                x = text_box.getX()
346 354
                y = text_box.getY()
......
359 367
        @date       2018.07.24
360 368
    '''
361 369

  
362
    def removeTextFromImage(self, imgSrc, offset):
363
        appDocData = AppDocData.instance()
364
        project = appDocData.getCurrentProject()
365

  
366
        path = os.path.join(project.getTempPath(), 'OCR_{}.png'.format(appDocData.imgName))
367
        if os.path.isfile(path):
368
            imgOCR = cv2.imread(path)
369
            imgOCR = \
370
            cv2.threshold(cv2.cvtColor(imgOCR, cv2.COLOR_BGR2GRAY), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
371

  
372
            # remove recognized text from image
373
            for text in self.textInfoList:
374
                x = round(text.getX() - offset[0])
375
                y = round(text.getY() - offset[1])
376
                width = round(text.getW())
377
                height = round(text.getH())
378
                self.removeText(imgSrc, (round(text.getX()), round(text.getY())), imgOCR[y:y + height, x:x + width])
379
            # up to here
380

  
381
    '''
382
        @brief  remove text from image by using ocr image
383
        @author
384
    '''
385

  
386
    def removeText(self, img, pt, imgOCR):
387
        try:
388
            x = round(pt[0])
389
            y = round(pt[1])
390
            width, height = imgOCR.shape[::-1]
391

  
392
            temp = img[y:y + height, x:x + width]
393
            imgOCR = cv2.erode(imgOCR, np.ones((3, 3), np.uint8))
394
            mask = cv2.bitwise_or(temp, imgOCR)
395
            imgXOR = cv2.bitwise_xor(temp, mask)
396
            img[y:y + height, x:x + width] = cv2.bitwise_not(imgXOR)
370
    def remove_text_from_image(self, imgSrc, offset):
371
        # remove recognized text from image
372
        for text in self.textInfoList:
373
            x = round(text.getX() - offset[0])
374
            y = round(text.getY() - offset[1])
375
            width = round(text.getW())
376
            height = round(text.getH())
377
            cv2.rectangle(imgSrc, (x, y), (x + width, y + height), 255, -1)
378
        # up to here
397 379

  
398
        except Exception as ex:
399
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
400
                                                       sys.exc_info()[-1].tb_lineno))
380
        # DEBUG
381
        #cv2.imwrite("c:\\temp\\remove_texts.png", imgSrc)
401 382

  
402
        return img
DTI_PID/DTI_PID/potrace.py
5 5
import numpy as np, cv2, subprocess
6 6
import os, sys
7 7
from xml.dom import minidom
8
import svg.path
9 8
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
10 9
import xml.etree.ElementTree as ET
11 10
import SymbolBase
DTI_PID/DTI_PID/tesseract_ocr_module.py
40 40
DEFAULT_CONF = """
41 41
    --psm {} -c tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-~.,/!@#$%&*(){}[]<>:;+=?\\"
42 42
"""
43
DEFAULT_CONF_COMM = "--psm {} -c preserve_interword_spaces=1"
43
DEFAULT_CONF_COMM = "--psm {}"
44 44

  
45 45

  
46 46
def exist_trained_data():
......
84 84
        configs = app_doc_data.getConfigs('Text Recognition', 'Page Segmentation Modes')
85 85
        _conf = DEFAULT_CONF_COMM.format(configs[0].value if configs else '3')
86 86
        if conf:
87
            _conf += f" tessedit_char_whitelist=\"{conf}\""
87
            _conf += f" -c tessedit_char_whitelist=\"{conf}\""
88 88

  
89 89
        oCRLang = language
90 90

  
......
100 100
            allowed_single_chars = []
101 101
        # up to here
102 102

  
103
        thickness = 3
103
        thickness = 10
104 104
        im = Image.fromarray(img)
105 105
        # add padding to increase text recognition
106 106
        im = ImageOps.expand(im, border=thickness, fill='white')
......
112 112
        merged_boxes = []
113 113

  
114 114
        # before
115
        """
116 115
        for box in bounding_boxes:
117 116
            if merged_boxes:
118 117
                tokens = box.split(' ')
......
121 120
                    miny = int(tokens[2])
122 121
                    maxx = int(tokens[3])
123 122
                    maxy = int(tokens[4])
123
                    tmp = QRect(minx, miny, maxx - minx, maxy - miny)
124

  
125
                    matches = [merged_box for merged_box in merged_boxes if
126
                               (merged_box.top() - tmp.center().y())*(merged_box.bottom() - tmp.center().y()) < 0]
127
                    if matches:
128
                        matches[0].setLeft(min(matches[0].left(), minx))
129
                        matches[0].setTop(min(matches[0].top(), miny))
130
                        matches[0].setRight(max(matches[0].right(), maxx))
131
                        matches[0].setBottom(max(matches[0].bottom(), maxy))
132
                    else:
133
                        merged_boxes.append(QRect(minx, miny, maxx - minx, maxy - miny))
134

  
124 135

  
136
                    """
125 137
                    top = merged_boxes[-1].top()
126 138
                    bottom = merged_boxes[-1].bottom()
127 139

  
......
132 144
                        merged_boxes[-1].setTop(min(merged_boxes[-1].top(), miny))
133 145
                        merged_boxes[-1].setRight(max(merged_boxes[-1].right(), maxx))
134 146
                        merged_boxes[-1].setBottom(max(merged_boxes[-1].bottom(), maxy))
147
                    """
135 148
            else:
136 149
                tokens = box.split(' ')
137 150
                if len(tokens) >= 5:
......
140 153
                    maxx = int(tokens[3])
141 154
                    maxy = int(tokens[4])
142 155
                    merged_boxes.append(QRect(minx, miny, maxx - minx, maxy - miny))
143
        """
144 156

  
157
        """
145 158
        # After
146 159
        for box in bounding_boxes:
147 160
            if merged_boxes:
......
200 213
                if go_loop:
201 214
                    break
202 215
        # After
216
        """
203 217

  
204 218
        for rect in merged_boxes:
205 219
            if not rect.isValid() or \

내보내기 Unified diff

클립보드 이미지 추가 (최대 크기: 500 MB)