#A bare-bone ink-jet printer
1 messages Β· Page 1 of 1 (latest)
in python, here a minimal test-bench
import copy
# The goal:
# We have a printer that can only print black and white squares, from an input image (a linear gradient) with
# many shades of gray, we need to reduce these colours to only white and black while still keeping a "feel" of
# the original gradient.
#
# input image:
# | ββββββββββββββ|
# | ββββββββββββββββ|
# | ββββββββββββββββββ|
# |ββββββββββββββββββββ|
# |ββββββββββββββββββββ|
# |ββββββββββββββββββββ|
# |ββββββββββββββββββββ|
# |ββββββββββββββββββββ|
# |ββββββββββββββββββββ|
# |ββββββββββββββββββββ|
#
# output image: (goal)
# | β β |
# | β β|
# | β β β β β|
# | β β β β|
# | β β β β βββ|
# | β β β βββ β|
# |β β β β β βββ ββ|
# | β β β β β ββββ|
# |β β β β ββββ βββββ|
# | β β β ββ βββ ββββββ|
# (pretty much, although I just hand-wrote it)
#
# This is called "dithering", a down-sampling strategy for colors, that conserves as best as it can the shades of the
# original image. There are various strategies to achieve that: unordered (floyd steinberg error diffusion algorithm),
# or ordered, such as here, with a threshold matrix which is an extension from the bayer's base matrix, which maximize
# the distance between two similar values in a matrix (eg: 2 and 3, 9 and 10...), also accounting for the wrap-around.
#
# I left it to you to implement a function that generates a Bayer's threshold matrix, whichever way you like best. The
# rest is pretty much there and finalized already.
# Without the bayer's matrix generator, the threshold is a mid-gray, which will rander our gradiant as a crude triangle.
edge_size = 10 # the base image is a square
# utilities
def print_2D_mat(mat):
for i in range(len(mat)):
for j in range(len(mat[0])):
print(f'{mat[j][i]:03d}', end =", ")
print() # end line
def discretize(val, min, max):
tone_map = " ββββ"
values_range = max-min
return tone_map[round(((val-min)/values_range)*(len(tone_map)-1))]
def print_img(img, min, max):
for i in range(len(base_image)):
print('|', end = "")
for j in range(len(base_image[0])):
symbol = discretize(base_image[j][i], min, max)
print(f'{symbol}{symbol}', end = "")
print('|') # end line
#############################
# Generates the base image:
def init_mat(default_value, size):
a = []
b = []
for k in range(0, size):
b.append(default_value)
for j in range(0, size):
a.append(copy.deepcopy(b))
return a
def apply_gradiant(matrix, min, max):
for(i) in range(len(matrix)):
for(j) in range(len(matrix[0])):
matrix[j][i] = round(min+((i+j)*(max-min)/(len(matrix)*2)))
return matrix
base_image = init_mat(0, edge_size)
apply_gradiant(base_image, 0, 100)
#display
print_2D_mat(base_image)
print_img(base_image, 0, 100)
######### task to work on:
def bayer_matrix(size, min, max):
matrix = init_mat(round((max-min)/2), size) # blank:
# |0, 0|
# |0, 0|
# TODO
# Need to find how to implement it
# cool resource-> https://blog.kaetemi.be/2015/04/01/practical-bayer-dithering/
# Do some computing, potentially recursively...
# with a size = 2,
# matrix = |0, 2|
# |3, 1|
# with a size = 4,
# matrix = | 0, 8, 2, 10|
# |12, 4, 14, 6|
# | 3, 11, 1, 9|
# |15, 7, 13, 5|
return matrix
#########
dithering_map_size = 16
dithering_threshold = bayer_matrix(dithering_map_size, 0, 100)
########################################
# finally I want to use the dithering bayer's threshold to dither the image to binary B&W (0 or 100% black only)
for i in range(edge_size):
print('|', end='')
for j in range(edge_size):
base_image_pixel_value = base_image[j][i]
j_in_dither_map = j%dithering_map_size
i_in_dither_map = i%dithering_map_size
dithering_map_threshold_value = dithering_threshold[j_in_dither_map][i_in_dither_map]
if base_image_pixel_value > dithering_map_threshold_value:
print("ββ", end="")
else:
print(" ", end="")
print('|') # end line
;compile