Posts Tagged 'Image Blending'

C# How to: Image Colour Average

Article purpose

This article’s intension is focussed on providing a discussion on the tasks involved in implementing Image Colour Averaging. Pixel colour averages are calculated from neighbouring pixels.

Sample source code

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

Using the Sample Application

The sample source code associated with this article includes a based sample application. The sample application is provided with the intention of illustrating the concepts explored in this article. In addition the sample application serves as a means of testing and replicating results.

By clicking the Load Image button users are able to select input/source from the local system. On the right hand side of the screen various controls enable the user to control the implementation of colour averaging. The three labelled Red, Green and Blue relates to whether an individual colour component is to be included in calculating colour averages.

The filter intensity can be specified through selecting a filter size from the dropdown , specifying higher values will result in output images expressing more colour averaging intensity.

Additional image filter effects can be achieved through implementing colour component shifting/swapping. When colour components are shifted left the result will be:

  • Blue is set to the original value of the Red component.
  • Red is set to the original value of the Green component.
  • Green is set to the original value of the Blue component.

When colour components are shifted right the result will be:

  • Red is set to the original value of the Blue component
  • Blue is set to the original value of the Green component
  • Green is set to the original value of the Red Component

Resulting can be saved by the user to the local file system by clicking the Save Image button. The following image is a screenshot of the Image Colour Average sample application in action:

Image Colour Average Sample Application

Averaging Colours

In this article and the accompanying sample source code colour averaging is implemented on a per pixel basis. An average colour value is calculated based on a pixel’s neighbouring pixels’ colour. Determining neighbouring pixels in the sample source code has been implemented in much the same method as . The major difference to is the absence of a fixed /.

Additional resulting visual effects can be achieved through various options/settings implemented whilst calculating colour averages. Additional options include being able to specify which colour component averages to implement. Furthermore colour components can be swapped/shifted around.

The sample source code implements the AverageColoursFilter , targeting the class. The extent or degree to which colour averaging will be evident in resulting can be controlled through specifying different values set to the matrixSize parameter. The matrixSize parameter in essence determines the number of neighbouring pixels involved in calculating an average colour.

The individual pixel colour components Red, Green and Blue can either be included or excluded in calculating averages. The three method boolean parameters applyBlue, applyGreen and applyRed will determine an individual colour components inclusion in averaging calculations. If a colour component is to be excluded from averaging the resulting will instead express the original source/input image’s colour component.

The intensity of a specific colour component average can be applied to another colour component by means of swapping/shifting colour components, which is indicated through the shiftType method parameter.

The following code snippet provides the implementation of the AverageColoursFilter :

public static Bitmap AverageColoursFilter(
                            this Bitmap sourceBitmap,  
                            int matrixSize,   
                            bool applyBlue = true, 
                            bool applyGreen = true, 
                            bool applyRed = true, 
                            ColorShiftType shiftType = 
                            ColorShiftType.None)  
{ 
    BitmapData sourceData =  
               sourceBitmap.LockBits(new Rectangle(0, 0, 
               sourceBitmap.Width, sourceBitmap.Height), 
               ImageLockMode.ReadOnly,  
               PixelFormat.Format32bppArgb); 

byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];
byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
int filterOffset = (matrixSize - 1) / 2; int calcOffset = 0;
int byteOffset = 0;
int blue = 0; int green = 0; int red = 0;
for (int offsetY = filterOffset; offsetY < sourceBitmap.Height - filterOffset; offsetY++) { for (int offsetX = filterOffset; offsetX < sourceBitmap.Width - filterOffset; offsetX++) { byteOffset = offsetY * sourceData.Stride + offsetX * 4;
blue = 0; green = 0; red = 0;
for (int filterY = -filterOffset; filterY <= filterOffset; filterY++) { for (int filterX = -filterOffset; filterX <= filterOffset; filterX++) { calcOffset = byteOffset + (filterX * 4) + (filterY * sourceData.Stride);
blue += pixelBuffer[calcOffset]; green += pixelBuffer[calcOffset + 1]; red += pixelBuffer[calcOffset + 2]; } }
blue = blue / matrixSize; green = green / matrixSize; red = red / matrixSize;
if (applyBlue == false) { blue = pixelBuffer[byteOffset]; }
if (applyGreen == false) { green = pixelBuffer[byteOffset + 1]; }
if (applyRed == false) { red = pixelBuffer[byteOffset + 2]; }
if (shiftType == ColorShiftType.None) { resultBuffer[byteOffset] = (byte)blue; resultBuffer[byteOffset + 1] = (byte)green; resultBuffer[byteOffset + 2] = (byte)red; resultBuffer[byteOffset + 3] = 255; } else if (shiftType == ColorShiftType.ShiftLeft) { resultBuffer[byteOffset] = (byte)green; resultBuffer[byteOffset + 1] = (byte)red; resultBuffer[byteOffset + 2] = (byte)blue; resultBuffer[byteOffset + 3] = 255; } else if (shiftType == ColorShiftType.ShiftRight) { resultBuffer[byteOffset] = (byte)red; resultBuffer[byteOffset + 1] = (byte)blue; resultBuffer[byteOffset + 2] = (byte)green; resultBuffer[byteOffset + 3] = 255; } } }
Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);
BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap; }

The definition of the ColorShiftType :

public enum ColorShiftType  
{
    None, 
    ShiftLeft, 
    ShiftRight 
}

Sample

The original image used in generating the sample images that form part of this article, has been licensed under the Attribution-Share Alike , , and license. The can be from .

Original Image

Rose_Amber_Flush_20070601

Colour Average Blue Size 11

