Dithering techniques

Share your advanced PureBasic knowledge/code with the community.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Dithering techniques

Post by BackupUser »

Restored from previous forum. Originally posted by El_Choni.

Along with ordered dither and Floyd-Steinberg dithering, for which you'll find examples in ImageViewer (available at Paul's site http://www.reelmediaproductions.pb/pb), there are more dithering techniques. Here are two examples of those. Both use a Hilbert curve, this is, a line which passes through all points whithout intersecting itself. They're used here for 32 to 1 bit translation.

Yes, I know, not too much useful, but fun to play with. You'll find them in next ImageViewer release.

Code: Select all

; Hilbert-Peano dithering

Declare Max(a, b)
Declare Log2(value)

#NONE = 0
#UP = 1
#LEFT = 2
#DOWN = 3
#RIGHT = 4

#SIZE = 16
#MAX = 16

Global cur_x, cur_y, img_width, img_height, img_ptr, error

Procedure dither_pixel(*pixel)
  px = PeekL(*pixel)
  px = ((px&$FF)+((px>> &$FF)+((px>>16)&$FF))/3
  pvalue = px+error
  If pvalue>=128
    pvalue = 255
  Else
    pvalue = 0
  EndIf
  error+px-pvalue
  If error>255:error-255:EndIf
  PokeL(*pixel, pvalue|(pvalue=0 And cur_x=0 And cur_ya:a = b:EndIf
  ProcedureReturn a
EndProcedure

Procedure Log2(value)
  result = 0
  While value>1
    value>>1
    result+1
  Wend
  ProcedureReturn result
EndProcedure


And Riemersma, supposed to enhance the previous technic:



; Riemersma dithering

Declare Max(a, b)
Declare Log2(value)
Declare.f Exp(value.f)

#E_NUMBER = 2.71828182 ; 2.718281819

#NONE = 0
#UP = 1
#LEFT = 2
#DOWN = 3
#RIGHT = 4

#SIZE = 16
#MAX = 16

Global cur_x, cur_y, img_width, img_height, img_ptr

Dim weights.f(#SIZE)
Dim error.f(#SIZE)

Procedure init_weights(size, max)
  m.f = Exp(Log(max)/(size-1))
  v.f = 1.0
  For i=0 To size-1
    weights(i) = v+0.5
    v*m
  Next i
EndProcedure

Procedure dither_pixel(*pixel)
  err = 0
  For i=0 To #SIZE-1
    err+(error(i)*weights(i))
  Next i
  px = PeekL(*pixel)
  px = ((px&$FF)+((px>> &$FF)+((px>>16)&$FF))/3
  pvalue = px+(err/#MAX)
  If pvalue>=128
    pvalue = 255
  Else
    pvalue = 0
  EndIf
  CopyMemory(error()+4, error(), (#SIZE-1)*4)
  error(#SIZE-1) = px-pvalue
  PokeL(*pixel, pvalue|(pvalue=0 And cur_x=0 And cur_ya:a = b:EndIf
  ProcedureReturn a
EndProcedure

Procedure Log2(value)
  result = 0
  While value>1
    value>>1
    result+1
  Wend
  ProcedureReturn result
EndProcedure

Procedure.f Exp(value.f)
  ProcedureReturn Pow(#E_NUMBER, value)
EndProcedure

Have a nice day,

El_Choni
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Jose.

Wow, cool, but I see litle difference between the two methods, is that my video card?
Thanks for sharing
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by El_Choni.

True, there is little difference. Riemersma uses limited error proliferation (uses last 16 errors, or last x errors). Hilbert-Peano uses all the previous errors.

About the Hilbert curve, here you'll find an example of how it looks like. It's supposed to work only in images which width and height are powers of two, but I've adapted it so it can be drawn on any image size (but it isn't a Hilbert curve any more, because it's cut by the borders of the image: the question is that it works):

Code: Select all

; Hilbert curve

Declare Max(a, b)
Declare Log2(value)

#NONE = 0
#UP = 1
#LEFT = 2
#DOWN = 3
#RIGHT = 4

Global cur_x, cur_y, img_width, img_height

Procedure move(direction)
  old_cur_x = cur_x
  old_cur_y = cur_y
  Select direction
    Case #LEFT
      cur_x-2
    Case #RIGHT
      cur_x+2
    Case #UP
      cur_y-2
    Case #DOWN
      cur_y+2
  EndSelect
  If cur_x>=0 And cur_x=0 And cur_ya:a = b:EndIf
  ProcedureReturn a
EndProcedure

Procedure Log2(value)
  result = 0
  While value>1
    value>>1
    result+1
  Wend
  ProcedureReturn result
EndProcedure
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Jose.

Im learning every day:)
Thanks El_Choni
Seymour Clufley
Addict
Addict
Posts: 1265
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Post by Seymour Clufley »

I'm trying to implement dithering and found this old thread.

Unfortunately this procedure has two lines that raise syntax errors:

Code: Select all

Procedure dither_pixel(*pixel) 
  px = PeekL(*pixel) 
  px = ((px&$FF)+((px>> &$FF)+((px>>16)&$FF))/3  ; ERROR
  pvalue = px+error 
  If pvalue>=128 
    pvalue = 255 
  Else 
    pvalue = 0 
  EndIf 
  error+px-pvalue 
  If error>255:error-255:EndIf 
  PokeL(*pixel, pvalue|(pvalue<< |(pvalue<<16)) ; ERROR
EndProcedure 
Does anyone know how they should be written? The second one appears to be missing a variable!
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Each of the 2 lines marked has a value missing.

E.g. in the first line px>> is expecting a value after the >> to give the number of bits to shift. You will need to look again at the original code.
I may look like a mule, but I'm not a complete ass.
Seymour Clufley
Addict
Addict
Posts: 1265
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Post by Seymour Clufley »

Well that's a bugger because it's El Choni's code, and he very rarely posts these days! I'll drop in a few numbers and see if anything looks right.
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Looks clear to me that in both cases the missing value is 8.
I may look like a mule, but I'm not a complete ass.
Post Reply