Определить количество строк и столбцов в табличном изображении с помощью OpenCV - PullRequest
3 голосов
/ 25 февраля 2020

Как мы можем получить количество строк и столбцов в таблице изображений с помощью Opencv.

Код для получения ящиков в таблице, которые я получаю правильно

contours, hierarchy = cv2.findContours(img_final_bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

def sort_contours(cnts, method="left-to-right"):
# initialize the reverse flag and sort index
reverse = False
i = 0
# handle if we need to sort in reverse
if method == "right-to-left" or method == "bottom-to-top":
    reverse = True
# handle if we are sorting against the y-coordinate rather than
# the x-coordinate of the bounding box
if method == "top-to-bottom" or method == "bottom-to-top":
    i = 1
# construct the list of bounding boxes and sort them from top to
# bottom
boundingBoxes = [cv2.boundingRect(c) for c in cnts]
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
    key=lambda b:b[1][i], reverse=reverse))
# return the list of sorted contours and bounding boxes
return (cnts, boundingBoxes)

(contours, boundingBoxes) = sort_contours(contours, method="top-to-bottom")

Ответы [ 3 ]

2 голосов
/ 27 февраля 2020

Вот потенциальный подход:

  1. Получение двоичного изображения. Загрузка изображения, преобразование в оттенки серого, Размытие по Гауссу , затем Порог Оцу .

  2. Удалить текст внутри ячеек. Найти контуры и фильтр с помощью cv2.contourArea, чтобы удалить текст, заполнив контуры с помощью cv2.drawContours

  3. Инвертировать изображение. Мы инвертируем изображение таким образом, чтобы ячейки были белыми, а фон - черным

  4. Сортировка ячеек и сумма строк / столбцов. Мы находим контуры , а затем сортируем контуры из top-to-bottom, используя imutils.contours.sort_contours. Затем мы перебираем контуры и находим центроид , чтобы получить (cX, cY) координаты. Идея состоит в том, что мы можем сравнить значение cY каждой ячейки, чтобы определить, является ли это новая строка или ячейка в той же строке, используя смещение. Ячейка должна находиться в той же строке, если значение cY равно некоторому значению смещения +/-. Если оно больше, значит, ячейка находится в новом ряду. Мы строим таблицу моделей, в которой длина таблицы дает вам строки, а длина любого индекса - количество столбцов.


Двоичное изображение

enter image description here

Удалены контуры текста + перевернутое изображение

enter image description here

Вот визуализация итерации по каждому ячейка для подсчета количества строк и столбцов

enter image description here

Результат

Rows: 7
Columns: 4

Код

import numpy as np
from imutils import contours
import cv2

# Load image, grayscale, Gaussian blur, Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Find contours and remove text inside cells
cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area < 4000:
        cv2.drawContours(thresh, [c], -1, 0, -1)

# Invert image
invert = 255 - thresh
offset, old_cY, first = 10, 0, True
visualize = cv2.cvtColor(invert, cv2.COLOR_GRAY2BGR)

# Find contours, sort from top-to-bottom and then sum up column/rows
cnts = cv2.findContours(invert, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="top-to-bottom")
for c in cnts:
    # Find centroid
    M = cv2.moments(c)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])

    # New row
    if (abs(cY) - abs(old_cY)) > offset:
        if first:
            row, table = [], []
            first = False
        old_cY = cY
        table.append(row)
        row = []

    # Cell in same row
    if ((abs(cY) - abs(old_cY)) <= offset) or first:
        row.append(1)

    # Uncomment to visualize 
    '''
    cv2.circle(visualize, (cX, cY), 10, (36, 255, 12), -1) 
    cv2.imshow('visualize', visualize)
    cv2.waitKey(200)
    '''

print('Rows: {}'.format(len(table)))
print('Columns: {}'.format(len(table[1])))

cv2.imshow('invert', invert)
cv2.imshow('thresh', thresh)
cv2.waitKey()
0 голосов
/ 26 апреля 2020

Еще один подход - сначала проверить, является ли она реальной таблицей. Для этого можно использовать преобразование линий, хотя, как только это будет сделано, вы можете использовать подход, описанный выше сотрудником.

0 голосов
/ 26 февраля 2020

Похоже, что простым решением было бы сначала посмотреть слева направо и проверить, является ли каждый пиксель черным (что будет означать, что мы нашли столбец. Затем сделайте то же самое для строк (если сверху вниз каждый пиксель черный , это означает, что он нашел строку).

Одним из осложнений является ширина строки, которая означает, что вы будете считать ее только 1 найденной строкой / столбцом, пока она не найдет белый цвет.

I Я мог бы разработать код для этого, но сейчас я не дома, поэтому, возможно, кто-то другой может написать код, и я удалю свой ответ позже. Я знаю, что это может быть комментарий, но у меня нет 50 репутации.

...