Atkinson dither algorithm

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Atkinson dither algorithm

J. Landman Gay via use-livecode
Hi All,

I am stuck trying to make this code for Bill Atkinson
dithering algorithm much more faster.
Any ways to speed this code?
Follow the recipe and watch out for lines broken
by mail character length limit.

Recipe:

1) Import an small image (200x200 pixels) and
name it as "Image" (you could import a small
transparent png or a small jpg image)

2) Optionally, create a scrollbar type slider
with a range between 0 and 255.
Set the name of this scrollbar as "ThresholdDither"
and move the slider to 127 or 0 or 255.

3) Paste the following script in a button and
click on it to run this code:

on mouseUp

   put the millisecs into startTime
   set the cursor to busy

   put the alphadata of img "Image" into tAlphaData
   put the imagedata of img "Image" into tVar
   -- img "Image" could be a grayscale image
   -- where all 3 channels: Red, Green, Blue
   -- are identical or a color image where only
   -- the red channel is used

   delete char 1 of tVar
   -- the first char of the imagedata is part
   -- of the alphadata or maskdata
   repeat with i = 1 to length(tVar) step 4
      put chartonum(char i of tVar) & space after fldhex
   end repeat
   delete last char of fldhex -- a space
   -- fldhex now contains a single channel of the RGB image
   -- converted to numbers between 0 and 255

   put the number of words of fldhex into lenghtofldhex
   put the width of img "Image" into tImageWidth
   put the height of img "Image" into tImageHeight

   repeat with i = 1 to lenghtofldhex step tImageWidth
   -- We need as many words per line, as pixels contains
   -- the image width (because each pixel is represented
   -- by a word and this word is number between 0 and 255)

   put word i to ( i + ((tImageWidth) - 1)) of fldhex & cr after fldhexa2
   end repeat

   put empty into fldhex
   delete last char of fldhexa2
   -- deleting the last cr character

   put the number of lines of fldhexa2 into sYsize
   put the number of words of line 1 of fldhexa2 into sXsize

   // get the scrollbar value
   -- tThreshold is a value between 0 and 255
   if existence(sb the "ThresholdDither") then
   put thumbPos of sb the "ThresholdDither" into tThreshold
   else
   put 127 into tThreshold
   end if

   repeat with tY = 1 to sYsize
      repeat with tX = 1 to sXsize

         put tX into tPixelPosition

         put word (tPixelPosition) of line tY of fldhexa2 into
tOldPixelValue

         if round(tOldPixelValue) <= tThreshold then
            put 0 into tNewPixelValue
         else
            put 255 into tNewPixelValue
         end if

         put (tOldPixelValue - tNewPixelValue)/8 into tDifusionError

         -- Atkinson dither add the diffusion error
         -- to 6 adjacent pixels
         --         x o o
         --      o o o
         --         o

         put tNewPixelValue & space after fldhexa3


            if tPixelPosition < sXsize then
               put tDifusionError + word (tPixelPosition + 1) of line tY of
fldhexa2 into word (tPixelPosition + 1) of line tY of fldhexa2


              if tPixelPosition < (sXsize-1) then
                  put tDifusionError + word (tPixelPosition + 2) of line tY
of fldhexa2 into word (tPixelPosition + 2) of line tY of fldhexa2
               end if


            end if


            if tY < sYsize then


               if tPixelPosition > 1 then
                  put tDifusionError + word (tPixelPosition - 1) of line tY
+ 1 of fldhexa2 into word (tPixelPosition - 1) of line tY + 1 of fldhexa2
               end if


               put tDifusionError + word (tPixelPosition) of line tY + 1 of
fldhexa2 into word (tPixelPosition) of line tY + 1 of fldhexa2


               if tPixelPosition < sXsize then
                  put tDifusionError + word (tPixelPosition + 1)  of line
tY + 1 of fldhexa2 into word (tPixelPosition + 1) of line tY + 1 of fldhexa2
               end if


               if tY < (sYsize - 1) then
                  put tDifusionError + word (tPixelPosition) of line tY + 2
of fldhexa2 into word (tPixelPosition) of line tY + 2 of fldhexa2
               end if


            end if

      end repeat
   end repeat

   replace "0" with "00" in fldhexa3
   replace "255" with "FF" in fldhexa3

   repeat with i = 1 to the number of words of fldhexa3
      put 00 & word i of fldhexa3 & word i of fldhexa3 & word i of fldhexa3
