Posts Tagged 'Linq to Bitmaps'

C# How to: Linq to Bitmaps – Partial Colour Inversion

Article Purpose

In this follow up article we further explore manipulating a  ’s underlying pixel data. This article is part 2 of the Linq to Bitmaps series, we’ll be focussing on partial colour inversion using queries.

Part 1: .

In my experience with previous articles I’ve written it seems that articles are better received by readers when accompanied by graphics/images. You will notice throughout this article I’ve added thumbnail images. All of the images originate from the same source image file and were created by the  accompanying sample application.

Sunflower-BlueSunflower-GreenSunflower-Invert-All-ShiftLeftSunflower-Invert-All-SwapBlueGreenFixRed200 Sunflower-Invert-All-SwapBlueRedFixGreen75

Sample source code

This article is accompanied by a sample source code Visual Studio project which is available for download here.

Sunflower-Invert-All-SwapRedGreenSunflower-Invert-All-SwapRedGreenFixBlue150Sunflower-Invert-BlueSunflower-Invert-Blue-GreenSunflower-Invert-BlueGreen-ShiftLeft

Using the sample Application

This article’s associated sample source code defines a sample application, detailing the concepts explored by this article. The sample application implements three types of image filters: Inverting Colours, Swapping each pixel’s colour components and Shifting pixels to different locations within the image data buffer. This article explores the Colour Inversion filter.

The image shown below is a screenshot of the Bitmap Pixel Manipulation application in action:

LinqToBitmaps_Screenshot

The sample application allows the user to specify an input source image which can then be modified by implementing an image filter. If desired the user has the option to save the new/result image to the file system.

Sunflower-Invert-BlueGreen-ShiftRightSunflower-Invert-BlueGreen-SwapBlueGreenSunflower-Invert-BlueGreen-SwapBlueGreenFixRed0Sunflower-Invert-BlueGreen-SwapBlueGreenFixRed125Sunflower-Invert-BlueGreen-SwapBlueRed

The Colour Inversion Filter

The Colour Inversion Filter can be implemented in various forms. The type of inversion is determined by the ColourInversionType , the definition as follows:

public  enum  ColourInversionType  
{
    All, 
    Blue, 
    Green, 
    Red, 
    BlueRed, 
    BlueGreen, 
    RedGreen, 
}

The following section provides an explanation of each Inversion Type:

  • All – Each Red, Green and Blue value will be subtracted from 255.
  • Blue – The value of Blue will be subtracted from 255, Green and Red values remain unchanged.
  • Green – The value of Green will be subtracted from 255, Blue and Red values remain unchanged.
  • Red – The value of Red will be subtracted from 255, Blue and Green values remain unchanged.
  • BlueRed – The value of Blue and Red will be subtracted from 255, Green  value remain unchanged.
  • BlueGreen – The value of Blue and Green will be subtracted from 255, Red value remain unchanged.
  • RedGreen – The value of Red and Green will be subtracted from 255, Blue value remain unchanged.

Sunflower-Invert-Blue-RedSunflower-Invert-BlueRed-SwapBlueGreenFixRed225Sunflower-Invert-BlueRed-SwapBlueRedFixGreen35Sunflower-Invert-BlueRed-SwapRedGreenFixBlue55Sunflower-Invert-Blue-ShiftLeft 

Applying Linq queries to Pixel Data

This article’s sample source code implements queries through the InvertColors extension method which targets the class. The definition is detailed by the following code snippet:

 public  static  Bitmap  InvertColors(this  Bitmap  sourceImage, 
                                 ColourInversionType  inversionType) 
{ 
    List <ArgbPixel > pixelListSource = GetPixelListFromBitmap(sourceImage); 

List <ArgbPixel > pixelListResult = null;
byte byte255 = 255;
switch (inversionType) { case ColourInversionType.All: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = (byte )(byte255 - t.blue), red = (byte )(byte255 - t.red), green = (byte )(byte255 - t.green), alpha = t.alpha, }).ToList();
break; } case ColourInversionType.Blue: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = (byte )(byte255 - t.blue), red = t.red, green = t.green, alpha = t.alpha, }).ToList();
break; } case ColourInversionType.Green: { pixelListResult = (from t in pixelListSource select new ArgbPixel {> blue = t.blue, red = t.red, green = (byte )(byte255 - t.green), alpha = t.alpha, }).ToList();
break; } case ColourInversionType.Red: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = t.blue, red = (byte )(byte255 - t.green), green = t.green, alpha = t.alpha, }).ToList();
break; } case ColourInversionType.BlueRed: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = (byte )(byte255 - t.blue), red = (byte )(byte255 - t.red), green = t.green, alpha = t.alpha, }).ToList();
break; } case ColourInversionType.BlueGreen: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = (byte )(byte255 - t.blue), red = t.red, green = (byte )(byte255 - t.green), alpha = t.alpha, }).ToList();
break; } case ColourInversionType.RedGreen: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = t.blue, red = (byte )(byte255 - t.blue), green = (byte )(byte255 - t.green), alpha = t.alpha, }).ToList();
break; } }
Bitmap resultBitmap = GetBitmapFromPixelList(pixelListResult, sourceImage.Width, sourceImage.Height);
return resultBitmap; }

