# Point Blur Effect

## Recommended Posts

Hello everyone,

I'm back. Not with some easy to make image. No, I've got something you might actually use: Point Blur.

Point Blur is a simple effect, doing the reverse of Zoom Blur. Whereas Zoom Blur blurs away from a certain point, Point Blur blurs to this point, hence Point Blur.

A couple of therms used in replies:

Point: the pixel, user defined, that's the centre of the point blur.

Current pixel: a plugin steps through each pixel, the "current pixel" is the pixel, he is calculating the colour for.

Step loop: the loop used to step through the pixels between current pixel and point.

A glance under the hood, requires some knowledge of mathematics:

Point Blur works by averaging the colours of the pixels in the line of that pixel and the point chosen.

For example:

Current Pixel = 0,0 (Coordinates (X,Y))

Point Chosen = 3,0

Pixel 1,0 = Black

Pixel 2,0 = White

Current Pixel is the average of the colours of the pixels in the line of itself and the point chosen (1,0 and 2,0), so it will be gray. Not all pixels are so simple, but with some application of trigonometric functions, it works.

The new render method uses the distance from the current pixel to affect the colour; longer distance, less effect on current pixel.

Enjoy.

Source:

Spoiler
```using System.Collections.Generic;
using System.Drawing;
using PaintDotNet;
using PaintDotNet.Effects;
using PaintDotNet.IndirectUI;
using PaintDotNet.PropertySystem;
using System;

namespace PointBlur
{
public class PointBlur : PropertyBasedEffect
{
public static string StaticName { get { return "Point Blur"; } }

public static Bitmap StaticImage { get { return new Bitmap(16, 16); } }

public enum PropertyNames
{
Point,
Length,
AlphaMultiplier,
Quality,
Old
}

public PointBlur()
{

}
//Properties from UI
protected override PropertyCollection OnCreatePropertyCollection()
{
List<Property> props = new List<Property>();
props.Add(new DoubleVectorProperty(PropertyNames.Point, new Pair<double, double>(0, 0), new Pair<double, double>(-1, -1), new Pair<double, double>(1, 1)));
return new PropertyCollection(props);
}
//UI Creation (using IndirectUI)
protected override ControlInfo OnCreateConfigUI(PropertyCollection props)
{
ControlInfo configUI = CreateDefaultConfigUI(props);
ImageResource img = ImageResource.FromImage(EnvironmentParameters.SourceSurface.CreateAliasedBitmap());
configUI.SetPropertyControlValue(PropertyNames.Point, ControlInfoPropertyNames.DisplayName, "Set convention point");
configUI.SetPropertyControlValue(PropertyNames.Point, ControlInfoPropertyNames.StaticImageUnderlay, img);

configUI.SetPropertyControlValue(PropertyNames.Length, ControlInfoPropertyNames.DisplayName, "Blur length");

configUI.SetPropertyControlValue(PropertyNames.Quality, ControlInfoPropertyNames.DisplayName, "Quality");

configUI.SetPropertyControlValue(PropertyNames.AlphaMultiplier, ControlInfoPropertyNames.DisplayName, "Alpha Multiplier");

configUI.SetPropertyControlValue(PropertyNames.Old, ControlInfoPropertyNames.DisplayName, "Old");

configUI.SetPropertyControlValue(PropertyNames.Old, ControlInfoPropertyNames.Description, "Render method selection, new one has higher quality (Old ignores Alpha Multiplier).");
return configUI;
}
//Variables used in code
Point point;
int length;
double quality;
bool old;
double alphaMultiplier;
//Receiving variables used
protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
{
Pair<double, double> tempPoint = (Pair<double, double>)newToken.GetProperty(PropertyNames.Point).Value;

Rectangle bounds = EnvironmentParameters.GetSelection(EnvironmentParameters.SourceSurface.Bounds).GetBoundsInt();

double x = ((tempPoint.First + 1) * bounds.Width / 2) + bounds.Left;
double y = ((tempPoint.Second + 1) * bounds.Height / 2) + bounds.Top;

point = new Point((int)x, (int)y);

length = (int)newToken.GetProperty(PropertyNames.Length).Value;

quality = (double)((double)1 / (int)newToken.GetProperty(PropertyNames.Quality).Value);

alphaMultiplier = (double)newToken.GetProperty(PropertyNames.AlphaMultiplier).Value;

old = (bool)newToken.GetProperty(PropertyNames.Old).Value;
base.OnSetRenderInfo(newToken, dstArgs, srcArgs);
}
//Starting the render
protected unsafe override void OnRender(Rectangle[] rois, int startIndex, int length)
{
for (int i = startIndex; i < startIndex + length; ++i)
{
Rectangle rect = rois[i];
if (old)
RenderOld(DstArgs.Surface, SrcArgs.Surface, rect);
else
RenderNew(DstArgs.Surface, SrcArgs.Surface, rect);
}
}
//The old render method
void RenderOld(Surface dst, Surface src, Rectangle rect)
{
Rectangle selection = EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();
for (int y = rect.Top; y < rect.Bottom; y++)
{
for (int x = rect.Left; x < rect.Right; x++)
{
//Angle from current pixel to point
double angle = Math.Atan2(point.Y - y, point.X - x);
angle = (Math.PI * 1.5) - angle;
//The colours used (all pixels colours between current pixel and point are added up to each other and stored in this array, later divided to end up with an average)
double[] colors = new double[4];
//The number I divide with (the plural is a remnant of a bad thought, removed by debugging)
double dividers = 0;

//Looping through pixels between current pixel and point (quality = 1/(quality from UI))
for (double i = 1; i < length; i += quality)
{
//Pixel coords of which colours are added up
int xPix = (int)((Math.Sin(angle) * i) + x).Clamp(src.Bounds.Left, src.Bounds.Right - 1);
int yPix = (int)((Math.Cos(angle) * i) + y).Clamp(src.Bounds.Top, src.Bounds.Bottom - 1);

colors[0] += src[xPix, yPix].A;
colors[1] += src[xPix, yPix].R;
colors[2] += src[xPix, yPix].B;
colors[3] += src[xPix, yPix].G;
dividers++;
}
ColorBgra pixel = new ColorBgra();
double color = colors[0] / dividers;
pixel.A = (byte)color;
color = colors[1] / dividers;
pixel.R = (byte)color;
color = colors[2] / dividers;
pixel.B = (byte)color;
color = colors[3] / dividers;
pixel.G = (byte)color;
dst[x, y] = pixel;
}
}
}

//The new render method
void RenderNew(Surface dst, Surface src, Rectangle rect)
{
Rectangle selection = EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();
for (int y = rect.Top; y < rect.Bottom; y++)
{
for (int x = rect.Left; x < rect.Right; x++)
{
//Angle from current pixel to point
double angle = Math.Atan2(point.Y - y, point.X - x);
angle = (Math.PI * 1.5) - angle;
//The colours used (all pixels colours between current pixel and point are added up to each other and stored in this array, later divided to end up with an average)
double[] colors = new double[4];
//The number I divide with (the plural is a remnant of a bad thought, removed by debugging)
double dividers = 0;

//Looping through pixels between current pixel and point (quality = 1/(quality from UI))
for (double i = 1; i < length; i += quality)
{
//Pixel coords of which colours are added up
int xPix = (int)((Math.Sin(angle) * i) + x).Clamp(src.Bounds.Left, src.Bounds.Right - 1);
int yPix = (int)((Math.Cos(angle) * i) + y).Clamp(src.Bounds.Top, src.Bounds.Bottom - 1);
double multiplier = length - i;

colors[0] += src[xPix, yPix].A * multiplier;
colors[1] += src[xPix, yPix].R * multiplier;
colors[2] += src[xPix, yPix].B * multiplier;
colors[3] += src[xPix, yPix].G * multiplier;
dividers += multiplier;
}
ColorBgra pixel = new ColorBgra();
double color = colors[0] * alphaMultiplier / dividers;
pixel.A = (byte)color.Clamp(0, 255);
color = colors[1] / dividers;
pixel.R = (byte)color;
color = colors[2] / dividers;
pixel.B = (byte)color;
color = colors[3] / dividers;
pixel.G = (byte)color;
dst[x, y] = pixel;
}
}
}
}
}```

