프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / LineDetector.py @ 5d8f9002

이력 | 보기 | 이력해설 | 다운로드 (26.1 KB)

1
import sys
2
import cv2
3
import numpy as np
4
import math
5
import shapely
6

    
7
class LineDetector():
8
    def __init__(self, image):
9
        try:
10
            thresh = 127
11
            self._image = image
12
            self.width, self.height = self._image.shape[::-1]
13
            self.Result = np.zeros((self.width, self.height, 3), np.uint8)
14
        except Exception as ex:
15
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
16

    
17
    '''
18
        @brief  dot product of given two vectors
19
        @author humkyung
20
        @date   2018.04.14
21
    '''
22
    def dotProduct(self, lhs, rhs):
23
        return sum([lhs[i]*rhs[i] for i in range(len(lhs))])
24

    
25
    '''
26
        @brief  get length of given vector
27
        @author humkyung
28
        @date   2018.04.14
29
    '''
30
    def getLength(self, lhs):
31
        return math.sqrt(self.dotProduct(lhs, lhs))
32

    
33
    '''
34
        @brief  get angle between given two vectors
35
        @author humkyung
36
        @date   2018.04.14
37
        @history    2018.05.29  Jeongwoo    Add try-exception
38
        @TODO : Need to modify case - Exception
39
    '''
40
    def getAngle(self, lhs, rhs):
41
        try:
42
            return math.acos(self.dotProduct(lhs, rhs) / (self.getLength(lhs) * self.getLength(rhs)))
43
        except Exception as ex:
44
            return sys.float_info.max
45
        
46
    """
47
        @brief  get distance between given two points
48
        @author humkyung
49
        @date   2018.04.13
50
    """
51
    def distanceTo(self, lhs, rhs):
52
        dx = rhs[0] - lhs[0]
53
        dy = rhs[1] - lhs[1]
54
        return math.sqrt(dx*dx + dy*dy)
55

    
56
    '''
57
        @brief  rotate given point about origin by angle
58
        @author humkyung
59
        @date   2018.04.12
60
    '''
61
    def rotatePoint(self, point, origin, angle):
62
        dx = point[0] - origin[0]
63
        dy = point[1] - origin[1]
64

    
65
        qx = origin[0] + math.cos(angle) * dx - math.sin(angle) * dy
66
        qy = origin[1] + math.sin(angle) * dx + math.cos(angle) * dy
67
        return [qx, qy]
68

    
69
    """
70
        @brief  두 직선이 평행한지 판별한다.
71
        @author humkyung
72
        @date   2018.??.??
73
    """
74
    def isParallel(self, lhs, rhs):
75
        try:
76
            vectors = [(lhs[1][0]-lhs[0][0], lhs[1][1]-lhs[0][1]), (rhs[1][0]-rhs[0][0], rhs[1][1]-rhs[0][1])]
77
            angle = self.getAngle(vectors[0], vectors[1])
78
            if (angle == 0) or (angle == math.pi): return True
79
        except ZeroDivisionError:
80
            return True
81

    
82
        return False
83
        
84
    '''
85
        @brief  check if given two lines are connected
86
        @author humkyung
87
        @date   2018.04.11
88
    '''
89
    def isConnected(self, lhs, rhs, toler=0):
90
        length = []
91

    
92
        try:
93
            # check if share one point
94
            dx = (lhs[0][0] - rhs[0][0])
95
            dy = (lhs[0][1] - rhs[0][1])
96
            length.append(math.sqrt(dx*dx + dy*dy))
97
            dx = (lhs[1][0] - rhs[0][0])
98
            dy = (lhs[1][1] - rhs[0][1])
99
            length.append(math.sqrt(dx*dx + dy*dy))
100
            dx = (lhs[0][0] - rhs[1][0])
101
            dy = (lhs[0][1] - rhs[1][1])
102
            length.append(math.sqrt(dx*dx + dy*dy))
103
            dx = (lhs[1][0] - rhs[1][0])
104
            dy = (lhs[1][1] - rhs[1][1])
105
            length.append(math.sqrt(dx*dx + dy*dy))
106
            matches = [len for len in length if len < toler]
