Page 1 of 2

Help converting short p5.js program to Purebasic

Posted: Mon Jul 08, 2024 10:51 pm
by matalog
I have went as far as my knowledge of p5.js will allow me to in trying to implement this code:

Code: Select all

let c     = null; //number of grey levels
let d     = null; //dimension of threshold map
let M     = null; //threshold map
let img   = null; //image reference
let img_Y = null; //bitmap array of relative luminance values of img
let img_D = null; //final dithered image

function preload() {
  //initilize constants
  c = 4;
  d = 8;
  //define threshold map
  M = [[0,32,8,40,2,34,10,42],
       [48,16,56,24,50,18,58,26],
       [12,44,4,36,14,46,6,38],
       [60,28,52,20,62,30,54,22],
       [3,35,11,43,1,33,9,41],
       [51,19,59,27,49,17,57,25],
       [15,47,7,39,13,45,5,37],
       [63,31,55,23,61,29,53,21]];
  for(let i=0; i<d; i++){
    for(let j=0; j<d; j++){
      M[i][j] = M[i][j]/(d*d); 
    }
  }
  //load image and allocate space for luminance image
  img   = loadImage("assests/mike.jpg");
  img_Y = new Array(img.width*img.height);
}

function setup() {
  //no loop canvas
  noLoop();
  pixelDensity(1);
  createCanvas(img.width,img.height);
}

function draw(){
  img_D = createImage(img.width,img.height);
  img_D.loadPixels();
  img.loadPixels();
  for(let i=0; i<img.height; i++){
    for(let j=0; j<img.width; j++){
      let idx = 4*(i*img.width+j);
      let T = M[j%d][i%d];
      img_D.pixels[idx  ] = 255*Math.floor(T+img.pixels[idx]*(c-1)/255)/(c-1);
      img_D.pixels[idx+1] = 255*Math.floor(T+img.pixels[idx+1]*(c-1)/255)/(c-1);
      img_D.pixels[idx+2] = 255*Math.floor(T+img.pixels[idx+2]*(c-1)/255)/(c-1);
      img_D.pixels[idx+3] = 255;
      }  
  }
  img_D.updatePixels();
  image(img_D,0,0);
}
From this page: https://spencerszabados.github.io/blog/ ... dithering/


This is what I have got so far:

Code: Select all

Global c=4
Global d=8
DataSection
  Data.a 0,32,8,40,2,34,10,42,                      ;  Set up bayer 8x8 array.
         48,16,56,24,50,18,58,26,
         12,44,4,36,14,46,6,38,
         60,28,52,20,62,30,54,22,
         3,35,11,43,1,33,9,41,
         51,19,59,27,49,17,57,25,
         15,47,7,39,13,45,5,37,
         63,31,55,23,61,29,53,21
EndDataSection
Dim M.f(8,8)
For y=1 To d
  For x=1 To d
    Read.a temp
    M(x,y)=temp/(8*8)
  Next
Next



#height=1000
#width=1500

