J'ai quelques centaines d'images (documents numérisés), la plupart sont de travers. Je voulais les dé-biaiser en utilisant Python.
Voici le code que j'ai utilisé:
import numpy as np
import cv2
from skimage.transform import radon
filename = 'path_to_filename'
# Load file, converting to grayscale
img = cv2.imread(filename)
I = cv2.cvtColor(img, COLOR_BGR2GRAY)
h, w = I.shape
# If the resolution is high, resize the image to reduce processing time.
if (w > 640):
I = cv2.resize(I, (640, int((h / w) * 640)))
I = I - np.mean(I) # Demean; make the brightness extend above and below zero
# Do the radon transform
sinogram = radon(I)
# Find the RMS value of each row and find "busiest" rotation,
# where the transform is lined up perfectly with the alternating dark
# text and white lines
r = np.array([np.sqrt(np.mean(np.abs(line) ** 2)) for line in sinogram.transpose()])
rotation = np.argmax(r)
print('Rotation: {:.2f} degrees'.format(90 - rotation))
# Rotate and save with the original resolution
M = cv2.getRotationMatrix2D((w/2,h/2),90 - rotation,1)
dst = cv2.warpAffine(img,M,(w,h))
cv2.imwrite('rotated.jpg', dst)
Ce code fonctionne bien avec la plupart des documents, sauf sous certains angles: (180 et 0) et (90 et 270) sont souvent détectés comme le même angle (c'est-à-dire qu'il ne fait pas de différence entre (180 et 0) et (90 et 270)). Je reçois donc beaucoup de documents à l'envers.
L'image obtenue que j'obtiens est la même que l'image d'entrée.
Y a-t-il une suggestion pour détecter si une image est à l'envers en utilisant Opencv et Python?
PS: J'ai essayé de vérifier l'orientation à l'aide des données EXIF, mais cela n'a conduit à aucune solution.
MODIFIER:
Il est possible de détecter l'orientation à l'aide de Tesseract (pytesseract pour Python), mais cela n'est possible que lorsque l'image contient beaucoup de caractères.
Pour tous ceux qui pourraient en avoir besoin:
import cv2
import pytesseract
print(pytesseract.image_to_osd(cv2.imread(file_name)))
Si le document contient suffisamment de caractères, il est possible que Tesseract détecte l'orientation. Cependant, lorsque l'image comporte peu de lignes, l'angle d'orientation suggéré par Tesseract est généralement incorrect. Cela ne peut donc pas être une solution à 100%.
script Python3/OpenCV4 pour aligner les documents numérisés.
Faites pivoter le document et additionnez les lignes. Lorsque le document a 0 et 180 degrés de rotation, il y aura beaucoup de pixels noirs dans l'image:
Utilisez une méthode de tenue de score. Marquez chaque image pour sa ressemblance avec un motif zébré. L'image avec le meilleur score a la rotation correcte. L'image à laquelle vous avez lié était désactivée de 0,5 degré. J'ai omis certaines fonctions pour plus de lisibilité, le code complet peut être trouvé ici .
# Rotate the image around in a circle
angle = 0
while angle <= 360:
# Rotate the source image
img = rotate(src, angle)
# Crop the center 1/3rd of the image (roi is filled with text)
h,w = img.shape
buffer = min(h, w) - int(min(h,w)/1.15)
roi = img[int(h/2-buffer):int(h/2+buffer), int(w/2-buffer):int(w/2+buffer)]
# Create background to draw transform on
bg = np.zeros((buffer*2, buffer*2), np.uint8)
# Compute the sums of the rows
row_sums = sum_rows(roi)
# High score --> Zebra stripes
score = np.count_nonzero(row_sums)
scores.append(score)
# Image has best rotation
if score <= min(scores):
# Save the rotatied image
print('found optimal rotation')
best_rotation = img.copy()
k = display_data(roi, row_sums, buffer)
if k == 27: break
# Increment angle and try again
angle += .75
cv2.destroyAllWindows()
Comment savoir si le document est à l'envers? Remplissez la zone du haut du document jusqu'au premier pixel non noir de l'image. Mesurez la zone en jaune. L'image qui a la plus petite zone sera celle qui se trouve à droite:
# Find the area from the top of page to top of image
_, bg = area_to_top_of_text(best_rotation.copy())
right_side_up = sum(sum(bg))
# Flip image and try again
best_rotation_flipped = rotate(best_rotation, 180)
_, bg = area_to_top_of_text(best_rotation_flipped.copy())
upside_down = sum(sum(bg))
# Check which area is larger
if right_side_up < upside_down: aligned_image = best_rotation
else: aligned_image = best_rotation_flipped
# Save aligned image
cv2.imwrite('/home/stephen/Desktop/best_rotation.png', 255-aligned_image)
cv2.destroyAllWindows()
En supposant que vous avez déjà exécuté la correction d'angle sur l'image, vous pouvez essayer ce qui suit pour savoir si elle est retournée:
La découverte de pic à l'étape 3 se fait en trouvant des sections avec des valeurs supérieures à la moyenne. Les sous-pics sont ensuite trouvés via argmax.
Voici une figure pour illustrer l'approche; Quelques lignes de votre exemple d'image
voici un code qui fait cela:
import cv2
import numpy as np
# load image, convert to grayscale, threshold it at 127 and invert.
page = cv2.imread('Page.jpg')
page = cv2.cvtColor(page, cv2.COLOR_BGR2GRAY)
page = cv2.threshold(page, 127, 255, cv2.THRESH_BINARY_INV)[1]
# project the page to the side and smooth it with a gaussian
projection = np.sum(page, 1)
gaussian_filter = np.exp(-(np.arange(-3, 3, 0.1)**2))
gaussian_filter /= np.sum(gaussian_filter)
smooth = np.convolve(projection, gaussian_filter)
# find the pixel values where we expect lines to start and end
mask = smooth > np.average(smooth)
edges = np.convolve(mask, [1, -1])
line_starts = np.where(edges == 1)[0]
line_endings = np.where(edges == -1)[0]
# count lines with peaks on the lower side
lower_peaks = 0
for start, end in Zip(line_starts, line_endings):
line = smooth[start:end]
if np.argmax(line) < len(line)/2:
lower_peaks += 1
print(lower_peaks / len(line_starts))
cela imprime 0,125 pour l'image donnée, donc ce n'est pas orienté correctement et doit être inversé.
Notez que cette approche peut mal se passer s'il y a des images ou tout ce qui n'est pas organisé en lignes dans l'image (peut-être des mathématiques ou des images). Un autre problème serait le nombre insuffisant de lignes, ce qui entraînerait de mauvaises statistiques.
Des polices différentes peuvent également entraîner des distributions différentes. Vous pouvez l'essayer sur quelques images et voir si l'approche fonctionne. Je n'ai pas assez de données.
Vous pouvez utiliser le module Alyn . Pour l'installer:
pip install alyn
Ensuite, pour l'utiliser pour redresser les images (extrait de la page d'accueil):
from alyn import Deskew
d = Deskew(
input_file='path_to_file',
display_image='preview the image on screen',
output_file='path_for_deskewed image',
r_angle='offest_angle_in_degrees_to_control_orientation')`
d.run()
Notez que Alyn
est uniquement pour le texte de redressement.