Detect Vertical&Horizontal Segments By OpenCV

Detect Vertical&Horizontal Segments By OpenCV,and Save the data to csv.

Steps:

  1. Using adaptiveThreshold to generate thresholded image.
  2. Using threshold to find lines.
  3. Save the data to csv by convert it to json.
  1 # coding=gbk
  2 import cv2
  3 import numpy as np
  4 import json
  5 import csv
  6 import os
  7 
  8 def find_lines(threshold, regions=None, direction='horizontal',
  9                line_scale=15, iterations=0):
 10     """Finds horizontal and vertical lines by applying morphological
 11     transformations on an image.
 12 
 13     Parameters
 14     ----------
 15     threshold : object
 16         numpy.ndarray representing the thresholded image.
 17     regions : list, optional (default: None)
 18         List of page regions that may contain tables of the form x1,y1,x2,y2
 19         where (x1, y1) -> left-top and (x2, y2) -> right-bottom
 20         in image coordinate space.
 21     direction : string, optional (default: 'horizontal')
 22         Specifies whether to find vertical or horizontal lines.
 23     line_scale : int, optional (default: 15)
 24         Factor by which the page dimensions will be divided to get
 25         smallest length of lines that should be detected.
 26 
 27         The larger this value, smaller the detected lines. Making it
 28         too large will lead to text being detected as lines.
 29     iterations : int, optional (default: 0)
 30         Number of times for erosion/dilation is applied.
 31 
 32         For more information, refer `OpenCV's dilate <https://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html#dilate>`_.
 33 
 34     Returns
 35     -------
 36     dmask : object
 37         numpy.ndarray representing pixels where vertical/horizontal
 38         lines lie.
 39     lines : list
 40         List of tuples representing vertical/horizontal lines with
 41         coordinates relative to a left-top origin in
 42         image coordinate space.
 43 
 44     """
 45     lines = []
 46 
 47     if direction == 'vertical':
 48         size = threshold.shape[0] // line_scale
 49         el = cv2.getStructuringElement(cv2.MORPH_RECT, (1, size))
 50     elif direction == 'horizontal':
 51         size = threshold.shape[1] // line_scale
 52         el = cv2.getStructuringElement(cv2.MORPH_RECT, (size, 1))
 53     elif direction is None:
 54         raise ValueError("Specify direction as either 'vertical' or"
 55                          " 'horizontal'")
 56 
 57     if regions is not None:
 58         region_mask = np.zeros(threshold.shape)
 59         for region in regions:
 60             x, y, w, h = region
 61             region_mask[y : y + h, x : x + w] = 1
 62         threshold = np.multiply(threshold, region_mask)
 63 
 64     threshold = cv2.erode(threshold, el)
 65     threshold = cv2.dilate(threshold, el)
 66     dmask = cv2.dilate(threshold, el, iterations=iterations)
 67 
 68     try:
 69         _, contours, _ = cv2.findContours(
 70             threshold.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 71     except ValueError:
 72         # for opencv backward compatibility
 73         contours, _ = cv2.findContours(
 74             threshold.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 75 
 76     for c in contours:
 77         x, y, w, h = cv2.boundingRect(c)
 78         x1, x2 = x, x + w
 79         y1, y2 = y, y + h
 80         if direction == 'vertical':
 81             lines.append(((x1 + x2) // 2, y2, (x1 + x2) // 2, y1))
 82         elif direction == 'horizontal':
 83             lines.append((x1, (y1 + y2) // 2, x2, (y1 + y2) // 2))
 84 
 85     return dmask, lines
 86 
 87 def adaptive_threshold(imagename, process_background=False, blocksize=15, c=-2):
 88     """Thresholds an image using OpenCV's adaptiveThreshold.
 89 
 90     Parameters
 91     ----------
 92     imagename : string
 93         Path to image file.
 94     process_background : bool, optional (default: False)
 95         Whether or not to process lines that are in background.
 96     blocksize : int, optional (default: 15)
 97         Size of a pixel neighborhood that is used to calculate a
 98         threshold value for the pixel: 3, 5, 7, and so on.
 99 
100         For more information, refer `OpenCV's adaptiveThreshold <https://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#adaptivethreshold>`_.
101     c : int, optional (default: -2)
102         Constant subtracted from the mean or weighted mean.
103         Normally, it is positive but may be zero or negative as well.
104 
105         For more information, refer `OpenCV's adaptiveThreshold <https://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#adaptivethreshold>`_.
106 
107     Returns
108     -------
109     img : object
110         numpy.ndarray representing the original image.
111     threshold : object
112         numpy.ndarray representing the thresholded image.
113 
114     """
115     img = cv2.imread(imagename)
116     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
117 
118     if process_background:
119         threshold = cv2.adaptiveThreshold(
120             gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
121             cv2.THRESH_BINARY, blocksize, c)
122     else:
123         threshold = cv2.adaptiveThreshold(
124             np.invert(gray), 255,
125             cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blocksize, c)
126     return img, threshold
127 
128 count = 0
129 root = 'E:/VGID_Text/Mycode/linelabel/PDF_JPG/'
130 rows=[]
131 for root, dirs, files in os.walk(root):
132     for img in files:
133         if img.endswith('jpg'):
134             img_path = root+'/'+img
135             image, threshold = adaptive_threshold(img_path)
136             find_lines(threshold)
137             vertical_mask, vertical_segments = find_lines(threshold, direction='vertical')
138             horizontal_mask, horizontal_segments = find_lines(threshold, direction='horizontal')
139             lines_list = vertical_segments + horizontal_segments
140             objects = []
141             lines_dict = {"objects":objects}
142             for line in lines_list:
143                 point1 = {"x": line[0], "y": line[1]}
144                 point2 = {"x": line[2], "y": line[3]}
145                 ptList = [point1,point2]
146                 polygon = {"ptList":ptList}
147                 line_dict ={"polygon":polygon,
148                             "name": "line",
149                             "type": 4,
150                             "color": "#aa40bf",
151                             "id": "6173cf75-ea09-4ff4-a75e-5cc99a5ea40e",
152                             "cur": 0,
153                             "lineStyle": "solid"
154                             }
155                 objects.append(line_dict)
156             lines_json = json.dumps(lines_dict)
157             print(count, lines_json)
158             row = [img_path, lines_json]
159             rows.append(row)
160             count = count + 1
161 with open('E:/线条标注3k+.csv', 'w', newline='') as csv_file:
162     csv_writer = csv.writer(csv_file)
163     csv_writer.writerow(['image_path','lines'])
164     for row in rows:
165         csv_writer.writerow(row)

Reference:Camelot:https://camelot-py.readthedocs.io/en/master/

 

posted @ 2019-05-22 20:01  Wind·Chaser  阅读(465)  评论(0)    收藏  举报