History repeats itself, because nobody was paying attention the first time.

##### Share on other sites

Most excellent. Thanks.

##### Share on other sites

I like this idea. Many thanks!

Knowledge is no burden to carry.

April Jones, 2012

##### Share on other sites

Thank you so much for this! I had been hoping for a blur that actually blur to a vanishing point! Nice name for the plug-in!

Officially retired from this forum. Have a nice day.

##### Share on other sites

Thanks guys, this plugin was the reason I started learning C#. I missed it, so now we're united.

If anyone has any functions, he would look to see implemented in the plugin, feel free to ask.

BTW, if anyone would like a look at the source, feel free to ask. Note: no comments.

Edited by Boude

History repeats itself, because nobody was paying attention the first time.

##### Share on other sites

Nice plug in Boude. Works a treat.

Please feel free to visit my Gallery on PDNFans

And my Alternatives to PDN

##### Share on other sites

If i may say so,

This is quite sexy. No lie.

##### Share on other sites

If i may say so,

This is quite sexy. No lie.

i agree

##### Share on other sites

Nice. I'd love to peek at the source...

##### Share on other sites

Ok guys, thanks for your great response. I might add some functions this weekend, if I have nothing better to do. (Surprisingly I also have a life)

@n d: Source added, even some comments (lucky guy). I don't know how experienced you're with C#, so if you've any questions, feel free to ask.

