Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating pixel noise with PIL Python

I am trying to generate training data of images with noise and text in them, similar to the image below:

Example Image

I have figured out how to generate the images with the right sized text but can't figure out how to generate the noise. At first I thought gaussian noise would be the right approach but that appeared to not be the right kind of noise.

from PIL import Image, ImageDraw, ImageFont
import numpy


img = Image.new('RGB', (250, 50), color = 'white')
fnt = ImageFont.truetype('/Library/Fonts/Arial.ttf', 36)
d = ImageDraw.Draw(img)
d.text((62,5), "3H1339", font=fnt, fill=(0,0,0))
img.save('imagetext.png')
like image 507
Pablo Escobar Avatar asked Jan 30 '20 17:01

Pablo Escobar


3 Answers

I think that you are looking for a salt-and-pepper noise. Each pixel have a probability to be destroyed (amount). Each noisy pixel have an equal probability to be a salty grain (white) or a pepper grain (black). Given a PIL image:

def add_salt_and_pepper(image, amount):

    output = np.copy(np.array(image))

    # add salt
    nb_salt = np.ceil(amount * output.size * 0.5)
    coords = [np.random.randint(0, i - 1, int(nb_salt)) for i in output.shape]
    output[coords] = 1

    # add pepper
    nb_pepper = np.ceil(amount* output.size * 0.5)
    coords = [np.random.randint(0, i - 1, int(nb_pepper)) for i in output.shape]
    output[coords] = 0

    return Image.fromarray(output)

That can be easily modified to have grains of random colors.

like image 114
Victor Deleau Avatar answered Oct 16 '22 13:10

Victor Deleau


Here's a Python PIL/Pillow version of the sort of thing I was doing with my ImageMagick answer. I create a white canvas and generate a random RGB colour on which I will base all the circles I draw, but using a slight variation for added fun. Then I draw a random number of circles of random sizes in random places, blur them and add the text.

#!/usr/bin/env python3

from PIL import Image, ImageDraw, ImageFont, ImageFilter
import numpy
from random import randint, seed

# Create white canvas and get drawing context
w, h = 250, 50
img  = Image.new('RGB', (w, h), color = 'white')
draw = ImageDraw.Draw(img)

# Let's have repeatable, deterministic randomness
seed(37)

# Generate a basic random colour, random RGB values 10-245
R, G, B = randint(10,245), randint(10,245), randint(10,245),

# Draw a random number of circles between 40-120
cmin = randint(50, 70)
cmax = randint(90,120)
for _ in range(cmin,cmax):
   # Choose RGB values for this circle, somewhat close (+/-10) to basic RGB
   r = R + randint(-10,10)
   g = G + randint(-10,10)
   b = B + randint(-10,10)
   diam = randint(5,11)
   x, y = randint(0,w), randint(0,h)
   draw.ellipse([x,y,x+diam,y+diam], fill=(r,g,b))

# Blur the background a bit
res = img.filter(ImageFilter.BoxBlur(3))

# Load font and draw text
draw = ImageDraw.Draw(res)
fnt = ImageFont.truetype('/Library/Fonts/Arial.ttf', 36)
draw.text((62,5), "3H1339", font=fnt, fill=(0,0,0))

# Save result
res.save('result.png')

enter image description here

like image 2
Mark Setchell Avatar answered Oct 16 '22 13:10

Mark Setchell


One can use ImageMagick 6 +noise random to generate your random spots image and then add text.

convert -size 250x50 xc:white +noise random -blur 0x1 -white-threshold 40% -fill black -gravity center -pointsize 48 -annotate +0+0 '9437TF' result.png


enter image description here

Or if you want just one color spots, then use -threshold in place of -white-threshold as:

convert -size 250x50 xc:white +noise random -blur 0x1 -threshold 45% -fill red -opaque black -gravity center -fill black -pointsize 48 -annotate +0+0 '9437TF' result.png


enter image description here

The pattern will be different each time you run it. If you want a reproducible pattern, then add -seed X. Each different X will produce a different pattern.

If on ImageMagick 7, change convert to magick.

If you want to do it in Python, then use Python Wand, which is based upon ImageMagick.

like image 1
fmw42 Avatar answered Oct 16 '22 15:10

fmw42