| import cv2 |
| import numpy as np |
|
|
|
|
| class Text: |
| def __init__(self, id, content, location): |
| self.id = id |
| self.content = content |
| self.location = location |
|
|
| self.width = self.location['right'] - self.location['left'] |
| self.height = self.location['bottom'] - self.location['top'] |
| self.area = self.width * self.height |
| self.word_width = self.width / len(self.content) |
|
|
| ''' |
| ******************************** |
| *** Relation with Other text *** |
| ******************************** |
| ''' |
| def is_justified(self, ele_b, direction='h', max_bias_justify=4): |
| ''' |
| Check if the element is justified |
| :param max_bias_justify: maximum bias if two elements to be justified |
| :param direction: |
| - 'v': vertical up-down connection |
| - 'h': horizontal left-right connection |
| ''' |
| l_a = self.location |
| l_b = ele_b.location |
| |
| if direction == 'v': |
| |
| if abs(l_a['left'] - l_b['left']) < max_bias_justify and abs(l_a['right'] - l_b['right']) < max_bias_justify: |
| return True |
| return False |
| elif direction == 'h': |
| |
| if abs(l_a['top'] - l_b['top']) < max_bias_justify and abs(l_a['bottom'] - l_b['bottom']) < max_bias_justify: |
| return True |
| return False |
|
|
| def is_on_same_line(self, text_b, direction='h', bias_gap=4, bias_justify=4): |
| ''' |
| Check if the element is on the same row(direction='h') or column(direction='v') with ele_b |
| :param direction: |
| - 'v': vertical up-down connection |
| - 'h': horizontal left-right connection |
| :return: |
| ''' |
| l_a = self.location |
| l_b = text_b.location |
| |
| if direction == 'v': |
| |
| if self.is_justified(text_b, direction='v', max_bias_justify=bias_justify): |
| |
| if abs(l_a['bottom'] - l_b['top']) < bias_gap or abs(l_a['top'] - l_b['bottom']) < bias_gap: |
| return True |
| return False |
| elif direction == 'h': |
| |
| if self.is_justified(text_b, direction='h', max_bias_justify=bias_justify): |
| |
| if abs(l_a['right'] - l_b['left']) < bias_gap or abs(l_a['left'] - l_b['right']) < bias_gap: |
| return True |
| return False |
|
|
| def is_intersected(self, text_b, bias): |
| l_a = self.location |
| l_b = text_b.location |
| left_in = max(l_a['left'], l_b['left']) + bias |
| top_in = max(l_a['top'], l_b['top']) + bias |
| right_in = min(l_a['right'], l_b['right']) |
| bottom_in = min(l_a['bottom'], l_b['bottom']) |
|
|
| w_in = max(0, right_in - left_in) |
| h_in = max(0, bottom_in - top_in) |
| area_in = w_in * h_in |
| if area_in > 0: |
| return True |
|
|
| ''' |
| *********************** |
| *** Revise the Text *** |
| *********************** |
| ''' |
| def merge_text(self, text_b): |
| text_a = self |
| top = min(text_a.location['top'], text_b.location['top']) |
| left = min(text_a.location['left'], text_b.location['left']) |
| right = max(text_a.location['right'], text_b.location['right']) |
| bottom = max(text_a.location['bottom'], text_b.location['bottom']) |
| self.location = {'left': left, 'top': top, 'right': right, 'bottom': bottom} |
| self.width = self.location['right'] - self.location['left'] |
| self.height = self.location['bottom'] - self.location['top'] |
| self.area = self.width * self.height |
|
|
| left_element = text_a |
| right_element = text_b |
| if text_a.location['left'] > text_b.location['left']: |
| left_element = text_b |
| right_element = text_a |
| self.content = left_element.content + ' ' + right_element.content |
| self.word_width = self.width / len(self.content) |
|
|
| def shrink_bound(self, binary_map): |
| bin_clip = binary_map[self.location['top']:self.location['bottom'], self.location['left']:self.location['right']] |
| height, width = np.shape(bin_clip) |
|
|
| shrink_top = 0 |
| shrink_bottom = 0 |
| for i in range(height): |
| |
| if shrink_top == 0: |
| if sum(bin_clip[i]) == 0: |
| shrink_top = 1 |
| else: |
| shrink_top = -1 |
| elif shrink_top == 1: |
| if sum(bin_clip[i]) != 0: |
| self.location['top'] += i |
| shrink_top = -1 |
| |
| if shrink_bottom == 0: |
| if sum(bin_clip[height-i-1]) == 0: |
| shrink_bottom = 1 |
| else: |
| shrink_bottom = -1 |
| elif shrink_bottom == 1: |
| if sum(bin_clip[height-i-1]) != 0: |
| self.location['bottom'] -= i |
| shrink_bottom = -1 |
|
|
| if shrink_top == -1 and shrink_bottom == -1: |
| break |
|
|
| shrink_left = 0 |
| shrink_right = 0 |
| for j in range(width): |
| |
| if shrink_left == 0: |
| if sum(bin_clip[:, j]) == 0: |
| shrink_left = 1 |
| else: |
| shrink_left = -1 |
| elif shrink_left == 1: |
| if sum(bin_clip[:, j]) != 0: |
| self.location['left'] += j |
| shrink_left = -1 |
| |
| if shrink_right == 0: |
| if sum(bin_clip[:, width-j-1]) == 0: |
| shrink_right = 1 |
| else: |
| shrink_right = -1 |
| elif shrink_right == 1: |
| if sum(bin_clip[:, width-j-1]) != 0: |
| self.location['right'] -= j |
| shrink_right = -1 |
|
|
| if shrink_left == -1 and shrink_right == -1: |
| break |
| self.width = self.location['right'] - self.location['left'] |
| self.height = self.location['bottom'] - self.location['top'] |
| self.area = self.width * self.height |
| self.word_width = self.width / len(self.content) |
|
|
| ''' |
| ********************* |
| *** Visualization *** |
| ********************* |
| ''' |
| def visualize_element(self, img, color=(0, 0, 255), line=1, show=False): |
| loc = self.location |
| cv2.rectangle(img, (loc['left'], loc['top']), (loc['right'], loc['bottom']), color, line) |
| if show: |
| print(self.content) |
| cv2.imshow('text', img) |
| cv2.waitKey() |
| cv2.destroyWindow('text') |
|
|