Sign in to follow this  
Followers 0
asura

Floyd-Steinberg dithering plugin

24 posts in this topic

FloydSteinbergExample.png

Simple plugin, no options, just run it on an image or a selection. You might want to adjust contrast or levels before running this plugin for better results. The example above was dithered without any prior adjustments.

Copy the dll into the effects folder to install it.

Source:

<no longer available - EER>

Asura

FloydSteinbergEffect.zip

Edited by Ego Eram Reputo
Attached zipped dll
0

Share this post


Link to post
Share on other sites

From looking at the source code, you are calling Clone() on the input Surface every time Render() is called. Your memory usage is going to explode, causing Paint.NET to crash a lot on anything but small images.

0

Share this post


Link to post
Share on other sites

:oops: I had some troubles getting my code to run properly in CodeLab. The problem was that the dithering needs to apply changes to the source surface, and in CodeLab it seemed to apply the effect twice. By cloning it I was able to get around that problem, but I forgot to dispose the copy afterwards. Or can I just apply the changes to the source surface without disturbing any code outside my plugin?

Regards, Asura

0

Share this post


Link to post
Share on other sites

If you make changes to the source surface, you can not "undo" the changes--that is, you break the undo function.

0

Share this post


Link to post
Share on other sites

I've uploaded the corrected code and dll. It's still cloning, but now it's cleaning up after itself as well.

Asura

0

Share this post


Link to post
Share on other sites

Lovely effects but this plugin appears to be different from the others - being a .rar file. Is this usable for XP? Doesn't seem to work when I drag the .rar file into the Effects folder.

0

Share this post


Link to post
Share on other sites

rar is an archived format like zip.

Download winRar from here and use that to open the rar file. Then you will be able to extract the dll from the rar file and place it into your effects folder.

0

Share this post


Link to post
Share on other sites

whaha! this is a funny plugin! :P

the only problem is that it doens't work good with darker pictures

0

Share this post


Link to post
Share on other sites
the only problem is that it doens't work good with darker pictures

Thus his comment...

You might want to adjust contrast or levels before running this plugin for better results.
0

Share this post


Link to post
Share on other sites
The example looks like the lizard woman from hell.

If that's what hell looks like... :wink:

0

Share this post


Link to post
Share on other sites
I've uploaded the corrected code and dll. It's still cloning, but now it's cleaning up after itself as well.

So on my quad-core CPU, it's still going to require 4x the memory as the original image to run your effect :( (one active rendering thread per logical CPU, with a minimum of 2 threads)

For a 7 megapixel image that means it'd require an additional 112 MB of memory ........ are you sure this requires writing to the source? I have this same algorithm implemented for saving GIF images and it just requires two passes of analysis, but doesn't require anything like this.

0

Share this post


Link to post
Share on other sites

I don't have any experience with more than one core at a time. I always assumed that the cores would work together by sharing at least some the memory. Oh well, learning moment...

Anyway, I've kicked pretty much everything out and started again.

It's now only using its source and destination surface, assisted by a much smaller buffer, just as big as the width of the image. Memory impact will be much lower. I've tested this with a 4000x5400 image: Loading the image increased memory usage by 176MB. Starting the effect made it increase by another 92MB (which it does with any effect, not just this one). During processing memory usage grew with about 5 or 6MB and it dropped back when it was done.

I found that my original code was rather slow on larger images, so I also made the processing loop more efficient using pointers instead of the surface indexers. On the test image it took about 11 seconds. The previous version would've taken a few minutes probably...

And since I was busy anyway, I also documented the code :)

The dll and source are available at the original locations.

0

Share this post


Link to post
Share on other sites

Ahh yes, this code looks much better now. The memory you are allocating will be insignificant. If you want to optimize performance further, I of course have tons of ideas. But I think you're probably already at the break-even point where any further optimization will be a lot of work and the gains will be proportionally much smaller than what you just gained. (well maybe you could gain, say, another 50% ... but 50% of 11 seconds isn't worth as much as the 80% [or whatever] of "a few minutes" you already got)

0

Share this post


Link to post
Share on other sites

Thanks for your constructive input :D I was already happy that it was faster than the 'Edge Detect' filter, which I think is a technically similar effect.

Where do you think I could gain a bit, 50% still sounds like a lot. I know it isn't, but you've got my curiosity triggered. Pointers for navigating through the cache as well, or something like that? Or throwing in some threads for the rois that need to be rendered?

0

Share this post


Link to post
Share on other sites

Well you're allocating at the start of every call to Render(). From a performance perspective it's better to have a static [ThreadStatic] variable for your cache variable, load it once into a method variable at the start of the Render() method (retrieving a static [ThreadStatic] var is expensive), make it bigger if necessary (if rect.Width > cache.Width { cache = new Cache(rect.Width) }). That will keep the cache in the CPU cache better, and reduce a lot of pressure on the GC (garbage collector).

0

Share this post


Link to post
Share on other sites

Hmm, I've tried the static cache, but then it isn't 'clean' when the Render method is called. The image still renders in a recognizable way, but it gets polluted with noise from previous renderings. Cleaning the cache by resetting all its elements at the start of the Render method pretty much cancels out the static cache gain.

However, when I change the ColorError class to a struct it gets much faster even when I'm creating new caches every time the Render method is called. The structs are created much faster than classes, and they're instantiated automatically when I create an array. Since the default value happens to be exactly what I need, I don't need to loop through the array afterwards. According to my profiler the Floyd-Steinberg calculations are also twice as fast.

I did some performance tests with arrays of structs and arrays of classes , and the structs turned out to be much faster then the classes, with half the number of GC collections as well. An array with just one struct isn't much faster than an array with one class, but it gets better with bigger arrays. With 10000 elements it's 4 times faster, with 500000 elements it's 80x faster.

So, that sounds like a gain. I'll upload a new version later today.

0

Share this post


Link to post
Share on other sites

That's weird. The performance tests I did on the separate parts promised some gain, but when I put the whole thing together it actually works a little slower with my test image. Memory usage is lower, but the number of GC collections stays the same.

I guess there are some other forces at work...

Since it doesn't improve at all I've kept the code as it was. So no new upload, sorry.

0

Share this post


Link to post
Share on other sites

Download link is broken here is a link to download it:

 

<snip!>

Edited by david.atwell
Nope.
0

Share this post


Link to post
Share on other sites

Download link is broken here is a link to download it:

 

 

Read This Post   Only download plugins from this forum. If the link is broken don't link to outside sources. ;)

Edited by mottoman
0

Share this post


Link to post
Share on other sites

I don't have a copy of this DLL to attach.  If anyone can provide a copy - please PM me.

0

Share this post


Link to post
Share on other sites

I don't have a copy of this DLL to attach.  If anyone can provide a copy - please PM me.

 

Not one from Megalo, of course.

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0