I actually copied half my code from MadJik's codelab to indirectUI (somewhere in plugin development), so you might want to take a sneak peak there as well.

History repeats itself, because nobody was paying attention the first time.

##### Share on other sites

You dont get the point correctly  i got a screenie bout it

this:

```double x = (tempPoint.First + 1) * bounds.Width / 2;
double y = (tempPoint.Second + 1) * bounds.Height / 2;
```

should be more like:

```double x = ((tempPoint.First + 1) * bounds.Width / 2) + bounds.Left;
double y = ((tempPoint.Second + 1) * bounds.Height / 2) + bounds.Top;
```

i think

##### Share on other sites

@Cookies: Thanks for pointing that out. Will fix it on next update.

After some research and another mind destroying one hour trip in the tube, I came across something one might call a bug (no errors, don't worry). On next update distance from pixel in the "step loop" will affect how much they affect the colour of "current pixel". In plain common English, it will look better.

Also possible new icon (instead of blank bitmap) and I increase the possibility of updating this weekend (now assumption worthy).

Even more, when I'm explaining stuff the plugin does, I notice to use certain words to describe aspects of the plugin, some of these are now described in the main post (top of page 1).

Edit:

Forget weekend, updated now.

point now set correctly

added alpha multiplier, for less lossy alpha increase

better render method, old one still included, but no longer updated

Edited by Boude

History repeats itself, because nobody was paying attention the first time.

##### Share on other sites

Thanks for the update

##### Share on other sites

• 3 weeks later...

Nice one: I remember making a request for someone to develop this type of plugin over 2 years ago

This should be very useful.

Thanks.

-CJ

##### Share on other sites

classy plugin. thanks Boude!

ciao OMA

##### Share on other sites

Thanks guys, this plugin is only a logical "spin-off" of zoom blur. So requests are logical, I can remember at least one other (negative zoom blur).

@cj: This plugin is pretty much exactly what you asked for, so great minds think the same.

While thinking about this, I had this idea: what if the plugin would blur in perspective (like atmospheric perspective, objects (read: "pixels") close to the vanishing point are blurred more then objects further away, of course this would be optional. So what do you think?

History repeats itself, because nobody was paying attention the first time.

##### Share on other sites

certainly would an interesting take on this already great plugin. would look forward to seeing how that version turns out. LOL!

ciao OMA

##### Share on other sites

certainly would an interesting take on this already great plugin. would look forward to seeing how that version turns out. LOL!

ciao OMA

thanks for the great plugin Boude..

great to see you back Oma..have admired your work immensely..albeit from afar..hope to see more from you soon..

regards j.d.

##### Share on other sites

very good plugin. Useful! Many thanks!

##### Share on other sites

After some messing around with my code, I found that a perspective blur wasn't possible (not without a huge workaround). The result isn't as good as you might expect. So you'll have to do with the current version.

History repeats itself, because nobody was paying attention the first time.

##### Share on other sites

• 4 months later...

Cool but ... it needs an icon I am new in the forums but i have been using paint.NET For a long time and htis was my first plug-in it needs an icon so I made some sort of it here you go!

maybe is not perfect but at least is an icon

Fantastic effect!

Edited by Ego Eram Reputo
Fixed malformed URL
##### Share on other sites

• 1 year later...

thank you friend excellent plugin

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×