[PYTHON] L'arrière-plan des caractères de l'image texte est surexposé pour faciliter la lecture.

Je prends souvent des photos de documents avec mon smartphone et je les utilise. C'est facile, mais c'est moins clair que celui capturé par le scanner. Pour faciliter la lecture des images au contraste terne, comme celles prises avec un smartphone, il est préférable d'augmenter la luminosité de l'arrière-plan tout en laissant les caractères noirs. En raison du processus de blanchiment de l'arrière-plan, il est devenu nécessaire de faire la distinction entre la partie caractère de l'image et la partie arrière-plan blanc uni, mais cela fonctionne bien si les statistiques des pixels pour chaque partie locale de l'image sont prises et que l'écart type des valeurs de pixel est utilisé pour le jugement. C'était.

À titre d'exemple, traitons l'image suivante. Vous devriez pouvoir agrandir chaque image en cliquant dessus. tarama36p.jpg Naoki Hatano, «Tara Majima Visionary Line» p.36

Aplatissement du graphite

Un processus d'aplatissement de l'histogramme est souvent effectué lors de la netteté d'une image. Lorsque la luminosité des pixels de l'image est dans une plage étroite, si vous l'étendez à toute la plage du format d'image, ou de 0 à 255 pour les images en échelle de gris, la différence entre les pixels augmentera et l'image deviendra plus claire. OpenCV a sa propre fonction, qui est expliquée en détail sur le lien ci-dessous. [Hystérogramme dans OpenCV> histogramme Partie 2: Aplatissement de l'histogramme](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histograms/py_histogram_equalization/py_histograms .html) En utilisant cela, l'image d'origine est mise en échelle de gris, puis l'histogramme est aplati dans l'image suivante. Montré avec le programme.

 bookimg = cv2.imread('tarama36p.jpg')
 img_gray = cv2.cvtColor(bookimg, cv2.COLOR_BGR2GRAY)
 
 equ = cv2.equalizeHist(img_gray)
 cv2.imwrite('tarama36pcv2.jpg', equ )

tarama36pcv2.jpg Le résultat ne donne pas l'impression que les personnages sont particulièrement clairs. Je ne savais pas de l'image originale, mais il semble que la page de droite est plus lumineuse que la gauche. Le reflet de la pièce métallique supérieure est mis en valeur. En fait, l'histogramme de cette image est le suivant, et la ligne rouge montre les valeurs maximale et minimale de la luminosité des pixels, mais comme les valeurs maximale et minimale se sont déjà étendues à toute la plage d'image, un simple aplatissement de l'histogramme L'effet de est faible. tarama36p_hist_maxmin.png OpenCV a également une fonction appelée aplatissement d'histogramme applicable, qui divise l'image en petits blocs et aplatit l'histogramme pour chaque bloc. Le résultat du traitement par ceci est l'image suivante.

 bookimg = cv2.imread('tarama36p.jpg')
 img_gray = cv2.cvtColor(bookimg, cv2.COLOR_BGR2GRAY)
 
 equ = cv2.equalizeHist(img_gray)
 cv2.imwrite('tarama36pcv2.jpg', equ )

tarama36pcv2cl1.jpg C'est plus facile à voir que cv2.equalizeHist (), mais pas autant qu'un scanner.

Rendre tous les pixels blancs d'un blanc pur

Le processus d'amélioration du contraste à usage général tente de laisser une certaine différence dans la valeur de pixel de la partie blanche. Dans le cas d'une image textuelle, des informations détaillées sur un fond blanc ne sont pas nécessaires, de sorte que tous les pixels au-dessus d'un certain seuil peuvent être complètement blancs et toutes les valeurs de pixels peuvent être réécrites à 255. Etant donné que le côté noir contient des informations sur la forme des caractères, la valeur de pixel d'origine est multipliée par une valeur inférieure à 1 et la valeur est déplacée vers le côté noir, mais la tendance d'origine est conservée. Le seuil est supposé être de 140 à partir de la valeur par la valeur médiane de l'histogramme. Le programme et les résultats du traitement sont les suivants.

    for y in range(img_gray.shape[0]):
         for x in range(img_gray.shape[1]):
             if img_gray[y][x] > 140:
                 img_gray[y][x] = 255
             else:
                 img_gray[y][x] = img_gray[y][x] * 0.5

    cv2.imwrite('tarama36p140.jpg', img_gray )