107
            # up to here
108

    
109
            return (len(matches) == 1)
110
        except Exception as ex:
111
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
112
        
113
        return False
114

    
115
    """
116
        @brief  check if given two lines lie on one line and share one point
117
        @author humkyung
118
        @date   2018.04.11
119
    """
120
    def isCollinear(self, lhs, rhs, toler):
121
        try:
122
            #print(lhs)
123
            #print(rhs)
124
            if self.isConnected(lhs, rhs, toler):
125
                dx1 = lhs[1][0] - lhs[0][0]
126
                dy1 = lhs[1][1] - lhs[0][1]
127
                length = math.sqrt(dx1*dx1 + dy1*dy1)
128
                dx1 /= length
129
                dy1 /= length
130
                dx2 = rhs[1][0] - rhs[0][0]
131
                dy2 = rhs[1][1] - rhs[0][1]
132
                length = math.sqrt(dx2*dx2 + dy2*dy2)
133
                dx2 /= length
134
                dy2 /= length
135

    
136
                dx = math.fabs(dx1) - math.fabs(dx2)
137
                dy = math.fabs(dy1) - math.fabs(dy2)
138

    
139
                return (math.sqrt(dx*dx + dy*dy) < 0.00001)
140
        except Exception as ex:
141
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
142

    
143
        return False
144

    
145
    '''
146
        @brief  connect given lines
147
        @author humkyung
148
        @date   2018.04.11
149
        @history    2018.05.16  Jeongwoo    Connect Lines with long distance points
150
    '''
151
    def connectLines(self, lines, toler):
152
        res = []
153

    
154
        pts = []
155
        #print(lines)
156
        maxthickness = 0
157
        for line in lines:
158
            pts.append(line[0])
159
            pts.append(line[1])
160
            maxthickness = line[2] if maxthickness < line[2] else maxthickness
161

    
162
        maxLength = None
163
        for lpt in pts:
164
            for rpt in pts:
165
                if lpt != rpt:
166
                    dx = rpt[0] - lpt[0]
167
                    dy = rpt[1] - lpt[1]
168
                    length = math.sqrt(dx * dx + dy * dy)
169
                    if maxLength is None or maxLength < length:
170
                        maxLength = length
171
                        res.clear()
172
                        res.append(lpt)
173
                        res.append(rpt)
174
                        res.append(maxthickness)
175
        #print(res)
176
        return res
177

    
178
    '''
179
        @brief      adjust start point
180
        @author     humkyung
181
        @date       2018.06.21
182
        @history    humkyung 2018.07.31 return -1 thickness tuple if near point is not black
183
    '''
184
    def adjustStartPoint(self, pt, dir):
185
        from AppDocData import AppDocData
186
        docData = AppDocData.instance()
187
        windowSize = docData.getSlidingWindowSize()
188

    
189
        try:
190
            white = 255
191
            black = 0
192

    
193
            norm = [-dir[1], dir[0]]
194
            if black == self._image[pt[1] + round(dir[1]*windowSize[1]), pt[0] + round(dir[0]*windowSize[1])]:
195
                _pt = [pt[0] + round(dir[0]*windowSize[1]), pt[1] + round(dir[1]*windowSize[1])]
196
            else:
197
                found = False
198
                for step in [1,2,-1,-2]:
199
                    if black == self._image[pt[1] + round(dir[1]*windowSize[1] + norm[1]*step), pt[0] + round(dir[0]*windowSize[1] + norm[0]*step)]:
200
                        _pt = [pt[0] + round(dir[0]*windowSize[1] + norm[0]*step), pt[1] + round(dir[1]*windowSize[1] + norm[1]*step)]
201
                        found = True
202
                        break
203

    
204
                if not found: return (pt, -1)
205

    
206
            color = black 
207
            lhs = [_pt[0], _pt[1]]
208
            lhscount = 1
209
            while color != white:
210
                lhs[0] = _pt[0] + round(norm[0]*lhscount)
211
                lhs[1] = _pt[1] + round(norm[1]*lhscount)
212
                color = self._image[lhs[1], lhs[0]]
213
                lhscount += 1
