Создание шума пикселей с PIL Python - PullRequest
3 голосов
/ 30 января 2020

Я пытаюсь сгенерировать тренировочные данные изображений с шумом и текстом на них, как на изображении ниже: Example Image Я выяснил, как генерировать изображения с текстом правильного размера, но могу не понять, как генерировать шум. Сначала я думал, что гауссовский шум будет правильным подходом, но это не тот тип шума.

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')

Ответы [ 4 ]

2 голосов
/ 30 января 2020

Мне потребуется некоторое время, чтобы сделать это в Python, но вы можете применить концепции самостоятельно, если я покажу вам метод. Я буду использовать ImageMagick , который установлен на большинстве Linux дистрибутивов и доступен для macOS и Windows. Вы просто запускаете его в Терминале.

Итак, чтобы создать solid фон, просто выберите 3 случайных значения RGB 0..255 и создайте изображение такого размера:

convert -size 250x50 xc:"rgb($((RANDOM%255)),$((RANDOM%255)),$((RANDOM%255)))" background.png

enter image description here

Чтобы создать маску, какие части фона вы хотите показать через:

convert -seed $RANDOM -size 50x10 xc: +noise random -colorspace gray -resize 250x50\! -blur 0x3  -edge 10  mask.png

enter image description here

Чтобы замаскировать изображение и нарисовать текст:

convert background.png mask.png -compose copyalpha -composite -gravity center -pointsize 48 -annotate 0 '9437TF' result.png

enter image description here

Теперь, если вы положите все это в oop и сгенерировать 32 случайных цветных изображения со случайной маской, вы можете передать результат в команду ImageMagick * montage и разместить их в сетке из 4 изображений:

#!/bin/bash

for x in {0..31} ; do
        convert -size 250x50 xc:"rgb($((RANDOM%255)),$((RANDOM%255)),$((RANDOM%255)))" background.png
        convert -seed $RANDOM -size 50x10 xc: +noise random -colorspace gray -resize 250x50\! -blur 0x3  -edge 10  mask.png
        convert background.png mask.png -compose copyalpha -composite -gravity center -pointsize 48 -annotate 0 '9437TF'  miff:-
done | magick montage -tile 4x -geometry +10+10 miff:-  result.png

enter image description here

Или вы можете нарисовать случайное число (скажем, около 80) кругов случайных радиусов и случайных цветов на белом фоне и размывать их случайным образом. Это может выглядеть так:

#!/bin/bash

MINCIRCLES=20
MINRADIUS=3
for x in {0..31} ; do
    convert -size 250x50 xc:white background.png
    ((R=RANDOM%255))
    ((G=RANDOM%255))
    ((B=RANDOM%255))
    NCIRCLES=$((MINCIRCLES+(RANDOM%40)))
    for c in $(seq $MINCIRCLES $NCIRCLES) ; do
        RADIUS=$((MINRADIUS+(RANDOM%8)))
        ((X=$RANDOM%250))
        ((Y=$RANDOM%50))
        ((P=X+RADIUS))
        mogrify -fill "rgb($R,$G,$B)" -draw "circle $X,$Y $P,$Y" background.png
    done
    convert background.png -blur x2 -gravity center -pointsize 48 -annotate 0 '9437TF'  miff:-
done  | magick montage -tile 4x -geometry +10+10 miff:-  result.png

enter image description here

2 голосов
/ 30 января 2020

Я думаю, что вы ищете шум соли и перца. Каждый пиксель имеет вероятность быть уничтоженным (количество). Каждый шумный пиксель имеет равную вероятность быть соленым зерном (белым) или перцем (черным). Дано изображение PIL:

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)

Это можно легко изменить, чтобы получить зерна случайных цветов.

1 голос
/ 03 февраля 2020

Можно использовать ImageMagick 6 + случайный шум для создания изображения случайных пятен, а затем добавить текст.

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

Или, если вы хотите использовать только одно цветовое пятно, используйте -threshold вместо -white-threshold как:

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

Шаблон будет отличаться при каждом его запуске. Если вам нужен воспроизводимый шаблон, добавьте -seed X. Каждый отдельный X будет создавать другой шаблон.

Если на ImageMagick 7, измените convert на magick.

Если вы хотите сделать это в Python, затем используйте Python Wand, основанный на ImageMagick.

0 голосов
/ 03 февраля 2020

Вот версия Python PIL / Pillow того, что я делал с моим ImageMagick ответом. Я создаю белый холст и генерирую случайный цвет RGB, на котором я буду основывать все круги, которые я рисую, но используя небольшое изменение для дополнительного веселья. Затем я рисую случайное количество кругов случайных размеров в случайных местах, размываю их и добавляю текст.

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

...