not affecting the already black text and white surrounding
thresholding would affect those. and so does gamma-mapping, brightness and contrast adjustments, ... load your picture up in an image editor, then play with curves, levels, or brightness and contrast.
if you threshold, pick a threshold above the gray text's gray value. that text will be thresholded to black.
you can come up with better approaches that leave the black text as is.
a "locally adaptive" method you could try:
- grayscale erode/dilate of some sufficient radius gives an estimate of how intense the text is, or where there is no text
- where there is text, you recalculate the pixel linearly (division, more or less)
let me know if you need more detail for this.
image gallery: https://imgur.com/a/IfutpMZ
#!/usr/bin/env python3
import os
import sys
import numpy as np
import cv2 as cv
impath = "1605707252792223.png"
if len(sys.argv) >= 2:
impath = sys.argv[1]
im = cv.imread(impath, cv.IMREAD_GRAYSCALE)
im = im.astype(np.float32)
im = im / 255 # rescale
im = 1 - im # inversion. ink is the signal, white paper isn't
# some "sensor noise" for demo, if you want to look at intermediate results
#im += np.random.normal(0.0, 0.02, size=im.shape)
# squares/rectangles
#morph_kernel = cv.getStructuringElement(shape=cv.MORPH_RECT, ksize=(5,5))
morph_kernel = np.ones((5,5))
# opencv's ellipses are ugly as sin
# alternative:
#import skimage.morphology
#morph_kernel = skimage.morphology.octagon(5,2)
# estimates intensity of text
dilated = cv.dilate(im, kernel=morph_kernel)
# tweak this threshold to catch faint text but not background
textmask = (dilated >= 0.15)
# 0.05 catches background noise of 0.02
# 0.25 loses some text
# rescale text pixel intensities
# this will obviously magnify noise around faint text
enhanced = im / dilated
# copy unmodified background back in
# (division magnified noise on background)
enhanced[~textmask] = im[~textmask]
# invert again for output
output = 1 - enhanced
cv.namedWindow("output", cv.WINDOW_NORMAL)
cv.imshow("output", output)
cv.waitKey(-1)
cv.destroyAllWindows()