The InvertColors extension method performs a simple select query returning a new instance of the ArgbPixel class adjusted according to the value of the ColourInversionType parameter passed.

Sunflower-Invert-Green-ShiftLeftSunflower-Invert-Green-SwapBlueGreenSunflower-Invert-Red-GreenSunflower-Invert-RedGreen-SwapBlueRedSunflower-Invert-RedGreen-SwapRedGreenFixBlue110

Filter implementation examples

This section contains the eye candy of this article. The following set of images were created from a single input source image. The source image has been released into the public domain and can be downloaded from Wikipedia.

The Original Image

Sunflower_USFWS

Filtered Images

Sunflower-BlueSunflower-GreenSunflower-Invert-All-ShiftLeftSunflower-Invert-All-SwapRedGreenFixBlue150Sunflower-Invert-BlueGreen-SwapBlueRedSunflower-Invert-Blue-RedSunflower-Invert-GreenSunflower-Invert-Red-GreenSunflower-Invert-RedGreen-SwapBlueRedSunflower-Invert-RedGreen-SwapRedGreenFixBlue110

C# How to: Bitmap Pixel manipulation using LINQ Queries

Article Purpose

In this article we explore manipulating a  ’s underlying pixel data. The process of Pixel data manipulation at its core feature the implementation of Queries targeting raw pixel data.

Update: I’ve published a follow-up article – Part 2: The banner images in this article were generated using the concepts explored in the follow-up article. The source image has been licenced under the Creative Commons Attribution-Share Alike 3.0 Unported license and can be downloaded from .

Led_Banner1

Sample source code

This article is accompanied by a sample source code Visual Studio project which is available for download here.

Led_Banner2

Using the sample Application

This article’s associated sample source code defines a sample application, detailing the concepts explored by this article. The sample application implements two types of image filters: Swapping each pixel’s colour components and shifting pixels to different locations within the image data buffer.

The image shown below is a screenshot of the Bitmap Pixel Manipulation application in action:

BitmapPixelManipulation

The sample application allows the user to specify an input source image which can then be modified by implementing an image filter. If desired the user has the option to save the new/result image to the file system.

Led_Banner3

Extracting Pixel values from a Bitmap image

The sample source code defines the ArgbPixel class which is implemented to represent an individual pixel. The definition as follows:

public class ArgbPixel
{
    public byte blue = 0;
    public byte green = 0;
    public byte red = 0;
    public byte alpha = 0;

public ArgbPixel() { }
public ArgbPixel(byte[] colorComponents) { blue = colorComponents[0]; green = colorComponents[1]; red = colorComponents[2]; alpha = colorComponents[3]; }
public byte[] GetColorBytes() { return new byte[]{blue, green, red, alpha}; } }

Each pixel is defined by four member variables of type byte: blue, red, green and alpha. The ArgbPixel class defines an overloaded constructor which allows for creating an instance by specifying the four colour components as byte values. By invoking the GetColorBytes method the calling code can access the underlying colour component byte values in the form of a byte array.

Led_Banner1

The Colour Swap filter

The Colour swap filter acts as an image filter by implementing various combinations of swapping each individual pixel’s Alpha, Red, Green and Blue colour channels. The sample source code defines the ColorSwapType , intended to provide a collection of possible pixel colour channel swap operations. The code snippet listed below provides the definition of the ColorSwapType type:

public enum ColourSwapType
{
    ShiftRight,
    ShiftLeft,
    SwapBlueAndRed,
    SwapBlueAndRedFixGreen,
    SwapBlueAndGreen,
    SwapBlueAndGreenFixRed,
    SwapRedAndGreen,
    SwapRedAndGreenFixBlue
}

