Paint.NET

Welcome to the Paint.NET forum!
It is currently Wed Nov 25, 2009 7:31 am

All times are UTC




Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Compare pixels for similarity to source pixel.
PostPosted: Mon Nov 02, 2009 10:07 pm 
Offline
User avatar

Joined: Tue Jul 25, 2006 10:12 pm
Posts: 3118
Location: Rochester, NY
I am toying with writing a plugin that compares surrounding pixels to the source pixel.

I understand (I think) what it would take to do an exact comparison. However, what would I do to check if a pixel is similar to the source based on a user specified percentage? Would I sum the each of the channels and simply do the math?

This would assume that I already know which pixels I'm comparing.

_________________
Image
Take responsibility for your own intelligence. ;) -Rick Brewster


Top
 Profile  
 
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Mon Nov 02, 2009 10:20 pm 
Offline
2008 "WEOMPA Award" and "Howard Hughes Award for Eccentricity" (Winner?)
User avatar

Joined: Mon Nov 05, 2007 6:20 pm
Posts: 8698
Location: UK
Am I right in thinking you're not sure how the different channels should influence the comparison's result?

_________________
Image
Wave Username: simonbrown60


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Mon Nov 02, 2009 10:28 pm 
Offline
User avatar

Joined: Tue Jul 25, 2006 10:12 pm
Posts: 3118
Location: Rochester, NY
well, I know I'm only concerned with RGB, not A. I actually think that I would want each channel to have an equal effect.

My problem is as follows

Source:
R= 125
G= 69
B= 78

Total = 272

Comparison Target:
R= 45
G= 215
B= 12

Total = 272

This leads me to believe that I would need to compare each channel separately...? I imaging that this would increase the processing time greatly.

Is there a quicker alternative? Is more information needed about the desired operation?

_________________
Image
Take responsibility for your own intelligence. ;) -Rick Brewster


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Mon Nov 02, 2009 10:41 pm 
Offline
2008 "WEOMPA Award" and "Howard Hughes Award for Eccentricity" (Winner?)
User avatar

Joined: Mon Nov 05, 2007 6:20 pm
Posts: 8698
Location: UK
barkbark00 wrote:
I imaging that this would increase the processing time greatly.


Have you tried it?

_________________
Image
Wave Username: simonbrown60


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Mon Nov 02, 2009 11:26 pm 
Offline
User avatar

Joined: Tue Jul 25, 2006 10:12 pm
Posts: 3118
Location: Rochester, NY
No, I'll be trying a few things tonight when I get home...

_________________
Image
Take responsibility for your own intelligence. ;) -Rick Brewster


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Wed Nov 04, 2009 6:03 am 
Offline
User avatar

Joined: Tue Jul 25, 2006 10:12 pm
Posts: 3118
Location: Rochester, NY
Code:
            int average=0, x2=0, y2=0;
           
            if(y!=selection.Top)
            {
                x2=x;
                y2=y+1;
                CurrentPixel = src[x2,y2];
            }


Trying look at the pixel above the actual "current pixel". Getting "Coordinates out of range" error. Is what I want to do possible?

_________________
Image
Take responsibility for your own intelligence. ;) -Rick Brewster


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Wed Nov 04, 2009 7:42 am 
Offline
User avatar

Joined: Wed Nov 30, 2005 11:40 pm
Posts: 1264
Location: Middle Tennessee
yes, so long as y != selection.Bottom... GetBilinearSampleWrapped/Clamped(x,y) is the easy way out (a bit more processing but not terribly much), a bounds check is easy but repetitive.

As far as math goes:

Try finding limits on the average for the given percentage instead of finding the average then testing against limits-- i.e.

double lowerLimitR = src[,].R * (percent/100);
double upperLimitR = src[,].R * (1/ (percent/100));

Note that the values percent/100 and 1/(percent/100) can be calculated in onSetRenderInfo to save processing time. Also note that in the context of Paint.NET tolerance percent would have to be the user input percentage subtracted from 100.

Additionally, most processing time nowadays gets spent on synchronous memory calls -- allocating thousands of blocks of memory is waaay more time-consuming than calculating some math functions--for example, selection options become slower when a selection becomes complex (undefinable by a simple function) since every pixel location must be stored into memory. Thus, for something such as this (math-heavy), the processing isn't that huge an issue until you start getting to the gaussian blur level, which is on the order of radius^2 *k operations per pixel (k because I really don't remember what the code looked like when I saw it last).

If you want help writing code, I'd need to know what the result you're trying to achieve is. There's generally more than one way to do something, and your way likely isn't my way ;)

_________________
Image
Kitteh all growed up :_(


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Wed Nov 04, 2009 2:54 pm 
Offline
User avatar

Joined: Tue Jul 25, 2006 10:12 pm
Posts: 3118
Location: Rochester, NY
I'm really just trying to learn C# for making plugins. I should probably start by learning C# as a whole... ;-)

My desire is to build a kind of noise cancellation plugin that does the following:

1. Averages all of the pixels surrounding src[x,y].
Code:
//  X X X
//  X O X
//  X X X
//  O = src[x,y]
//  X = pixels to consider in average (if they exist).

2. Read a user specified decimal value (as Amount1).

3. Replace src[x,y] with with:
Code:
(src[x,y]*(1-Amount1))+(value of averaged data*Amount1))
//not quite pseudo-code...