tarama36p140.jpg Sur le côté droit, le fond était blanc et les caractères étaient clairs comme prévu. Le reflet supplémentaire des pièces métalliques a également disparu. Cependant, comme la partie inférieure gauche était sombre dans son ensemble, la partie d'arrière-plan était reconnue comme noire et accentuée. Cependant, si vous définissez le seuil en bas à gauche, la partie du personnage volera en blanc sur le côté droit cette fois. Autrement dit, le seuil approprié dépend de l'emplacement de l'image.

Traitez l'image en blocs

Semblable à l'aplatissement d'histogramme applicable, l'image originale est divisée en blocs de 64 points verticalement et horizontalement, et des seuils appropriés sont obtenus et traités pour chacun. La façon de déterminer le seuil est importante, mais ici, la valeur du seuil est définie de sorte que la moitié inférieure de la valeur médiane de chaque pixel de bloc, c'est-à-dire 1/4 du pixel de bloc entier, soit considérée comme noire. Une fonction qui renvoie un seuil avec l'image de bloc img comme argument est écrite en Python comme suit. C'est une idée approximative à utiliser, mais elle semble renvoyer une valeur raisonnablement raisonnable. Cependant, le texte en noir et blanc ne fonctionnera pas.

 import numpy as np
 def getBWThrsh(img):
     med = np.median(img)
     fild = img[img < med]
     return np.median(fild) 

Le résultat traité est l'image suivante. De plus, le processus de calcul de la moyenne de l'histogramme est également effectué pour chaque bloc, et au lieu de simplement remplacer 255 pour les zones blanches, remplacez le pixel d'origine par un coefficient tel que la majorité de l'arrière-plan dépasse 256. Il y a. La plupart d'entre eux sont blancs, mais les parties les plus sombres sont laissées. tarama36p_s0.00b64.jpg Le fond des personnages est joliment blanc, mais les caractères sur la dernière page sont légèrement transparents sur le fond blanc où il n'y a pas de caractères. L'image suivante est agrandie. a3bcf44c70f2e1a919809ebccd290c54-png.png Il n'y a qu'une très légère différence de nuances dans la partie où la page arrière est transparente, mais en effectuant le processus de calcul de la moyenne de l'histogramme, les caractères arrière sont sortis à merveille.

Faites une distinction entre les lettres et le fond blanc

Étant donné que la dernière page est transparente, je souhaite éviter le processus de calcul de la moyenne de l'histogramme sur fond blanc. Comment faire la distinction entre la partie texte et la partie arrière-plan blanc? Jusqu'à présent, nous avons effectué un traitement statistique avec numpy pour chaque bloc pour trouver la valeur médiane des pixels, mais j'ai eu l'idée que l'écart type des valeurs de pixel peut être utilisé pour distinguer les caractères et les arrière-plans blancs. L'arrière-plan blanc a moins de variation dans les valeurs de pixel et l'écart type est petit, et la partie caractère aura une valeur plus grande. Quoi qu'il en soit, j'ai trouvé l'écart type des pixels de chaque bloc, créé un histogramme pour voir quel type de valeur est grand et examiné la tendance. tarama36p_stdhist.png Il y a un pic sur la petite valeur sur le côté gauche, mais c'est probablement un bloc sur fond blanc. Un fond blanc peut être déterminé en fixant une valeur seuil de l'écart type à une valeur incluant ce pic. Si le seuil est réglé trop petit, la poussière sur un fond blanc restera, et s'il est défini grand, même si une partie de petits caractères est incluse dans le fond blanc, il sera considéré comme un fond blanc et sera ébréché, il est donc en fait difficile de définir un seuil approprié. Quoi qu'il en soit, l'image ci-dessous montre le processus de distinction entre les caractères et le fond blanc et rend le fond blanc complètement blanc. tarama36p_s6.00b64.jpg Il y avait beaucoup de déchets laissés dans des endroits autres que le texte environnant, mais je pense que la partie de texte a été traitée avec soin. Puisqu'il est maintenant possible de faire la distinction entre les arrière-plans blancs et les arrière-plans non blancs sur une base bloc par bloc, si les blocs de fond blanc sont continus, ce seront les marges environnantes, s'il y a des caractères lâches dans les marges, ce sera nonble, etc. J'ai le sentiment qu'elle peut s'appliquer à divers jugements.

