I have a picture. It's a calligraphic letter.
I need to make it filled with dots so that all the dots follow each other and correspond to the thickness of the letter line, that is, if the letter line becomes thicker, then the dot becomes larger. here is an example:
(That's the letter it turns out to be)
I tried to work with the skeleton of a photo using OpenCV and Pillow, but nothing worked out, I will be very glad if you help me, thank you in advance!
Played around a bit and arrived at this rather naive approach that looks to iteratively place dots and that seems to produce results somewhat in the direction of what I believe you are looking for:
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
# read image into numpy array
img = np.asarray(Image.open('../zZfpE.jpg'))
# binarize and coarse-graining
img = (img[::2, ::2, 0] < 128).astype(int)
def make_dots(
img, # 2d np array of 1s and 0s
spd=25, # speed up factor
marg=0.5, # minimum spacing between dots relative to dot size,
max_ds=27, # maximum dot diameter in pixels
min_ds=6, # minimum dot diameter in pixels
):
# start with blank image
img2 = np.zeros(img.shape)
h, w = img.shape
# keep track of areas occupied by dots
occ = set()
ofs = int(spd ** 0.5)
# iterate over dot sizes, decreasing
for t in np.arange(max_ds, min_ds, -5):
# iterate over pixels
for i in range(0, h, ofs):
for j in range(0, w, ofs):
d = 0
# increase dot diameter while 1. within bounds, b. corners of bounding box are black and 3. not already occupied
while (
i + d < h and j + d < w
) and all(
[img[i + d, j + d], img[i, j + d], img[i + d, j]]
) and not any(
[(i + d1, j + d2) in occ for d1, d2 in [(0, d), (d, 0), (d, d)]]
):
d += 1
# consider dot only if exceeding threshold
if d > t:
m = int(marg * d)
ci = i + d // 2
cj = j + d // 2
d2 = (d//2) ** 2
# iterate over pixels in bounding box of dot + margin
for a in range(i-m, i+d+m):
for b in range(j-m, j+d+m):
# mark pixel as occupied by dot
occ.add((a, b))
# if within radius, draw to image
if (ci - a) ** 2 + (cj - b) ** 2 < d2:
img2[a, b] = 1
return img2
plt.imshow(np.hstack((img, make_dots(img))), cmap='gray_r')
plt.axis('off')
plt.tight_layout()
While it's somewhat brittle / hacky, it (w/ tailoring of parameters to the data at hand, or a modified version of it) may still be useful and if not, at least serve as some inspiration hopefully, hence sharing here.