Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

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 of some sufficient radius gives an estimate of how dark text is, or where there is no text - where there is text (estimate is less than some white threshold) but it's not black enough (estimate is more than a black threshold), you recalculate the pixel linearly

let me know if you need more detail for this.

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 of some sufficient radius gives an estimate of how dark text is, or where there is no text - where there is text (estimate is less than some white threshold) but it's not black enough (estimate is more than a black threshold), you recalculate the pixel linearly

let me know if you need more detail for this.

image gallery: https://imgur.com/a/IfutpMZ

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: - try:

  • grayscale erode of some sufficient radius gives an estimate of how dark text is, or where there is no text - text
  • where there is text (estimate is less than some white threshold) but it's not black enough (estimate is more than a black threshold), you recalculate the pixel linearly

let me know if you need more detail for this.

image gallery: https://imgur.com/a/IfutpMZ

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 erode/dilate of some sufficient radius gives an estimate of how dark intense the text is, or where there is no text
  • where there is text (estimate is less than some white threshold) but it's not black enough (estimate is more than a black threshold), text, you recalculate the pixel linearlylinearly (division, more or less)

let me know if you need more detail for this.

image gallery: https://imgur.com/a/IfutpMZ

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

output

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

outputyour input my output

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

your input my outputmy output

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

your input my output

#!/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
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()

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

your input my output

#!/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
im 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()

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

your input intermediate result my output

#!/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()