Les sources ci-dessus sont les suivantes. Si vous écrivez le nom du fichier que vous souhaitez convertir dans l'argument de sharpenImg () sur la ligne du bas, un fichier avec un fond blanc sera créé. Pour le moment, la conversion prend plusieurs dizaines de secondes, mais je pense que si vous le réécrivez avec C etc., ce sera une vitesse de traitement pratique.

import cv2
from matplotlib import pyplot as plt
import numpy as np

def getStdThrsh(img, Blocksize):
    stds = []
    for y in range( 0, img.shape[0], Blocksize ):
        for x in range( 0, img.shape[0], Blocksize ):
            pimg = img[y:y+Blocksize, x:x+Blocksize]
            std = np.std( pimg )
            minv = np.min( pimg )
            maxv = np.max( pimg )
            stds.append(std)

    hist = np.histogram( stds, bins=64 )
    peaki = np.argmax(hist[0])   

    #plt.hist( stds, bins=64 )
    #plt.show()

    slim = 6.0
    for n in range(peaki,len(hist[0])-1):
        if hist[0][n] < hist[0][n+1]:
            slim = hist[1][n+1]
            break

    if slim > 6.0:
        slim = 6.0
    
    return slim

def getBWThrsh(img):
    med = np.median(img)
    fild = img[img < med]
    return np.median(fild)

def getWbias( img, bwthr ):
    wimg = img[ img > bwthr ]
    hist = np.histogram( wimg, bins=16 )
    agm = np.argmax(hist[0])
    return hist[1][agm]

def getOutputName( title, slim ):
    return title + "_s{:04.2f}.jpg ".format( slim )

def sharpenImg(imgfile):
    Testimagefile = imgfile
    TestimageTitle = Testimagefile.split('.')[0]
    Blocksize = 64
    Bbias = 0.2

    bookimg = cv2.imread( Testimagefile )
    img_gray = cv2.cvtColor(bookimg, cv2.COLOR_BGR2GRAY)
    outimage = img_gray.copy()

    slim = getStdThrsh(img_gray, Blocksize)
    for y in range( 0, img_gray.shape[0], Blocksize ):
        s = ""
        for x in range( 0, img_gray.shape[1], Blocksize ):
            pimg = img_gray[y:y+Blocksize, x:x+Blocksize]
            std = np.std( pimg )
            minv = np.min( pimg )
            maxv = np.max( pimg )
            pimg -= minv

            cimg = pimg.copy()
            if maxv != minv:
                for sy in range (cimg.shape[0]):
                    for sx in range( cimg.shape[1] ):
                        cimg[sy][sx] = (cimg[sy][sx]*255.0)/(maxv - minv)

            bwthrsh = getBWThrsh( pimg )
            wb = getWbias( cimg, bwthrsh )
            if wb == 0:
                wbias = 1.5
            else:
                wbias = 256 / wb
            
            if std < slim:
                s = s + "B"
                for sy in range (pimg.shape[0]):
                    for sx in range( pimg.shape[1] ):
                        outimage[y+sy][x+sx] = 255
            else:
                s = s + "_"
                for sy in range (cimg.shape[0]):
                    for sx in range( cimg.shape[1] ):
                        if cimg[sy][sx] > bwthrsh:
                            v = cimg[sy][sx]
                            v = v * wbias
                            if v > 255:
                                v = 255
                            outimage[y+sy][x+sx] = v
                        else:
                            outimage[y+sy][x+sx] = cimg[sy][sx] * Bbias
        print( "{:4d} {:s}".format( y, s ) )

    cv2.imwrite(getOutputName(TestimageTitle, slim), outimage )

if __name__ =='__main__':
    sharpenImg('tarama36p.jpg')

https://github.com/pie-xx/TextImageViewer

Recommended Posts