Colour Average Blue Size 11

Colour Average Blue Size 11 Shift Left

Colour Average Blue Size 11 Shift Left

Colour Average Blue Size 11 Shift Right

Colour Average Blue Size 11 Shift Right

Colour Average Green Size 11 Shift Right

Colour Average Green Size 11 Shift Right

Colour Average Green, Blue Size 11

Colour Average Green, Blue Size 11

Colour Average Green, Blue Size 11 Shift Left

Colour Average Green, Blue Size 11 Shift Left

Colour Average Green, Blue Size 11 Shift Right

Colour Average Green, Blue Size 11 Shift Right

Colour Average Red Size 11

Colour Average Red Size 11

Colour Average Red Size 11 Shift Left

Colour Average Red Size 11 Shift Left

Colour Average Red, Blue Size 11

Colour Average Red, Blue Size 11

Colour Average Red, Blue Size 11 Shift Left

Colour Average Red, Blue Size 11 Shift Left

Colour Average Red, Green Size 11

Colour Average Red, Green Size 11

Colour Average Red, Green Size 11 Shift Left

Colour Average Red, Green Size 11 Shift Left

Colour Average Red, Green Size 11 Shift Right

Colour Average Red, Green Size 11 Shift Right

Colour Average Red, Green, Blue Size 11

Colour Average Red, Green, Blue Size 11

Colour Average Red, Green, Blue Size 11 Shift Left

Colour Average Red, Green, Blue Size 11 Shift Left

Colour Average Red, Green, Blue Size 11 Shift Right

Colour Average Red, Green, Blue Size 11 Shift Right

Related Articles and Feedback

Feedback and questions are always encouraged. If you know of an alternative implementation or have ideas on a more efficient implementation please share in the comments section.

I’ve published a number of articles related to imaging and images of which you can find URL links here:

Image Filters: Colourful Processors

Overview

Today has been my best day in terms of Likes and Views on my website. I have come to the obvious conclusion that most people are more interested in seeing pretty pictures than they are in reading articles on source code.

That’s ok, I also like pretty pictures SmileI have uploaded some more eye candy. The images were created by modifying an image originally authored by Konstantin Lanzet. The original image file is licensed under the Attribution-Share Alike 3.0 Unported license, and can be downloaded from .

As a point of interest, all of the filters implemented were done through software I had written from scratch. Most of the application source code have been discussed in various articles and published here on my . All applications and related source code are of course open source.

This is what the original image looks like:


KL_Intel_D8086


After applying various colour filters and a bit of copy and paste the result:

Chips_1


Chips_2


Chips_3 


Chips_5


Chips_6


Chips_7

Image Filters: Light bulb Patterns

Overview

I’ve started development on pattern based colour filtering today. The software still needs some work, but so far the results are starting to look quite promising.

At this point I’ve only implemented variable sized checkerboard patterns. The idea being to divide an image into a number of squares and then to only include alternating squares when applying various colour filters.

Keep in mind all of the images shown below were generated from the same source image. The original image reflects a fairly standard image of a clear glass bayonet light bulb.

The original source image used to generate the images featured in this article has been licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license and can be downloaded from Wikipedia.

 

LightBulb_1 LightBulb_2
LightBulb_3 LightBulb_4
LightBulb_5 LightBulb_6
LightBulb_7 LightBulb_8
LightBulb_9 LightBulb_10
LightBulb_11 LightBulb_12
LightBulb_13 LightBulb_14
LightBulb_15 LightBulb_16
LightBulb_17 LightBulb_18
LightBulb_20 LightBulb_21
LightBulb_22 LightBulb_23
LightBulb_24  

Image Filters: Sunflower

The Original

This image filter features an implementation of the technical details explained in the article .

A single source/input image was used to generate the following images. The source image has been released into the and can be downloaded from .

The Original

Sunflower USFWS

Filtered Images

Sunflower ShiftLeftSunflower ShiftRightSunflower SwapBlueAndGreenSunflower SwapBlueAndGreenFixRed0Sunflower SwapBlueAndGreenFixRed100Sunflower SwapBlueAndGreenFixRed140Sunflower SwapBlueAndRedSunflower SwapBlueAndRedFixGreen0Sunflower SwapBlueAndRedFixGreen85Sunflower SwapRedAndGreenSunflower SwapRedAndGreenFixBlue0Sunflower SwapRedAndGreenFixBlue180Sunflower SwapRedAndGreenFixBlue215

Image Filters: The Red Hot Chilli Peppers live in concert

The Original

All of the images featured in this article were generated from the same the input source image file. Each image illustrates the implementation of a different colour filter.

The original source image is a photo I had taken myself during a live concert performance by The Red Hot Chilli Peppers, performed at Soccer City, Johannesburg, South Africa.

The colour filter technical details are explored in the articles: C# How to: Blending Bitmap images using colour filters and C# How to: Swapping Bitmap ARGB Colour Channels.

Original Image

RHCP_Original

Filtered Images

RHCP_AmberRHCP_BlueGreenRHCP_BluePinkRHCP_BrightBlueRHCP_BrightBlueTintRHCP_BrightGreenRHCP_BrightGreenTintRHCP_BrightWhiteRHCP_BrightYellowRHCP_DarkPinkRHCP_GreenRHCP_GreenYellowTintRHCP_LavenderRHCP_LightBlueRHCP_NeonGreenRHCP_OrangeRHCP_VioletRHCP_Yellow


Dewald Esterhuizen

Blog Stats

  • 462,971 hits

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

Join 210 other followers

Archives

Twitter feed


%d bloggers like this: