Page 1 of 1

Dithering techniques

Posted: Fri Apr 04, 2003 6:09 am
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

Posted: Fri Apr 04, 2003 3:00 pm
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

Posted: Fri Apr 04, 2003 3:47 pm
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

Posted: Fri Apr 04, 2003 4:00 pm
by BackupUser
Restored from previous forum. Originally posted by Jose.

Im learning every day:)
Thanks El_Choni

Posted: Mon Aug 31, 2009 11:15 am
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!

Posted: Mon Aug 31, 2009 11:20 am
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.

Posted: Mon Aug 31, 2009 12:48 pm
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.

Posted: Mon Aug 31, 2009 12:52 pm
by srod
Looks clear to me that in both cases the missing value is 8.