<jupyter_start><jupyter_text>just intensity<jupyter_code>page_x_inches: float = 17 # inches
page_y_inches: float = 11 # inches
border:float = 30.

px = utils.DistanceConverter(page_x_inches, 'inches').mm
py = utils.DistanceConverter(page_y_inches, 'inches').mm
page_format = f'{px}mmx{py}mm'
drawbox = sg.box(border, border, px-border, py-border)

xmin, ymin, xmax, ymax = drawbox.bounds

selem = disk(2)
img = filters.rank.mean(img/img.max(), selem)
img = io.imread(image_path)
img = rgb2gray(img)

img = rescale(img, 0.5)

# x, y = np.mgrid[-10:10:255j, -10:10:255j]
# img = np.sin(x ** 2 + y ** 2)
def sample_points_from_matrix(matrix, n_points):
    vec = matrix.ravel()
    choice_inds = np.random.choice(len(vec), size=n_points, p=vec/vec.sum())
    choice_vec = np.zeros_like(vec)
    choice_vec[choice_inds] = 1
    choice_locs = choice_vec.reshape(matrix.shape)
    ycs, xcs = np.where(choice_locs)
    return [Point(x, y) for x,y in zip(xcs, ycs)]
pts = sample_points_from_matrix(img**2, n_points=12000)
pts = gp.make_like(MultiPoint(pts), drawbox)
cs = MultiLineString([pt.buffer(0.9, resolution=4).boundary for pt in pts])
csb = so.unary_union([c.buffer(0.1) for c in cs])
tris = MultiPolygon(so.triangulate(MultiPoint(pts)))
# tris = gp.make_like(tris, drawbox)
sns.displot([np.log10(t.area) for t in tris])
# tris = tris.buffer(-0.2, join_style=2, cap_style=2, resolution=2)
ftris = MultiPolygon([p for p in tris if p.area <5])
uftris = so.unary_union(ftris)
stp = gp.ScaleTransPrms(n_iters=100, d_buffer=-0.3, d_translate_factor=0.6, angles=np.radians(-60))
stp.d_buffers *= gp.gaussian_random_walk(n=stp.d_buffers.shape[0], step_std=10)

all_fills = []
for p in uftris:
    fills = gp.scale_trans(p, **stp.prms)
    mfills = gp.merge_LineStrings([f.boundary for f in fills])
    all_fills.append(mfills)

fill_layer = gp.merge_LineStrings(all_fills)
sk = vsketch.Vsketch()
sk.size(page_format)
sk.scale('1mm')
sk.penWidth('0.25mm')
# sk.geometry(csb.boundary)
# sk.geometry(fill_layer)
sk.geometry(ftris.boundary)
sk.display(color_mode='None')
savepath = '/mnt/c/code/side/plotter_images/oned_outputs/0115_louie_delauney_flat.svg'

sk.save(savepath)

vpype_commands = 'reloop linesimplify --tolerance 0.05mm linemerge --tolerance 0.3mm linesort'
vpype_str = f'vpype read -q 0.05mm {savepath} {vpype_commands} write {savepath}'

os.system(vpype_str)<jupyter_output><empty_output><jupyter_text>just intensity<jupyter_code>page_x_inches: float = 17 # inches
page_y_inches: float = 11 # inches
border:float = 30.

px = utils.DistanceConverter(page_x_inches, 'inches').mm
py = utils.DistanceConverter(page_y_inches, 'inches').mm
page_format = f'{px}mmx{py}mm'
drawbox = sg.box(border, border, px-border, py-border)

xmin, ymin, xmax, ymax = drawbox.bounds

img = io.imread(image_path)
img = rgb2gray(img)

img = rescale(img, 0.95)

# x, y = np.mgrid[-10:10:255j, -10:10:255j]
# img = np.sin(x ** 2 + y ** 2)
def sample_points_from_matrix(matrix, n_points):
    vec = matrix.ravel()
    choice_inds = np.random.choice(len(vec), size=n_points, p=vec/vec.sum())
    choice_vec = np.zeros_like(vec)
    choice_vec[choice_inds] = 1
    choice_locs = choice_vec.reshape(matrix.shape)
    ycs, xcs = np.where(choice_locs)
    return [Point(x, y) for x,y in zip(xcs, ycs)]
pts = sample_points_from_matrix(img**2, n_points=12000)
pts = gp.make_like(MultiPoint(pts), drawbox)
cs = MultiLineString([pt.buffer(0.9, resolution=4).boundary for pt in pts])
csb = so.unary_union([c.buffer(0.1) for c in cs])
tris = MultiPolygon(so.triangulate(MultiPoint(pts)))
tris = tris.buffer(-0.25, join_style=2, cap_style=2, resolution=2)
def split_LineString(ls):
    vertices = len(ls.coords)-1
    return [LineString((ls.coords[i], ls.coords[i+1])) for i in range(vertices)]