214

    
215
            color = black 
216
            rhs = [_pt[0], _pt[1]]
217
            rhscount = 1
218
            while color != white:
219
                rhs[0] = _pt[0] - round(norm[0]*rhscount)
220
                rhs[1] = _pt[1] - round(norm[1]*rhscount)
221
                color = self._image[rhs[1], rhs[0]]
222
                rhscount += 1
223

    
224
            size = lhscount + rhscount
225
            offset = round((lhscount - rhscount)*0.5) if size < windowSize[1] else 0
226
            #print(size)
227
            return ([pt[0] + norm[0]*offset, pt[1] + norm[1]*offset], size if size > windowSize[1] else windowSize[1])
228
        except Exception as ex:
229
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
230

    
231
        return (pt, windowSize[1])
232

    
233
    '''
234
        @brief      symbol을 기준으로 양쪽으로 이미지에서 직선을 검출한다.
235
        @author     humkyung
236
        @date       2018.04.??
237
        @history    humkyung 2018.04.11 merge lines which are collinear or connected    
238
                    humkyung 2018.04.12 rotate connection points by symbol angle
239
                    humkyung 2018.04.12 use connection points without rotating(already rotated)
240
                    humkyung 2018.09.01 use connector's direction for detecting line
241
    '''
242
    def detectConnectedLine(self, symbol, offsetX, offsetY):
243
        res = []
244

    
245
        try:
246
            pool = []
247
            if (0 == symbol.angle) or (1.57 == symbol.angle) or (3.14 == symbol.angle) or (4.71 == symbol.angle):
248
                for connector in symbol.connectors:
249
                    ## get direction of connector
250
                    direction = connector.dir()
251
                    if direction is None:
252
                        dx = connector.sceneConnectPoint[0] - symbol.origin[0]
253
                        dy = connector.sceneConnectPoint[1] - symbol.origin[1]
254
                    else:
255
                        dx, dy = direction[0], direction[1]
256
                    #print('dx : ' + str(dx) + ', dy : ' + str(dy))
257
                    ## up to here
258

    
259
                    length = math.sqrt(dx*dx + dy*dy)
260
                    if length > 0:
261
                        dx /= length
262
                        dy /= length
263

    
264
                        if abs(dx) < 0.1:   # vertical line
265
                            dir = [0,1 if dy > 0 else -1]
266
                            pt = [round(connector.sceneConnectPoint[0] - offsetX), round(connector.sceneConnectPoint[1] - offsetY)]
267
                            pt, thickness = self.adjustStartPoint(pt, dir)
268
                            if thickness != -1: pool.append([dir, pt, thickness, True if not pool else False])
269
                            #print("v")
270
                        elif abs(dy) < 0.1: # horizontal line
271
                            dir = [1 if dx > 0 else -1,0]
272
                            pt = [round(connector.sceneConnectPoint[0] - offsetX), round(connector.sceneConnectPoint[1] - offsetY)]
273
                            pt, thickness = self.adjustStartPoint(pt, dir)
274
                            if thickness != -1: pool.append([dir, pt, thickness, True if not pool else False])
275
                            #print("h")
276
                    #print(thickness)
277
                #print(pool)
278

    
279
            #print(len(pool))
280
            while len(pool) > 0:
281
                dir, pt, thickness, forward = pool.pop()
282
                line = self.detectLine(pt, dir, thickness, forward)
283
                if line is not None:
284
                    line.append(thickness)
285
                    #print(line)
286
                    res.append(line if forward else [line[1], line[0], thickness])
287
                    if ([1,0] == dir) or ([-1,0] == dir):   # turn up/down
288
                        connectedPt = [line[1][0], pt[1]]
289
                        pt, thickness = self.adjustStartPoint(connectedPt, [0,1])
290
                        if thickness != -1: pool.append([[0,1], pt, thickness, forward])
291
                        pt, thickness = self.adjustStartPoint(connectedPt, [0,-1])
292
                        if thickness != -1: pool.append([[0,-1], pt, thickness, not forward])
293
                    elif ([0,1] == dir) or ([0,-1] == dir): # turn left/right