UsePNGImageDecoder()  
OpenWindow(0,0,0,#width,#height,"Ordered Dithering Test")

LoadImage(2,"image.png")                 ;  Load an image to image 2 for processing - This is the source image
ImageGadget(0,0,0,ImageWidth(2),ImageHeight(2),ImageID(2))       ; Set up a gadget to display it.
SetGadgetState(0,ImageID(2))


Dim img_Y(ImageWidth(2),ImageHeight(2))  ;  I'm not sure where this is used in the code to be honest.


Dim imgnew(ImageWidth(2),ImageHeight(2)) ;  My plan is to use this array to draw the New dithered image to, 
                                         ; so that I can have the source image As the live Drawing image used With StartDrawing() 
                                         ;  to Read from And just write To the Array instead of drawing To a second image.


CreateImage(3,ImageWidth(2),ImageHeight(2))   ;  Create new image to draw dithered image to from imgnew() array after source image has been processed.


StartDrawing(ImageOutput(2))      ;  Read from Image(2)
For i=0 To ImageHeight(2)-1
  For j=1 To ImageWidth(2)-1
    idx = 4*(i*ImageWidth(2)+j)      ;  I think I will have to use a different idx method in Purebasic
    T = M(j%d,i%d)
    imgnew(j,i)=Point(j,i)           ;  For now I just copy image(2) to array imgnew()
    
                                                ;  to be honest at this stage i'm not sure how idx is used in p5.js

    
    
  Next
Next

StopDrawing()

StartDrawing(ImageOutput(3))
For y=0 To ImageHeight(2)-1
  For x=0 To ImageWidth(2)-1
    Plot(x,y,imgnew(x,y))
  Next
Next
StopDrawing()


ImageGadget(1,750,0,ImageWidth(3),ImageHeight(3),ImageID(3))       ; Set up a gadget to display image(3)
SetGadgetState(1,ImageID(3))


Repeat 
  Event = WaitWindowEvent()
  Select Event
  EndSelect
Until Event = #PB_Event_CloseWindow Or quit=#True

Any tips on how to make the last step to add dithering to the output image?

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 12:12 am
by idle
something like this but I suspect the math will be floats

Code: Select all

Structure mrgba 
  r.a
  g.a
  b.a
  a.a 
EndStructure   

Define *p.mrgba, col.l 

StartDrawing(ImageOutput(2))      ;  Read from Image(2)
For i=0 To ImageHeight(2)-1
  For j=1 To ImageWidth(2)-1
    T = M(j%d,i%d)
    col = Point(j,i) 
    *p = @col 
    *p\r = (255 * (T + *p\r * (c-1)/255)/(c-1)) & 255 
    *p\g = (255 * (T + *p\g * (c-1)/255)/(c-1)) & 255
    *p\b = (255 * (T + *p\b * (c-1)/255)/(c-1)) & 255
    *p\q = 255  
    imgnew(j,i)= col            ;  For now I just copy image(2) to array imgnew()
                                ;  to be honest at this stage i'm not sure how idx is used in p5.js
 Next
Next

StopDrawing()

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 10:04 am
by matalog
Thanks for the guidance, I don't think I would have guessed that the idx was accessing pixels rgb values!

That has left me very close to the same algorithm, but some is not quite right yet.

Image

It shouldn't have that grid pattern in it.

This is the code I am using to create this:

Code: Select all

Global c=4
Global d=8
DataSection
  Data.a 0,32,8,40,2,34,10,42,                      ;  Set up bayer 8x8 array.
         48,16,56,24,50,18,58,26,
         12,44,4,36,14,46,6,38,
         60,28,52,20,62,30,54,22,
         3,35,11,43,1,33,9,41,
         51,19,59,27,49,17,57,25,
         15,47,7,39,13,45,5,37,
         63,31,55,23,61,29,53,21
EndDataSection
Dim M.f(8,8)
For y=1 To d
  For x=1 To d
    Read.a temp
    M(x,y)=temp/(d*d)
  Next
Next


#height=1000
#width=1500

UsePNGImageDecoder()  
OpenWindow(0,0,0,#width,#height,"Ordered Dithering Test")

LoadImage(2,"car.png")                 ;  Load an image to image 2 for processing - This is the source image
ImageGadget(0,0,0,ImageWidth(2),ImageHeight(2),ImageID(2))       ; Set up a gadget to display it.
SetGadgetState(0,ImageID(2))

Dim img_Y(ImageWidth(2),ImageHeight(2))  ;  I'm not sure where this is used in the code to be honest.

Dim imgnew(ImageWidth(2),ImageHeight(2)) ;  My plan is to use this array to draw the New dithered image to, 
                                         ; so that I can have the source image As the live Drawing image used With StartDrawing() 
                                         ;  to Read from And just write To the Array instead of drawing To a second image.

CreateImage(3,ImageWidth(2),ImageHeight(2))   ;  Create new image to draw dithered image to from imgnew() array after source image has been processed.

Structure mrgb
  r.a
  g.a
  b.a
  
EndStructure   

Define *p.mrgb, col.l 

StartDrawing(ImageOutput(2))      ;  Read from Image(2)
For i=0 To ImageHeight(2)-1
  For j=1 To ImageWidth(2)-1
    T = M(j%d,i%d)
    col = Point(j,i) 
    *p = @col 
    *p\r = (255 * Round(T + *p\r * (c-1)/255,#PB_Round_Down)/(c-1)) 
    *p\g = (255 * Round(T + *p\g * (c-1)/255,#PB_Round_Down)/(c-1)) 
    *p\b = (255 * Round(T + *p\b * (c-1)/255,#PB_Round_Down)/(c-1)) 
    imgnew(j,i)= RGB(*p\r,*p\g,*p\b)      
    
  Next
Next

StopDrawing()

StartDrawing(ImageOutput(3))
For y=0 To ImageHeight(3)-1
  For x=0 To ImageWidth(3)-1
    Plot(x,y,imgnew(x,y))
  Next
Next
StopDrawing()

ImageGadget(1,ImageWidth(2),0,ImageWidth(3),ImageHeight(3),ImageID(3))       ; Set up a gadget to display image(3)
SetGadgetState(1,ImageID(3))

Repeat 
  Event = WaitWindowEvent()
  Select Event
  EndSelect
Until Event = #PB_Event_CloseWindow Or quit=#True
Any ideas on the last small difference?

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 10:45 am
by wilbert
matalog wrote: Tue Jul 09, 2024 10:04 am Any ideas on the last small difference?
Array indices are zero based.
Try this instead

Code: Select all

Dim M.f(7,7)
For y=0 To d-1
  For x=0 To d-1
    Read.a temp
    M(x,y)=temp/(d*d)
  Next
Next

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 10:58 am
by RASHAD
Try

Code: Select all

M(x,y)=temp/(16*16)
Or

Code: Select all

M(x,y)=temp/(12*12)

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 11:25 am
by RASHAD
With idle modification

Code: Select all

Global c=16
If c < 12
  c = 12
EndIf
Global d=8
If d > 8
  d = 8
EndIf
DataSection
  Data.a 0,32,8,40,2,34,10,42,                      ;  Set up bayer 8x8 array.
         48,16,56,24,50,18,58,26,
         12,44,4,36,14,46,6,38,
         60,28,52,20,62,30,54,22,
         3,35,11,43,1,33,9,41,
         51,19,59,27,49,17,57,25,
         15,47,7,39,13,45,5,37,
         63,31,55,23,61,29,53,21
EndDataSection
Dim M.f(d,d)
For y=1 To d
  For x=1 To d
    Read.a temp
    M(x,y)=temp/(c*c)
  Next
Next

#height=1000
#width=1500

UsePNGImageDecoder()  
OpenWindow(0,0,0,#width,#height,"Ordered Dithering Test")

LoadImage(2,GetTemporaryDirectory()+"girl_2.png")                 ;  Load an image to image 2 for processing - This is the source image
ImageGadget(0,0,0,ImageWidth(2),ImageHeight(2),ImageID(2))        ; Set up a gadget to display it.
SetGadgetState(0,ImageID(2))


Dim img_Y(ImageWidth(2),ImageHeight(2))  ;  I'm not sure where this is used in the code to be honest.


Dim imgnew(ImageWidth(2),ImageHeight(2)) ;  My plan is to use this array to draw the New dithered image to, 
                                         ; so that I can have the source image As the live Drawing image used With StartDrawing() 
                                         ;  to Read from And just write To the Array instead of drawing To a second image.


CreateImage(3,ImageWidth(2),ImageHeight(2))   ;  Create new image to draw dithered image to from imgnew() array after source image has been processed.

Structure mrgba 
  r.a
  g.a
  b.a
  a.a 
EndStructure   

Define *p.mrgba, col.l 

StartDrawing(ImageOutput(2))      ;  Read from Image(2)
For i=0 To ImageHeight(2)-1
  For j=0 To ImageWidth(2)-1
    T = M(j%d,i%d)
    col = Point(j,i) 
    *p = @col 
    *p\r = (255 * (T + *p\r * (c-1)/255)/(c-1)) & 255 
    *p\g = (255 * (T + *p\g * (c-1)/255)/(c-1)) & 255
    *p\b = (255 * (T + *p\b * (c-1)/255)/(c-1)) & 255
    *p\a = 255  
    imgnew(j,i)= col            ;  For now I just copy image(2) to array imgnew()
                                ;  to be honest at this stage i'm not sure how idx is used in p5.js
  Next
Next
StopDrawing()

StartDrawing(ImageOutput(3))
For y=0 To ImageHeight(2)-1
  For x=0 To ImageWidth(2)-1
    Plot(x,y,imgnew(x,y))
  Next
Next
StopDrawing()

ImageGadget(1,750,0,ImageWidth(3),ImageHeight(3),ImageID(3))       ; Set up a gadget to display image(3)
SetGadgetState(1,ImageID(3))

Repeat 
  Event = WaitWindowEvent()
  Select Event
  EndSelect
Until Event = #PB_Event_CloseWindow Or quit=#True


Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 1:01 pm
by matalog
I uploaded an image and the p5.js code to p5.js.org. The code works fine as it is described on the page, and you can see the result. It works fine with c=4 and even c=3 and c=2.

This is the result:Image
This is the result I am getting from the PB program:

Image

They are different still, I'm still missing something, this is the code, which had had the grid removed by wilbert's suggestion:

Code: Select all

Global c=4
Global d=8
DataSection
  Data.a 0,32,8,40,2,34,10,42,                      ;  Set up bayer 8x8 array.
         48,16,56,24,50,18,58,26,
         12,44,4,36,14,46,6,38,
         60,28,52,20,62,30,54,22,
         3,35,11,43,1,33,9,41,
         51,19,59,27,49,17,57,25,
         15,47,7,39,13,45,5,37,
         63,31,55,23,61,29,53,21
EndDataSection
Dim M.f(7,7)
For y=0 To d-1
  For x=0 To d-1
    Read.a temp
    M(x,y)=temp/(d*d)
  Next
Next

#height=1000
#width=1500

UsePNGImageDecoder()  
OpenWindow(0,0,0,#width,#height,"Ordered Dithering Test")

LoadImage(2,"C:\Users\mccar\Desktop\car.png")                 ;  Load an image to image 2 for processing - This is the source image
ImageGadget(0,0,0,ImageWidth(2),ImageHeight(2),ImageID(2))       ; Set up a gadget to display it.
SetGadgetState(0,ImageID(2))

Dim img_Y(ImageWidth(2),ImageHeight(2))  ;  I'm not sure where this is used in the code to be honest.

Dim imgnew(ImageWidth(2),ImageHeight(2)) ;  My plan is to use this array to draw the New dithered image to, 
                                         ; so that I can have the source image As the live Drawing image used With StartDrawing() 
                                         ;  to Read from And just write To the Array instead of drawing To a second image.

CreateImage(3,ImageWidth(2),ImageHeight(2))   ;  Create new image to draw dithered image to from imgnew() array after source image has been processed.

Structure mrgb
  r.a
  g.a
  b.a
  
EndStructure   

Define *p.mrgb, col.l 

StartDrawing(ImageOutput(2))      ;  Read from Image(2)
For i=0 To ImageHeight(2)-1
  For j=1 To ImageWidth(2)-1
    T = M(j%d,i%d)
    col = Point(j,i) 
    *p = @col 
    *p\r = (255 * Round(T + *p\r * (c-1)/255,#PB_Round_Down)/(c-1)) 
    *p\g = (255 * Round(T + *p\g * (c-1)/255,#PB_Round_Down)/(c-1)) 
    *p\b = (255 * Round(T + *p\b * (c-1)/255,#PB_Round_Down)/(c-1)) 
    imgnew(j,i)= RGB(*p\r,*p\g,*p\b)      
    
  Next
Next

StopDrawing()

StartDrawing(ImageOutput(3))
For y=0 To ImageHeight(3)-1
  For x=0 To ImageWidth(3)-1
    Plot(x,y,imgnew(x,y))
  Next
Next
StopDrawing()

ImageGadget(1,ImageWidth(2),0,ImageWidth(3),ImageHeight(3),ImageID(3))       ; Set up a gadget to display image(3)
SetGadgetState(1,ImageID(3))

Repeat 
  Event = WaitWindowEvent()
  Select Event
  EndSelect
Until Event = #PB_Event_CloseWindow Or quit=#True

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 1:35 pm
by wilbert
I looked at it some more ...
M() is an array of floats so T also needs to be defined as a float.

Code: Select all

    T.f = M(j%d,i%d)
    col = Point(j,i) 
    *p = @col 

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 1:50 pm
by matalog
wilbert wrote: Tue Jul 09, 2024 1:35 pm I looked at it some more ...
M() is an array of floats so T also needs to be defined as a float.

Code: Select all

    T.f = M(j%d,i%d)
    col = Point(j,i) 
    *p = @col 
And now it is working, thanks a lot Wilbert, and everyone else for chipping in.

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 3:41 pm
by SMaag
I guess the forumla for the dithering is wrong:

look at Wikipedia
https://en.wikipedia.org/wiki/Ordered_dithering

The Bayer matirx seems to be for Pixel values from 0..255 dircetly

newColor = (Color + r x M(x mod n, y mod n) -0.5)

I guess in this case M() should contain the % values and r is a factor to create RGB values

So if we use directly the RGB values

Code: Select all

newColor = Color + BayerValue - 127.5
and now we have to do a 0 and 255 saturation

newRed = Red(Color) + M(x,y) -127.5

if newRed < 0
  newRed = 0
ElseIf newRed >255
  newRed = 255
 Endif
  

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 3:55 pm
by SMaag
Update:

As I understand the NewColor is

newC = Color + BayerDither - DitherNormal

The Dithernormal is probably the Max(BayerDither)/2
Then we have to limit the newC to 0..255

UPDATE 20240709: 18:03 The result is much better now!

Code: Select all

EnableExplicit

Global c=16
If c < 12
  c = 12
EndIf

Global D=8
If D > 8
  D = 8
EndIf

DataSection
  BayerMatrixBase:
  Data.i  0,32, 8,40, 2,34,10,42                      ;  Set up Bayer 8x8 Matrix Array.
  Data.i 48,16,56,24,50,18,58,26
  Data.i 12,44, 4,36,14,46, 6,38
  Data.i 60,28,52,20,62,30,54,22
  Data.i  3,35,11,43, 1,33, 9,41
  Data.i 51,19,59,27,49,17,57,25
  Data.i 15,47, 7,39,13,45, 5,37
  Data.i 63,31,55,23,61,29,53,21
EndDataSection

Dim M.f(D,D)
Define.i y,x, temp

For y=1 To D
  For x=1 To D
    Read.i temp
    ; The Pixel offset value has to be calculated by 1/64 x Matrix()
    ; This results in vlaues [0 .. 63/64] but we need a symetric interval 
    ; excatly it is the halfe of 63/64 = 0.4921875 = 0.5
    M(x,y) = (temp/64 -0.4921875)  ; now we get a symetric offset from -0.4921875 to 0.4921875
    ; This Matrix Value we have to multiply later with our DitheringFactor what's normally 255/8 = 32
  Next
Next

#height=1000
#width=1500

UsePNGImageDecoder()  
UseJPEGImageDecoder()

OpenWindow(0,0,0,#width,#height,"Ordered Dithering Test")

Define ImageFile.s
;ImageFile ="Image_Panorama1.jpg"
ImageFile = GetTemporaryDirectory()+"girl_2.png"

LoadImage(2, ImageFile)                 ;  Load an image to image 2 for processing - This is the source image


ImageGadget(0,0,0,ImageWidth(2),ImageHeight(2),ImageID(2))        ; Set up a gadget to display it.
SetGadgetState(0,ImageID(2))


Dim img_Y(ImageWidth(2),ImageHeight(2))  ;  I'm not sure where this is used in the code to be honest.


Dim imgnew(ImageWidth(2),ImageHeight(2)) ;  My plan is to use this array to draw the New dithered image to, 
                                         ; so that I can have the source image As the live Drawing image used With StartDrawing() 
                                         ;  to Read from And just write To the Array instead of drawing To a second image.


CreateImage(3,ImageWidth(2),ImageHeight(2))   ;  Create new image to draw dithered image to from imgnew() array after source image has been processed.

Structure mrgba 
  r.a
  g.a
  b.a
  a.a 
EndStructure   

Define *p.mrgba, col.l 
Define.i I, J, res, BayerDither
Define.i rd,gn,bl

StartDrawing(ImageOutput(2))      ;  Read from Image(2)

Macro ColorSaturation(Value)
  If Value > 255
    Value = 255
  ElseIf Value < 0
    Value = 0
  EndIf
EndMacro


For I=0 To ImageHeight(2)-1
  For J=0 To ImageWidth(2)-1
    
    #DitherFactor = 32  ; it's probalby 256/8 ! This is the r vlaue form Wikipedia
    BayerDither = (M(J % D, I % D) * #DitherFactor)
    
    col = Point(J,I) 
    
    ; RED    
    rd =  Red(col) + BayerDither
    ColorSaturation(rd)
    
    ; GREEN    
    gn = Green(col) + BayerDither
    ColorSaturation(gn)

    ; BLUE    
    bl = Blue(col) + BayerDither
    ColorSaturation(bl)
     
    imgnew(J,I)= RGBA(rd, gn, bl, 255)            ;  For now I just copy image(2) to array imgnew()
                                ;  to be honest at this stage i'm not sure how idx is used in p5.js
  Next
Next
StopDrawing()

StartDrawing(ImageOutput(3))
For y=0 To ImageHeight(2)-1
  For x=0 To ImageWidth(2)-1
    Plot(x,y,imgnew(x,y))
  Next
Next
StopDrawing()

ImageGadget(1,750,0,ImageWidth(3),ImageHeight(3),ImageID(3))       ; Set up a gadget to display image(3)
SetGadgetState(1,ImageID(3))

Repeat 
  Define Event, quit
  Event = WaitWindowEvent()
  Select Event
  EndSelect
Until Event = #PB_Event_CloseWindow Or quit=#True

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 6:22 pm
by miskox
Just a side question:

Code: Select all

M(x,y)=temp/(d*d)
Wouldn't this be faster:

Code: Select all

M(x,y)=temp/d/d
Saso

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 9:13 pm
by wilbert
miskox wrote: Tue Jul 09, 2024 6:22 pm Wouldn't this be faster:

Code: Select all

M(x,y)=temp/d/d
No, the opposite.
A division is a lot slower as a multiplication.
If you are aiming for performance, try to avoid the division (and modulo) operator as much as possible.
In this case the M array is only 8x8 so it's not that important but if you would have a very big array, the best thing would be to calculate 1/(d*d) before the loop and multiply temp with that.

Re: Help converting short p5.js program to Purebasic

Posted: Tue Jul 09, 2024 11:49 pm
by idle
Smaggs is looking good

The previous issue with the kernel was the indices. you need to fill from 0 to d-1 before it was 1 to d and x mod 8 when x is 8 = 0

Code: Select all

Dim M.f(8,8)
For y=0 To d-1
  For x=0 To d-1
    Read.a temp
    M(x,y)=temp/(d*d)
  Next
Next

ok this seems right now, T needs to be a float

Code: Select all

Global c=4
Global d=8
DataSection
  Data.a 0,32,8,40,2,34,10,42,                      ;  Set up bayer 8x8 array.
         48,16,56,24,50,18,58,26,
         12,44,4,36,14,46,6,38,
         60,28,52,20,62,30,54,22,
         3,35,11,43,1,33,9,41,
         51,19,59,27,49,17,57,25,
         15,47,7,39,13,45,5,37,
         63,31,55,23,61,29,53,21
EndDataSection
Dim M.f(8,8)
For y=0 To d-1
  For x=0 To d-1
    Read.a temp
    M(x,y)=temp/(d*d)
  Next
Next


#height=1000
#width=1500

UsePNGImageDecoder()  
OpenWindow(0,0,0,#width,#height,"Ordered Dithering Test")

LoadImage(2,"car.png")                 ;  Load an image to image 2 for processing - This is the source image
ImageGadget(0,0,0,ImageWidth(2),ImageHeight(2),ImageID(2))       ; Set up a gadget to display it.
SetGadgetState(0,ImageID(2))

Dim img_Y(ImageWidth(2),ImageHeight(2))  ;  I'm not sure where this is used in the code to be honest.

Dim imgnew(ImageWidth(2),ImageHeight(2)) ;  My plan is to use this array to draw the New dithered image to, 
                                         ; so that I can have the source image As the live Drawing image used With StartDrawing() 
                                         ;  to Read from And just write To the Array instead of drawing To a second image.

CreateImage(3,ImageWidth(2),ImageHeight(2))   ;  Create new image to draw dithered image to from imgnew() array after source image has been processed.

Structure mrgb
  r.a
  g.a
  b.a
  a.a
EndStructure   

Define *p.mrgb, col.l,t.f 

StartDrawing(ImageOutput(2))      ;  Read from Image(2)
For i=0 To ImageHeight(2)-1
  For j=0 To ImageWidth(2)-1
    T = M(j%d,i%d)
    col = Point(j,i) 
    *p = @col 
    *p\r = (255.0 * Round(T + *p\r * (c-1)/255.0,#PB_Round_Down)/(c-1)) 
    *p\g = (255.0 * Round(T + *p\g * (c-1)/255.0,#PB_Round_Down)/(c-1)) 
    *p\b = (255.0 * Round(T + *p\b * (c-1)/255.0,#PB_Round_Down)/(c-1)) 
    *p\a = 255  
    imgnew(j,i)= RGBA(*p\r,*p\g,*p\b,255)      
    
  Next
Next

StopDrawing()

StartDrawing(ImageOutput(3))
For y=0 To ImageHeight(3)-1
  For x=0 To ImageWidth(3)-1
    Plot(x,y,imgnew(x,y))
  Next
Next
StopDrawing()

ImageGadget(1,ImageWidth(2),0,ImageWidth(3),ImageHeight(3),ImageID(3))       ; Set up a gadget to display image(3)
SetGadgetState(1,ImageID(3))

Repeat 
  Event = WaitWindowEvent()
  Select Event
  EndSelect
Until Event = #PB_Event_CloseWindow Or quit=#True


Re: Help converting short p5.js program to Purebasic

Posted: Wed Jul 10, 2024 1:50 pm
by SMaag
Step by step I understand the Bayer Dithering.
I tried to calculate the BayerMatrix with the Wikiepdia documentation but I wasn't able to do this.
It's not the best documentation and it is hard to understand. So I searched for some expamle code!
That's a horrible thing! At least I figuerd out something from a pyton and a java code. Both I did not understand.
But from the comments I was able to reconstruct a kind of algorithm.
After some try and error it works!

Code: Select all

Procedure CreateBayerMatrix(N, Array Mx(2))
  
  Protected K, X, Y, g 
  Protected d = 1 << N    ; perform 2^N
  
  Dim Mx(d-1,d-1)       ; Dim, Redim the Matrix Array
  
  Debug "Print the calculation values"
  Debug ""
  
  For Y = 0 To d-1      ; The lines   
    Debug "Line = " + Str(Y)
    
    For X = 0 To d-1    ; The line entries
      
      g=0                   ; set g = 0
      For K=0 To N-1
        g = g<<2            ; Shift g 2 bits left, because we process the 2 lowest bits in each iteration
        
        If (1<<K) & X       ; If the K'th bit of X is set
          g = g | 2         ; Set bit #1 => (g Or 2)
        EndIf
        
        If (1<<K) & Y       ; If the K'th bit of Y is set
          g = g ! 3         ; Toggle bits #0 And #1
        EndIf       
      Next
      
      Mx(X, Y) = g   
      Debug "g= " + g

    Next
  Next
EndProcedure

Dim BMx(0,0)

#MatrixBaseDimension = 3          ; 3 results in 2^3 : what is a 8x8 Matrix
CreateBayerMatrix(#MatrixBaseDimension, BMx())

Define X,Y
Debug ""
Debug "Now print the Matrix Array"
For Y=0 To ArraySize(BMx(),2)
  Debug "Line " + Str(Y+1)
  For X=0 To ArraySize(BMx(),1)
    Debug BMx(X,Y)
  Next
Next