MJW Posted November 30, 2008 Share Posted November 30, 2008 Here's a CodeLab plugin I wrote to average the color over a selection. I realize it's pretty simple, and could probably be done more efficiently, but it was useful to me, and may be useful to someone else. #region UICode #endregion // The sums may overflow if the selection contains more than 16 MB pixels. // The solution would be to use doubles for r, g, and b. private bool firstTime = true; private ColorBgra averageColor = new ColorBgra(); void Render(Surface dst, Surface src, Rectangle rect) { PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds); Rectangle selection = selectionRegion.GetBoundsInt(); ColorBgra CurrentPixel; if (firstTime) { uint r = 0, g = 0, b = 0, n = 0; firstTime = false; for (int y = selection.Top; y < selection.Bottom; y++) { for (int x = selection.Left; x < selection.Right; x++) { if (selectionRegion.IsVisible(x, y)) { CurrentPixel = src[x, y]; b += CurrentPixel.B; g += CurrentPixel.G; r += CurrentPixel.R; n++; } } } if (n > 0) { double recipN = 1.0 / (double)n; averageColor = ColorBgra.FromBgr((byte)(recipN * (double)b + 0.5), (byte)(recipN * (double)g + 0.5), (byte)(recipN * (double)r + 0.5)); } } for (int y = rect.Top; y < rect.Bottom; y++) { for (int x = rect.Left; x < rect.Right; x++) { averageColor.A = src[x, y].A; dst[x, y] = averageColor; } } } ---ADDED DEC 1, 2008--- Here is a pre-built DLL. It's the same as the version in my first reply. It has an icon, and uses ulongs instead of uints to sum r, g, b, so there's no overflow problem with very large selections. AverageSelectionColor.zip ---ADDED NOV 20, 2009--- Here is a new version (1.2), which I believe will behave correctly on multiple core systems. The old version could potentially give incorrect results due to a race condition between threads running on different cores. This is discussed in detail here. (I don't have a multiple-core system, so I wasn't able to test whether the fix achieved its purpose.) I also made another slight change. I renamed the effect "Average Color (RGB)" for two reasons. First, I thought the name "Average Color of Selection" was unnecessarily wordy; and second, Neil Cassidy has written a similar effect that works in HSL space called "Average Color (HSL)" so I thought it'd be nice to have parallel names. ---ADDED NOV 21, 2009--- I realized there was a problem for multicore systems with the way I handled the alpha value. I fixed it, and downloaded the corrected version. Since the file had only been downloaded once, I decided not to change the version number, which is still 1.2. AverageColorOfSelection1.2.zip Quote Link to comment Share on other sites More sharing options...
Simon Brown Posted November 30, 2008 Share Posted November 30, 2008 Not everyone has CodeLab, as most users have no interest in writing plugins - so here is the DLL. ACoS.zip Quote Link to comment Share on other sites More sharing options...
pyrochild Posted November 30, 2008 Share Posted November 30, 2008 What is CodLab? Is it some sort of scientific facility dedicated to ... fish? If data size is a concern, why not use ulongs rather than uints for r, g, and b? Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
MJW Posted December 1, 2008 Author Share Posted December 1, 2008 Thanks to Simon Brown for making a DLL version. I tend to forget that not everyone has -- or wants to have -- CodeLab. As to why I used uints instead of ulongs, it's mostly that I didn't think of it. The 16 megapixel limitation didn't seem significant when I wrote the routine, since I'm very unlikely to use selections that are that big. Just before I posted it, I decided I ought to mention the limitation in a comment. Since ulongs would be better, I've included a new version of the DLL using ulongs instead of uints. I also added a little icon. I haven't tried uploading a file before, so I've got my fingers crossed. AverageSelectionColor.zip I'm curious as to why "isVisible" is the test for whether a pixel is selected. I thought maybe there'd be an "isSelected" property, but there wasn't. Does anyone know if "isVisible" is only testing for whether the pixel is selected, or if not, whether there's a more direct test for selection? Also, I edited the title to omit the CodeLab (or CodLab) part, since with the availability of the DLL it really doesn't matter. Quote Link to comment Share on other sites More sharing options...
david.atwell Posted December 1, 2008 Share Posted December 1, 2008 Also, is there someway I can edit the title to say CodeLab instead of CodLab? There's a little button near the bottom of your post that looks like this: Hit that, and you can change anything in your post. :-) Quote The Doctor: There was a goblin, or a trickster, or a warrior... A nameless, terrible thing, soaked in the blood of a billion galaxies. The most feared being in all the cosmos. And nothing could stop it, or hold it, or reason with it. One day it would just drop out of the sky and tear down your world.Amy: But how did it end up in there?The Doctor: You know fairy tales. A good wizard tricked it.River Song: I hate good wizards in fairy tales; they always turn out to be him. Link to comment Share on other sites More sharing options...
MJW Posted December 1, 2008 Author Share Posted December 1, 2008 Thanks David. I've edited the title to be less fishy. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted December 1, 2008 Share Posted December 1, 2008 I'm curious as to why "isVisible" is the test for whether a pixel is selected. I thought maybe there'd be an "isSelected" property, but there wasn't. Does anyone know if "isVisible" is only testing for whether the pixel is selected, or if not, whether there's a more direct test for selection? IsVisible = is visible in the selection. You can remove this check altogether. Paint.NET won't be passing non-selected pixels to your plugin at all, and this check is redundant (and slow). Thanks David. I've edited the title to be less fishy. I see what you did thar. Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
MJW Posted December 1, 2008 Author Share Posted December 1, 2008 isVisible = is visible in the selection. You can remove this check altogether. Paint.NET won't be passing non-selected pixels to your plugin at all, and this check is redundant (and slow). I don't see how the "isVisible" check can be removed. I can see why it's not needed on the output side (which is why I didn't include it), since Paint.NET only sends updated pixels to the selected region. But when I'm computing the average color, I only want to average pixels that are actually within the selection. The loop is operating over a bounding rectangle for the selection (defined by selection.Left, etc.), so for non-rectangular selections some sort of extra test is needed to exclude pixels that lie within the rectangle but outside the selection. Let me add (via an edit) that it seems to me that without the test, the pixel count, n, would always be (selection.Right - selection.Left) * (selection.Bottom - selection.Top), which certainly won't work. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted December 1, 2008 Share Posted December 1, 2008 If the selection is non-rectangular, Paint.NET splits it into dozens or hundreds of rectangular selections. The regions passed to your CodeLab script are guaranteed to be in the selection. By calculating the entire selection's average color every time one of these sub-selections is given to your plugin, you're making it do a lot more work than it needs to. You only need to calculate the selection's average once. In this version of CodeLab, though, it's kind of unavoidable. (Older versions had a "hack"...) Still, to only even bother looking at the selections pixels, and never need to call IsVisible, use selection.getregionscansint() (or something like that) which returns the array of rectangles that defines the selection. Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
MJW Posted December 1, 2008 Author Share Posted December 1, 2008 If the selection is non-rectangular, Paint.NET splits it into dozens or hundreds of rectangular selections. The regions passed to your CodeLab script are guaranteed to be in the selection. But the part of the code that uses the isVisible test isn't the output loop; it's the section that calculates the average. And that's got to be done for all the selected pixels, not just those that fall within the specific slice that the call is responsible for outputting. The only way I can see to know which pixels to include is with the isVisible calls. By calculating the entire selection's average color every time one of these sub-selections is given to your plugin, you're making it do a lot more work than it needs to. You only need to calculate the selection's average once. In this version of CodeLab, though, it's kind of unavoidable. The purpose of the global firstTime flag is to avoid recalculating the average each time a new slice is passed. I'm almost certain the purpose is achieved, since I tested the method with the following routine: #region UICode #endregion private byte r = 255, g = 255, b = 255; void Render(Surface dst, Surface src, Rectangle rect) { for (int y = rect.Top; y < rect.Bottom; y++) { for (int x = rect.Left; x < rect.Right; x++) { dst[x,y] = ColorBgra.FromBgra(b, g, r, 255); } } if (r < 250) { r += 50; } else { r = 0; if (g < 250) { g += 50; } else { g = 0; if (b < 250) { b += 50; } else { b = 0; } } } } When I run this under CodeLab or as the generated DLL, the result is a bunch of different colored stripes, with a single white (255, 255, 255) stripe. This shows the r, g, b values are reset for the first slice, and then maintain their previous values for subsequent slices. In the color averaging plugin, firstTime is true when the first slice is rendered, so the average color is computed and stored in a global variable, and firstTime is set to false. On subsequent slices, firstTime is false, so the average isn't recomputed. (BTW, I didn't come up with the idea of using a global flag. It was contained in a comment by Curtis in a thread which was was, coincidentally, on the very same subject of computing the average color. Unfortunately, the example given, while very efficient, wasn't very flexible, since it always computed the average for the entire image.) Quote Link to comment Share on other sites More sharing options...
Ash Posted December 1, 2008 Share Posted December 1, 2008 Please put your file and any new updates in the 1st post. Thanks. Quote All creations Ash + Paint.NET [ Googlepage | deviantArt | Club PDN | PDN Fan ] Link to comment Share on other sites More sharing options...
JamesCameronBlogspot Posted September 4, 2009 Share Posted September 4, 2009 I just wanted to recognize all of your guys' work. I installed Paint.net a few months ago (at the suggestion of my brother), but I'm just starting to use it now, and it's great. Thanks for all the plug-ins (I just downloaded "Average Color") and, then, for the tutorial on how to actually install them. Between Firefox, OpenOffice, Paint.net, and about five other programs I've got, I always feel blessed and grateful for all the coders who work on opensource projects. For people with limited financial resources (like me), they're just a complete lifesaver. (One small suggestion: when you're resizing a selected image, ideally there'd be an option where you could lock in the proportions - so that the width-to-height ratio remains the same - because, right now, I'm eyeballing it.) Thank you all so much. Quote Link to comment Share on other sites More sharing options...
BoltBait Posted September 4, 2009 Share Posted September 4, 2009 (One small suggestion: when you're resizing a selected image, ideally there'd be an option where you could lock in the proportions - so that the width-to-height ratio remains the same - because, right now, I'm eyeballing it.) Hold down the shift key when resizing. Quote Click to play: Download: BoltBait's Plugin Pack | CodeLab | and how about a Computer Dominos Game Link to comment Share on other sites More sharing options...
JamesCameronBlogspot Posted November 25, 2009 Share Posted November 25, 2009 Hold down the shift key when resizing. Thanks a lot. Quote Link to comment Share on other sites More sharing options...
jsoba77 Posted April 15, 2022 Share Posted April 15, 2022 (edited) On 11/30/2008 at 10:14 AM, MJW said: Here's a CodeLab plugin I wrote to average the color over a selection. I realize it's pretty simple, and could probably be done more efficiently, but it was useful to me, and may be useful to someone else. #region UICode #endregion // The sums may overflow if the selection contains more than 16 MB pixels. // The solution would be to use doubles for r, g, and b. private bool firstTime = true; private ColorBgra averageColor = new ColorBgra(); void Render(Surface dst, Surface src, Rectangle rect) { PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds); Rectangle selection = selectionRegion.GetBoundsInt(); ColorBgra CurrentPixel; if (firstTime) { uint r = 0, g = 0, b = 0, n = 0; firstTime = false; for (int y = selection.Top; y < selection.Bottom; y++) { for (int x = selection.Left; x < selection.Right; x++) { if (selectionRegion.IsVisible(x, y)) { CurrentPixel = src[x, y]; b += CurrentPixel.B; g += CurrentPixel.G; r += CurrentPixel.R; n++; } } } if (n > 0) { double recipN = 1.0 / (double)n; averageColor = ColorBgra.FromBgr((byte)(recipN * (double)b + 0.5), (byte)(recipN * (double)g + 0.5), (byte)(recipN * (double)r + 0.5)); } } for (int y = rect.Top; y < rect.Bottom; y++) { for (int x = rect.Left; x < rect.Right; x++) { averageColor.A = src[x, y].A; dst[x, y] = averageColor; } } } ---ADDED DEC 1, 2008--- Here is a pre-built DLL. It's the same as the version in my first reply. It has an icon, and uses ulongs instead of uints to sum r, g, b, so there's no overflow problem with very large selections. AverageSelectionColor.zip 4.19 kB · 3,493 downloads ---ADDED NOV 20, 2009--- Here is a new version (1.2), which I believe will behave correctly on multiple core systems. The old version could potentially give incorrect results due to a race condition between threads running on different cores. This is discussed in detail here. (I don't have a multiple-core system, so I wasn't able to test whether the fix achieved its purpose.) I also made another slight change. I renamed the effect "Average Color (RGB)" for two reasons. First, I thought the name "Average Color of Selection" was unnecessarily wordy; and second, Neil Cassidy has written a similar effect that works in HSL space called "Average Color (HSL)" so I thought it'd be nice to have parallel names. ---ADDED NOV 21, 2009--- I realized there was a problem for multicore systems with the way I handled the alpha value. I fixed it, and downloaded the corrected version. Since the file had only been downloaded once, I decided not to change the version number, which is still 1.2. AverageSelectionColor1.2.zip 4.33 kB · 3,540 downloads Hey mate, is there an updated link for this as the download seems corrupt Thanks This is what downloads instead Edited April 15, 2022 by jsoba77 1 Quote Link to comment Share on other sites More sharing options...
ardneh Posted April 15, 2022 Share Posted April 15, 2022 Rename the downloaded file to: AverageSelectionColor.zip 2 Quote Link to comment Share on other sites More sharing options...
MJW Posted April 15, 2022 Author Share Posted April 15, 2022 5 hours ago, jsoba77 said: Hey mate, is there an updated link for this as the download seems corrupt Thanks. I downloaded, renamed it, then uploaded the renamed version. I hope it has the correct name now. I have no idea why the filename was changed to that random string of letters. 1 Quote Link to comment Share on other sites More sharing options...
jsoba77 Posted April 16, 2022 Share Posted April 16, 2022 23 hours ago, ardneh said: Rename the downloaded file to: AverageSelectionColor.zip 18 hours ago, MJW said: Thanks. I downloaded, renamed it, then uploaded the renamed version. I hope it has the correct name now. I have no idea why the filename was changed to that random string of letters. Thanks a lot guys Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.