294
                        connectedPt = [pt[0], line[1][1]]
295
                        pt, thickness = self.adjustStartPoint(connectedPt, [1,0])
296
                        if thickness != -1: pool.append([[1,0], pt, thickness, forward])
297
                        pt, thickness = self.adjustStartPoint(connectedPt, [-1,0])
298
                        if thickness != -1: pool.append([[-1,0], pt, thickness, not forward])
299
            #print(res)
300
            return res
301
        except Exception as ex:
302
            from App import App 
303
            from AppDocData import MessageType
304

    
305
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
306
            App.mainWnd().addMessage.emit(MessageType.Error, message)
307

    
308
    '''
309
        @breif      merge lines(1.connect collinear lines 2.connect lines)
310
        @author     humkyung
311
        @date       2018.04.11
312
        @history    humkyung 2018.04.12 continue loop if line is not in connectedLines
313
                    Jeongwoo 2018.05.16 Make comments if-statement
314
    '''
315
    def mergeLines(self, connectedLines, toler):
316
        try:
317
            for line in connectedLines[:]:
318
                if line not in connectedLines: continue
319
                matches = [param for param in connectedLines if (line != param) and self.isCollinear(line, param, toler)]
320
                if len(matches) > 0:
321
                    #print(len(matches))
322
                    matches.append(line)
323
                    #if len(matches) > 2: matches = matches[0:2] # pick last two objects
324
                    mergedLine = self.connectLines(matches, toler)
325
                    if mergedLine is not None and len(mergedLine) > 0:
326
                        connectedLines.append(mergedLine)
327
                        for match in matches: connectedLines.remove(match)
328
        except Exception as ex:
329
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
330

    
331
    '''
332
        @brief  connect line to nearest connection point of symbol
333
        @author humkyung
334
        @date   2018.04.13
335
    '''
336
    def connectLineToSymbol(self, line, offset, symbol):
337
        #print(line)
338
        startPt = line[0]
339
        distStart = [(self.distanceTo(startPt, (connector.sceneConnectPoint[0]-offset[0], connector.sceneConnectPoint[1]-offset[1])), (connector.sceneConnectPoint[0]-offset[0], connector.sceneConnectPoint[1]-offset[1])) for connector in symbol.connectors]
340
        distStart.sort()
341

    
342
        endPt = line[1]
343
        distEnd = [(self.distanceTo(endPt, (connector.sceneConnectPoint[0]-offset[0], connector.sceneConnectPoint[1]-offset[1])), (connector.sceneConnectPoint[0]-offset[0], connector.sceneConnectPoint[1]-offset[1])) for connector in symbol.connectors]
344
        distEnd.sort()
345

    
346
        if distStart[0][0] < distEnd[0][0]:
347
            dx = distStart[0][1][0] - startPt[0]
348
            dy = distStart[0][1][1] - startPt[1]
349
            dir = (line[1][0] - line[0][0], line[1][1] - line[0][1])
350
            if abs(dir[0]) > abs(dir[1]):
351
                for i in range(1, len(line)-1):
352
                    line[i][1] += dy
353
            else:
354
                for i in range(1, len(line)-1):
355
                    line[i][0] += dx
356
            line[0][0] = distStart[0][1][0]
357
            line[0][1] = distStart[0][1][1]
358
        else:
359
            dx = distEnd[0][1][0] - endPt[0]
360
            dy = distEnd[0][1][1] - endPt[1]
361
            dir = (line[1][0] - line[0][0], line[1][1] - line[0][1])
362
            if abs(dir[0]) > abs(dir[1]):
363
                for i in range(0, len(line)-2):
364
                    line[i][1] += dy
365
            else:
366
                for i in range(0, len(line)-2):
367
                    line[i][0] += dx
368
            line[1][0] = distEnd[0][1][0]
369
            line[1][1] = distEnd[0][1][1]
370

    
371
    '''
372
        @brief  extend line to intersection point
373
        @author humkyung
374
        @date   2018.04.14
375
    '''
376
    def connectLineToLine(self, lhs, rhs, toler=20):
377
        try:
378
            dx = rhs[1][0] - rhs[0][0]
