more code formatting

refactoring-2024-08-merged^2
cneud 9 months ago
parent 713b90e084
commit 1a95bca22d

@ -200,7 +200,8 @@ def main(
)
eynollah.run()
# pcgts = eynollah.run()
##eynollah.writer.write_pagexml(pcgts)
# eynollah.writer.write_pagexml(pcgts)
if __name__ == "__main__":
main()

@ -2,10 +2,12 @@ from .processor import EynollahProcessor
from click import command
from ocrd.decorators import ocrd_cli_options, ocrd_cli_wrap_processor
@command()
@ocrd_cli_options
def main(*args, **kwargs):
return ocrd_cli_wrap_processor(EynollahProcessor, *args, **kwargs)
if __name__ == '__main__':
main()

@ -9,6 +9,7 @@ from .utils import crop_image_inside_box
from .utils.rotate import rotate_image_different
from .utils.resize import resize_image
class EynollahPlotter():
"""
Class collecting all the plotting and image writing methods
@ -50,11 +51,12 @@ class EynollahPlotter():
plt.rcParams["font.size"] = "40"
im = plt.imshow(text_regions_p[:, :])
colors = [im.cmap(im.norm(value)) for value in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]], label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]],
label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in
values]
plt.legend(handles=patches, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.0, fontsize=40)
plt.savefig(os.path.join(self.dir_of_layout, self.image_filename_stem + "_layout_main.png"))
def save_plot_of_layout_main_all(self, text_regions_p, image_page):
if self.dir_of_all is not None:
values = np.unique(text_regions_p[:, :])
@ -68,7 +70,9 @@ class EynollahPlotter():
plt.subplot(1, 2, 2)
im = plt.imshow(text_regions_p[:, :])
colors = [im.cmap(im.norm(value)) for value in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]], label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]],
label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in
values]
plt.legend(handles=patches, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.0, fontsize=60)
plt.savefig(os.path.join(self.dir_of_all, self.image_filename_stem + "_layout_main_and_page.png"))
@ -82,7 +86,9 @@ class EynollahPlotter():
plt.rcParams["font.size"] = "40"
im = plt.imshow(text_regions_p[:, :])
colors = [im.cmap(im.norm(value)) for value in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]], label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]],
label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in
values]
plt.legend(handles=patches, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.0, fontsize=40)
plt.savefig(os.path.join(self.dir_of_layout, self.image_filename_stem + "_layout.png"))
@ -99,7 +105,9 @@ class EynollahPlotter():
plt.subplot(1, 2, 2)
im = plt.imshow(text_regions_p[:, :])
colors = [im.cmap(im.norm(value)) for value in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]], label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]],
label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in
values]
plt.legend(handles=patches, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.0, fontsize=60)
plt.savefig(os.path.join(self.dir_of_all, self.image_filename_stem + "_layout_and_page.png"))
@ -115,7 +123,9 @@ class EynollahPlotter():
plt.subplot(1, 2, 2)
im = plt.imshow(textline_mask_tot_ea[:, :])
colors = [im.cmap(im.norm(value)) for value in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]], label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in values]
patches = [mpatches.Patch(color=colors[np.where(values == i)[0][0]],
label="{l}".format(l=pixels[int(np.where(values_indexes == i)[0][0])])) for i in
values]
plt.legend(handles=patches, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.0, fontsize=60)
plt.savefig(os.path.join(self.dir_of_all, self.image_filename_stem + "_textline_and_page.png"))
@ -131,6 +141,7 @@ class EynollahPlotter():
cv2.imwrite(os.path.join(self.dir_of_all, self.image_filename_stem + "_page.png"), image_page)
if self.dir_save_page is not None:
cv2.imwrite(os.path.join(self.dir_save_page, self.image_filename_stem + "_page.png"), image_page)
def save_enhanced_image(self, img_res):
cv2.imwrite(os.path.join(self.dir_out, self.image_filename_stem + "_enhanced.png"), img_res)
@ -141,7 +152,8 @@ class EynollahPlotter():
plt.subplot(1, 2, 1)
plt.imshow(img_patch_org)
plt.subplot(1, 2, 2)
plt.plot(gaussian_filter1d(img_patch_org.sum(axis=1), 3),np.array(range(len(gaussian_filter1d(img_patch_org.sum(axis=1), 3)))),linewidth=8)
plt.plot(gaussian_filter1d(img_patch_org.sum(axis=1), 3),
np.array(range(len(gaussian_filter1d(img_patch_org.sum(axis=1), 3)))), linewidth=8)
plt.xlabel('Density of textline prediction in direction of X axis', fontsize=60)
plt.ylabel('Height', fontsize=60)
plt.yticks([0, len(gaussian_filter1d(img_patch_org.sum(axis=1), 3))])
@ -155,7 +167,8 @@ class EynollahPlotter():
plt.plot(angels, np.array(var_res), '-o', markersize=25, linewidth=4)
plt.xlabel('angle', fontsize=50)
plt.ylabel('variance of sum of rotated textline in direction of x axis', fontsize=50)
plt.plot(angels[np.argmax(var_res)],var_res[np.argmax(np.array(var_res))] ,'*',markersize=50,label='Angle of deskewing=' +str("{:.2f}".format(angels[np.argmax(var_res)]))+r'$\degree$')
plt.plot(angels[np.argmax(var_res)], var_res[np.argmax(np.array(var_res))], '*', markersize=50,
label='Angle of deskewing=' + str("{:.2f}".format(angels[np.argmax(var_res)])) + r'$\degree$')
plt.legend(loc='best')
plt.savefig(os.path.join(self.dir_of_all, self.image_filename_stem + '_rotation_angle.png'))
@ -167,9 +180,9 @@ class EynollahPlotter():
box = [x, y, w, h]
croped_page, page_coord = crop_image_inside_box(box, image_page)
croped_page = resize_image(croped_page, int(croped_page.shape[0] / self.scale_y), int(croped_page.shape[1] / self.scale_x))
croped_page = resize_image(croped_page, int(croped_page.shape[0] / self.scale_y),
int(croped_page.shape[1] / self.scale_x))
path = os.path.join(self.dir_of_cropped_images, self.image_filename_stem + "_" + str(index) + ".jpg")
cv2.imwrite(path, croped_page)
index += 1

@ -22,6 +22,7 @@ from .utils.pil_cv2 import pil2cv
OCRD_TOOL = loads(resource_string(__name__, 'ocrd-tool.json').decode('utf8'))
class EynollahProcessor(Processor):
def __init__(self, *args, **kwargs):

@ -9,8 +9,6 @@ from utils import *
from metrics import *
def configuration():
gpu_options = tf.compat.v1.GPUOptions(allow_growth=True)
session = tf.compat.v1.Session(config=tf.compat.v1.ConfigProto(gpu_options=gpu_options))
@ -29,5 +27,3 @@ if __name__=='__main__':
model = resnet50_unet(n_classes, input_height, input_width, weight_decay, pretraining)
model.load_weights(dir_of_weights)
model.save('./name_in_another_python_version.h5')

@ -2,8 +2,8 @@ from keras import backend as K
import tensorflow as tf
import numpy as np
def focal_loss(gamma=2., alpha=4.):
def focal_loss(gamma=2., alpha=4.):
gamma = float(gamma)
alpha = float(alpha)
@ -37,8 +37,10 @@ def focal_loss(gamma=2., alpha=4.):
fl = tf.multiply(alpha, tf.multiply(weight, ce))
reduced_fl = tf.reduce_max(fl, axis=1)
return tf.reduce_mean(reduced_fl)
return focal_loss_fixed
def weighted_categorical_crossentropy(weights=None):
""" weighted_categorical_crossentropy
@ -58,7 +60,10 @@ def weighted_categorical_crossentropy(weights=None):
* labels_floats, axis=-1), 1.0)
per_pixel_loss = per_pixel_loss * weight_mask[:, :, :, None]
return tf.reduce_mean(per_pixel_loss)
return loss
def image_categorical_cross_entropy(y_true, y_pred, weights=None):
"""
:param y_true: tensor of shape (batch_size, height, width) representing the ground truth.
@ -77,6 +82,8 @@ def image_categorical_cross_entropy(y_true, y_pred, weights=None):
per_pixel_loss = per_pixel_loss * weight_mask[:, :, :, None]
return tf.reduce_mean(per_pixel_loss)
def class_tversky(y_true, y_pred):
smooth = 1.0 # 1.00
@ -92,11 +99,13 @@ def class_tversky(y_true, y_pred):
beta = 0.8
return (true_pos + smooth) / (true_pos + alpha * false_neg + (beta) * false_pos + smooth)
def focal_tversky_loss(y_true, y_pred):
pt_1 = class_tversky(y_true, y_pred)
gamma = 1.3 # 4./3.0#1.3#4.0/3.00# 0.75
return K.sum(K.pow((1 - pt_1), gamma))
def generalized_dice_coeff2(y_true, y_pred):
n_el = 1
for dim in y_true.shape:
@ -112,6 +121,8 @@ def generalized_dice_coeff2(y_true, y_pred):
denominator = w * K.sum(denominator, (0, 1, 2))
denominator = K.sum(denominator)
return 2 * numerator / denominator
def generalized_dice_coeff(y_true, y_pred):
axes = tuple(range(1, len(y_pred.shape) - 1))
Ncl = y_pred.shape[-1]
@ -131,8 +142,11 @@ def generalized_dice_coeff(y_true, y_pred):
return gen_dice_coef
def generalized_dice_loss(y_true, y_pred):
return 1 - generalized_dice_coeff2(y_true, y_pred)
def soft_dice_loss(y_true, y_pred, epsilon=1e-6):
'''
Soft dice loss calculation for arbitrary batch size, number of classes, and number of spatial dimensions.
@ -160,7 +174,9 @@ def soft_dice_loss(y_true, y_pred, epsilon=1e-6):
denominator = K.sum(K.square(y_pred) + K.square(y_true), axes)
return 1.00 - K.mean(numerator / (denominator + epsilon)) # average over classes and batch
def seg_metrics(y_true, y_pred, metric_name, metric_type='standard', drop_last = True, mean_per_class=False, verbose=False):
def seg_metrics(y_true, y_pred, metric_name, metric_type='standard', drop_last=True, mean_per_class=False,
verbose=False):
"""
Compute mean metrics of two segmentation masks, via Keras.
@ -250,6 +266,7 @@ def seg_metrics(y_true, y_pred, metric_name, metric_type='standard', drop_last =
return K.mean(non_zero_sum / non_zero_count)
def mean_iou(y_true, y_pred, **kwargs):
"""
Compute mean Intersection over Union of two segmentation masks, via Keras.
@ -257,6 +274,8 @@ def mean_iou(y_true, y_pred, **kwargs):
Calls metrics_k(y_true, y_pred, metric_name='iou'), see there for allowed kwargs.
"""
return seg_metrics(y_true, y_pred, metric_name='iou', **kwargs)
def Mean_IOU(y_true, y_pred):
nb_classes = K.int_shape(y_pred)[-1]
iou = []
@ -276,6 +295,7 @@ def Mean_IOU(y_true, y_pred):
iou = tf.gather(iou, indices=tf.where(legal_labels))
return K.mean(iou)
def iou_vahid(y_true, y_pred):
nb_classes = tf.shape(y_true)[-1] + tf.to_int32(1)
true_pixels = K.argmax(y_true, axis=-1)
@ -292,8 +312,8 @@ def iou_vahid(y_true, y_pred):
def IoU_metric(Yi, y_predi):
## mean Intersection over Union
## Mean IoU = TP/(FN + TP + FP)
# mean Intersection over Union
# Mean IoU = TP/(FN + TP + FP)
y_predi = np.argmax(y_predi, axis=3)
y_testi = np.argmax(Yi, axis=3)
IoUs = []
@ -308,14 +328,15 @@ def IoU_metric(Yi,y_predi):
def IoU_metric_keras(y_true, y_pred):
## mean Intersection over Union
## Mean IoU = TP/(FN + TP + FP)
# mean Intersection over Union
# Mean IoU = TP/(FN + TP + FP)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
return IoU_metric(y_true.eval(session=sess), y_pred.eval(session=sess))
def jaccard_distance_loss(y_true, y_pred, smooth=100):
"""
Jaccard = (|X & Y|)/ (|X|+ |Y| - |X & Y|)
@ -334,5 +355,3 @@ def jaccard_distance_loss(y_true, y_pred, smooth=100):
sum_ = K.sum(K.abs(y_true) + K.abs(y_pred), axis=-1)
jac = (intersection + smooth) / (sum_ - intersection + smooth)
return (1 - jac) * smooth

@ -16,6 +16,7 @@ def one_side_pad( x ):
x = Lambda(lambda x: x[:, :-1, :-1, :])(x)
return x
def identity_block(input_tensor, kernel_size, filters, stage, block):
"""The identity block is the block that has no conv layer at shortcut.
# Arguments
@ -103,7 +104,6 @@ def resnet50_unet_light(n_classes,input_height=224,input_width=224,weight_decay=
assert input_height % 32 == 0
assert input_width % 32 == 0
img_input = Input(shape=(input_height, input_width, 3))
if IMAGE_ORDERING == 'channels_last':
@ -112,20 +112,19 @@ def resnet50_unet_light(n_classes,input_height=224,input_width=224,weight_decay=
bn_axis = 1
x = ZeroPadding2D((3, 3), data_format=IMAGE_ORDERING)(img_input)
x = Conv2D(64, (7, 7), data_format=IMAGE_ORDERING, strides=(2, 2),kernel_regularizer=l2(weight_decay), name='conv1')(x)
x = Conv2D(64, (7, 7), data_format=IMAGE_ORDERING, strides=(2, 2), kernel_regularizer=l2(weight_decay),
name='conv1')(x)
f1 = x
x = BatchNormalization(axis=bn_axis, name='bn_conv1')(x)
x = Activation('relu')(x)
x = MaxPooling2D((3, 3), data_format=IMAGE_ORDERING, strides=(2, 2))(x)
x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))
x = identity_block(x, 3, [64, 64, 256], stage=2, block='b')
x = identity_block(x, 3, [64, 64, 256], stage=2, block='c')
f2 = one_side_pad(x)
x = conv_block(x, 3, [128, 128, 512], stage=3, block='a')
x = identity_block(x, 3, [128, 128, 512], stage=3, block='b')
x = identity_block(x, 3, [128, 128, 512], stage=3, block='c')
@ -145,22 +144,17 @@ def resnet50_unet_light(n_classes,input_height=224,input_width=224,weight_decay=
x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c')
f5 = x
if pretraining:
model = Model(img_input, x).load_weights(resnet50_Weights_path)
v512_2048 = Conv2D(512, (1, 1), padding='same', data_format=IMAGE_ORDERING, kernel_regularizer=l2(weight_decay))(f5)
v512_2048 = (BatchNormalization(axis=bn_axis))(v512_2048)
v512_2048 = Activation('relu')(v512_2048)
v512_1024 = Conv2D(512, (1, 1), padding='same', data_format=IMAGE_ORDERING, kernel_regularizer=l2(weight_decay))(f4)
v512_1024 = (BatchNormalization(axis=bn_axis))(v512_1024)
v512_1024 = Activation('relu')(v512_1024)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(v512_2048)
o = (concatenate([o, v512_1024], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -168,7 +162,6 @@ def resnet50_unet_light(n_classes,input_height=224,input_width=224,weight_decay=
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(o)
o = (concatenate([o, f3], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -176,7 +169,6 @@ def resnet50_unet_light(n_classes,input_height=224,input_width=224,weight_decay=
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(o)
o = (concatenate([o, f2], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -184,8 +176,6 @@ def resnet50_unet_light(n_classes,input_height=224,input_width=224,weight_decay=
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(o)
o = (concatenate([o, f1], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -193,7 +183,6 @@ def resnet50_unet_light(n_classes,input_height=224,input_width=224,weight_decay=
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(o)
o = (concatenate([o, img_input], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -201,21 +190,18 @@ def resnet50_unet_light(n_classes,input_height=224,input_width=224,weight_decay=
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = Conv2D(n_classes, (1, 1), padding='same', data_format=IMAGE_ORDERING, kernel_regularizer=l2(weight_decay))(o)
o = (BatchNormalization(axis=bn_axis))(o)
o = (Activation('softmax'))(o)
model = Model(img_input, o)
return model
def resnet50_unet(n_classes, input_height=224, input_width=224, weight_decay=1e-6, pretraining=False):
assert input_height % 32 == 0
assert input_width % 32 == 0
img_input = Input(shape=(input_height, input_width, 3))
if IMAGE_ORDERING == 'channels_last':
@ -224,20 +210,19 @@ def resnet50_unet(n_classes,input_height=224,input_width=224,weight_decay=1e-6,p
bn_axis = 1
x = ZeroPadding2D((3, 3), data_format=IMAGE_ORDERING)(img_input)
x = Conv2D(64, (7, 7), data_format=IMAGE_ORDERING, strides=(2, 2),kernel_regularizer=l2(weight_decay), name='conv1')(x)
x = Conv2D(64, (7, 7), data_format=IMAGE_ORDERING, strides=(2, 2), kernel_regularizer=l2(weight_decay),
name='conv1')(x)
f1 = x
x = BatchNormalization(axis=bn_axis, name='bn_conv1')(x)
x = Activation('relu')(x)
x = MaxPooling2D((3, 3), data_format=IMAGE_ORDERING, strides=(2, 2))(x)
x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))
x = identity_block(x, 3, [64, 64, 256], stage=2, block='b')
x = identity_block(x, 3, [64, 64, 256], stage=2, block='c')
f2 = one_side_pad(x)
x = conv_block(x, 3, [128, 128, 512], stage=3, block='a')
x = identity_block(x, 3, [128, 128, 512], stage=3, block='b')
x = identity_block(x, 3, [128, 128, 512], stage=3, block='c')
@ -260,11 +245,11 @@ def resnet50_unet(n_classes,input_height=224,input_width=224,weight_decay=1e-6,p
if pretraining:
Model(img_input, x).load_weights(resnet50_Weights_path)
v1024_2048 = Conv2D( 1024 , (1, 1) , padding='same', data_format=IMAGE_ORDERING,kernel_regularizer=l2(weight_decay) )( f5 )
v1024_2048 = Conv2D(1024, (1, 1), padding='same', data_format=IMAGE_ORDERING, kernel_regularizer=l2(weight_decay))(
f5)
v1024_2048 = (BatchNormalization(axis=bn_axis))(v1024_2048)
v1024_2048 = Activation('relu')(v1024_2048)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(v1024_2048)
o = (concatenate([o, f4], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -272,7 +257,6 @@ def resnet50_unet(n_classes,input_height=224,input_width=224,weight_decay=1e-6,p
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(o)
o = (concatenate([o, f3], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -280,7 +264,6 @@ def resnet50_unet(n_classes,input_height=224,input_width=224,weight_decay=1e-6,p
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(o)
o = (concatenate([o, f2], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -288,7 +271,6 @@ def resnet50_unet(n_classes,input_height=224,input_width=224,weight_decay=1e-6,p
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(o)
o = (concatenate([o, f1], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -296,7 +278,6 @@ def resnet50_unet(n_classes,input_height=224,input_width=224,weight_decay=1e-6,p
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = (UpSampling2D((2, 2), data_format=IMAGE_ORDERING))(o)
o = (concatenate([o, img_input], axis=MERGE_AXIS))
o = (ZeroPadding2D((1, 1), data_format=IMAGE_ORDERING))(o)
@ -304,14 +285,10 @@ def resnet50_unet(n_classes,input_height=224,input_width=224,weight_decay=1e-6,p
o = (BatchNormalization(axis=bn_axis))(o)
o = Activation('relu')(o)
o = Conv2D(n_classes, (1, 1), padding='same', data_format=IMAGE_ORDERING, kernel_regularizer=l2(weight_decay))(o)
o = (BatchNormalization(axis=bn_axis))(o)
o = (Activation('softmax'))(o)
model = Model(img_input, o)
return model

@ -22,6 +22,7 @@ each class will be defined with a RGB value and beside images a text file of cla
This classes.txt file is required for dhsegment tool.
"""
class pagexml2img:
def __init__(self, dir_in, out_dir, output_type):
self.dir = dir_in
@ -33,7 +34,6 @@ class pagexml2img:
Listing all ground truth page xml files. All files are needed to have xml format.
"""
gt_all = os.listdir(self.dir)
self.gt_list = [file for file in gt_all if file.split('.')[len(file.split('.')) - 1] == 'xml']
@ -49,9 +49,6 @@ class pagexml2img:
[0, 0, 255, 0, 0, 0, 1, 0],
[0, 255, 255, 0, 0, 0, 0, 1]])
for index in tqdm(range(len(self.gt_list))):
try:
tree1 = ET.parse(self.dir + '/' + self.gt_list[index])
@ -71,58 +68,69 @@ class pagexml2img:
co_table = []
for tag in region_tags:
if tag.endswith('}TextRegion') or tag.endswith('}Textregion') or tag.endswith('}textRegion') or tag.endswith('}textregion'):
if tag.endswith('}TextRegion') or tag.endswith('}Textregion') or tag.endswith(
'}textRegion') or tag.endswith('}textregion'):
for nn in root1.iter(tag):
for co_it in nn.iter(link + 'Coords'):
if bool(co_it.attrib) == False:
c_t_in = []
for ll in nn.iter(link + 'Point'):
c_t_in.append([ int(np.float(ll.attrib['x'])) , int(np.float(ll.attrib['y'])) ])
c_t_in.append(
[int(np.float(ll.attrib['x'])), int(np.float(ll.attrib['y']))])
co_text.append(np.array(c_t_in))
print(co_text)
elif bool(co_it.attrib) == True and 'points' in co_it.attrib.keys():
p_h = co_it.attrib['points'].split(' ')
co_text.append( np.array( [ [ int(x.split(',')[0]) , int(x.split(',')[1]) ] for x in p_h] ) )
co_text.append(
np.array([[int(x.split(',')[0]), int(x.split(',')[1])] for x in p_h]))
elif tag.endswith('}ImageRegion') or tag.endswith('}Imageregion') or tag.endswith('}imageRegion') or tag.endswith('}imageregion'):
elif tag.endswith('}ImageRegion') or tag.endswith('}Imageregion') or tag.endswith(
'}imageRegion') or tag.endswith('}imageregion'):
for nn in root1.iter(tag):
for co_it in nn.iter(link + 'Coords'):
if bool(co_it.attrib) == False:
c_i_in = []
for ll in nn.iter(link + 'Point'):
c_i_in.append([ int(np.float(ll.attrib['x'])) , int(np.float(ll.attrib['y'])) ])
c_i_in.append(
[int(np.float(ll.attrib['x'])), int(np.float(ll.attrib['y']))])
co_img.append(np.array(c_i_in))
elif bool(co_it.attrib) == True and 'points' in co_it.attrib.keys():
p_h = co_it.attrib['points'].split(' ')
co_img.append( np.array( [ [ int(x.split(',')[0]) , int(x.split(',')[1]) ] for x in p_h] ) )
co_img.append(
np.array([[int(x.split(',')[0]), int(x.split(',')[1])] for x in p_h]))
elif tag.endswith('}SeparatorRegion') or tag.endswith('}Separatorregion') or tag.endswith('}separatorRegion') or tag.endswith('}separatorregion'):
elif tag.endswith('}SeparatorRegion') or tag.endswith('}Separatorregion') or tag.endswith(
'}separatorRegion') or tag.endswith('}separatorregion'):
for nn in root1.iter(tag):
for co_it in nn.iter(link + 'Coords'):
if bool(co_it.attrib) == False:
c_s_in = []
for ll in nn.iter(link + 'Point'):
c_s_in.append([ int(np.float(ll.attrib['x'])) , int(np.float(ll.attrib['y'])) ])
c_s_in.append(
[int(np.float(ll.attrib['x'])), int(np.float(ll.attrib['y']))])
co_sep.append(np.array(c_s_in))
elif bool(co_it.attrib) == True and 'points' in co_it.attrib.keys():
p_h = co_it.attrib['points'].split(' ')
co_sep.append( np.array( [ [ int(x.split(',')[0]) , int(x.split(',')[1]) ] for x in p_h] ) )
co_sep.append(
np.array([[int(x.split(',')[0]), int(x.split(',')[1])] for x in p_h]))
elif tag.endswith('}TableRegion') or tag.endswith('}tableRegion') or tag.endswith('}Tableregion') or tag.endswith('}tableregion'):
elif tag.endswith('}TableRegion') or tag.endswith('}tableRegion') or tag.endswith(
'}Tableregion') or tag.endswith('}tableregion'):
for nn in root1.iter(tag):
for co_it in nn.iter(link + 'Coords'):
if bool(co_it.attrib) == False:
c_ta_in = []
for ll in nn.iter(link + 'Point'):
c_ta_in.append([ int(np.float(ll.attrib['x'])) , int(np.float(ll.attrib['y'])) ])
c_ta_in.append(
[int(np.float(ll.attrib['x'])), int(np.float(ll.attrib['y']))])
co_table.append(np.array(c_ta_in))
elif bool(co_it.attrib) == True and 'points' in co_it.attrib.keys():
p_h = co_it.attrib['points'].split(' ')
co_table.append( np.array( [ [ int(x.split(',')[0]) , int(x.split(',')[1]) ] for x in p_h] ) )
co_table.append(
np.array([[int(x.split(',')[0]), int(x.split(',')[1])] for x in p_h]))
else:
pass
@ -133,7 +141,8 @@ class pagexml2img:
img_poly = cv2.fillPoly(img, pts=co_table, color=(0, 255, 255))
try:
cv2.imwrite(self.output_dir+'/'+self.gt_list[index].split('-')[1].split('.')[0]+'.png',img_poly )
cv2.imwrite(self.output_dir + '/' + self.gt_list[index].split('-')[1].split('.')[0] + '.png',
img_poly)
except:
cv2.imwrite(self.output_dir + '/' + self.gt_list[index].split('.')[0] + '.png', img_poly)
except:
@ -160,58 +169,69 @@ class pagexml2img:
co_table = []
for tag in region_tags:
if tag.endswith('}TextRegion') or tag.endswith('}Textregion') or tag.endswith('}textRegion') or tag.endswith('}textregion'):
if tag.endswith('}TextRegion') or tag.endswith('}Textregion') or tag.endswith(
'}textRegion') or tag.endswith('}textregion'):
for nn in root1.iter(tag):
for co_it in nn.iter(link + 'Coords'):
if bool(co_it.attrib) == False:
c_t_in = []
for ll in nn.iter(link + 'Point'):
c_t_in.append([ int(np.float(ll.attrib['x'])) , int(np.float(ll.attrib['y'])) ])
c_t_in.append(
[int(np.float(ll.attrib['x'])), int(np.float(ll.attrib['y']))])
co_text.append(np.array(c_t_in))
print(co_text)
elif bool(co_it.attrib) == True and 'points' in co_it.attrib.keys():
p_h = co_it.attrib['points'].split(' ')
co_text.append( np.array( [ [ int(x.split(',')[0]) , int(x.split(',')[1]) ] for x in p_h] ) )
co_text.append(
np.array([[int(x.split(',')[0]), int(x.split(',')[1])] for x in p_h]))
elif tag.endswith('}ImageRegion') or tag.endswith('}Imageregion') or tag.endswith('}imageRegion') or tag.endswith('}imageregion'):
elif tag.endswith('}ImageRegion') or tag.endswith('}Imageregion') or tag.endswith(
'}imageRegion') or tag.endswith('}imageregion'):
for nn in root1.iter(tag):
for co_it in nn.iter(link + 'Coords'):
if bool(co_it.attrib) == False:
c_i_in = []
for ll in nn.iter(link + 'Point'):
c_i_in.append([ int(np.float(ll.attrib['x'])) , int(np.float(ll.attrib['y'])) ])
c_i_in.append(
[int(np.float(ll.attrib['x'])), int(np.float(ll.attrib['y']))])
co_img.append(np.array(c_i_in))
elif bool(co_it.attrib) == True and 'points' in co_it.attrib.keys():
p_h = co_it.attrib['points'].split(' ')
co_img.append( np.array( [ [ int(x.split(',')[0]) , int(x.split(',')[1]) ] for x in p_h] ) )
co_img.append(
np.array([[int(x.split(',')[0]), int(x.split(',')[1])] for x in p_h]))
elif tag.endswith('}SeparatorRegion') or tag.endswith('}Separatorregion') or tag.endswith('}separatorRegion') or tag.endswith('}separatorregion'):
elif tag.endswith('}SeparatorRegion') or tag.endswith('}Separatorregion') or tag.endswith(
'}separatorRegion') or tag.endswith('}separatorregion'):
for nn in root1.iter(tag):
for co_it in nn.iter(link + 'Coords'):
if bool(co_it.attrib) == False:
c_s_in = []
for ll in nn.iter(link + 'Point'):
c_s_in.append([ int(np.float(ll.attrib['x'])) , int(np.float(ll.attrib['y'])) ])
c_s_in.append(
[int(np.float(ll.attrib['x'])), int(np.float(ll.attrib['y']))])
co_sep.append(np.array(c_s_in))
elif bool(co_it.attrib) == True and 'points' in co_it.attrib.keys():
p_h = co_it.attrib['points'].split(' ')
co_sep.append( np.array( [ [ int(x.split(',')[0]) , int(x.split(',')[1]) ] for x in p_h] ) )
co_sep.append(
np.array([[int(x.split(',')[0]), int(x.split(',')[1])] for x in p_h]))
elif tag.endswith('}TableRegion') or tag.endswith('}tableRegion') or tag.endswith('}Tableregion') or tag.endswith('}tableregion'):
elif tag.endswith('}TableRegion') or tag.endswith('}tableRegion') or tag.endswith(
'}Tableregion') or tag.endswith('}tableregion'):
for nn in root1.iter(tag):
for co_it in nn.iter(link + 'Coords'):
if bool(co_it.attrib) == False:
c_ta_in = []
for ll in nn.iter(link + 'Point'):
c_ta_in.append([ int(np.float(ll.attrib['x'])) , int(np.float(ll.attrib['y'])) ])
c_ta_in.append(
[int(np.float(ll.attrib['x'])), int(np.float(ll.attrib['y']))])
co_table.append(np.array(c_ta_in))
elif bool(co_it.attrib) == True and 'points' in co_it.attrib.keys():
p_h = co_it.attrib['points'].split(' ')
co_table.append( np.array( [ [ int(x.split(',')[0]) , int(x.split(',')[1]) ] for x in p_h] ) )
co_table.append(
np.array([[int(x.split(',')[0]), int(x.split(',')[1])] for x in p_h]))
else:
pass
@ -221,28 +241,33 @@ class pagexml2img:
img_poly = cv2.fillPoly(img, pts=co_sep, color=(3, 3, 3))
img_poly = cv2.fillPoly(img, pts=co_table, color=(4, 4, 4))
try:
cv2.imwrite(self.output_dir+'/'+self.gt_list[index].split('-')[1].split('.')[0]+'.png',img_poly )
cv2.imwrite(self.output_dir + '/' + self.gt_list[index].split('-')[1].split('.')[0] + '.png',
img_poly)
except:
cv2.imwrite(self.output_dir + '/' + self.gt_list[index].split('.')[0] + '.png', img_poly)
except:
pass
def run(self):
self.get_content_of_dir()
self.get_images_of_ground_truth()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-dir_in', '--dir_in', dest='inp1', default=None, help='directory of page-xml files')
parser.add_argument('-dir_out','--dir_out', dest='inp2', default=None, help='directory where ground truth images would be written')
parser.add_argument('-type','--type', dest='inp3', default=None, help='this defines how output should be. A 2d image array or a 3d image array encoded with RGB color. Just pass 2d or 3d. The file will be saved one directory up. 2D image array is 3d but only information of one channel would be enough since all channels have the same values.')
parser.add_argument('-dir_out', '--dir_out', dest='inp2', default=None,
help='directory where ground truth images would be written')
parser.add_argument('-type', '--type', dest='inp3', default=None,
help='this defines how output should be. A 2d image array or a 3d image array encoded with RGB color. Just pass 2d or 3d. The file will be saved one directory up. 2D image array is 3d but only information of one channel would be enough since all channels have the same values.')
options = parser.parse_args()
possibles = globals()
possibles.update(locals())
x = pagexml2img(options.inp1, options.inp2, options.inp3)
x.run()
if __name__=="__main__":
main()
if __name__ == "__main__":
main()

@ -11,6 +11,7 @@ from metrics import *
from keras.models import load_model
from tqdm import tqdm
def configuration():
keras.backend.clear_session()
tf.reset_default_graph()
@ -19,12 +20,12 @@ def configuration():
os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID'
config = tf.ConfigProto(log_device_placement=False, allow_soft_placement=True)
config.gpu_options.allow_growth = True
config.gpu_options.per_process_gpu_memory_fraction = 0.95 # 0.95
config.gpu_options.visible_device_list = "0"
set_session(tf.Session(config=config))
def get_dirs_or_files(input_data):
if os.path.isdir(input_data):
image_input, labels_input = os.path.join(input_data, 'images/'), os.path.join(input_data, 'labels/')
@ -33,8 +34,10 @@ def get_dirs_or_files(input_data):
assert os.path.isdir(labels_input), "{} is not a directory".format(labels_input)
return image_input, labels_input
ex = Experiment()
@ex.config
def config_params():
n_classes = None # Number of classes. If your case study is binary case the set it to 2 and otherwise give your number of cases.
@ -69,18 +72,17 @@ def config_params():
weighted_loss = False
data_is_provided = False
@ex.automain
def run(n_classes, n_epochs, input_height,
input_width, weight_decay, weighted_loss,
index_start, dir_of_start_model, is_loss_soft_dice,
n_batch,patches,augmentation,flip_aug
,blur_aug,scaling, binarization,
n_batch, patches, augmentation, flip_aug,
blur_aug, scaling, binarization,
blur_k, scales, dir_train, data_is_provided,
scaling_bluring, scaling_binarization, rotation,
rotation_not_90, thetha, scaling_flip, continue_training,
flip_index, dir_eval, dir_output, pretraining, learning_rate):
if data_is_provided:
dir_train_flowing = os.path.join(dir_output, 'train')
dir_eval_flowing = os.path.join(dir_output, 'eval')
@ -119,18 +121,15 @@ def run(n_classes,n_epochs,input_height,
else:
os.makedirs(dir_eval_flowing)
os.mkdir(dir_flow_train_imgs)
os.mkdir(dir_flow_train_labels)
os.mkdir(dir_flow_eval_imgs)
os.mkdir(dir_flow_eval_labels)
# set the gpu configuration
configuration()
# writing patches into a sub-folder in order to be flowed from directory.
provide_patches(dir_img, dir_seg, dir_flow_train_imgs,
dir_flow_train_labels,
@ -148,8 +147,6 @@ def run(n_classes,n_epochs,input_height,
rotation_not_90, thetha, scaling_flip,
augmentation=False, patches=patches)
if weighted_loss:
weights = np.zeros(n_classes)
if data_is_provided:
@ -170,20 +167,18 @@ def run(n_classes,n_epochs,input_height,
except:
pass
weights = 1.00 / weights
weights = weights / float(np.sum(weights))
weights = weights / float(np.min(weights))
weights = weights / float(np.sum(weights))
if continue_training:
if is_loss_soft_dice:
model = load_model(dir_of_start_model, compile=True, custom_objects={'soft_dice_loss': soft_dice_loss})
if weighted_loss:
model = load_model (dir_of_start_model, compile = True, custom_objects={'loss': weighted_categorical_crossentropy(weights)})
model = load_model(dir_of_start_model, compile=True,
custom_objects={'loss': weighted_categorical_crossentropy(weights)})
if not is_loss_soft_dice and not weighted_loss:
model = load_model(dir_of_start_model, compile=True)
else:
@ -194,7 +189,6 @@ def run(n_classes,n_epochs,input_height,
# if you want to see the model structure just uncomment model summary.
# model.summary()
if not is_loss_soft_dice and not weighted_loss:
model.compile(loss='categorical_crossentropy',
optimizer=Adam(lr=learning_rate), metrics=['accuracy'])
@ -221,18 +215,7 @@ def run(n_classes,n_epochs,input_height,
epochs=1)
model.save(dir_output + '/' + 'model_' + str(i) + '.h5')
# os.system('rm -rf '+dir_train_flowing)
# os.system('rm -rf '+dir_eval_flowing)
# model.save(dir_output+'/'+'model'+'.h5')

@ -10,7 +10,6 @@ import imutils
import math
def bluring(img_in, kind):
if kind == 'guass':
img_blur = cv2.GaussianBlur(img_in, (5, 5), 0)
@ -20,8 +19,8 @@ def bluring(img_in,kind):
img_blur = cv2.blur(img_in, (5, 5))
return img_blur
def elastic_transform(image, alpha, sigma,seedj, random_state=None):
def elastic_transform(image, alpha, sigma, seedj, random_state=None):
"""Elastic deformation of images as described in [Simard2003]_.
.. [Simard2003] Simard, Steinkraus and Platt, "Best Practices for
Convolutional Neural Networks applied to Visual Document Analysis", in
@ -42,6 +41,7 @@ def elastic_transform(image, alpha, sigma,seedj, random_state=None):
distored_image = map_coordinates(image, indices, order=1, mode='reflect')
return distored_image.reshape(image.shape)
def rotation_90(img):
img_rot = np.zeros((img.shape[1], img.shape[0], img.shape[2]))
img_rot[:, :, 0] = img[:, :, 0].T
@ -49,6 +49,7 @@ def rotation_90(img):
img_rot[:, :, 2] = img[:, :, 2].T
return img_rot
def rotatedRectWithMaxArea(w, h, angle):
"""
Given a rectangle of size wxh that has been rotated by 'angle' (in
@ -76,6 +77,7 @@ def rotatedRectWithMaxArea(w, h, angle):
return wr, hr
def rotate_max_area(image, rotated, rotated_label, angle):
""" image: cv2 image matrix object
angle: in degree
@ -88,11 +90,14 @@ def rotate_max_area(image,rotated, rotated_label,angle):
x1 = w // 2 - int(wr / 2)
x2 = x1 + int(wr)
return rotated[y1:y2, x1:x2], rotated_label[y1:y2, x1:x2]
def rotation_not_90_func(img, label, thetha):
rotated = imutils.rotate(img, thetha)
rotated_label = imutils.rotate(label, thetha)
return rotate_max_area(img, rotated, rotated_label, thetha)
def color_images(seg, n_classes):
ann_u = range(n_classes)
if len(np.shape(seg)) == 3:
@ -112,6 +117,8 @@ def color_images(seg, n_classes):
def resize_image(seg_in, input_height, input_width):
return cv2.resize(seg_in, (input_width, input_height), interpolation=cv2.INTER_NEAREST)
def get_one_hot(seg, input_height, input_width, n_classes):
seg = seg[:, :, 0]
seg_f = np.zeros((input_height, input_width, n_classes))
@ -121,8 +128,8 @@ def get_one_hot(seg,input_height,input_width,n_classes):
def IoU(Yi, y_predi):
## mean Intersection over Union
## Mean IoU = TP/(FN + TP + FP)
# mean Intersection over Union
# Mean IoU = TP/(FN + TP + FP)
IoUs = []
classes_true = np.unique(Yi)
@ -137,6 +144,8 @@ def IoU(Yi,y_predi):
print("_________________")
print("Mean IoU: {:4.3f}".format(mIoU))
return mIoU
def data_gen(img_folder, mask_folder, batch_size, input_height, input_width, n_classes):
c = 0
n = [f for f in os.listdir(img_folder) if not f.startswith('.')] # os.listdir(img_folder) #List of training images
@ -152,13 +161,15 @@ def data_gen(img_folder, mask_folder, batch_size,input_height, input_width,n_cla
filename = n[i].split('.')[0]
train_img = cv2.imread(img_folder + '/' + n[i]) / 255.
train_img = cv2.resize(train_img, (input_width, input_height),interpolation=cv2.INTER_NEAREST)# Read an image from folder and resize
train_img = cv2.resize(train_img, (input_width, input_height),
interpolation=cv2.INTER_NEAREST) # Read an image from folder and resize
img[i - c] = train_img # add to array - img[0], img[1], and so on.
train_mask = cv2.imread(mask_folder + '/' + filename + '.png')
# print(mask_folder+'/'+filename+'.png')
# print(train_mask.shape)
train_mask = get_one_hot( resize_image(train_mask,input_height,input_width),input_height,input_width,n_classes)
train_mask = get_one_hot(resize_image(train_mask, input_height, input_width), input_height, input_width,
n_classes)
# train_mask = train_mask.reshape(224, 224, 1) # Add extra dimension for parity with train_img size [512 * 512 * 3]
mask[i - c] = train_mask
@ -166,14 +177,13 @@ def data_gen(img_folder, mask_folder, batch_size,input_height, input_width,n_cla
img[i - c] = np.ones((input_height, input_width, 3)).astype('float')
mask[i - c] = np.zeros((input_height, input_width, n_classes)).astype('float')
c += batch_size
if(c+batch_size>=len(os.listdir(img_folder))):
if c + batch_size >= len(os.listdir(img_folder)):
c = 0
random.shuffle(n)
yield img, mask
def otsu_copy(img):
img_r = np.zeros(img.shape)
img1 = img[:, :, 0]
@ -186,8 +196,9 @@ def otsu_copy(img):
img_r[:, :, 1] = threshold1
img_r[:, :, 2] = threshold1
return img_r
def get_patches(dir_img_f,dir_seg_f,img,label,height,width,indexer):
def get_patches(dir_img_f, dir_seg_f, img, label, height, width, indexer):
if img.shape[0] < height or img.shape[1] < width:
img, label = do_padding(img, label, height, width)
@ -220,7 +231,6 @@ def get_patches(dir_img_f,dir_seg_f,img,label,height,width,indexer):
index_y_u = img_h
index_y_d = img_h - height
img_patch = img[index_y_d:index_y_u, index_x_d:index_x_u, :]
label_patch = label[index_y_d:index_y_u, index_x_d:index_x_u, :]
@ -230,8 +240,8 @@ def get_patches(dir_img_f,dir_seg_f,img,label,height,width,indexer):
return indexer
def do_padding(img,label,height,width):
def do_padding(img, label, height, width):
height_new = img.shape[0]
width_new = img.shape[1]
@ -256,8 +266,6 @@ def do_padding(img,label,height,width):
def get_patches_num_scale(dir_img_f, dir_seg_f, img, label, height, width, indexer, n_patches, scaler):
if img.shape[0] < height or img.shape[1] < width:
img, label = do_padding(img, label, height, width)
@ -267,7 +275,6 @@ def get_patches_num_scale(dir_img_f,dir_seg_f,img,label,height,width,indexer,n_p
height_scale = int(height * scaler)
width_scale = int(width * scaler)
nxf = img_w / float(width_scale)
nyf = img_h / float(height_scale)
@ -294,7 +301,6 @@ def get_patches_num_scale(dir_img_f,dir_seg_f,img,label,height,width,indexer,n_p
index_y_u = img_h
index_y_d = img_h - height_scale
img_patch = img[index_y_d:index_y_u, index_x_d:index_x_u, :]
label_patch = label[index_y_d:index_y_u, index_x_d:index_x_u, :]
@ -307,6 +313,7 @@ def get_patches_num_scale(dir_img_f,dir_seg_f,img,label,height,width,indexer,n_p
return indexer
def get_patches_num_scale_new(dir_img_f, dir_seg_f, img, label, height, width, indexer, scaler):
img = resize_image(img, int(img.shape[0] * scaler), int(img.shape[1] * scaler))
label = resize_image(label, int(label.shape[0] * scaler), int(label.shape[1] * scaler))
@ -320,7 +327,6 @@ def get_patches_num_scale_new(dir_img_f,dir_seg_f,img,label,height,width,indexer
height_scale = int(height * 1)
width_scale = int(width * 1)
nxf = img_w / float(width_scale)
nyf = img_h / float(height_scale)
@ -347,7 +353,6 @@ def get_patches_num_scale_new(dir_img_f,dir_seg_f,img,label,height,width,indexer
index_y_u = img_h
index_y_d = img_h - height_scale
img_patch = img[index_y_d:index_y_u, index_x_d:index_x_u, :]
label_patch = label[index_y_d:index_y_u, index_x_d:index_x_u, :]
@ -368,7 +373,6 @@ def provide_patches(dir_img,dir_seg,dir_flow_train_imgs,
scaling_bluring, scaling_binarization, rotation,
rotation_not_90, thetha, scaling_flip,
augmentation=False, patches=False):
imgs_cv_train = np.array(os.listdir(dir_img))
segs_cv_train = np.array(os.listdir(dir_seg))
@ -376,30 +380,35 @@ def provide_patches(dir_img,dir_seg,dir_flow_train_imgs,
for im, seg_i in tqdm(zip(imgs_cv_train, segs_cv_train)):
img_name = im.split('.')[0]
if not patches:
cv2.imwrite(dir_flow_train_imgs+'/img_'+str(indexer)+'.png', resize_image(cv2.imread(dir_img+'/'+im),input_height,input_width ) )
cv2.imwrite(dir_flow_train_labels+'/img_'+str(indexer)+'.png' , resize_image(cv2.imread(dir_seg+'/'+img_name+'.png'),input_height,input_width ) )
cv2.imwrite(dir_flow_train_imgs + '/img_' + str(indexer) + '.png',
resize_image(cv2.imread(dir_img + '/' + im), input_height, input_width))
cv2.imwrite(dir_flow_train_labels + '/img_' + str(indexer) + '.png',
resize_image(cv2.imread(dir_seg + '/' + img_name + '.png'), input_height, input_width))
indexer += 1
if augmentation:
if flip_aug:
for f_i in flip_index:
cv2.imwrite(dir_flow_train_imgs + '/img_' + str(indexer) + '.png',
resize_image(cv2.flip(cv2.imread(dir_img+'/'+im),f_i),input_height,input_width) )
resize_image(cv2.flip(cv2.imread(dir_img + '/' + im), f_i), input_height,
input_width))
cv2.imwrite(dir_flow_train_labels + '/img_' + str(indexer) + '.png',
resize_image(cv2.flip(cv2.imread(dir_seg+'/'+img_name+'.png'),f_i),input_height,input_width) )
resize_image(cv2.flip(cv2.imread(dir_seg + '/' + img_name + '.png'), f_i),
input_height, input_width))
indexer += 1
if blur_aug:
for blur_i in blur_k:
cv2.imwrite(dir_flow_train_imgs + '/img_' + str(indexer) + '.png',
(resize_image(bluring(cv2.imread(dir_img+'/'+im),blur_i),input_height,input_width) ) )
(resize_image(bluring(cv2.imread(dir_img + '/' + im), blur_i), input_height,
input_width)))
cv2.imwrite(dir_flow_train_labels + '/img_' + str(indexer) + '.png',
resize_image(cv2.imread(dir_seg+'/'+img_name+'.png'),input_height,input_width) )
resize_image(cv2.imread(dir_seg + '/' + img_name + '.png'), input_height,
input_width))
indexer += 1
if binarization:
cv2.imwrite(dir_flow_train_imgs + '/img_' + str(indexer) + '.png',
resize_image(otsu_copy(cv2.imread(dir_img + '/' + im)), input_height, input_width))
@ -408,11 +417,6 @@ def provide_patches(dir_img,dir_seg,dir_flow_train_imgs,
resize_image(cv2.imread(dir_seg + '/' + img_name + '.png'), input_height, input_width))
indexer += 1
if patches:
indexer = get_patches(dir_flow_train_imgs, dir_flow_train_labels,
@ -422,8 +426,6 @@ def provide_patches(dir_img,dir_seg,dir_flow_train_imgs,
if augmentation:
if rotation:
indexer = get_patches(dir_flow_train_imgs, dir_flow_train_labels,
rotation_90(cv2.imread(dir_img + '/' + im)),
rotation_90(cv2.imread(dir_seg + '/' + img_name + '.png')),
@ -432,7 +434,10 @@ def provide_patches(dir_img,dir_seg,dir_flow_train_imgs,
if rotation_not_90:
for thetha_i in thetha:
img_max_rotated,label_max_rotated=rotation_not_90_func(cv2.imread(dir_img+'/'+im),cv2.imread(dir_seg+'/'+img_name+'.png'),thetha_i)
img_max_rotated, label_max_rotated = rotation_not_90_func(cv2.imread(dir_img + '/' + im),
cv2.imread(
dir_seg + '/' + img_name + '.png'),
thetha_i)
indexer = get_patches(dir_flow_train_imgs, dir_flow_train_labels,
img_max_rotated,
label_max_rotated,
@ -445,13 +450,11 @@ def provide_patches(dir_img,dir_seg,dir_flow_train_imgs,
input_height, input_width, indexer=indexer)
if blur_aug:
for blur_i in blur_k:
indexer = get_patches(dir_flow_train_imgs, dir_flow_train_labels,
bluring(cv2.imread(dir_img + '/' + im), blur_i),
cv2.imread(dir_seg + '/' + img_name + '.png'),
input_height, input_width, indexer=indexer)
if scaling:
for sc_ind in scales:
indexer = get_patches_num_scale_new(dir_flow_train_imgs, dir_flow_train_labels,
@ -464,15 +467,14 @@ def provide_patches(dir_img,dir_seg,dir_flow_train_imgs,
cv2.imread(dir_seg + '/' + img_name + '.png'),
input_height, input_width, indexer=indexer)
if scaling_bluring:
for sc_ind in scales:
for blur_i in blur_k:
indexer = get_patches_num_scale_new(dir_flow_train_imgs, dir_flow_train_labels,
bluring(cv2.imread(dir_img + '/' + im), blur_i),
cv2.imread(dir_seg + '/' + img_name + '.png'),
input_height,input_width,indexer=indexer,scaler=sc_ind)
input_height, input_width, indexer=indexer,
scaler=sc_ind)
if scaling_binarization:
for sc_ind in scales:
@ -486,12 +488,7 @@ def provide_patches(dir_img,dir_seg,dir_flow_train_imgs,
for f_i in flip_index:
indexer = get_patches_num_scale_new(dir_flow_train_imgs, dir_flow_train_labels,
cv2.flip(cv2.imread(dir_img + '/' + im), f_i),
cv2.flip(cv2.imread(dir_seg+'/'+img_name+'.png') ,f_i) ,
input_height,input_width,indexer=indexer,scaler=sc_ind)
cv2.flip(cv2.imread(dir_seg + '/' + img_name + '.png'),
f_i),
input_height, input_width, indexer=indexer,
scaler=sc_ind)

@ -5,6 +5,8 @@ from shapely import geometry
from .rotate import rotate_image, rotation_image_new
from multiprocessing import Process, Queue, cpu_count
from multiprocessing import Pool
def contours_in_same_horizon(cy_main_hor):
X1 = np.zeros((len(cy_main_hor), len(cy_main_hor)))
X2 = np.zeros((len(cy_main_hor), len(cy_main_hor)))
@ -22,6 +24,7 @@ def contours_in_same_horizon(cy_main_hor):
all_args.append(list(set(list_h)))
return np.unique(np.array(all_args, dtype=object))
def find_contours_mean_y_diff(contours_main):
M_main = [cv2.moments(contours_main[j]) for j in range(len(contours_main))]
cy_main = [(M_main[j]["m01"] / (M_main[j]["m00"] + 1e-32)) for j in range(len(M_main))]
@ -42,6 +45,7 @@ def get_text_region_boxes_by_given_contours(contours):
del contours
return boxes, contours_new
def filter_contours_area_of_image(image, contours, hierarchy, max_area, min_area):
found_polygons_early = list()
@ -55,6 +59,7 @@ def filter_contours_area_of_image(image, contours, hierarchy, max_area, min_area
found_polygons_early.append(np.array([[point] for point in polygon.exterior.coords], dtype=np.uint))
return found_polygons_early
def filter_contours_area_of_image_tables(image, contours, hierarchy, max_area, min_area):
found_polygons_early = list()
@ -65,7 +70,7 @@ def filter_contours_area_of_image_tables(image, contours, hierarchy, max_area, m
polygon = geometry.Polygon([point[0] for point in c])
# area = cv2.contourArea(c)
area = polygon.area
##print(np.prod(thresh.shape[:2]))
# print(np.prod(thresh.shape[:2]))
# Check that polygon has area greater than minimal area
# print(hierarchy[0][jv][3],hierarchy )
if area >= min_area * np.prod(image.shape[:2]) and area <= max_area * np.prod(image.shape[:2]): # and hierarchy[0][jv][3]==-1 :
@ -73,6 +78,7 @@ def filter_contours_area_of_image_tables(image, contours, hierarchy, max_area, m
found_polygons_early.append(np.array([[point] for point in polygon.exterior.coords], dtype=np.int32))
return found_polygons_early
def find_new_features_of_contours(contours_main):
areas_main = np.array([cv2.contourArea(contours_main[j]) for j in range(len(contours_main))])
@ -107,9 +113,9 @@ def find_new_features_of_contours(contours_main):
# dis_x=np.abs(x_max_main-x_min_main)
return cx_main, cy_main, x_min_main, x_max_main, y_min_main, y_max_main, y_corr_x_min_from_argmin
def find_features_of_contours(contours_main):
def find_features_of_contours(contours_main):
areas_main = np.array([cv2.contourArea(contours_main[j]) for j in range(len(contours_main))])
M_main = [cv2.moments(contours_main[j]) for j in range(len(contours_main))]
cx_main = [(M_main[j]['m10']/(M_main[j]['m00']+1e-32)) for j in range(len(M_main))]
@ -120,12 +126,14 @@ def find_features_of_contours(contours_main):
y_min_main = np.array([np.min(contours_main[j][:, 0, 1]) for j in range(len(contours_main))])
y_max_main = np.array([np.max(contours_main[j][:, 0, 1]) for j in range(len(contours_main))])
return y_min_main, y_max_main
def return_parent_contours(contours, hierarchy):
contours_parent = [contours[i] for i in range(len(contours)) if hierarchy[0][i][3] == -1]
return contours_parent
def return_contours_of_interested_region(region_pre_p, pixel, min_area=0.0002):
# pixels of images are identified by 5
@ -145,6 +153,7 @@ def return_contours_of_interested_region(region_pre_p, pixel, min_area=0.0002):
return contours_imgs
def do_work_of_contours_in_image(queue_of_all_params, contours_per_process, indexes_r_con_per_pro, img, slope_first):
cnts_org_per_each_subprocess = []
index_by_text_region_contours = []
@ -165,7 +174,6 @@ def do_work_of_contours_in_image(queue_of_all_params, contours_per_process, inde
cont_int[0][:, 0, 0] = cont_int[0][:, 0, 0] + np.abs(img_copy.shape[1] - img.shape[1])
cont_int[0][:, 0, 1] = cont_int[0][:, 0, 1] + np.abs(img_copy.shape[0] - img.shape[0])
cnts_org_per_each_subprocess.append(cont_int[0])
queue_of_all_params.put([cnts_org_per_each_subprocess, index_by_text_region_contours])
@ -200,6 +208,8 @@ def get_textregion_contours_in_org_image_multi(cnts, img, slope_first):
print(all_index_text_con)
return cnts_org
def loop_contour_image(index_l, cnts, img, slope_first):
img_copy = np.zeros(img.shape)
img_copy = cv2.fillPoly(img_copy, pts=[cnts[index_l]], color=(1, 1, 1))
@ -209,7 +219,7 @@ def loop_contour_image(index_l, cnts,img, slope_first):
# print(img.shape,'img')
img_copy = rotation_image_new(img_copy, -slope_first)
##print(img_copy.shape,'img_copy')
# print(img_copy.shape,'img_copy')
# plt.imshow(img_copy)
# plt.show()
@ -224,6 +234,7 @@ def loop_contour_image(index_l, cnts,img, slope_first):
# print(np.shape(cont_int[0]))
return cont_int[0]
def get_textregion_contours_in_org_image_multi2(cnts, img, slope_first):
cnts_org = []
@ -233,6 +244,7 @@ def get_textregion_contours_in_org_image_multi2(cnts, img, slope_first):
return cnts_org
def get_textregion_contours_in_org_image(cnts, img, slope_first):
cnts_org = []
@ -246,7 +258,7 @@ def get_textregion_contours_in_org_image(cnts, img, slope_first):
# print(img.shape,'img')
img_copy = rotation_image_new(img_copy, -slope_first)
##print(img_copy.shape,'img_copy')
# print(img_copy.shape,'img_copy')
# plt.imshow(img_copy)
# plt.show()
@ -263,13 +275,14 @@ def get_textregion_contours_in_org_image(cnts, img, slope_first):
return cnts_org
def get_textregion_contours_in_org_image_light(cnts, img, slope_first):
h_o = img.shape[0]
w_o = img.shape[1]
img = cv2.resize(img, (int(img.shape[1]/3.), int(img.shape[0]/3.)), interpolation=cv2.INTER_NEAREST)
##cnts = list( (np.array(cnts)/2).astype(np.int16) )
# cnts = list( (np.array(cnts)/2).astype(np.int16) )
# cnts = cnts/2
cnts = [(i / 3).astype(np.int32) for i in cnts]
cnts_org = []
@ -283,7 +296,7 @@ def get_textregion_contours_in_org_image_light(cnts, img, slope_first):
# print(img.shape,'img')
img_copy = rotation_image_new(img_copy, -slope_first)
##print(img_copy.shape,'img_copy')
# print(img_copy.shape,'img_copy')
# plt.imshow(img_copy)
# plt.show()
@ -300,6 +313,7 @@ def get_textregion_contours_in_org_image_light(cnts, img, slope_first):
return cnts_org
def return_contours_of_interested_textline(region_pre_p, pixel):
# pixels of images are identified by 5
@ -317,6 +331,7 @@ def return_contours_of_interested_textline(region_pre_p, pixel):
contours_imgs = filter_contours_area_of_image_tables(thresh, contours_imgs, hierarchy, max_area=1, min_area=0.000000003)
return contours_imgs
def return_contours_of_image(image):
if len(image.shape) == 2:
@ -329,6 +344,7 @@ def return_contours_of_image(image):
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
return contours, hierarchy
def return_contours_of_interested_region_by_min_size(region_pre_p, pixel, min_size=0.00003):
# pixels of images are identified by 5
@ -348,6 +364,7 @@ def return_contours_of_interested_region_by_min_size(region_pre_p, pixel, min_si
return contours_imgs
def return_contours_of_interested_region_by_size(region_pre_p, pixel, min_area, max_area):
# pixels of images are identified by 5
@ -367,4 +384,3 @@ def return_contours_of_interested_region_by_size(region_pre_p, pixel, min_area,
img_ret = np.zeros((region_pre_p.shape[0], region_pre_p.shape[1], 3))
img_ret = cv2.fillPoly(img_ret, pts=contours_imgs, color=(1, 1, 1))
return img_ret[:, :, 0]

@ -3,6 +3,7 @@ from collections import Counter
REGION_ID_TEMPLATE = 'region_%04d'
LINE_ID_TEMPLATE = 'region_%04d_line_%04d'
class EynollahIdCounter():
def __init__(self, region_idx=0, line_idx=0):

@ -6,6 +6,7 @@ from .contour import (
return_parent_contours,
)
def adhere_drop_capital_region_into_corresponding_textline(
text_regions_p,
polygons_of_drop_capitals,
@ -44,7 +45,7 @@ def adhere_drop_capital_region_into_corresponding_textline(
# plt.imshow(img_con[:,:,0])
# plt.show()
##img_con=cv2.dilate(img_con, kernel, iterations=30)
# img_con=cv2.dilate(img_con, kernel, iterations=30)
# plt.imshow(img_con[:,:,0])
# plt.show()
@ -185,7 +186,7 @@ def adhere_drop_capital_region_into_corresponding_textline(
# contours_biggest[:,0,1]=contours_biggest[:,0,1]#-all_box_coord[int(region_final)][0]
# print(np.shape(contours_biggest),'contours_biggest')
# print(np.shape(all_found_textline_polygons[int(region_final)][arg_min]))
##contours_biggest=contours_biggest.reshape(np.shape(contours_biggest)[0],np.shape(contours_biggest)[2])
# contours_biggest=contours_biggest.reshape(np.shape(contours_biggest)[0],np.shape(contours_biggest)[2])
all_found_textline_polygons[int(region_final)][arg_min] = contours_biggest
except:
pass
@ -230,7 +231,7 @@ def adhere_drop_capital_region_into_corresponding_textline(
contours_biggest[:, 0, 0] = contours_biggest[:, 0, 0] # -all_box_coord[int(region_final)][2]
contours_biggest[:, 0, 1] = contours_biggest[:, 0, 1] # -all_box_coord[int(region_final)][0]
##contours_biggest=contours_biggest.reshape(np.shape(contours_biggest)[0],np.shape(contours_biggest)[2])
# contours_biggest=contours_biggest.reshape(np.shape(contours_biggest)[0],np.shape(contours_biggest)[2])
all_found_textline_polygons[int(region_final)][arg_min] = contours_biggest
# all_found_textline_polygons[int(region_final)][arg_min]=contours_biggest
@ -239,7 +240,7 @@ def adhere_drop_capital_region_into_corresponding_textline(
else:
pass
##cx_t,cy_t ,_, _, _ ,_,_= find_new_features_of_contours(all_found_textline_polygons[int(region_final)])
# cx_t,cy_t ,_, _, _ ,_,_= find_new_features_of_contours(all_found_textline_polygons[int(region_final)])
# ##print(all_box_coord[j_cont])
# ##print(cx_t)
# ##print(cy_t)
@ -464,6 +465,7 @@ def adhere_drop_capital_region_into_corresponding_textline(
# ####pass
return all_found_textline_polygons
def filter_small_drop_capitals_from_no_patch_layout(layout_no_patch, layout1):
drop_only = (layout_no_patch[:, :, 0] == 4) * 1
@ -499,4 +501,3 @@ def filter_small_drop_capitals_from_no_patch_layout(layout_no_patch, layout1):
layout_no_patch = cv2.fillPoly(layout_no_patch, pts=contours_drop_parent_final, color=(4, 4, 4))
return layout_no_patch

@ -3,18 +3,17 @@ import cv2
from scipy.signal import find_peaks
from scipy.ndimage import gaussian_filter1d
from .contour import find_new_features_of_contours, return_contours_of_interested_region
from .resize import resize_image
from .rotate import rotate_image
def get_marginals(text_with_lines, text_regions, num_col, slope_deskew, kernel=None):
mask_marginals = np.zeros((text_with_lines.shape[0], text_with_lines.shape[1]))
mask_marginals = mask_marginals.astype(np.uint8)
text_with_lines = text_with_lines.astype(np.uint8)
##text_with_lines=cv2.erode(text_with_lines,self.kernel,iterations=3)
# text_with_lines=cv2.erode(text_with_lines,self.kernel,iterations=3)
text_with_lines_eroded = cv2.erode(text_with_lines, kernel, iterations=5)
@ -23,12 +22,13 @@ def get_marginals(text_with_lines, text_regions, num_col, slope_deskew, kernel=N
elif text_with_lines.shape[0] > 1500 and text_with_lines.shape[0] <= 1800:
text_with_lines = resize_image(text_with_lines, int(text_with_lines.shape[0] * 1.5), text_with_lines.shape[1])
text_with_lines = cv2.erode(text_with_lines, kernel, iterations=5)
text_with_lines=resize_image(text_with_lines,text_with_lines_eroded.shape[0],text_with_lines_eroded.shape[1])
text_with_lines = resize_image(text_with_lines, text_with_lines_eroded.shape[0],
text_with_lines_eroded.shape[1])
else:
text_with_lines = resize_image(text_with_lines, int(text_with_lines.shape[0] * 1.8), text_with_lines.shape[1])
text_with_lines = cv2.erode(text_with_lines, kernel, iterations=7)
text_with_lines=resize_image(text_with_lines,text_with_lines_eroded.shape[0],text_with_lines_eroded.shape[1])
text_with_lines = resize_image(text_with_lines, text_with_lines_eroded.shape[0],
text_with_lines_eroded.shape[1])
text_with_lines_y = text_with_lines.sum(axis=0)
text_with_lines_y_eroded = text_with_lines_eroded.sum(axis=0)
@ -44,21 +44,15 @@ def get_marginals(text_with_lines, text_regions, num_col, slope_deskew, kernel=N
else:
min_textline_thickness = 40
if thickness_along_y_percent >= 14:
text_with_lines_y_rev = -1 * text_with_lines_y[:]
# print(text_with_lines_y)
# print(text_with_lines_y_rev)
# plt.plot(text_with_lines_y)
# plt.show()
text_with_lines_y_rev = text_with_lines_y_rev - np.min(text_with_lines_y_rev)
# plt.plot(text_with_lines_y_rev)
@ -75,39 +69,30 @@ def get_marginals(text_with_lines, text_regions, num_col, slope_deskew, kernel=N
first_nonzero = (next((i for i, x in enumerate(region_sum_0) if x), None))
last_nonzero = (next((i for i, x in enumerate(region_sum_0_updown) if x), None))
last_nonzero = len(region_sum_0) - last_nonzero
##img_sum_0_smooth_rev=-region_sum_0
# img_sum_0_smooth_rev=-region_sum_0
mid_point = (last_nonzero + first_nonzero) / 2.
one_third_right = (last_nonzero - mid_point) / 3.0
one_third_left = (mid_point - first_nonzero) / 3.0
# img_sum_0_smooth_rev=img_sum_0_smooth_rev-np.min(img_sum_0_smooth_rev)
peaks, _ = find_peaks(text_with_lines_y_rev, height=0)
peaks = np.array(peaks)
# print(region_sum_0[peaks])
# #plt.plot(region_sum_0)
# #plt.plot(peaks,region_sum_0[peaks],'*')
# #plt.show()
# print(first_nonzero,last_nonzero,peaks)
peaks=peaks[(peaks>first_nonzero) & ((peaks<last_nonzero))]
peaks = peaks[(peaks > first_nonzero) & (peaks < last_nonzero)]
# print(first_nonzero,last_nonzero,peaks)
# print(region_sum_0[peaks]<10)
# ###peaks=peaks[region_sum_0[peaks]<25 ]
@ -123,21 +108,16 @@ def get_marginals(text_with_lines, text_regions, num_col, slope_deskew, kernel=N
peaks_right = peaks[peaks > (mid_point + one_third_right)]
peaks_left = peaks[peaks < (mid_point - one_third_left)]
try:
point_right = np.min(peaks_right)
except:
point_right = last_nonzero
try:
point_left = np.max(peaks_left)
except:
point_left = first_nonzero
# print(point_left,point_right)
# print(text_regions.shape)
if point_right >= mask_marginals.shape[1]:
@ -167,7 +147,6 @@ def get_marginals(text_with_lines, text_regions, num_col, slope_deskew, kernel=N
if max_point_of_right_marginal >= text_regions.shape[1]:
max_point_of_right_marginal = text_regions.shape[1] - 1
# print(np.min(index_x_interest) ,np.max(index_x_interest),'minmaxnew')
# print(mask_marginals_rotated.shape,text_regions.shape,'mask_marginals_rotated')
# plt.imshow(mask_marginals)
@ -185,7 +164,8 @@ def get_marginals(text_with_lines, text_regions, num_col, slope_deskew, kernel=N
min_area_text = 0.00001
polygons_of_marginals = return_contours_of_interested_region(text_regions, pixel_img, min_area_text)
cx_text_only,cy_text_only ,x_min_text_only,x_max_text_only, y_min_text_only ,y_max_text_only,y_cor_x_min_main=find_new_features_of_contours(polygons_of_marginals)
cx_text_only, cy_text_only, x_min_text_only, x_max_text_only, y_min_text_only, y_max_text_only, y_cor_x_min_main = find_new_features_of_contours(
polygons_of_marginals)
text_regions[(text_regions[:, :] == 4)] = 1
@ -219,9 +199,6 @@ def get_marginals(text_with_lines, text_regions, num_col, slope_deskew, kernel=N
if len(x_min_marginals_right) == 0:
x_min_marginals_right = [text_regions.shape[1] - 1]
# print(x_min_marginals_left[0],x_min_marginals_right[0],'margo')
# print(marginlas_should_be_main_text,'marginlas_should_be_main_text')
@ -242,7 +219,6 @@ def get_marginals(text_with_lines, text_regions, num_col, slope_deskew, kernel=N
# plt.plot(peaks,region_sum_0[peaks],'*')
# plt.show()
# plt.imshow(text_regions)
# plt.show()

@ -5,15 +5,18 @@ from cv2 import COLOR_GRAY2BGR, COLOR_RGB2BGR, COLOR_BGR2RGB, cvtColor, imread
# from sbb_binarization
def cv2pil(img):
return Image.fromarray(np.array(cvtColor(img, COLOR_BGR2RGB)))
def pil2cv(img):
# from ocrd/workspace.py
color_conversion = COLOR_GRAY2BGR if img.mode in ('1', 'L') else COLOR_RGB2BGR
pil_as_np_array = np.array(img).astype('uint8') if img.mode == '1' else np.array(img)
return cvtColor(pil_as_np_array, color_conversion)
def check_dpi(img):
try:
if isinstance(img, Image.Image):

@ -1,4 +1,5 @@
import cv2
def resize_image(img_in, input_height, input_width):
return cv2.resize(img_in, (input_width, input_height), interpolation=cv2.INTER_NEAREST)

@ -3,6 +3,7 @@ import math
import imutils
import cv2
def rotatedRectWithMaxArea(w, h, angle):
if w <= 0 or h <= 0:
return 0, 0
@ -25,6 +26,7 @@ def rotatedRectWithMaxArea(w, h, angle):
return wr, hr
def rotate_max_area_new(image, rotated, angle):
wr, hr = rotatedRectWithMaxArea(image.shape[1], image.shape[0], math.radians(angle))
h, w, _ = rotated.shape
@ -34,16 +36,19 @@ def rotate_max_area_new(image, rotated, angle):
x2 = x1 + int(wr)
return rotated[y1:y2, x1:x2]
def rotation_image_new(img, thetha):
rotated = imutils.rotate(img, thetha)
return rotate_max_area_new(img, rotated, thetha)
def rotate_image(img_patch, slope):
(h, w) = img_patch.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, slope, 1.0)
return cv2.warpAffine(img_patch, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
def rotate_image_different(img, slope):
# img = cv2.imread('images/input.jpg')
num_rows, num_cols = img.shape[:2]
@ -52,6 +57,7 @@ def rotate_image_different( img, slope):
img_rotation = cv2.warpAffine(img, rotation_matrix, (num_cols, num_rows))
return img_rotation
def rotate_max_area(image, rotated, rotated_textline, rotated_layout, rotated_table_prediction, angle):
wr, hr = rotatedRectWithMaxArea(image.shape[1], image.shape[0], math.radians(angle))
h, w, _ = rotated.shape
@ -61,6 +67,7 @@ def rotate_max_area(image, rotated, rotated_textline, rotated_layout, rotated_ta
x2 = x1 + int(wr)
return rotated[y1:y2, x1:x2], rotated_textline[y1:y2, x1:x2], rotated_layout[y1:y2, x1:x2], rotated_table_prediction[y1:y2, x1:x2]
def rotation_not_90_func(img, textline, text_regions_p_1, table_prediction, thetha):
rotated = imutils.rotate(img, thetha)
rotated_textline = imutils.rotate(textline, thetha)
@ -68,6 +75,7 @@ def rotation_not_90_func(img, textline, text_regions_p_1, table_prediction, thet
rotated_table_prediction = imutils.rotate(table_prediction, thetha)
return rotate_max_area(img, rotated, rotated_textline, rotated_layout, rotated_table_prediction, thetha)
def rotation_not_90_func_full_layout(img, textline, text_regions_p_1, text_regions_p_fully, thetha):
rotated = imutils.rotate(img, thetha)
rotated_textline = imutils.rotate(textline, thetha)
@ -75,6 +83,7 @@ def rotation_not_90_func_full_layout(img, textline, text_regions_p_1, text_regio
rotated_layout_full = imutils.rotate(text_regions_p_fully, thetha)
return rotate_max_area_full_layout(img, rotated, rotated_textline, rotated_layout, rotated_layout_full, thetha)
def rotate_max_area_full_layout(image, rotated, rotated_textline, rotated_layout, rotated_layout_full, angle):
wr, hr = rotatedRectWithMaxArea(image.shape[1], image.shape[0], math.radians(angle))
h, w, _ = rotated.shape
@ -83,4 +92,3 @@ def rotate_max_area_full_layout(image, rotated, rotated_textline, rotated_layout
x1 = w // 2 - int(wr / 2)
x2 = x1 + int(wr)
return rotated[y1:y2, x1:x2], rotated_textline[y1:y2, x1:x2], rotated_layout[y1:y2, x1:x2], rotated_layout_full[y1:y2, x1:x2]

@ -29,6 +29,7 @@ from ocrd_models.ocrd_page import (
to_xml)
def create_page_xml(imageFilename, height, width):
now = datetime.now()
pcgts = PcGtsType(
@ -46,6 +47,7 @@ def create_page_xml(imageFilename, height, width):
))
return pcgts
def xml_reading_order(page, order_of_texts, id_of_marginalia):
region_order = ReadingOrderType()
og = OrderedGroupType(id="ro357564684568544579089")
@ -59,6 +61,7 @@ def xml_reading_order(page, order_of_texts, id_of_marginalia):
og.add_RegionRefIndexed(RegionRefIndexedType(index=str(region_counter.get('region')), regionRef=id_marginal))
region_counter.inc('region')
def order_and_id_of_texts(found_polygons_text_region, found_polygons_text_region_h, matrix_of_orders, indexes_sorted, index_of_types, kind_of_texts, ref_point):
indexes_sorted = np.array(indexes_sorted)
index_of_types = np.array(index_of_types)

@ -20,6 +20,7 @@ from ocrd_models.ocrd_page import (
)
import numpy as np
class EynollahXmlWriter():
def __init__(self, *, dir_out, image_filename, curved_line, textline_light, pcgts=None):
@ -54,7 +55,8 @@ class EynollahXmlWriter():
points_page_print = points_page_print + ' '
return points_page_print[:-1]
def serialize_lines_in_marginal(self, marginal_region, all_found_textline_polygons_marginals, marginal_idx, page_coord, all_box_coord_marginals, slopes_marginals, counter):
def serialize_lines_in_marginal(self, marginal_region, all_found_textline_polygons_marginals, marginal_idx,
page_coord, all_box_coord_marginals, slopes_marginals, counter):
for j in range(len(all_found_textline_polygons_marginals[marginal_idx])):
coords = CoordsType()
textline = TextLineType(id=counter.next_line_id, Coords=coords)
@ -63,37 +65,54 @@ class EynollahXmlWriter():
for l in range(len(all_found_textline_polygons_marginals[marginal_idx][j])):
if not (self.curved_line or self.textline_light):
if len(all_found_textline_polygons_marginals[marginal_idx][j][l]) == 2:
textline_x_coord = max(0, int((all_found_textline_polygons_marginals[marginal_idx][j][l][0] + all_box_coord_marginals[marginal_idx][2] + page_coord[2]) / self.scale_x) )
textline_y_coord = max(0, int((all_found_textline_polygons_marginals[marginal_idx][j][l][1] + all_box_coord_marginals[marginal_idx][0] + page_coord[0]) / self.scale_y) )
textline_x_coord = max(0, int((all_found_textline_polygons_marginals[marginal_idx][j][l][0] +
all_box_coord_marginals[marginal_idx][2] + page_coord[
2]) / self.scale_x))
textline_y_coord = max(0, int((all_found_textline_polygons_marginals[marginal_idx][j][l][1] +
all_box_coord_marginals[marginal_idx][0] + page_coord[
0]) / self.scale_y))
else:
textline_x_coord = max(0, int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][0] + all_box_coord_marginals[marginal_idx][2] + page_coord[2]) / self.scale_x) )
textline_y_coord = max(0, int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][1] + all_box_coord_marginals[marginal_idx][0] + page_coord[0]) / self.scale_y) )
textline_x_coord = max(0, int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][0] +
all_box_coord_marginals[marginal_idx][2] + page_coord[
2]) / self.scale_x))
textline_y_coord = max(0, int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][1] +
all_box_coord_marginals[marginal_idx][0] + page_coord[
0]) / self.scale_y))
points_co += str(textline_x_coord)
points_co += ','
points_co += str(textline_y_coord)
if (self.curved_line or self.textline_light) and np.abs(slopes_marginals[marginal_idx]) <= 45:
if len(all_found_textline_polygons_marginals[marginal_idx][j][l]) == 2:
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0] + page_coord[2]) / self.scale_x))
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0] + page_coord[
2]) / self.scale_x))
points_co += ','
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][1] + page_coord[0]) / self.scale_y))
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][1] + page_coord[
0]) / self.scale_y))
else:
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][0] + page_coord[2]) / self.scale_x))
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][0] +
page_coord[2]) / self.scale_x))
points_co += ','
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][1] + page_coord[0]) / self.scale_y))
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][1] +
page_coord[0]) / self.scale_y))
elif (self.curved_line or self.textline_light) and np.abs(slopes_marginals[marginal_idx]) > 45:
if len(all_found_textline_polygons_marginals[marginal_idx][j][l]) == 2:
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0] + all_box_coord_marginals[marginal_idx][2] + page_coord[2]) / self.scale_x))
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0] +
all_box_coord_marginals[marginal_idx][2] + page_coord[2]) / self.scale_x))
points_co += ','
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][1] + all_box_coord_marginals[marginal_idx][0] + page_coord[0]) / self.scale_y))
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][1] +
all_box_coord_marginals[marginal_idx][0] + page_coord[0]) / self.scale_y))
else:
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][0] + all_box_coord_marginals[marginal_idx][2] + page_coord[2]) / self.scale_x))
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][0] +
all_box_coord_marginals[marginal_idx][2] + page_coord[2]) / self.scale_x))
points_co += ','
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][1] + all_box_coord_marginals[marginal_idx][0] + page_coord[0]) / self.scale_y))
points_co += str(int((all_found_textline_polygons_marginals[marginal_idx][j][l][0][1] +
all_box_coord_marginals[marginal_idx][0] + page_coord[0]) / self.scale_y))
points_co += ' '
coords.set_points(points_co[:-1])
def serialize_lines_in_region(self, text_region, all_found_textline_polygons, region_idx, page_coord, all_box_coord, slopes, counter):
def serialize_lines_in_region(self, text_region, all_found_textline_polygons, region_idx, page_coord, all_box_coord,
slopes, counter):
self.logger.debug('enter serialize_lines_in_region')
for j in range(len(all_found_textline_polygons[region_idx])):
coords = CoordsType()
@ -104,11 +123,15 @@ class EynollahXmlWriter():
for idx_contour_textline, contour_textline in enumerate(all_found_textline_polygons[region_idx][j]):
if not (self.curved_line or self.textline_light):
if len(contour_textline) == 2:
textline_x_coord = max(0, int((contour_textline[0] + region_bboxes[2] + page_coord[2]) / self.scale_x))
textline_y_coord = max(0, int((contour_textline[1] + region_bboxes[0] + page_coord[0]) / self.scale_y))
textline_x_coord = max(0, int((contour_textline[0] + region_bboxes[2] + page_coord[
2]) / self.scale_x))
textline_y_coord = max(0, int((contour_textline[1] + region_bboxes[0] + page_coord[
0]) / self.scale_y))
else:
textline_x_coord = max(0, int((contour_textline[0][0] + region_bboxes[2] + page_coord[2]) / self.scale_x))
textline_y_coord = max(0, int((contour_textline[0][1] + region_bboxes[0] + page_coord[0]) / self.scale_y))
textline_x_coord = max(0, int((contour_textline[0][0] + region_bboxes[2] + page_coord[
2]) / self.scale_x))
textline_y_coord = max(0, int((contour_textline[0][1] + region_bboxes[0] + page_coord[
0]) / self.scale_y))
points_co += str(textline_x_coord)
points_co += ','
points_co += str(textline_y_coord)
@ -128,9 +151,11 @@ class EynollahXmlWriter():
points_co += ','
points_co += str(int((contour_textline[1] + region_bboxes[0] + page_coord[0]) / self.scale_y))
else:
points_co += str(int((contour_textline[0][0] + region_bboxes[2]+page_coord[2])/self.scale_x))
points_co += str(
int((contour_textline[0][0] + region_bboxes[2] + page_coord[2]) / self.scale_x))
points_co += ','
points_co += str(int((contour_textline[0][1] + region_bboxes[0]+page_coord[0])/self.scale_y))
points_co += str(
int((contour_textline[0][1] + region_bboxes[0] + page_coord[0]) / self.scale_y))
points_co += ' '
coords.set_points(points_co[:-1])
@ -140,7 +165,11 @@ class EynollahXmlWriter():
with open(out_fname, 'w') as f:
f.write(to_xml(pcgts))
def build_pagexml_no_full_layout(self, found_polygons_text_region, page_coord, order_of_texts, id_of_texts, all_found_textline_polygons, all_box_coord, found_polygons_text_region_img, found_polygons_marginals, all_found_textline_polygons_marginals, all_box_coord_marginals, slopes, slopes_marginals, cont_page, polygons_lines_to_be_written_in_xml, found_polygons_tables):
def build_pagexml_no_full_layout(self, found_polygons_text_region, page_coord, order_of_texts, id_of_texts,
all_found_textline_polygons, all_box_coord, found_polygons_text_region_img,
found_polygons_marginals, all_found_textline_polygons_marginals,
all_box_coord_marginals, slopes, slopes_marginals, cont_page,
polygons_lines_to_be_written_in_xml, found_polygons_tables):
self.logger.debug('enter build_pagexml_no_full_layout')
# create the file structure
@ -156,16 +185,22 @@ class EynollahXmlWriter():
for mm in range(len(found_polygons_text_region)):
textregion = TextRegionType(id=counter.next_region_id, type_='paragraph',
Coords=CoordsType(points=self.calculate_polygon_coords(found_polygons_text_region[mm], page_coord)),
Coords=CoordsType(
points=self.calculate_polygon_coords(found_polygons_text_region[mm],
page_coord)),
)
page.add_TextRegion(textregion)
self.serialize_lines_in_region(textregion, all_found_textline_polygons, mm, page_coord, all_box_coord, slopes, counter)
self.serialize_lines_in_region(textregion, all_found_textline_polygons, mm, page_coord, all_box_coord,
slopes, counter)
for mm in range(len(found_polygons_marginals)):
marginal = TextRegionType(id=counter.next_region_id, type_='marginalia',
Coords=CoordsType(points=self.calculate_polygon_coords(found_polygons_marginals[mm], page_coord)))
Coords=CoordsType(
points=self.calculate_polygon_coords(found_polygons_marginals[mm],
page_coord)))
page.add_TextRegion(marginal)
self.serialize_lines_in_marginal(marginal, all_found_textline_polygons_marginals, mm, page_coord, all_box_coord_marginals, slopes_marginals, counter)
self.serialize_lines_in_marginal(marginal, all_found_textline_polygons_marginals, mm, page_coord,
all_box_coord_marginals, slopes_marginals, counter)
for mm in range(len(found_polygons_text_region_img)):
img_region = ImageRegionType(id=counter.next_region_id, Coords=CoordsType())
@ -201,7 +236,13 @@ class EynollahXmlWriter():
return pcgts
def build_pagexml_full_layout(self, found_polygons_text_region, found_polygons_text_region_h, page_coord, order_of_texts, id_of_texts, all_found_textline_polygons, all_found_textline_polygons_h, all_box_coord, all_box_coord_h, found_polygons_text_region_img, found_polygons_tables, found_polygons_drop_capitals, found_polygons_marginals, all_found_textline_polygons_marginals, all_box_coord_marginals, slopes, slopes_h, slopes_marginals, cont_page, polygons_lines_to_be_written_in_xml):
def build_pagexml_full_layout(self, found_polygons_text_region, found_polygons_text_region_h, page_coord,
order_of_texts, id_of_texts, all_found_textline_polygons,
all_found_textline_polygons_h, all_box_coord, all_box_coord_h,
found_polygons_text_region_img, found_polygons_tables, found_polygons_drop_capitals,
found_polygons_marginals, all_found_textline_polygons_marginals,
all_box_coord_marginals, slopes, slopes_h, slopes_marginals, cont_page,
polygons_lines_to_be_written_in_xml):
self.logger.debug('enter build_pagexml_full_layout')
# create the file structure
@ -216,35 +257,48 @@ class EynollahXmlWriter():
for mm in range(len(found_polygons_text_region)):
textregion = TextRegionType(id=counter.next_region_id, type_='paragraph',
Coords=CoordsType(points=self.calculate_polygon_coords(found_polygons_text_region[mm], page_coord)))
Coords=CoordsType(
points=self.calculate_polygon_coords(found_polygons_text_region[mm],
page_coord)))
page.add_TextRegion(textregion)
self.serialize_lines_in_region(textregion, all_found_textline_polygons, mm, page_coord, all_box_coord, slopes, counter)
self.serialize_lines_in_region(textregion, all_found_textline_polygons, mm, page_coord, all_box_coord,
slopes, counter)
self.logger.debug('len(found_polygons_text_region_h) %s', len(found_polygons_text_region_h))
for mm in range(len(found_polygons_text_region_h)):
textregion = TextRegionType(id=counter.next_region_id, type_='header',
Coords=CoordsType(points=self.calculate_polygon_coords(found_polygons_text_region_h[mm], page_coord)))
Coords=CoordsType(
points=self.calculate_polygon_coords(found_polygons_text_region_h[mm],
page_coord)))
page.add_TextRegion(textregion)
self.serialize_lines_in_region(textregion, all_found_textline_polygons_h, mm, page_coord, all_box_coord_h, slopes_h, counter)
self.serialize_lines_in_region(textregion, all_found_textline_polygons_h, mm, page_coord, all_box_coord_h,
slopes_h, counter)
for mm in range(len(found_polygons_marginals)):
marginal = TextRegionType(id=counter.next_region_id, type_='marginalia',
Coords=CoordsType(points=self.calculate_polygon_coords(found_polygons_marginals[mm], page_coord)))
Coords=CoordsType(
points=self.calculate_polygon_coords(found_polygons_marginals[mm],
page_coord)))
page.add_TextRegion(marginal)
self.serialize_lines_in_marginal(marginal, all_found_textline_polygons_marginals, mm, page_coord, all_box_coord_marginals, slopes_marginals, counter)
self.serialize_lines_in_marginal(marginal, all_found_textline_polygons_marginals, mm, page_coord,
all_box_coord_marginals, slopes_marginals, counter)
for mm in range(len(found_polygons_drop_capitals)):
page.add_TextRegion(TextRegionType(id=counter.next_region_id, type_='drop-capital',
Coords=CoordsType(points=self.calculate_polygon_coords(found_polygons_drop_capitals[mm], page_coord))))
Coords=CoordsType(points=self.calculate_polygon_coords(
found_polygons_drop_capitals[mm], page_coord))))
for mm in range(len(found_polygons_text_region_img)):
page.add_ImageRegion(ImageRegionType(id=counter.next_region_id, Coords=CoordsType(points=self.calculate_polygon_coords(found_polygons_text_region_img[mm], page_coord))))
page.add_ImageRegion(ImageRegionType(id=counter.next_region_id, Coords=CoordsType(
points=self.calculate_polygon_coords(found_polygons_text_region_img[mm], page_coord))))
for mm in range(len(polygons_lines_to_be_written_in_xml)):
page.add_SeparatorRegion(ImageRegionType(id=counter.next_region_id, Coords=CoordsType(points=self.calculate_polygon_coords(polygons_lines_to_be_written_in_xml[mm], [0 , 0, 0, 0]))))
page.add_SeparatorRegion(ImageRegionType(id=counter.next_region_id, Coords=CoordsType(
points=self.calculate_polygon_coords(polygons_lines_to_be_written_in_xml[mm], [0, 0, 0, 0]))))
for mm in range(len(found_polygons_tables)):
page.add_TableRegion(TableRegionType(id=counter.next_region_id, Coords=CoordsType(points=self.calculate_polygon_coords(found_polygons_tables[mm], page_coord))))
page.add_TableRegion(TableRegionType(id=counter.next_region_id, Coords=CoordsType(
points=self.calculate_polygon_coords(found_polygons_tables[mm], page_coord))))
return pcgts
@ -262,4 +316,3 @@ class EynollahXmlWriter():
coords += str(int((value_bbox[0][1] + page_coord[0]) / self.scale_y))
coords = coords + ' '
return coords[:-1]

@ -10,12 +10,14 @@ from unittest import TestCase as VanillaTestCase, skip, main as unittests_main
import pytest
from ocrd_utils import disableLogging, initLogging
def main(fn=None):
if fn:
sys.exit(pytest.main([fn]))
else:
unittests_main()
class TestCase(VanillaTestCase):
@classmethod
@ -26,6 +28,7 @@ class TestCase(VanillaTestCase):
disableLogging()
initLogging()
class CapturingTestCase(TestCase):
"""
A TestCase that needs to capture stderr/stdout and invoke click CLI.

@ -1,6 +1,7 @@
from tests.base import main
from eynollah.eynollah.utils.counter import EynollahIdCounter
def test_counter_string():
c = EynollahIdCounter()
assert c.next_region_id == 'region_0001'
@ -11,6 +12,7 @@ def test_counter_string():
assert c.region_id(999) == 'region_0999'
assert c.line_id(999, 888) == 'region_0999_line_0888'
def test_counter_init():
c = EynollahIdCounter(region_idx=2)
assert c.get('region') == 2
@ -19,6 +21,7 @@ def test_counter_init():
c.reset()
assert c.get('region') == 2
def test_counter_methods():
c = EynollahIdCounter()
assert c.get('region') == 0
@ -29,5 +32,6 @@ def test_counter_methods():
c.inc('region', -9)
assert c.get('region') == 1
if __name__ == '__main__':
main(__file__)

@ -3,9 +3,11 @@ from pathlib import Path
from eynollah.eynollah.utils.pil_cv2 import check_dpi
from tests.base import main
def test_dpi():
fpath = str(Path(__file__).parent.joinpath('resources', 'kant_aufklaerung_1784_0020.tif'))
assert 230 == check_dpi(cv2.imread(fpath))
if __name__ == '__main__':
main(__file__)

@ -8,6 +8,7 @@ testdir = Path(__file__).parent.resolve()
EYNOLLAH_MODELS = environ.get('EYNOLLAH_MODELS', str(testdir.joinpath('..', 'models_eynollah').resolve()))
class TestEynollahRun(TestCase):
def test_full_run(self):
@ -20,5 +21,6 @@ class TestEynollahRun(TestCase):
print(code, out, err)
assert not code
if __name__ == '__main__':
main(__file__)

@ -4,11 +4,13 @@ from ocrd_models.ocrd_page import to_xml
PAGE_2019 = 'http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15'
def test_create_xml():
pcgts = create_page_xml('/path/to/img.tif', 100, 100)
xmlstr = to_xml(pcgts)
assert 'xmlns:pc="%s"' % PAGE_2019 in xmlstr
assert 'Metadata' in xmlstr
if __name__ == '__main__':
main([__file__])

Loading…
Cancel
Save