all_lines = []
for ls in tri_edges:
    all_lines += split_LineString(ls)
max_length = 15
flines = MultiLineString([l for l in all_lines if l.length<max_length])
# tris = tris.buffer(-0.2, join_style=2, cap_style=2, resolution=2)
ftris = MultiPolygon([p for p in tris if p.area <1])
uftris = so.unary_union(ftris)
stp = gp.ScaleTransPrms(n_iters=100, d_buffer=-0.3, d_translate_factor=0.6, angles=np.radians(-60))
stp.d_buffers *= gp.gaussian_random_walk(n=stp.d_buffers.shape[0], step_std=10)

all_fills = []
for p in rts:
    fills = gp.scale_trans(p, **stp.prms)
    mfills = gp.merge_LineStrings([f.boundary for f in fills])
    all_fills.append(mfills)

fill_layer = gp.merge_LineStrings(all_fills)
sk = vsketch.Vsketch()
sk.size(page_format)
sk.scale('1mm')
sk.penWidth('0.25mm')
# sk.geometry(csb.boundary)
# sk.geometry(fill_layer)
# sk.geometry(ftris.boundary)
sk.geometry(flines)
sk.display(color_mode='None')
savepath = '/mnt/c/code/side/plotter_images/oned_outputs/0115_louie_delauney_flat.svg'

sk.save(savepath)

vpype_commands = 'reloop linesimplify --tolerance 0.05mm linemerge --tolerance 0.3mm linesort'
vpype_str = f'vpype read -q 0.05mm {savepath} {vpype_commands} write {savepath}'

os.system(vpype_str)<jupyter_output><empty_output><jupyter_text>intensity pixel remap<jupyter_code>image_path = Path('/mnt/c/code/side/plotter_images/louiehat.jpg')
page_x_inches: float = 17 # inches
page_y_inches: float = 11 # inches
border:float = 15.

size_string = '11.7×16.5 inches'
size, units = size_string.split(' ')
size.split('x')
ppr = utils.Paper('A3')
px = utils.DistanceConverter(page_x_inches, 'inches').mm
py = utils.DistanceConverter(page_y_inches, 'inches').mm
page_format = f'{px}mmx{py}mm'
drawbox = sg.box(border, border, px-xborder, py-yborder)

xmin, ymin, xmax, ymax = drawbox.bounds

img =  rgb2gray(io.imread(image_path))
img = rgb2gray(img)

img = rescale(img, 0.125)

# Contrast stretching
# p2, p98 = np.percentile(img, (2, 99))
# img_rescale = exposure.rescale_intensity(img, in_range=(p2, p98)) * 0.8 +0.1

img_rescale = exposure.equalize_adapthist(img, clip_limit=0.1, nbins=32) * 0.79 +0.2

selem = disk(2)
filt_img = filters.rank.mean(img_rescale, selem)

angle_farid = angle(filters.farid_h(filt_img),
                    filters.farid_v(filt_img))

f, axs = plt.subplots(1,3, figsize=(12,8))
axs[0].imshow(img)
axs[1].imshow(img_rescale)
axs[2].imshow(angle_farid)
df = geopandas.GeoDataFrame({'geometry':polys})
pixel_width=0.9
pixel_height=0.9
prms = []
for y, row in tqdm(enumerate(img_rescale)):
    for x, intensity in enumerate(row):
        
        p = gp.centered_box(Point(x, y), width=pixel_width, height=pixel_height)
        a = angle_farid[y, x]
        prm = {
            'geometry':p,
            'x':x,
            'y':y,
            'raw_pixel_width':pixel_width,
            'raw_pixel_height':pixel_height,
            'intensity': intensity,
            'angle':a,
            'group': 'raw_hatch_pixel',
            
        }
        prms.append(prm)
raw_hatch_pixels = geopandas.GeoDataFrame(prms)
import yaml
@dataclass
class RasterHatchParam(gp.DataClassBase):
    image_path: str = None
rhp = RasterHatchParam(image_path='/mnt/c/code/side/plotter_images/louiehat.jpg')
rhp.angle_jitter_gen = angle_jitter_gen
with open('/mnt/c/data/test_param.yaml', mode='w') as ff:
    ff.write(yaml.dump(rhp))

with open('/mnt/c/data/test_param.yaml', mode="r") as fx:
    y = yaml.load(fx)