379
            dy = rhs[1][1] - rhs[0][1]
380
            length = math.sqrt(dx*dx + dy*dy)
381
            if length == 0: return
382
            dx /= length
383
            dy /= length
384
            rightLine = [(rhs[0][0]-dx*toler, rhs[0][1]-dy*toler), (rhs[1][0]+dx*toler, rhs[1][1]+dy*toler)]
385
            shapelyRightLine = shapely.geometry.LineString(rightLine)
386

    
387
            dx = lhs[1][0] - lhs[0][0]
388
            dy = lhs[1][1] - lhs[0][1]
389
            length = math.sqrt(dx*dx + dy*dy)
390
            if length == 0: return
391
            dx /= length
392
            dy /= length
393
            line = [(lhs[0][0]-dx*toler, lhs[0][1]-dy*toler), (lhs[1][0]+dx*toler, lhs[1][1]+dy*toler)]
394
            shapelyLine = shapely.geometry.LineString(line)
395

    
396
            pt = shapelyRightLine.intersection(shapelyLine)
397
            if (pt is not None) and (type(pt) == shapely.geometry.point.Point):
398
                if self.isExternalPoint(lhs, pt):
399
                    if self.distanceTo(lhs[0], (pt.x, pt.y)) < self.distanceTo(lhs[1], (pt.x, pt.y)):
400
                        lhs[0][0] = pt.x
401
                        lhs[0][1] = pt.y
402
                    else:
403
                        lhs[1][0] = pt.x
404
                        lhs[1][1] = pt.y
405
                        
406
                if self.isExternalPoint(rhs, pt):
407
                    if self.distanceTo(rhs[0], (pt.x, pt.y)) < self.distanceTo(rhs[1], (pt.x, pt.y)):
408
                        rhs[0][0] = pt.x
409
                        rhs[0][1] = pt.y
410
                    else:
411
                        rhs[1][0] = pt.x
412
                        rhs[1][1] = pt.y
413
        except Exception as ex:
414
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[1].tb_lineno))
415

    
416
    def isExternalPoint(self, line, pt):
417
        try:
418
            dx = line[1][0] - line[0][0]
419
            dy = line[1][1] - line[0][1]
420
            lineLength = math.sqrt(dx * dx + dy * dy)
421
            
422
            dx = pt.x - line[0][0]
423
            dy = pt.y - line[0][1]
424
            length = math.sqrt(dx * dx + dy * dy)
425
            if length > lineLength:
426
                return True
427

    
428
            dx = pt.x - line[1][0]
429
            dy = pt.y - line[1][1]
430
            length = math.sqrt(dx * dx + dy * dy)
431
            if length > lineLength:
432
                return True
433

    
434
            return False
435
        except Exception as ex:
436
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[1].tb_lineno))
437
                
438
    '''
439
        @brief  detech line thickness
440
        @author humkyung
441
        @date   2018.05.18
442
    '''
443
    def detectLineThickness(self, pt, dir):
444
        import math
445
        from AppDocData import AppDocData
446
        docData = AppDocData.instance()
447
        windowSize = docData.getSlidingWindowSize()
448

    
449
        white = 255
450
        black = 0
451
        color = white
452

    
453
        norm = [-dir[1], dir[0]]
454
        if black == self._image[pt[1] + round(dir[1]*windowSize[1]), pt[0] + round(dir[0]*windowSize[1])]:
455
            _pt = [pt[0] + round(dir[0]*windowSize[1]), pt[1] + round(dir[1]*windowSize[1])]
456
        else:
457
            return windowSize[1]
458

    
459
        color = black 
460
        lhs = [pt[0], pt[1]]
461
        count = 1
462
        while color != white:
463
            lhs[0] = pt[0] + round(norm[0]*count)
464
            lhs[1] = pt[1] + round(norm[1]*count)
465
            color = self._image[lhs[1], lhs[0]]
466
            count += 1
467

    
468
        color = black 
469
        rhs = [pt[0], pt[1]]
470
        count = 1
471
        while color != white:
472
            rhs[0] = pt[0] - round(norm[0]*count)
473
            rhs[1] = pt[1] - round(norm[1]*count)
