Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change pixels for improve contrast in picture

I have input image file with hidden text, problem is difference of pixels of hidden text is really small, sometimes only 1px. I want change pixels for see this text.

Because never working with something similar idea is convert image to numpy array and replace values by dict:

from PIL import Image
import matplotlib

img = Image.open('4YtCA.jpg')
data = np.array( img, dtype='uint8' )
#print (data)

a = np.ravel(data)
u, c = np.unique(a, return_counts=True)
print (u)
[ 48  49  50  51  77  78  79  80 100 101 102 103 121 122 123 124 142 143
 144 145 164 165 166 167 188 189 190 191 208 209 210 211 212 230 231 232
 233 253 254 255]

#new values for replace
new = (u.reshape(-1, 4) / [1,2,3,4]).astype(int)
print (new)
[[ 48  24  16  12]
 [ 77  39  26  20]
 [100  50  34  25]
 [121  61  41  31]
 [142  71  48  36]
 [164  82  55  41]
 [188  94  63  47]
 [208 104  70  52]
 [212 115  77  58]
 [233 126  84  63]]

d = dict(zip(u, np.ravel(new)))
#print (d)

#https://stackoverflow.com/a/46868996
indexer = np.array([d.get(i, -1) for i in range(data.min(), data.max() + 1)])

out = indexer[(data - data.min())]

matplotlib.image.imsave('out.png', out.astype(np.uint8))

I think my solution is not nice, because last value are not seen very well. Is possible change pixels to some different colors like red, green, purple? Or change contract some better way? The best should be change each pixels some smart way, but not idea how.

Input image:

input

Output image:

out

like image 599
jezrael Avatar asked Jan 02 '20 11:01

jezrael


2 Answers

You could try a histogram equalisation. I'll just do it with ImageMagick in the Terminal for now to demonstrate:

magick hidden.jpg -equalize -rotate -90 result.png

enter image description here

Or a "Local Adaptive Threshold" - see here:

magick hidden.jpg -lat 50x50 -rotate -90 result.png

enter image description here

If you are running v6 ImageMagick, replace magick with convert in the previous commands.


This is pretty equivalent in Python:

from PIL import Image 
from skimage.filters import threshold_local 
import numpy as np 

# Open image in greyscale 
im = Image.open('hidden.jpg').convert('L') 
na = np.array(im) 

# Local Adaptive Threshold 
LAT = threshold_local(na, 49) 
result = na > LAT 

Image.fromarray((result*255).astype(np.uint8)).save('result.png') 

If you really, really don't want to introduce a new dependency on skimage, you can use PIL or Numpy to generate a blurred copy of your image and subtract the blurred from the original and then threshold the difference image. That looks like this:

#!/usr/bin/env python3

from PIL import Image, ImageFilter
import numpy as np

# Open image in greyscale, and make heavily blurred copy
im = Image.open('hidden.jpg').convert('L')
blur = im.filter(ImageFilter.BoxBlur(25))

# Go to Numpy for maths!
na = np.array(im)
nb = np.array(blur)

# Local Adaptive Threshold
res = na >= nb

# Save
Image.fromarray((res*255).astype(np.uint8)).save('result.png')
like image 180
Mark Setchell Avatar answered Oct 13 '22 20:10

Mark Setchell


from PIL import Image
import numpy as np

img = Image.open('4YtCA.jpg').convert('L') 

data = np.array(img, dtype='uint8')
u, c = np.unique(data, return_counts=True)

# Set the background colors to white and the rest to black
#data = np.where(np.isin(data, u[c>17000]), 255, 0).astype(np.uint8)
data = np.isin(data, u[c>17000]).astype(np.uint8) * 255  # thanks to Mad Physicist

# Create new image and save
img_new = Image.fromarray(data)
img_new.save('4YtCA_new.jpg')

enter image description here

like image 45
Andreas K. Avatar answered Oct 13 '22 21:10

Andreas K.