Я написал код для обнаружения столбцов из изображения таблицы. Я выполнил следующие шаги:
- Удаление горизонтальных строк из изображения таблицы
- Инвертирование изображения
- Применение расширения с ядром (25,4) для 2 итераций .
- Применить эрозию к расширенному изображению с ядром (2,6) за 3 итерации.
- Вычислить сумму столбца изображения на результирующем изображении. Теперь я нахожу долины в окне.
- Рассчитать размер окна как 35% ширины изображения.
- Рассчитать горизонтальный порог, чтобы рассматривать долины как долины внутри областей окна. (с порогом изменения минимумов-максимумов 0,1 и гауссовой сигмой = 15)
- Сгладьте область окна с гауссовой сигмой = 15 и найдите долины, которые находятся ниже горизонтального порога, установив высоту = горизонтальный порог, рассчитанный выше.
- Теперь у нас есть список всех возможных долин (координат столбцов) с ложными срабатываниями.
удаление ложных срабатываний из приведенного выше списка
- Столбцы, пересекающие текстовые области (порог пересечения более 2 текстовых областей)
- Объединить несколько столбцов, представленных в большом столбцовом пространстве, в один столбец
Проблема в следующем:
- Если для определения столбца достаточно расстояния между словами в таблице, то столбец будет отображаться там:
дополнительный столбец обращается в описании
Если столбец пустой или не имеет достаточных значений для обнаружения впадин, столбец не будет отрисован.
столбец не отображается между номером чека и описанием
Мне нужно решение этих двух проблем. Есть ли другой способ выполнить эту задачу более точно?
import cv2
from google.colab.patches import cv2_imshow
import os
from google.colab import files
import numpy as np
import matplotlib.pyplot as plt
from itertools import groupby
from operator import itemgetter
from scipy.ndimage.filters import gaussian_filter1d
from scipy.signal import find_peaks
from cv2 import imwrite
import pandas as pd
image = cv2.imread("table_with_rows.png") #handle corner cases with jpeg images
#print(image.shape)
img=image
#Convert to grayscale
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
#Threshold the grayscale image
thresh = cv2.threshold(gray, 220, 255, cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)[1] #
print(thresh.shape)
# Remove horizontal
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (20,1))
detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(image, [c], -1, (0,255,0), 2)
x,y,w,h = cv2.boundingRect(c)
#print(x,y,w,h)
if x == 0 or y==0:
img[y-2:y+h+2,x:x+w+1]=255 #Taking two pixels above and below and making them white too
else:
img[y-2:y+h+2,x-1:x+w+1]=255 #If the bounding box doesn't start from zeroth pixel then we can use a pixel before the x co-od also
cv2.imwrite("row_removed_1.jpg",img)
cv2_imshow(image)
img = cv2.imread("row_removed_1.jpg", 0)
h, w = img.shape
window_size = int(w*0.35)
inv_img = 255-img
dilation_kernel = np.ones((25,2),np.uint8)
dilation = cv2.dilate(inv_img,dilation_kernel,iterations = 2)
inv_dilation=cv2.bitwise_not(dilation)
erosion_kernel=np.ones((2,8),np.uint8)
erosion = cv2.erode(dilation,erosion_kernel,iterations = 3)
cv2_imshow(erosion)
#Taking column-wise sum of pixel values in image (returns a list)
img_col_sum = np.sum(erosion,axis=0).tolist()
#Normalising the values of img col sum
for i in range(len(img_col_sum)):
img_col_sum[i]=img_col_sum[i]/max(img_col_sum)
print('window_size :::',window_size)
print('*********** Image col sum graph after normalization ***********')
#Plotting the graph of columnwise sum
plt.plot(img_col_sum)
#plt.savefig("img_col_sum_" + filename)
plt.show()
deviation = 300 if window_size > 300 else window_size
peaks=[]
for i in range(0,len(img_col_sum),window_size):
i = 0 if i==0 else (i-deviation) ## version2
print('i===', i)
window_val = img_col_sum[i:i+window_size+300]
#print(window_val)
ysmoothed_15 = gaussian_filter1d(window_val,sigma=15)
#Plotting the smoothed graph (to pick the dips in graph)
plt.plot(ysmoothed_15)
#plt.savefig("img_col_sum_flattened_" + str(filename.split('.')[0]))
plt.title('with sigma 15')
plt.show()
#Getting minimas of the smoothened graph and plotting
min_peaks_15,_=find_peaks(-1*ysmoothed_15)
a = np.array(ysmoothed_15)
#print(a[peaks])
plt.plot(ysmoothed_15)
plt.plot(min_peaks_15,ysmoothed_15[min_peaks_15],"x", label='min - x')
#max_minima_val = 0
print('..... minimas for window .....')
print(ysmoothed_15[min_peaks_15])
max_minima_val = np.min(ysmoothed_15[min_peaks_15] if len(min_peaks_15)!=0 else 0 )
print(max_minima_val)
#Getting maximas of the smoothened graph and plotting
max_peaks_15,_=find_peaks(ysmoothed_15)
a = np.array(ysmoothed_15)
#print(a[peaks])
plt.plot(ysmoothed_15)
plt.plot(max_peaks_15,ysmoothed_15[max_peaks_15],"o", label='max - o')
plt.show()
print('..... maximas for window .....')
print(ysmoothed_15[max_peaks_15])
max_maxima_val = np.max(ysmoothed_15[max_peaks_15] if len(max_peaks_15)!=0 else 1)
print(max_maxima_val)
diff = max_maxima_val - max_minima_val
print('difference between minima and maxima point for the range of {0} - {1} ===> {2}'.format(i,(i+window_size+300),diff))
#################### . calculate plateau ###########################
######## first check if plateau region is below threshold then only draw column
print('checking plateau............................!!!!!!')
print(i)
#if window_val[0] < height:
diff1 = np.diff(window_val)
#array([ 0, 0, 0, 2, 1, -2, 0, 0, 0])
gradient = np.sign(diff1)
if gradient[0] == 0:
peaks.append(i)
print('column will be drawn at :::: ', i)
# if difference between minima and maxima is greater than certain threshold then only there is variation which can be considered as column
if diff > 0.1 :
height = max_minima_val + diff/1.5
print('Threshold for the range of {0} - {1} ===> {2}'.format(i,(i+window_size+300),height))
ysmoothed_20 = gaussian_filter1d(window_val,sigma=15)
#Plotting the smoothed graph (to pick the dips in graph)
#plt.plot(ysmoothed_20)
#plt.savefig("img_col_sum_flattened_" + str(filename.split('.')[0]))
#plt.show()
#Getting minimas of the smoothened graph and plotting
win_peaks_20,_=find_peaks(-1*ysmoothed_20, height = -1*height)
a = np.array(ysmoothed_20)
#print(a[peaks])
plt.plot(ysmoothed_20)
plt.plot(win_peaks_20,ysmoothed_20[win_peaks_20],"x")
plt.title('with sigma 15')
plt.show()
x_cord_win_peaks = [x + i for x in win_peaks_20]
peaks.extend(x_cord_win_peaks)
#print(peaks)
# for loop of window is completed
print('troughs by taking winodws',peaks)
########## after this false positive is removed through ocr response