bbox = box(*raw_hatch_pixels.total_bounds)
_, transform = gp.make_like(bbox, drawbox, return_transform=True)
A = gp.AffineMatrix(**transform)
scaled_hatch_pixels = raw_hatch_pixels.copy()
scaled_hatch_pixels['geometry'] = scaled_hatch_pixels.affine_transform(A.A_flat)
scaled_hatch_pixels['scaled_pixel_height'] = scaled_hatch_pixels['geometry'].apply(gp.get_height)
scaled_hatch_pixels['scaled_pixel_width'] = scaled_hatch_pixels['geometry'].apply(gp.get_width)
angle_jitter_gen = gp.make_callable(ss.norm(loc=0, scale=10).rvs)
pixel_rotation_gen = gp.make_callable(0)
new_rows = []
for i, row in tqdm(scaled_hatch_pixels.iterrows(), total=len(scaled_hatch_pixels)):
    r = row.copy()
    r['angle_jitter'] = angle_jitter_gen()
    r['hatch_angle'] = r['angle'] + r['angle_jitter']
    r['pixel_rotation'] = pixel_rotation_gen()
    p = r['geometry']
    r['spacing'] = r['intensity']  # could be a transformation though
    if abs(r['pixel_rotation']) > np.finfo(float).eps:
        p = sa.rotate(p, r['pixel_rotation'])
    f = gp.hatchbox(p, spacing=r['spacing'], angle=r['hatch_angle'])
    r['geometry'] = f
    new_rows.append(r)
    
fills = geopandas.GeoDataFrame(new_rows)
fills = fills[fills.length > 0]
sk = vsketch.Vsketch()
sk.size(page_format)
sk.scale('1mm')
sk.penWidth('0.25mm')
sk.stroke(1)
sk.geometry(fills)
for tolerance in np.linspace(0.3, 0.9, 6):
    sk.vpype(f'linemerge --tolerance {tolerance}mm')
sk.vpype('linesimplify --tolerance 0.2mm')
%%time
sk.vpype('linesort')
sk.display(color_mode='None')
savepath = '/mnt/c/code/side/plotter_images/oned_outputs/0138_louie_flow_high_res_jittered_angle.svg'

sk.save(savepath)

image_path='/mnt/c/code/side/plotter_images/joey_bun.jpg'
filename='138_joeybun_test.svg'
paper_size:str = '11x17 inches'
border:float=20  # mm
image_rescale_factor:float=0.04
farid_disk_size:int=2
hist_clip_limit=0.1
hist_nbins=32
hatch_spacing_min=0.2  # mm
hatch_spacing_max=1.  # mm
pixel_width=0.9  # mm
pixel_height=0.9  # mm
angle_jitter='0'
pixel_rotation='0'
merge_tolerances=[0.3, 0.4, 0.5]  # mm
simplify_tolerances=[0.2]  # mm
savedir='/mnt/c/code/side/plotter_images/oned_outputs'
def local_angle(dx, dy):
    """Calculate the angles between horizontal and vertical operators."""
    return np.mod(np.arctan2(dy, dx), np.pi)

# make page
paper = Paper(paper_size)
drawbox = paper.get_drawbox(border)

# load
img =  rgb2gray(io.imread(Path(image_path)))
img_rescale = rescale(img, image_rescale_factor)

# 
img_contrast_adj = exposure.equalize_adapthist(img_rescale, clip_limit=hist_clip_limit, nbins=hist_nbins)
img_renorm = img_contrast_adj * (hatch_spacing_max - hatch_spacing_min) + hatch_spacing_min

# calc dominant angle
selem = disk(2)
filt_img = filters.rank.mean(img_renorm, selem)
angle_farid = local_angle(filters.farid_h(filt_img), filters.farid_v(filt_img))

# make pixel polys
prms = []
for y, row in tqdm(enumerate(img_renorm)):
    for x, intensity in enumerate(row):

        p = gp.centered_box(Point(x, y), width=pixel_width, height=pixel_height)
        a = angle_farid[y, x]
        prm = {
            'geometry':p,
            'x':x,
            'y':y,
            'raw_pixel_width':pixel_width,
            'raw_pixel_height':pixel_height,
            'intensity': intensity,
            'angle':a,
            'group': 'raw_hatch_pixel',

        }
        prms.append(prm)
raw_hatch_pixels = geopandas.GeoDataFrame(prms)

#  rescale polys to fit in drawbox
bbox = box(*raw_hatch_pixels.total_bounds)
_, transform = gp.make_like(bbox, drawbox, return_transform=True)
A = gp.AffineMatrix(**transform)
scaled_hatch_pixels = raw_hatch_pixels.copy()
scaled_hatch_pixels['geometry'] = scaled_hatch_pixels.affine_transform(A.A_flat)
scaled_hatch_pixels['scaled_pixel_height'] = scaled_hatch_pixels['geometry'].apply(gp.get_height)
scaled_hatch_pixels['scaled_pixel_width'] = scaled_hatch_pixels['geometry'].apply(gp.get_width)

# distributions etc
angle_jitter_gen = gp.make_callable(eval(angle_jitter))
pixel_rotation_gen = gp.make_callable(eval(pixel_rotation))