474
            color = self._image[rhs[1], rhs[0]]
475
            count += 1
476

    
477
        dx = rhs[0] - lhs[0]
478
        dy = rhs[1] - lhs[1]
479
        return math.sqrt(dx*dx + dy*dy)
480

    
481
    '''
482
        @brief      detect a line along given direction
483
        @author     humkyung
484
        @date       2018.04
485
        @history    humkyung 2018.05.18 add parameter for thickness
486
                    Jeongwoo 2018.05.18 Read LineLengthConfig and Comapare on if-statement
487
    '''
488
    def detectLine(self, pt, dir, thickness, forward):
489
        from AppDocData import AppDocData
490

    
491
        lineLengthConfigs = AppDocData.instance().getConfigs('Small Line Minimum Length', 'Min Length')
492
        lineMinLength = int(lineLengthConfigs[0].value) if 1 == len(lineLengthConfigs) else 10
493
        try:
494
            white = [255]
495
            windowSize = AppDocData.instance().getSlidingWindowSize()
496
            xHalf = round(windowSize[0]*0.5)
497
            yHalf = round(windowSize[1]*0.5)
498

    
499
            if ([1,0] == dir):
500
                image = self._image[(pt[1]-yHalf):(pt[1]+yHalf), pt[0]:self.width]
501
                imgWidth, imgHeight = image.shape[::-1]
502
                i = 0
503
                for i in range(imgWidth-windowSize[0]):
504
                    window = image[0:windowSize[1], i:i+windowSize[0]]
505
                    if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break
506
                if i > lineMinLength:
507
                    #self._image[(pt[1]-yHalf):(pt[1]+yHalf), pt[0]:(pt[0]+i)] = white
508
                    cv2.line(self._image, (pt[0],pt[1]), (pt[0]+i,pt[1]), 255, thickness)
509
                    return [[pt[0], pt[1]], [pt[0] + i - round(thickness*0.5), pt[1]]]
510
            elif ([-1,0] == dir):
511
                image = self._image[(pt[1]-yHalf):(pt[1]+yHalf), 0:pt[0]]
512
                imgWidth, imgHeight = image.shape[::-1]
513
                i = 0
514
                for i in range(imgWidth-windowSize[0], -1, -1):
515
                    window = image[0:windowSize[1], i:i+windowSize[0]]
516
                    if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break
517
                if abs(pt[0] - i - windowSize[0]) > lineMinLength: 
518
                    #self._image[int(pt[1]-yHalf):int(pt[1]+yHalf), (i+windowSize[0]+yHalf):pt[0]] = white
519
                    cv2.line(self._image, (i+windowSize[0],pt[1]), (pt[0],pt[1]), 255, thickness)
520
                    return [[pt[0], pt[1]], [i+windowSize[0]+round(thickness*0.5), pt[1]]]
521
            elif ([0,1] == dir):
522
                windowSize.reverse()
523
                xHalf = round(windowSize[0]*0.5)
524
                yHalf = round(windowSize[1]*0.5)
525

    
526
                image = self._image[pt[1]:self.height, int(pt[0]-xHalf):int(pt[0]+xHalf)]
527
                imgWidth, imgHeight = image.shape[::-1]
528
                i = 0
529
                for i in range(imgHeight-windowSize[1]):
530
                    window = image[i:i+windowSize[1], 0:windowSize[0]]
531
                    if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break
532
                if i > lineMinLength:
533
                    #self._image[(pt[1]):(pt[1]+i), (pt[0]-xHalf):(pt[0]+xHalf)] = white
534
                    cv2.line(self._image, (pt[0],pt[1]), (pt[0],pt[1]+i), 255, thickness)
535
                    return [[pt[0], pt[1]], [pt[0], pt[1] + i - round(thickness*0.5)]]
536
            elif ([0,-1] == dir):
537
                windowSize.reverse()
538
                xHalf = round(windowSize[0]*0.5)
539
                yHalf = round(windowSize[1]*0.5)
540

    
541
                image = self._image[0:pt[1], (pt[0]-xHalf):(pt[0]+xHalf)]
542
                imgWidth, imgHeight = image.shape[::-1]
