Sign in to follow this  
BoltBait

Black and White+ plugin v1.1 Updated Nov 10, 2018

Recommended Posts

Black and White+

version 1.1

 

Black and White+ includes 3 different algorithms to convert a color image into a black-and-white image.
 

  • Luminosity Method

    Shade of Gray = 0.299 * Red + 0.587 * Green + 0.114 * Blue

    This is the default method.  This is how the built-in Black-and-White effect converts a color image to black-and-white.  This method gives different weights to Red, Green, and Blue.  Other methods treat each color equally.
     
  • Average Method

    Shade of Gray = (Red + Green + Blue) / 3
     
  • Lightness Method

    Shade of Gray = [Max(Red,Green,Blue) + Min(Red,Green,Blue)] / 2
     

Every color photograph is different. You'll just need to try each method to see which one works best for your specific photograph.

 

Brightness/Contrast

 

In addition to converting your photograph to black-and-white, I've also provided access to the Brightness and Contrast adjustments.  For a more dramatic effect, decrease the brightness (try -10) and increase the contrast (try +10).
 

BandWPlusUI.png

 

BWDifferences.pngBWResults.png

 

Download

 

Until I add this to my plugin pack, you can download it here:

Download

 

 

 

Source Code

 

Here is the icon: BandWPlus.png and here is the CodeLab source:

// Name: Black and White+
// Author: BoltBait
// Title: BoltBait's Black and White+ v1.1
// Version: 1.1
// Desc: Convert image to Black and White
// Keywords: Black and White|B&W
// URL: http://BoltBait.com/pdn
#region UICode
ListBoxControl Amount1 = 0; // |Luminosity Method|Average Method|Lightness Method
IntSliderControl Amount2 = 0; // [-100,100] Brightness/Contrast
IntSliderControl Amount3 = 0; // [-100,100]
#endregion

BrightnessAndContrastAdjustment bacAdjustment = new BrightnessAndContrastAdjustment();
PropertyCollection bacProps;

private double Max3(double x, double y, double z)
{
    return (x > y) ? ((x > z) ? x : z) : ((y > z) ? y : z);
}

private double Min3(double x, double y, double z)
{
    return (x < y) ? ((x < z) ? x : z) : ((y < z) ? y : z);
}

protected override void OnDispose(bool disposing)
{
    if (disposing)
    {
        if (bacAdjustment != null) bacAdjustment.Dispose();
        bacAdjustment = null;
    }

    base.OnDispose(disposing);
}

void PreRender(Surface dst, Surface src)
{
    bacProps = bacAdjustment.CreatePropertyCollection();
    PropertyBasedEffectConfigToken bacParameters = new PropertyBasedEffectConfigToken(bacProps);
    bacParameters.SetPropertyValue(BrightnessAndContrastAdjustment.PropertyNames.Brightness, Amount2);
    bacParameters.SetPropertyValue(BrightnessAndContrastAdjustment.PropertyNames.Contrast, Amount3);
    bacAdjustment.SetRenderInfo(bacParameters, new RenderArgs(dst), new RenderArgs(src));
}

unsafe void Render(Surface dst, Surface src, Rectangle rect)
{
    // Call the Brightness and Contrast Adjustment function
    bacAdjustment.Render(new Rectangle[1] {rect},0,1);

    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        if (IsCancelRequested) return;
        ColorBgra* dstPtr = dst.GetPointAddressUnchecked(rect.Left, y);
        for (int x = rect.Left; x < rect.Right; x++)
        {
            ColorBgra CurrentPixel = *dstPtr;
            byte K = CurrentPixel.R;

            if (!(CurrentPixel.R == CurrentPixel.G && CurrentPixel.G == CurrentPixel.B))
            {
                switch (Amount1)
                {
                    case 0:
                        K = (byte)((0.299f * CurrentPixel.R) + (0.587f * CurrentPixel.G) + (0.114f * CurrentPixel.B));
                        break;
                    case 1:
                        K = (byte)((CurrentPixel.R + CurrentPixel.G + CurrentPixel.B) / 3.0);
                        break;
                    case 2:
                        K = (byte)((Max3(CurrentPixel.R, CurrentPixel.G, CurrentPixel.B) + Min3(CurrentPixel.R, CurrentPixel.G, CurrentPixel.B)) / 2.0);
                        break;
                    default:
                        break;
                }
            }
            CurrentPixel = ColorBgra.FromBgra(K,K,K,CurrentPixel.A);

            *dstPtr = CurrentPixel;
            dstPtr++;
        }
    }
}

 

Note: User MJW also made a Black and White+ plugin. His has way more adjustments than mine. I'm not sure, but you might be able to use his to get the same results as mine... I just couldn't figure out how to do it.  If you like LOTS of things to tinker with, you might give his a try.

 

The above is for Paint.NET v4.1.4+

 

Paint.NET v3.5.11

 

I'm sure someone will come along shortly and compile this for you.

  • Like 3

Share this post


Link to post
Share on other sites
10 hours ago, BoltBait said:

Shade of Gray = 0.2126 * Red + 0.7152 * Green + 0.0722 * Blue

 

May I ask how you decided on the three numbers?  I mean, why those number?  Were they arbitrarily selected?

Share this post


Link to post
Share on other sites
6 hours ago, TrevorOutlaw said:

May I ask how you decided on the three numbers?

 

Got them from Wikipedia: https://en.wikipedia.org/wiki/Grayscale

 

Looking at the code, Paint.NET actually uses these numbers:

 

0.299 * Red + 0.587 * Green + 0.114 * Blue

 

I will update my code to use these numbers instead of the Wikipedia page's values.

 

 

 

NOTE: Moving this to the Dev Center until the bugs are worked out...

 

Edit: I have corrected the algorithm above.  Now, the algorithm is matching what Paint.NET used to do.  Newer Paint.NET versions use a GPU enhanced version of the Black and White algorithm, and even though the numbers are the same, the results are SLIGHTLY different.  But, the CodeLab script above is solid and I will republish tonight once I update the built-in help file.

 

 

  • Like 1

Share this post


Link to post
Share on other sites

Thank you, BoltBait.  I also appreciate the source code so I can look at it and study it.  I'm about to take C++ for my last Computer Science class (engineering management major) requirement, so...

 

 

  • Like 2

Share this post


Link to post
Share on other sites

OK, I've updated the help file and rebuilt the dll.

 

Moved back to the plugin forum.

  • Upvote 1

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