new_rows = []
for i, row in tqdm(scaled_hatch_pixels.iterrows(), total=len(scaled_hatch_pixels)):
    r = row.copy()
    r['angle_jitter'] = angle_jitter_gen()
    r['hatch_angle'] = r['angle'] + r['angle_jitter']
    r['pixel_rotation'] = pixel_rotation_gen()
    p = r['geometry']
    r['spacing'] = r['intensity']  # could be a transformation though
    if abs(r['pixel_rotation']) > np.finfo(float).eps:
        p = sa.rotate(p, r['pixel_rotation'])
    f = gp.hatchbox(p, spacing=r['spacing'], angle=r['hatch_angle'])
    r['geometry'] = f
    new_rows.append(r)

fills = geopandas.GeoDataFrame(new_rows)
fills = fills[fills.length > 0]
fill_layer = gp.merge_LineStrings(fills.geometry)
fills<jupyter_output><empty_output><jupyter_text>debug<jupyter_code>border=20
paper_size:str = '14x11 inches'  
        # make page
paper = Paper(paper_size)
drawbox = paper.get_drawbox(border)
image_path = '/mnt/c/code/side/plotter_images/205_subdivide.png'
image_rescale_factor = 0.01
smooth_disk_size:int=2
hist_clip_limit=0.1
hist_nbins=32
hatch_spacing_min=0.3  # mm
hatch_spacing_max=1.  # mm
pixel_width=0.9  # mm
pixel_height=0.9 # mm
angle_jitter='0'  # degrees
pixel_rotation='0' # degrees
merge_tolerances=[0.3, 0.4, 0.5]  # mm
simplify_tolerances=[0.2]  # mm
def local_angle(dx, dy):
    """Calculate the angles between horizontal and vertical operators."""
    return np.mod(np.arctan2(dy, dx), np.pi)
# load
img =  rgb2gray(io.imread(Path(image_path)))
img_rescale = rescale(img, image_rescale_factor)

# 
img_renorm = exposure.equalize_adapthist(img_rescale, clip_limit=hist_clip_limit, nbins=hist_nbins)

# calc dominant angle
selem = disk(smooth_disk_size)
filt_img = filters.rank.mean(img_renorm, selem)
angle_farid = local_angle(filters.farid_h(filt_img), filters.farid_v(filt_img))
# make pixel polys
prms = []
for y, row in tqdm(enumerate(img_renorm)):
    for x, intensity in enumerate(row):

        p = gp.centered_box(Point(x, y), width=pixel_width, height=pixel_height)
        a = np.degrees(angle_farid[y, x])
        prm = {
            'geometry':p,
            'x':x,
            'y':y,
            'raw_pixel_width':pixel_width,
            'raw_pixel_height':pixel_height,
            'intensity': intensity,
            'angle':a,
            'group': 'raw_hatch_pixel',

        }
        prms.append(prm)
raw_hatch_pixels = geopandas.GeoDataFrame(prms)
#  rescale polys to fit in drawbox
bbox = box(*raw_hatch_pixels.total_bounds)
_, transform = gp.make_like(bbox, drawbox, return_transform=True)
A = gp.AffineMatrix(**transform)
scaled_hatch_pixels = raw_hatch_pixels.copy()
scaled_hatch_pixels['geometry'] = scaled_hatch_pixels.affine_transform(A.A_flat)
scaled_hatch_pixels['scaled_pixel_height'] = scaled_hatch_pixels['geometry'].apply(gp.get_height)
scaled_hatch_pixels['scaled_pixel_width'] = scaled_hatch_pixels['geometry'].apply(gp.get_width)

# distributions etc
angle_jitter_gen = gp.make_callable(eval(angle_jitter))
pixel_rotation_gen = gp.make_callable(eval(pixel_rotation))


scaled_hatch_pixels['angle_jitter'] = angle_jitter_gen(len(scaled_hatch_pixels))
scaled_hatch_pixels['hatch_angle'] = scaled_hatch_pixels['angle'] + scaled_hatch_pixels['angle_jitter']
scaled_hatch_pixels['pixel_rotation'] = pixel_rotation_gen(len(scaled_hatch_pixels))
spacing_func = functools.partial(np.interp, xp=[0, 1], fp=[hatch_spacing_min, hatch_spacing_max])
scaled_hatch_pixels['spacing'] = spacing_func(scaled_hatch_pixels['intensity'])
scaled_hatch_pixels['spacing']
r['spacing'] = r['intensity']<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14314652261985145, 'fraction_numerical': 0.02072923700202566, 'mean_word_length': 5.135459817729909, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '377234', 'license': 'MIT', 'n_tokens_mistral': 6130, 'n_tokens_neox': 5847, 'n_words': 943, 'path': 'scratch/009_image_processing.ipynb', 'repo_name': 'ANaka/genpen', 'size': '14810'}