The following section provides an explanation of each Colour Swap method:

  • ShiftRight – Starting with Blue each colour channel’s value will be copied to the colour channel to the right.
  • ShiftLeft – Starting with Blue each colour channel’s value will be copied to the colour channel to the left.
  • SwapBlueAndRed – Blue and Red values are swapped, Green remains unchanged.
  • SwapBlueAndRedFixGreen – Blue and Red values are swapped, each pixel’s Green value is set to the same value as specified by the calling code.
  • SwapBlueAndGreen – Blue and Green values are swapped, Red remains unchanged.
  • SwapBlueAndGreenFixRed – Blue and Green values are swapped, each pixel’s Red value is set to the same value as specified by the calling code.
  • SwapRedAndGreen – Red and Green values are swapped, Blue remains unchanged.
  • SwapRedAndGreenFixBlue – Red and Green values are swapped, each pixel’s Blue value is set to the same value as specified by the calling code.

Led_Banner2

From a Bitmap buffer to a Pixel List

The sample source provides the definition for the GetPixelListFromBitmap method. The purpose behind this method is to read a ’s underlying colour component byte buffer data and create a generic collection of type ArgbPixel. By representing the data as a generic collection we are able implement query operations. The code snippet below details the GetPixelListFromBitmap method definition.

private static List<ArgbPixel> GetPixelListFromBitmap(Bitmap sourceImage)
{
     BitmapData sourceData = sourceImage.LockBits(new Rectangle(0, 0, 
                 sourceImage.Width, sourceImage.Height), 
                 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

byte[] sourceBuffer = new byte[sourceData.Stride * sourceData.Height]; Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, sourceBuffer.Length); sourceImage.UnlockBits(sourceData);
List<ArgbPixel> pixelList = new List<ArgbPixel>(sourceBuffer.Length / 4);
using (MemoryStream memoryStream = new MemoryStream(sourceBuffer)) { memoryStream.Position = 0; BinaryReader binaryReader = new BinaryReader(memoryStream);
while (memoryStream.Position + 4 <= memoryStream.Length) { ArgbPixel pixel = new ArgbPixel(binaryReader.ReadBytes(4)); pixelList.Add(pixel); }
binaryReader.Close(); }
return pixelList; }

The GetPixelListFromBitmap accepts a parameter and returns a generic collection of type ArgbPixel. Within the method body the first operation performed involves locking the pixel data in memory by invoking the method. By locking data in memory we are in effect signalling the to not shift around in memory the underlying data whilst we are busy accessing the data.

Next, the sample source code implements the method in order to copy the ’s colour component data in the form of a byte array. Once we’ve copied the pixel data we can unlock the by invoking .

The final operation performed by the GetPixelListFromBitmap involves iterating through the byte array of colour components. With each loop we make use of a , reading four bytes at a time and passing the result to the overloaded constructor exposed by the ArgbPixel class.

Led_Banner3

Applying Linq queries to Pixel Data

This article’s sample source code implements queries through the SwapColors extension method which targets the Bitmap class. The definition is detailed by the following code snippet:

 public static Bitmap SwapColors(this Bitmap sourceImage, 
                                 ColourSwapType swapType, 
                                 byte fixedValue = 0)
{
     List<ArgbPixel> pixelListSource = GetPixelListFromBitmap(sourceImage);

List<ArgbPixel> pixelListResult = null;
switch (swapType) { case ColourSwapType.ShiftRight: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = t.red, red = t.green, green = t.blue, alpha = t.alpha}).ToList(); break; } case ColourSwapType.ShiftLeft: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = t.green, red = t.blue, green = t.red, alpha = t.alpha}).ToList(); break; } case ColourSwapType.SwapBlueAndRed: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = t.red, red = t.blue, green = t.green, alpha = t.alpha}).ToList(); break; case ColourSwapType.SwapBlueAndRedFixGreen: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = t.red, red = t.blue, green = fixedValue, alpha = t.alpha}).ToList(); break; } case ColourSwapType.SwapBlueAndGreen: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = t.green, red = t.red, green = t.blue, alpha = t.alpha}).ToList(); break; } case ColourSwapType.SwapBlueAndGreenFixRed: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = t.green, red = fixedValue, green = t.blue, alpha = t.alpha}).ToList(); break; } case ColourSwapType.SwapRedAndGreen: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = t.blue, red = t.green, green = t.red, alpha = t.alpha}).ToList(); break; } case ColourSwapType.SwapRedAndGreenFixBlue: { pixelListResult = (from t in pixelListSource select new ArgbPixel { blue = fixedValue, red = t.green, green = t.red, alpha = t.alpha}).ToList(); break; } }
Bitmap resultBitmap = GetBitmapFromPixelList(pixelListResult, sourceImage.Width, sourceImage.Height);
return resultBitmap; }