L'arrière-plan des caractères de l'image texte est surexposé pour faciliter la lecture.
Utilisez Pillow pour rendre l'image transparente et en superposer une partie seulement
Développer la source devicetree pour faciliter la lecture
Python Open CV a essayé d'afficher l'image sous forme de texte.
J'ai essayé d'extraire le texte du fichier image en utilisant Tesseract du moteur OCR
Facilitez la compréhension de l'affichage des exceptions du module Python
Vous qui coloriez le journal pour le rendre plus facile à voir
Comptez le nombre de caractères dans le texte dans le presse-papiers sur Mac
Pour vérifier si la clé spécifiée se trouve dans le compartiment spécifié dans Boto 3
Comment implémenter du code Java en arrière-plan de Red Hat (Linux ONE)
Que faire lorsqu'une partie de l'image d'arrière-plan devient transparente lorsque l'image transparente est combinée avec Oreiller
[Reconnaissance d'image] Comment lire le résultat de l'annotation automatique avec VoTT
[TensorFlow 2] Il est recommandé de lire la quantité de fonction de TFRecord en unités de lots.
Conseils pour faciliter la lecture des documents d'audition Python
Comment enregistrer les informations de point caractéristique de l'image dans un fichier et l'utiliser pour la mise en correspondance
Une histoire sur un ingénieur qui a remarqué l'émo de la cryptographie et tente de l'implémenter en Python
Différentes façons de lire la dernière ligne d'un fichier csv en Python
En Python, changez le comportement de la méthode en fonction de la façon dont elle est appelée
Comment afficher dans toute la fenêtre lors de la définition de l'image d'arrière-plan avec tkinter
L'expérience de Hackason selon laquelle il est le plus important de comprendre les sentiments de l'organisateur
Comment rendre la largeur de police du notebook jupyter mis dans pyenv égale
L'apprentissage en profondeur facilite considérablement la visualisation du laps de temps des changements physiques
Facilitez la spécification de l'heure d'AWS CloudWatch Events avec CDK.
Qu'est-ce que wheezy dans l'image Docker Python?
Copiez la liste en Python
J'ai essayé de corriger la forme trapézoïdale de l'image
Lire la sortie du sous-processus, ouvrir en temps réel
Je ne peux pas saisir de caractères dans la zone de texte! ?? !! ?? !! !! ??
Rendre la progression de dd visible sur la barre de progression
Je veux faire briller l'éclairage LED de l'ErgoDox EZ, mais dites-moi ce qu'est la LED en premier lieu
[Solution] Lorsque "0001" est inséré dans la colonne de chaîne de sqlite3, il est entré comme "1".
Comment identifier l'élément avec le plus petit nombre de caractères dans une liste Python?
[Python] Changer la couleur du texte et la couleur d'arrière-plan d'un mot clé spécifique dans la sortie d'impression
Que faire si la barre de progression n'est pas affichée dans tqdm de python
Découvrez le nombre maximum de caractères dans un texte multiligne stocké dans un bloc de données
Comment vérifier en Python si l'un des éléments d'une liste est dans une autre liste
J'ai essayé de faciliter la modification du paramètre du proxy authentifié sur Jupyter
Il est facile d'exécuter SQL avec Python et de générer le résultat dans Excel
Il est difficile d'installer un écran vert, je n'ai donc découpé que le visage et l'ai superposé sur l'image de fond
Un moyen simple de mettre en cache la valeur dans le décorateur de propriété. En lecture seule. Notez qu'il conserve la mise en cache jusqu'à ce que l'objet soit supprimé.
Un outil pour créer des images de masque pour ETC en Python
Modèle de script python pour lire le contenu du fichier
Comment obtenir le nombre de chiffres en Python
Lisez le fichier csv et affichez-le dans le navigateur
Convertissez l'image au format .zip en PDF avec Python
Vérifiez s'il s'agit d'Unix dans le langage de script
Comment éliminer les caractères déformés dans l'image de sortie matplotlib
Comment utiliser Decorator dans Django et comment le créer
Vérifiez s'il s'agit d'Unix dans le langage de script
Pour faire l'équivalent de Ruby ObjectSpace._id2ref en Python
Déployez la page de gestion en production pour faciliter la maintenance.
Est-ce un problème d'éliminer le besoin de ressources humaines analogiques à l'ère de l'IA?
Le son émis par M. Tick sur le lieu de travail est ... J'ai réussi à le faire avec le code
Notez ce que vous voulez faire à l'avenir avec Razpai
[Dance Dance Revolution] Est-il possible de prédire le niveau de difficulté (pied) à partir de la valeur du radar groove?
La ventilation est importante. Ce que j'ai fait pour garder une trace de la concentration de C02 dans la pièce
Que faire si l'image n'est pas affichée à l'aide de matplotlib etc. dans le conteneur Docker
Comment compter rapidement la fréquence d'apparition des caractères à partir d'une chaîne de caractères en Python?
Renvoyez les données d'image avec Flask of Python et dessinez-les dans l'élément canvas de HTML
L'image est affichée dans l'environnement de développement local, mais l'image n'est pas affichée sur le serveur distant de VPS.