after tVar2
   end repeat
   put binaryEncode("H*",tVar2) into tVar3

   create img
   set the height of it to the height of img "Image"
   set the width of it to the width of img "Image"
   set the imagedata of it to tVar3
   set the alphaData of it to tAlphaData

   put the millisecs - startTime && "milliseconds to create Atkinson Dither"

end mouseUp

Thanks in advance!
Al
_______________________________________________
use-livecode mailing list
[hidden email]
Please visit this url to subscribe, unsubscribe and manage your subscription preferences:
http://lists.runrev.com/mailman/listinfo/use-livecode
Reply | Threaded
Open this post in threaded view
|

Re: Atkinson dither algorithm

J. Landman Gay via use-livecode
I have posted a demo stack in the forums:
https://forums.livecode.com/viewtopic.php?f=10&t=29935

Have a nice weekend!
Al

On Sat, Oct 7, 2017 at 1:52 AM, Alejandro Tejada <[hidden email]>
wrote:

> Hi All,
>
> I am stuck trying to make this code for Bill Atkinson
> dithering algorithm much more faster.
> Any ways to speed this code?
> Follow the recipe and watch out for lines broken
> by mail character length limit.
>
> Recipe:
>
> 1) Import an small image (200x200 pixels) and
> name it as "Image" (you could import a small
> transparent png or a small jpg image)
>
> 2) Optionally, create a scrollbar type slider
> with a range between 0 and 255.
> Set the name of this scrollbar as "ThresholdDither"
> and move the slider to 127 or 0 or 255.
>
> 3) Paste the following script in a button and
> click on it to run this code:
>
> on mouseUp
>
>    put the millisecs into startTime
>    set the cursor to busy
>
>    put the alphadata of img "Image" into tAlphaData
>    put the imagedata of img "Image" into tVar
>    -- img "Image" could be a grayscale image
>    -- where all 3 channels: Red, Green, Blue
>    -- are identical or a color image where only
>    -- the red channel is used
>
>    delete char 1 of tVar
>    -- the first char of the imagedata is part
>    -- of the alphadata or maskdata
>    repeat with i = 1 to length(tVar) step 4
>       put chartonum(char i of tVar) & space after fldhex
>    end repeat
>    delete last char of fldhex -- a space
>    -- fldhex now contains a single channel of the RGB image
>    -- converted to numbers between 0 and 255
>
>    put the number of words of fldhex into lenghtofldhex
>    put the width of img "Image" into tImageWidth
>    put the height of img "Image" into tImageHeight
>
>    repeat with i = 1 to lenghtofldhex step tImageWidth
>    -- We need as many words per line, as pixels contains
>    -- the image width (because each pixel is represented
>    -- by a word and this word is number between 0 and 255)
>
>    put word i to ( i + ((tImageWidth) - 1)) of fldhex & cr after fldhexa2
>    end repeat
>
>    put empty into fldhex
>    delete last char of fldhexa2
>    -- deleting the last cr character
>
>    put the number of lines of fldhexa2 into sYsize
>    put the number of words of line 1 of fldhexa2 into sXsize
>
>    // get the scrollbar value
>    -- tThreshold is a value between 0 and 255
>    if existence(sb the "ThresholdDither") then
>    put thumbPos of sb the "ThresholdDither" into tThreshold
>    else
>    put 127 into tThreshold
>    end if
>
>    repeat with tY = 1 to sYsize
>       repeat with tX = 1 to sXsize
>
>          put tX into tPixelPosition
>
>          put word (tPixelPosition) of line tY of fldhexa2 into
> tOldPixelValue
>
>          if round(tOldPixelValue) <= tThreshold then
>             put 0 into tNewPixelValue
>          else
>             put 255 into tNewPixelValue
>          end if
>
>          put (tOldPixelValue - tNewPixelValue)/8 into tDifusionError
>
>          -- Atkinson dither add the diffusion error
>          -- to 6 adjacent pixels
>          --         x o o
>          --      o o o
>          --         o
>
>          put tNewPixelValue & space after fldhexa3
>
>
>             if tPixelPosition < sXsize then
>                put tDifusionError + word (tPixelPosition + 1) of line tY
> of fldhexa2 into word (tPixelPosition + 1) of line tY of fldhexa2
>
>
>               if tPixelPosition < (sXsize-1) then
>                   put tDifusionError + word (tPixelPosition + 2) of line
> tY of fldhexa2 into word (tPixelPosition + 2) of line tY of fldhexa2
>                end if
>
>
>             end if
>
>
>             if tY < sYsize then
>
>
>                if tPixelPosition > 1 then
>                   put tDifusionError + word (tPixelPosition - 1) of line
> tY + 1 of fldhexa2 into word (tPixelPosition - 1) of line tY + 1 of fldhexa2
>                end if
>
>
>                put tDifusionError + word (tPixelPosition) of line tY + 1
> of fldhexa2 into word (tPixelPosition) of line tY + 1 of fldhexa2
>
>
>                if tPixelPosition < sXsize then
>                   put tDifusionError + word (tPixelPosition + 1)  of line
> tY + 1 of fldhexa2 into word (tPixelPosition + 1) of line tY + 1 of fldhexa2
>                end if
>
>
>                if tY < (sYsize - 1) then
>                   put tDifusionError + word (tPixelPosition) of line tY +
> 2 of fldhexa2 into word (tPixelPosition) of line tY + 2 of fldhexa2
>                end if
>
>
>             end if
>
>       end repeat
>    end repeat
>
>    replace "0" with "00" in fldhexa3
>    replace "255" with "FF" in fldhexa3
>
>    repeat with i = 1 to the number of words of fldhexa3
>       put 00 & word i of fldhexa3 & word i of fldhexa3 & word i of
> fldhexa3 after tVar2
>    end repeat
>    put binaryEncode("H*",tVar2) into tVar3
>
>    create img
>    set the height of it to the height of img "Image"
>    set the width of it to the width of img "Image"
>    set the imagedata of it to tVar3
>    set the alphaData of it to tAlphaData
>
>    put the millisecs - startTime && "milliseconds to create Atkinson
> Dither"
>
> end mouseUp
>
> Thanks in advance!
> Al
>
>
>
_______________________________________________
use-livecode mailing list
[hidden email]
Please visit this url to subscribe, unsubscribe and manage your subscription preferences:
http://lists.runrev.com/mailman/listinfo/use-livecode
Reply | Threaded
Open this post in threaded view
|