The SwapColors extension method accepts as parameters an value of type ColourSwapType and a byte parameter fixedValue defined with a default value of 0.

The GetPixelListFromBitmap method discussed earlier is implemented in order to create a generic of type ArgbPixel. The bulk of the method’s implementation is performed next by applying a switch statement on the ColourSwapType parameter. The original List<ArgbPixel> collection is used to populate a resulting List<ArgbPixel> collection. Assignment from source to result collection occurs through a query implementing the relevant ColourSwapType.

The last operation performed by the SwapColors extension method involves converting the resulting List<ArgbPixel> collection back to a object through invoking the GetBitmapFromPixelList method. The following section provides a description of the GetBitmapFromPixelList method.

Led_Banner1

From a Pixel List to a Bitmap

In the sample source code the GetPixelListFromBitmap method discussed earlier, is complimented by its inverse, the GetBitmapFromPixelList method. As the name implied the GetBitmapFromPixelList method’s purpose is to convert a generic of type ArgbPixel to a object. The definition as follows:

private static Bitmap GetBitmapFromPixelList(List<ArgbPixel> pixelList, int width, int height)
{
     Bitmap resultBitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);

BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] resultBuffer = new byte[resultData.Stride * resultData.Height];
using (MemoryStream memoryStream = new MemoryStream(resultBuffer)) { memoryStream.Position = 0; BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
foreach (ArgbPixel pixel in pixelList) { binaryWriter.Write(pixel.GetColorBytes()); }
binaryWriter.Close(); }
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length); resultBitmap.UnlockBits(resultData);
return resultBitmap; }

The GetBitmapFromPixelList method accepts as parameters a generic of type ArgbPixel, width and height of type int. The width and height parameters indicates the size of the original , which will be used when creating a new resulting .

The first step performed by the GetBitmapFromPixelList method is to create a resulting object and locking into memory the underlying data by invoking the method.

The bulk of the work performed by the GetBitmapFromPixelList method occurs in the form of iterating the List of ArgbPixel parameter and writing the Pixel’s underlying colour components to a byte buffer related to the resulting .

In the last step being performed byte array of colour component data is copied to the resulting by invoking .

Led_Banner2

Reversing a List of Pixels

As an additional example the sample source code also defines the FlipPixels extension method. This method provides a quick implementation of turning a image upside down. The implementation as follows:

public static Bitmap FlipPixels(this Bitmap sourceImage)
{
     List<ArgbPixel> pixelList = GetPixelListFromBitmap(sourceImage);

pixelList.Reverse();
Bitmap resultBitmap = GetBitmapFromPixelList(pixelList, sourceImage.Width, sourceImage.Height);
return resultBitmap; }

The FlipPixels extension method targets the class and returns a object. As discussed earlier the method invokes the GetPixelListFromBitmap and GetBitmapFromPixelList methods. Reversing the order of the ArgbPixel objects is achieved through invoking the method.

Led_Banner3

Filter implementation examples

This section contains the eye candy of this article. The following set of images were created from a single input source image. The original image is licensed under the Creative Commons Attribution 2.0 Generic license and can be downloaded from Wikipedia.

The Original Image

SunflowerSunset2

Shift Left

ShiftLeft

Shift Right

ShiftRight

Swap Blue and Red

SwapBlueAndRed

Swap Blue and Red, fix Green at 0

SwapBlueAndRedFixGreen0

Swap Blue and Green

SwapBlueAndGreen

Swap Blue and Green, fix Red at 25

SwapBlueAndGreenFixRed25

Swap Red and Green

SwapRedAndGreen

Swap Red and Green, fix Blue at 0

SwapRedAndGreenFixBlue0

Swap Red and Green, fix Blue at 115

SwapRedAndGreenFixBlue115

Swap Red and Green, fix Blue at 200

SwapRedAndGreenFixBlue200


Dewald Esterhuizen

Blog Stats

  • 868,532 hits

Enter your email address to follow and receive notifications of new posts by email.

Join 228 other subscribers

Archives

RSS SoftwareByDefault on MSDN

  • An error has occurred; the feed is probably down. Try again later.