'Glitch' Art Filters - again

Pixel Sorting. That what these looks like. The third one however is a bit more complicated than that.

While working on the filter I was talking about in my g’mic thread, I came up with this filter as it’s going to be incorporated into that filter. What glitch does this resemble the most?

NOTE: Random Shade Stripe Layer was added to Mona Lisa, then Destination In Blending mode was used. Then flattened to use the filter I made.

What this filter does is blend pixels by pixels within either x or y axis and either direction. So, you get this pixel stretch effect, but it’s not actually anything like pixel streak. There is different rules that determines how they get blended. However, what does it look like when combined with random shade stripe.

I just did what I wanted. A new glitch art filter may be coming though it would be nice if other scripters here can extend it.

rep_auda_test:
repeat $! l[$>]
 if d==1
  ow={w}
  oh={h}
  os={s}
  unroll x
  s x,$os a c
  s x,-1 unroll x a x
  #Insert your command here#
   f. j(min(j(-10,0,0,0,0,2),i,j(10,0,0,0,0,2))*.05)
  #End#
  s x,-$os
  unroll c
  a x
  #Insert your command here#
  #End#
  unroll x
  #Insert your command here#
   f. avg(max(j(int(x/$ow)*.5,0,0,0,0,2),i),i)
   f. j((x/w)^2*30,0,0,0,1,1)*.05
  #End#
  $ow,$oh,1,$os,"begin(
  const sc=w#0/s;
  );
  poschan=c*wh;
  posxy=x+w*y;
  pos=poschan+posxy;
  i(#0,pos,0,0,0);
  "
  k.
 fi
endl done

Another pic with s x,5 rv[n1,n2] a x

1 Like

Why didn’t I think of unrolling it before? Maybe I could shove an analog style low pass filter in there if I’ve got time (a popular term for that is ‘zero-delay feedback’ but it’s a misnomer). Regardless, you’ve made a template for a whole class of scripts which can simulate sound-to-image databending. I wonder what a PSOLA time-stretcher would do…

I’ve been really busy with other things and I’m still haunted by that 3D cubim-ish script that I wanted to make (I still can’t figure out how to do the antialiasing in 3D)!

1 Like

Well, not the whole template. I just had inserted another Insert your command here and that contains all pixels while channels are appended together. So, now you do have the whole template. I think we could collaborate on it together as it seem to be a long term project.

I decided to experiment with permute. Problem is rolling it back. It can be shortened to permute $val Unroll x “your command here” rollback. I’ll ping @David_Tschumperle for ideas.


@Joan_Rake1 Now, I think I managed to create a better script thanks to @garagecoder.

rep_auda:
('$1')
l. s x remove_duplicates a x if w#-1!=4 error exit fi endl
4,1,1,1,"begin(
numid_xyzc=[120,121,122,99];
);
numid_xyzc[find(#-1,numid_xyzc[x],0,1)];"
img2text. , unpermute_string=${} rm[-2,-1]
permute $1
whds={[w,h,d,s]}
unroll x
#Insert Code Here#
f x%2?j(10,0,0,0):j(-10,0,0,0)
#End#
r $whds,-1
permute $unpermute_string

So, I think this part is solved. The hard part is making it work with variety of different functions and to make it useful for cli and gui at once. I think that’s a big project.

This was achieved with a modified version of the above using this line:

f j(i*(5*x/(w-1)-int(5*x/(w-1))))

Another pic:

1 Like

I’m now trying to make a generalised JPEG-style encoder with a user-specified tile size. I want to use David’s trick of generating a image of individual IDCT tiles. I’ve tried doing it using at "idct", but with larger tile sizes it gets very slow. I want to generate the tiles directly from cosines but I’m not sure how. This one does both at the same time, and I want the first to be what the second is now.

rm
tw=8
th=8
{$tw^2},{$th^2},1,1
#slow
+f "!((x%("$tw"+1))||(y%("$th"+1)))?255" at. "idct",$tw,$th
#should eventually be the faster way
f[0] "begin(tw="$tw";th="$th");
tx=(x-(x%tw))/tw;
ty=(y-(y%th))/th;
cx=cos((x*tx/tw+(1*tx))*pi);
cy=cos((y*ty/th+(1*ty))*pi);
cx*cy
"
rv
nm[-2,-1] real,mine
n 0,255

I’ve got something which looks similar but it’s a bit off. I don’t know if there’s a square root involved…

rm
tw=8
th=8
{$tw^2},{$th^2},1,1
+f "!((x%("$tw"+1))||(y%("$th"+1)))?255" at. "idct",$tw,$th

f[0] "begin(tw="$tw";th="$th");
tx=(x-(x%tw))/tw;
ty=(y-(y%th))/th;
cx=cos((2*x+1)*tx*pi*0.5/tw)/sqrt(tw);
cy=cos((2*y+1)*ty*pi*0.5/th)/sqrt(th);
tx!=0?(cx*=sqrt(2));
ty!=0?(cy*=sqrt(2));
val=cx*cy;
((tx+ty)%2)?(val*=-1);
val
"

The massive slowdown comes from apply_tiles. I don’t get where the idct comes from though and what it’s suppose to do. Maybe with that info I could come up with a theory on how to make a faster version, but you already have a version that’s 15 times faster.

Also, here’s the analysis of difference/xor if that would help

image

XOR Analysis

image

Difference analysis

Thanks. While you were replying I updated it because I found something after doing some research. What I’ve got now is almost like what I want but there’s a constant factor missing and I’m not sure how this constant factor varies.

I think you got it actually with the new update. Blend difference reveals this when comparing normalized images.

[2] = '[unnamed]_c1':
  size = (64,64,1,1) [16 Kio of floats].
  data = (0,0,0,0,0,0,0,0,0,0,1.52588e-05,1.52588e-05,(...),0,7.62939e-06,0,7.62939e-06,7.62939e-06,1.52588e-05,7.62939e-06,1.52588e-05,7.62939e-06,0,7.62939e-06,0).
  min = 0, max = 2.28882e-05, mean = 7.56842e-06, std = 6.54397e-06, coords_min = (0,0,0,0), coords_max = (13,8,0,0).

Now it’s just a matter of normalizing your result.

The constant factor I was looking for is 64, but I can always take that out. I now have something from which I can easily make an IDCT, but in his command, David left out the DCT entirely. I have to figure out how he did that.

rm
tw=8
th=8
{$tw^2},{$th^2},1,1
f "begin(tw="$tw";th="$th");
tx=(x-(x%tw))/tw;
ty=(y-(y%th))/th;
cx=cos((2*x+1)*tx*pi*0.5/tw)/sqrt(tw);
cy=cos((2*y+1)*ty*pi*0.5/th)/sqrt(th);
tx!=0?(cx*=sqrt(2));
ty!=0?(cy*=sqrt(2));
val=cx*cy;
((tx+ty)%2)?(val*=-1);
val*64;
"

dct = discrete cosine transform
idct = inverse of that

2 Likes

I figure that I can use these tiles for both the DCT and the IDCT…

I want this filter to be able to run on 3-channel images, with a separate DCT tile size for each channel. I would need to generate up to three DCT tile sets but if two or more channels have the same tile sizes, I could just re-use them. How would I be able to do this? I need to:

  • make the required tile sets, up to three of them
  • use the correct tile sets for each channel

I also have a broken implementation with a fixed tile size for all channels. As usual, unless I seek attention and post it first, I will never figure it out.

dct_tileset:
{$1^2},{$2^2},1,1
f. "begin(tw=$1;th=$2);
tx=(x-(x%tw))/tw;
ty=(y-(y%th))/th;
cx=cos((2*x+1)*tx*pi*0.5/tw);
cy=cos((2*y+1)*ty*pi*0.5/th);
val=cx*cy;
((tx+ty)%2)?(val*=-1);
val
"

fx_jpeg :

to_rgb
tw=8
th=8
dct_tileset $tw,$th

nm. cosines
repeat {$!-1} l[$>,cosines]
ww={w(#0)}
hh={h(#0)}
r[0] {w(#0)+(-w(#0)%$tw)},{h(#0)+(-h(#0)%$th)},1,100%,0,3

s[0] c

repeat 3
[$>]
f[$>] >"
begin_t(const tw="$tw";const th="$th";const twh=tw*th);
if (!(x%tw) && !(y%th),
res=vector(#twh,0);
ref(crop(x,y,tw,th),src);
for (l = 0, l<th, ++l, for (k = 0, k<tw, ++k, off = k + th*l; res += src[off]*crop(#"$cosines",k*tw,l*th,tw,th,1)));
draw(#-1,res,x,y,0,0,tw,th);
); i"
round.
f[$>] >"
begin_t(const tw="$tw";const th="$th";const twh=tw*th;res=vector(#twh));
if (!(x%tw) && !(y%th),
res=vector(#twh,0);
ref(crop(x,y,tw,th),src);
for (l = 0, l<th, ++l, for (k = 0, k<tw, ++k, off = k + th*l; res += src[off]*crop(#"$cosines",k*tw,l*th,tw,th,1)));
draw(#"$>",res,x,y,0,0,tw,th);
); i"
rm.

done
a[0-2] c
r[0] $ww,$hh,1,100%,0,3
endl done

Inserting : before begin on dct_tileset gives 0 s run instead of .16 s. I’ll figure the channels part for you.

EDIT: I don’t think I can figure it out. Maybe has to do with crop. Try crop(x,y,z,c,w,h,d,s) instead of crop(x,y,w,h)

EDIT 2: There is also the option of using a smaller image to manipulate a bigger image. Fill can be used to manipulate outside image. See ‘rep_recc’.

I realise that I am actually running two IDCTs. I can generate a tile set for a DCT but I want to figure out a faster way.

rm
tw=8
th=8
{$tw^2},{$th^2},1,1
+f "!((x%("$tw"+1))||(y%("$th"+1)))?1" at. "dct",$tw,$th
n 0,255
display

Edit: I’ve figured out how to make the DCT tileset, and now the encoder is working for square tiles. For some reason it doesn’t work for non-square tiles.

dct_tileset:
{$1^2},{$2^2},1,1
f. :"begin(const tw=$1;const th=$2;const stw=sqrt(tw);const sth=sqrt(th);const itw=1/tw;const ith=1/th;const istw=sqrt(itw);const isth=sqrt(ith);const s2=sqrt(2));
px=x%tw;
py=y%th;
tx=(x-(px))*itw;
ty=(y-(py))*ith;
cx=cos((tx*0.5+((tx+0.5)*x*itw))*pi)*istw;
cy=cos((ty*0.5+((ty+0.5)*y*ith))*pi)*isth;
px!=0?(cx*=s2);
py!=0?(cy*=s2);
val=cx*cy;
val;
"

idct_tileset:
{$1^2},{$2^2},1,1
f. :"begin(const tw=$1;const th=$2;const stw=sqrt(tw);const sth=sqrt(th);const itw=1/tw;const ith=1/th;const istw=sqrt(itw);const isth=sqrt(ith);const s2=sqrt(2));
px=x%tw;
py=y%th;
tx=(x-(px))*itw;
ty=(y-(py))*ith;
cx=cos((x+0.5)*tx*pi*itw)*istw;
cy=cos((y+0.5)*ty*pi*ith)*isth;
tx!=0?(cx*=s2);
ty!=0?(cy*=s2);
val=cx*cy;
((tx+ty)%2)?(val*=-1);
val;
"

fx_jpeg :

to_rgb
tw=8
th=8
dct_tileset $tw,$th
idct_tileset $tw,$th
nm[-2,-1] dct,idct

repeat {$!-2} l[$>,dct,idct]
ww={w(#0)}
hh={h(#0)}
r[0] {w(#0)+(-w(#0)%$tw)},{h(#0)+(-h(#0)%$th)},1,100%,0,3

s[0] c

repeat 3
[$>]
f[$>] :"
begin_t(const tw="$tw";const th="$th";const twh=tw*th);
if (!(x%tw) && !(y%th),
res=vector(#twh,0);
ref(crop(x,y,tw,th),src);
for (l = 0, l<th, ++l, for (k = 0, k<tw, ++k, off = k + th*l; res += src[off]*crop(#"$dct",k*tw,l*th,tw,th,1)));
draw(#-1,res,x,y,0,0,tw,th);
); i"

f. :"
begin_t(const tw="$tw";const th="$th";const twh=tw*th;res=vector(#twh));
if (!(x%tw) && !(y%th),
res=vector(#twh,0);
ref(crop(x,y,tw,th),src);
for (l = 0, l<th, ++l, for (k = 0, k<tw, ++k, off = k + th*l; res += src[off]*crop(#"$idct",k*tw,l*th,tw,th,1)));
draw(#"$>",res,x,y,0,0,tw,th);
); i"

rm.
done
a[0-2] c
r[0] {$ww},{$hh},1,100%,0,3
endl done
rm[dct,idct]
display

When the second dimension is smaller than the first, it looks all wrong. When it’s larger, all the values in the resulting image turn to NaN.

Edit: a simple fix, I should’ve used tw and not th.

fx_jpeg :

to_rgb
tw=$1
th=$2
dct_tileset $tw,$th
idct_tileset $tw,$th
nm[-2,-1] dct,idct

repeat {$!-2} l[$>,dct,idct]
ww={w(#0)}
hh={h(#0)}
r[0] {w(#0)+(-w(#0)%$tw)},{h(#0)+(-h(#0)%$th)},1,100%,0,3

s[0] c

repeat 3
[$>]
f[$>] :"
begin_t(const tw="$tw";const th="$th";const twh=tw*th);
if (!(x%tw) && !(y%th),
res=vector(#twh,0);
ref(crop(x,y,tw,th),src);
for (l = 0, l<th, ++l, for (k = 0, k<tw, ++k,
off = k + tw*l;
res += src[off]*crop(#"$dct",k*tw,l*th,tw,th,1)));
draw(#-1,res,x,y,0,0,tw,th);
); i"

f. :"
begin_t(const tw="$tw";const th="$th";const twh=tw*th;res=vector(#twh));
if (!(x%tw) && !(y%th),
res=vector(#twh,0);
ref(crop(x,y,tw,th),src);
for (l = 0, l<th, ++l, for (k = 0, k<tw, ++k,
off = k + tw*l;
res += src[off]*crop(#"$idct",k*tw,l*th,tw,th,1)));
draw(#"$>",res,x,y,0,0,tw,th);
); i"
rm.
done
a[0-2] c
r[0] {$ww},{$hh},1,100%,0,3
endl done
rm[dct,idct]

@Joan_Rake1

Made some changes to speed it up a bit.

fx_jpeg :

tw=$1
th=$2
dct_tileset $tw,$th
idct_tileset $tw,$th
nm[-2,-1] dct,idct

repeat {$!-2} l[$>,dct,idct]
 ww={w(#0)}
 hh={h(#0)}
 r[0] {w(#0)+(-w(#0)%$tw)},{h(#0)+(-h(#0)%$th)},1,100%,0,3

 {w#0},{h#0},{d#0},{s#0}

 f[0] :"
  begin_t(const tw="$tw";const th="$th";const twh=tw*th);
  if (!(x%tw) && !(y%th),
  res=vector(#twh,0);
  ref(crop(x,y,z,c,tw,th,1,1),src);
  for (l = 0, l<th, ++l, 
   for (k = 0, k<tw, ++k,
    off = k + tw*l;
    res += src[off]*crop(#"$dct",k*tw,l*th,tw,th,1)
   );
  );
  draw(#-1,res,x,y,z,c,tw,th,1,1);
  );i"

 f. :"
  begin_t(const tw="$tw";const th="$th";const twh=tw*th;res=vector(#twh));
  if (!(x%tw) && !(y%th),
   res=vector(#twh,0);
   ref(crop(x,y,z,c,tw,th,1,1),src);
   for (l = 0, l<th, ++l, for (k = 0, k<tw, ++k,
   off = k + tw*l;
   res += src[off]*crop(#"$idct",k*tw,l*th,tw,th,1)));
   draw(#0,res,x,y,z,c,tw,th,1,1);
  );i"
  rm.

 r[0] {$ww},{$hh},1,100%,0,3
endl done
rm[dct,idct]

I might try to code up using small image to speed it up and eliminate the !(x%tw) && !(y%th).

Thanks for this, but I need to keep the channels separate so that I can use different tile sizes for each of them in future. I might try the other optimisation you’re talking about. In the meantime, here’s a new version with a quality setting:

fx_jpeg :

to_rgb
tw=$1
th=$2
q=$3
dct_tileset $tw,$th
idct_tileset $tw,$th
nm[-2,-1] dct,idct

repeat {$!-2} l[$>,dct,idct]
ww={w(#0)}
hh={h(#0)}
r[0] {w(#0)+(-w(#0)%$tw)},{h(#0)+(-h(#0)%$th)},1,100%,0,3

csswap[0] 0,15 s[0] c 

repeat 3
{w#0},{h#0},{d#0},{s#0}
f[$>] :"
begin_t(const tw="$tw";const th="$th";const twh=tw*th);
if (!(x%tw) && !(y%th),
res=vector(#twh,0);
ref(crop(x,y,tw,th),src);
for (l = 0, l<th, ++l, for (k = 0, k<tw, ++k,
off = k + tw*l;
res += src[off]*crop(#"$dct",k*tw,l*th,tw,th,1)));
draw(#-1,res,x,y,0,0,tw,th);
); i"

f. :"begin_t(const qual=1024*(1-"$q"*0.01)^3);round(i,qual)"

f. :"
begin_t(const tw="$tw";const th="$th";const twh=tw*th;res=vector(#twh));
if (!(x%tw) && !(y%th),
res=vector(#twh,0);
ref(crop(x,y,tw,th),src);
for (l = 0, l<th, ++l, for (k = 0, k<tw, ++k,
off = k + tw*l;
res += src[off]*crop(#"$idct",k*tw,l*th,tw,th,1)));
draw(#"$>",res,x,y,0,0,tw,th);
); i"
rm.
done
a[0-2] c csswap[0] 15,0
r[0] {$ww},{$hh},1,100%,0,3
endl done
rm[dct,idct]

What I would do is put $3 into $1, and then utilize vectorv($2–1) where v is size or variable that represent size to allow multiple inputs (tiles per channels). Just from your code, I can see that you need to adjust the code a lot to utilize separate tile size per channel and have the best optimum speed possible.

I don’t know what you mean by this.

I also want to specify different tile offsets for each channel so it’s as if the image has been cropped.

I’m saying that you should use vectors to do that task. $2–1 means from second variable to last variables. This makes it possible to do what you want. You can access element of vectors out of eval/fill via {($vector)[pos]} or {($vector)[pos,size]}.

1 Like