Re: Atkinson dither algorithm

J. Landman Gay via use-livecode
In reply to this post by J. Landman Gay via use-livecode
Hi Al,

I already posted on the forums, but for completeness also here:

a lot can be done by replacing repeat with with repeat for each where you can.

 --    repeat with i = 1 to the number of words of fldhexa3
   --       put 00 & word i of fldhexa3 & word i of fldhexa3 & word i of fldhexa3 after tVar2
   --    end repeat

   repeat for each word theWord in fldhexa3
      put 00 & theword & theword & theword after tVar2
   end repeat


A sidenode:

I always use strict compile mode, therefore I added the needed variable declarations and noticed you use startTime as a variablename, which is a reserved keyword. That is not a good idea.  (I noticed, because I managed to freeze liveCode where I fixed only half of the use of startTime. Booom.)

Cheers,

malte
_______________________________________________
use-livecode mailing list
[hidden email]
Please visit this url to subscribe, unsubscribe and manage your subscription preferences:
http://lists.runrev.com/mailman/listinfo/use-livecode
Reply | Threaded
Open this post in threaded view
|

Re: Atkinson dither algorithm

J. Landman Gay via use-livecode
In reply to this post by J. Landman Gay via use-livecode
Hi Malte,

Malte Brill wrote:
> I already posted on the forums, but for completeness also here:
> a lot can be done by replacing repeat with with repeat for each where you
can.
>
> --    repeat with i = 1 to the number of words of fldhexa3
> --    put 00 & word i of fldhexa3 & word i of fldhexa3 & word i of
fldhexa3 after tVar2
> --    end repeat
>
> repeat for each word theWord in fldhexa3
>  put 00 & theword & theword & theword after tVar2
> end repeat

This change reduced the time in a 25%!
Wonderful. Thanks a lot Malte :-D

> I always use strict compile mode, therefore I added the needed variable
> declarations and noticed you use startTime as a variablename, which is a
> reserved keyword. That is not a good idea.  (I noticed, because I managed
to
> freeze liveCode where I fixed only half of the use of startTime. Booom.)

startTime is a property of media players, so I am surprised that
LiveCode do not warn me about this. :-o

Also, I will try others less complex and simpler dithering algorithms as
Floyd-Steinberg and Sierra Lite to measure total time differences.

http://www.tannerhelland.com/4660/dithering-eleven-algorithms-source-code/

Malte, Thanks again for taking a look and improve this code!
Have a nice weekend!

Al
_______________________________________________
use-livecode mailing list
[hidden email]
Please visit this url to subscribe, unsubscribe and manage your subscription preferences:
http://lists.runrev.com/mailman/listinfo/use-livecode