543
                i = 0
544
                for i in range(imgHeight-windowSize[1], -1, -1):
545
                    window = image[i:i+windowSize[1], 0:windowSize[0]]
546
                    if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break
547
                if abs(pt[1] - i - windowSize[1]) > lineMinLength:
548
                    #self._image[(i+windowSize[1]):pt[1], (pt[0]-xHalf):(pt[0]+xHalf)] = white
549
                    cv2.line(self._image, (pt[0],i+windowSize[1]), (pt[0],pt[1]), 255, thickness)
550
                    return [[pt[0], pt[1]], [pt[0], i+windowSize[1]+round(thickness*0.5)]]
551
        except Exception as ex:
552
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
553

    
554
        return None
555

    
556
    def detectLineWithoutSymbol(self, path):
557
        '''
558
            @brief  detect remain line after detection using symbol info
559
            @author euisung
560
            @date   2019.03.28
561
        '''
562
        import os
563
        from AppDocData import AppDocData
564
        from HoughBundler import HoughBundler
565

    
566
        docData = AppDocData.instance()
567
        project = docData.getCurrentProject()
568

    
569
        diffFilePath = os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(path))
570
        if os.path.isfile(diffFilePath):
571
            imgDiff = cv2.threshold(cv2.cvtColor(cv2.imread(diffFilePath, 1), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)[1]
572

    
573
            ## remove already detected line
574
            lines = docData.lines
575
            for line in lines:
576
                line.drawToImage(imgDiff, 255, thickness) if line.thickness is None else line.drawToImage(imgDiff, 255, line.thickness)
577
            #cv2.imwrite(diffFilePath, imgDiff)
578
            #cv2.imwrite(os.path.join(project.getTempPath(), "DIFF_2_" + os.path.basename(path)), imgDiff)
579
            ## up to here
580

    
581
            imgNot = np.ones(imgDiff.shape, np.uint8)
582
            cv2.bitwise_not(imgDiff, imgNot)
583
            imgNot = cv2.dilate(imgNot, np.ones((8,8), np.uint8))
584

    
585
            image, contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
586

    
587
            smallContours = []
588
            minimumSize = docData.getConfigs('Filter', 'MinimumSize') * 2
589
            lineLengthConfigs = docData.getConfigs('Small Line Minimum Length', 'Min Length')
590
            lineMinLength = int(lineLengthConfigs[0].value) if 1 == len(lineLengthConfigs) else 30
591
            for contour in contours:
592
                [x, y, w, h] = cv2.boundingRect(contour)
593

    
594
                # remove too small one
595
                if len(minimumSize) is 1:
596
                    if (w * h < int(minimumSize[0].value) * int(minimumSize[0].value)):
597
                        smallContours.append(contour)
598
            imgNotRemoveSmall = cv2.drawContours(imgNot, smallContours, -1, 0, -1)
599

    
600
            # detect line
601
            edged = cv2.Canny(imgNotRemoveSmall, 100, 200)
602

    
603
            rate = 25
604
            lines = cv2.HoughLinesP(image=edged, rho=1, theta=np.pi/180, threshold=rate, minLineLength=lineMinLength*2, maxLineGap=25)
605

    
606
            houghBundler = HoughBundler().process_lines(lines, None)
607

    
608
            remainLine = []
609
            for line in houghBundler:
610
                remainLine.append([[line[0][0], line[0][1]], [line[1][0], line[1][1]]])
611

    
612
            return remainLine
613

    
614
    '''
615
        @brief  save the result of image
616
        @author humkyung
617
        @date   2018.04.14
618
    '''
619
    def saveImage(self):
620
        import datetime
621
        from AppDocData import AppDocData
622

    
623
        try:
624
            nowDate = datetime.datetime.now()
625
            path = AppDocData.instance().getCurrentProject().getTempPath() + '/{}_{}_line_detector.png'.format(nowDate.strftime('%Y-%m-%d'), nowDate.strftime('%H %M %S'))
626
            cv2.imwrite(path, self._image)
627
        except Exception as ex:
628
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
클립보드 이미지 추가 (최대 크기: 500 MB)