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. Naoki Hatano, «Tara Majima Visionary Line» p.36
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 )
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. 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 )
C'est plus facile à voir que cv2.equalizeHist (), mais pas autant qu'un scanner.
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 )
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.
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. 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. 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.
É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. 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. 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