Last active
January 9, 2024 23:41
-
-
Save 0racle/f48586b6b2c05d13e3abbcb046e91dfb to your computer and use it in GitHub Desktop.
Dithering with Error Diffusion in J
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'media/imagekit/color_space' | |
require 'graphics/png' | |
require 'graphics/pplatimg' | |
coinsert 'pplatimg' | |
ParseDiff =: {{ | |
'p d' =. (}: ; {:) ];._2 y | |
t =. ". '/%' rplc~ d | |
c =. (+./@(' ' ~: ]) {{ (1, 2 </\ x) <;.1&(x&#) y }}"1 ]) p | |
a =. {. ($ #: I.@,) > 'X' +./@e.~L:0 c | |
i =. ($ #: I.@,) > '\d+' (rxin)L:0 c | |
e =. t * ".@> (< i) { c | |
o =. i -"1 a | |
o ; e | |
}} | |
floyd =: {{)n | |
X 7 | |
3 5 1 | |
(1/16) | |
}} | |
jarvis =: {{)n | |
X 7 5 | |
3 5 7 5 3 | |
1 3 5 3 1 | |
(1/48) | |
}} | |
stucki =: {{)n | |
X 8 4 | |
2 4 8 4 2 | |
1 2 4 2 1 | |
(1/42) | |
}} | |
atkinson =: {{)n | |
X 1 1 | |
1 1 1 | |
1 | |
(1/8) | |
}} | |
burkes =: {{)n | |
X 8 4 | |
2 4 8 4 2 | |
(1/32) | |
}} | |
sierra =: {{)n | |
X 5 3 | |
2 4 5 4 2 | |
2 3 2 | |
(1/32) | |
}} | |
sierraTwo =: {{)n | |
X 4 3 | |
1 2 3 2 1 | |
(1/16) | |
}} | |
sierraLite =: {{)n | |
X 2 | |
1 1 | |
(1/4) | |
}} | |
Pad =: ({: ,~ {. , ])"1@({: ,~ {. , ]) | |
Dither =: {{ | |
'o d' =. ParseDiff x NB. offset and diffusion | |
e =. >./ | , o NB. get max offset | |
p =. (Pad^:e) y NB. pad edges for offset | |
'h w' =. $ y NB. rows/cols of unpadded image | |
for_j. e + i. h do. NB. each row (skip padding) | |
for_k. e + i. w do. NB. each col (skip padding) | |
a =. (<j,k) { p NB. active pixel | |
c =. <.@+&0.5 a NB. closest color | |
q =. d * a - c NB. quantize | |
i =. (j,k) <@:+"1 o NB. calculate offset | |
p =. (c, (q + i { p)) ((j,k);i)} p NB. update pixes | |
end. | |
end. | |
(< (e&+)@i.&.> $ y) { p NB. trim pading | |
}} | |
Grayscale =: ((0&{)"1)@:RGB_to_YUV | |
Greyscale =: ((0&{)"1)@:to255@:RGB_to_yiq | |
Luminance =: 0.299 0.587 0.114 <.@+/@(*"1) ] | |
img =. (3 # 256) #: readimg 'Pictures/david.jpg' | |
mat =. to01 Greyscale (con_exp^:0) img | |
res =. sierra Dither mat | |
viewrgb rgb_to_i"1 [ 255 * 3 #"0 res | |
NB. Save png | |
NB. 'dither-test.png' writepng~ rgb_to_i"1 [ 255 * 3 #"0 res |
Thinking about colored dithering, I think if your palette is made up of uniform segments of each RGB channel you should probably be able to do dithering just the same as grey scale by treating each channel equally. I.e. rather than extract a channel, simply run the algorithm across all channels. However, if picking the closest color is not simply picking the closest value in each channel, I think it gets more complicated.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Notes
1 { img
)con_exp
(contrast expansion)res
straight toviewmat
but it doesn't size 100% by default.a ,. b
) and compareThe error diffusion patterns came from here