I'm not the kind of person that has to do everything myself, so if someone can make this plugin work using simple code that I would likely understand, I will not be mad... I am more likely to learn from examples than personal failures... ;-)

_________________
Image
Take responsibility for your own intelligence. ;) -Rick Brewster


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Wed Nov 04, 2009 3:33 pm 
Offline
User avatar

Joined: Tue Jul 25, 2006 10:12 pm
Posts: 3118
Location: Rochester, NY
Sorry for double post...

The post above may seem like a different course than what I was originally describing.

This is what I wanted to do originally:

Test each of the 8 pixels immediately surrounding the src (if !null) for similarity to the src based on user defined percent/decimal value.

Keep track of how many of the surrounding pixels = !null.

Allow user to set a requirement for how many of the surround pixels (adjusted to account for the null pixels) the src has to match for it not to be considered noise.

Pixels failing the second test are replaced with the average of the pixels they did not match.
--

Anyway, the idea from my previous post came about in an attempt to simplify things for now as I "learn the ropes".

_________________
Image
Take responsibility for your own intelligence. ;) -Rick Brewster


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Wed Nov 04, 2009 6:56 pm 
Offline
User avatar

Joined: Wed Nov 30, 2005 11:40 pm
Posts: 1264
Location: Middle Tennessee
Here's your "original" source:
Code:
#region UICode
int Amount1=20;   //[0,100]Tolerance
int Amount2=1;    //[1,8]Matching pixels
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{
    ColorBgra CurrentPixel;
    byte B, G, R;
    int totalB, totalG, totalR;
    int matches;
    double lowerLimitR, lowerLimitG, lowerLimitB;
    double upperLimitR, upperLimitG, upperLimitB;
    double percent, percentInverse;
    ColorBgra[] pixels = new ColorBgra[8]; // Array for containing surrounding pixels. Indices:
    // 0 1 2
    // 3 x 4 (x is the current pixel)
    // 5 6 7
    percent = (100-Amount1)/100;
    percentInverse = 1/percent;
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            //Set limits:
            lowerLimitR = src[x,y].R * percent;
            lowerLimitG = src[x,y].G * percent;
            lowerLimitB = src[x,y].B * percent;
            upperLimitR = src[x,y].R * percentInverse;
            upperLimitG = src[x,y].G * percentInverse;
            upperLimitB = src[x,y].B * percentInverse;
            //Clear the loop variables
            totalB = 0;
            totalG = 0;
            totalR = 0;
            matches = 0;
            // Get our pixels.  Technically, you could use a kernel here,
            // But it's not worth it for 8 pixels.
            CurrentPixel = src[x,y];
            pixels[0] = src.GetBilinearSampleClamped(x-1, y-1);
            pixels[1] = src.GetBilinearSampleClamped(x  , y-1);
            pixels[2] = src.GetBilinearSampleClamped(x+1, y-1);
            pixels[3] = src.GetBilinearSampleClamped(x-1, y  );
            pixels[4] = src.GetBilinearSampleClamped(x+1, y  );
            pixels[5] = src.GetBilinearSampleClamped(x-1, y+1);
            pixels[6] = src.GetBilinearSampleClamped(x  , y+1);
            pixels[7] = src.GetBilinearSampleClamped(x+1, y+1);
            // Loop through the array and...
            foreach(ColorBgra s in pixels)
            {
                // Test if the pixel matches,
                if (s.B < upperLimitB && s.B > lowerLimitB &&
                    s.G < upperLimitG && s.G > lowerLimitG &&
                    s.R < upperLimitR && s.R > lowerLimitR)
                    matches++;
                // and add to our total that we will average if needed.
                totalB += s.B;
                totalG += s.G;
                totalR += s.R;
            }
            // Test for matches
            if (matches >= Amount2)
                dst[x,y] = CurrentPixel;
            else // Average if needed.  Using src[,].A so stuff doesn't look goofy if it is antialiased.
                dst[x,y] = ColorBgra.FromBgra(Int32Util.ClampToByte(totalB/8), Int32Util.ClampToByte(totalG/8), Int32Util.ClampToByte(totalR/8), CurrentPixel.A);
        }
    }
}


Now, notice the effect of this--it leaves a ring around any noise that is of the noise's intensity averaged with 7 pixels surrounding it. To combat this, you could, for example, make a public (technically static but codelab assumes static) boolean array (outside the Render function so that all instances of Render() can access it) of the dimensions of the selection and set that array[x,y] to true if you found noise, and then make sure that you don't repeat the dst[x,y] = ColorBgra.FromBgra(...) line if any of the surrounding pixels are true.

Edit:
Also.. you had wonderful bits about null. Remember always that null and not defined are two different things--you can define a variable as null if its type has support for a null value, however, attempting to access a variable that isn't in memory (such as something outside the bounds of an array) directly will crash the program. GetBilinearSampleClamped saves you any of the mess that is testing for constraints by simply returning the pixel closest to the point you're trying to access that exists on the given surface (think of lines going out from the defined surface that are the same pixel value as where they start on the edge).

_________________
Image
Kitteh all growed up :_(


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Wed Nov 04, 2009 9:39 pm 
Offline
User avatar

Joined: Tue Jul 25, 2006 10:12 pm
Posts: 3118
Location: Rochester, NY
Wow, this is great to see in real life...even if it doesn't do much. ;-)

I now know that my attempts were nowhere close to a working effect. Thank you very much for the code and the helpful tips/comments! I have learned quite a bit just following the effect's workflow.

I'm gonna play with this code and see if I can get it to dynamically grow the comparison region; turn it into a blur effect. lol.

EDIT:
Illnab1024 wrote:
Now, notice the effect of this--it leaves a ring around any noise that is of the noise's intensity averaged with 7 pixels surrounding it. To combat this, you could, for example, make a public (technically static but codelab assumes static) boolean array (outside the Render function so that all instances of Render() can access it) of the dimensions of the selection and set that array[x,y] to true if you found noise, and then make sure that you don't repeat the dst[x,y] = ColorBgra.FromBgra(...) line if any of the surrounding pixels are true.
Is this something that would require me to loop through the src twice? Once to identify and store the location of the noise, then a second pass to remove it without using any of the noise pixels in the averaging of surrounding pixels...

_________________
Image
Take responsibility for your own intelligence. ;) -Rick Brewster


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Thu Nov 05, 2009 12:30 am 
Offline
User avatar

Joined: Wed Nov 30, 2005 11:40 pm
Posts: 1264
Location: Middle Tennessee
Ultimately to optimize the algorithm you would have to do the matching test for the current pixel AND the 8 pixels surrounding, figure out which pixel had the least matches surrounding it, and do the noise removal (average of the pixels surrounding it) on that pixel and not any of the others. What I originally proposed is more or less stupid in that it only half-works.

_________________
Image
Kitteh all growed up :_(


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Thu Nov 05, 2009 2:28 am 
Offline
User avatar

Joined: Sat Sep 19, 2009 11:26 pm
Posts: 47
This is a really good idea! One of the problems with Eigen Blur is that it doesn't correctly handle pixels that "don't exist"... i.e. those which are white and fully transparent. I was thinking about this a week or two ago, and I presumed that the problem could be solved by weighting the contribution of each pixel by the product of the Gaussian filter's weight at that location and the pixel's alpha value, keeping track of the sum of all such weights over the window, and then dividing by the sum at the end. This would essentially be an extension of what Illnab1024 has done above. I haven't actually tested it though. I think I decided that it would yield poor results in some corner case, but I can't remember the details. You should keep experimenting with this!

By the way, a good size for 2D convolution kernels is 5x5. If you make them any larger, they will be very slow unless you separate them into a pair of 1D filters, which is a little difficult to do. Performance in the 5x5 case is roughly the same whether the filter is separated or not... I think that many things hardcode a 5x5 kernel size for this reason.

And if the size is fixed, and relatively small, you can unroll it, as Illnab1024 has done in the code above. The unrolled version will be very fast, and is still easy to understand. I'm not sure how much unrolling the compiler will do, it might depend on the machine.

_________________


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Thu Nov 05, 2009 3:16 am 
Offline
User avatar

Joined: Wed Nov 30, 2005 11:40 pm
Posts: 1264
Location: Middle Tennessee
It would make sense that as long as the amount of cycles in a loop weren't based on a dynamic variable optimization would unroll it fully.

Also, I was messing with convolution filter code a few days ago, and I don't exactly remember what I did as far as summing goes.. it was like.. ensure the sum of all elements in the kernel are 1 and then for each nonzero element, do math (summation), and then clamp to byte (either by modulo 256 or by <0 => 0, >255 => 255).

Anyway, gaussian filter code is fun. Ha.

_________________
Image
Kitteh all growed up :_(


Top
 Profile  
 
 Post subject: Re: Compare pixels for similarity to source pixel.
PostPosted: Thu Nov 05, 2009 3:19 am 
Offline
Paint.NET Lead Developer
User avatar

Joined: Tue Jul 19, 2005 6:22 pm
Posts: 8891
Location: Kirkland, WA
"Pixels that don't fully exist"

That would be any color with an alpha value of zero. If your code is correct, they will all be equivalent. But, the math gets pretty cranky especially when you're accumulating many color values to calculate 1 output color. Look at the various overloads for ColorBgra.Blend(). They will do the alpha weighting correctly.

_________________
The Paint.NET Blog: http://blog.getpaint.net/
Donations are always appreciated! http://www.getpaint.net/donate.html
Paint.NET Search Engine: http://searchpaint.net

Image


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Hosted by Forumer & phpBB

Get your Forumer™ today!

Adding a forum to your website is a great way to get return visitors.

» Get your own Free Forum!

Terms of Use

Privacy Policy

Report Abuse

Copyright © 2003-2009 Forumer. All Rights Reserved. | Copyright © paint.NET