C# How to: Image Arithmetic

Article Purpose

The objective of this article is to illustrate Arithmetic being implemented when blending/combining two separate into a single result . The types of Image Arithmetic discussed are: Average, Add, SubtractLeft, SubtractRight, Difference, Multiply, Min, Max and Amplitude.

I created the following by implementing Image Arithmetic using as input a photo of a friend’s ear and a photograph taken at a live concert performance by The Red Hot Chili Peppers.

The-RHCP-Sound_Scaled

Sample source code

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

Download15

Using the Sample Application

The Sample source code accompanying this article includes a Sample Application developed on a platform. The Sample Application is indented to provide an implementation of the various types of Image Arithmetic explored in this article.

The Image Arithmetic sample application allows the user to select two source/input from the local file system. The user interface defines a ComboBox dropdown populated with entries relating to types of Image Arithmetic.

The following is a screenshot taken whilst creating the “Red Hot Chili Peppers Concert – Side profile Ear” blended illustrated in the first shown in this article. Notice the stark contrast when comparing the source/input preview . Implementing Image Arithmetic allows us to create a smoothly blended result :

ImageArithmetic_SampleApplication

Newly created can be saved to the local file system by clicking the ‘Save Image’ button.

Image Arithmetic

In simple terms Image Arithmetic involves the process of performing calculations on two ’ corresponding pixel colour components. The values resulting from performing calculations represent a single which is combination of the two original source/input . The extent to which a source/input will be represented in the resulting is dependent on the type of Image Arithmetic employed.

The ArithmeticBlend Extension method

In this article Image Arithmetic has been implemented as a single targeting the class. The ArithmeticBlend expects as parameters two source/input objects and a value indicating the type of Image Arithmetic to perform.

The ColorCalculationType defines an value for each type of Image Arithmetic supported. The definition as follows:

public enum ColorCalculationType 
{ 
   Average, 
   Add, 
   SubtractLeft, 
   SubtractRight, 
   Difference, 
   Multiply, 
   Min, 
   Max, 
   Amplitude 
}

It is only within the ArithmeticBlend that we perform Image Arithmetic. This method accesses the underlying pixel data of each sample and creates copies stored in arrays. Each element within the array data buffer represents a single colour component, either Alpha, Red, Green or Blue.

The following code snippet details the implementation of the ArithmeticBlend :

 public static Bitmap ArithmeticBlend(this Bitmap sourceBitmap, Bitmap blendBitmap,  
                                 ColorCalculator.ColorCalculationType calculationType) 
{ 
    BitmapData sourceData = sourceBitmap.LockBits(new Rectangle (0, 0, 
                            sourceBitmap.Width, sourceBitmap.Height), 
                            ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 

byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height]; Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length); sourceBitmap.UnlockBits(sourceData);
BitmapData blendData = blendBitmap.LockBits(new Rectangle (0, 0, blendBitmap.Width, blendBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] blendBuffer = new byte [blendData.Stride * blendData.Height]; Marshal.Copy(blendData.Scan0, blendBuffer, 0, blendBuffer.Length); blendBitmap.UnlockBits(blendData);
for (int k = 0; (k + 4 < pixelBuffer.Length) && (k + 4 < blendBuffer.Length); k += 4) { pixelBuffer[k] = ColorCalculator.Calculate(pixelBuffer[k], blendBuffer[k], calculationType);
pixelBuffer[k + 1] = ColorCalculator.Calculate(pixelBuffer[k + 1], blendBuffer[k + 1], calculationType);
pixelBuffer[k + 2] = ColorCalculator.Calculate(pixelBuffer[k + 2], blendBuffer[k + 2], calculationType); }
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(pixelBuffer, 0, resultData.Scan0, pixelBuffer.Length); resultBitmap.UnlockBits(resultData);
return resultBitmap; }

We access and copy the underlying pixel data of each input by making use of the method and also the method.

The method iterates both array data buffers simultaneously, having set the for loop condition to regard the array size of both arrays. Scenarios where array data buffers will differ in size occurs when the source specified are not equal in terms of size dimensions.

Notice how each iteration increments the loop counter by a factor of four allowing us to treat each iteration as a complete pixel value. Remember that each data buffer element represents an individual colour component. Every four elements represents a single pixel consisting of the components: Alpha, Red, Green and Blue

Take Note: The ordering of colour components are the exact opposite of the expected order. Each pixel’s colour components are ordered: Blue, Green, Red, Alpha. Since we are iterating an entire pixel with each iteration the for loop counter value will always equate to an element index representing the Blue colour component. In order to access the Red and Green colour components we simply add the values one and two respectively to the for loop counter value, depending on whether accessing the Green or Red colour components.

The task of performing the actual arithmetic has been encapsulated within the static Calculate method, a public member of the static class ColorCalculator. The Calculate method is more detail in the following section of this article.

The final task performed by the ArithmeticBlend method involves creating a new instance of the class which is then updated/populated using the resulting array data buffer previously modified.

The ColorCalculator.Calculate method

The algorithms implemented in Image Arithmetic are encapsulated within the ColorCalculator.Calculate method. When implementing this method no knowledge of the technical implementation details are required. The parameters required are two values each representing a single colour component, one from each source . The only other required parameter is an value of type ColorCalculationType which will indicate which type of Image Arithmetic should be implemented using the parameters as operands.

The following code snippet details the full implementation of the ColorCalculator.Calculate method:

 public static byte Calculate(byte color1, byte color2, 
                   ColorCalculationType calculationType) 
{ 
    byte resultValue = 0; 
    int intResult = 0; 

if (calculationType == ColorCalculationType.Add) { intResult = color1 + color2; } else if (calculationType == ColorCalculationType.Average) { intResult = (color1 + color2) / 2; } else if (calculationType == ColorCalculationType.SubtractLeft) { intResult = color1 - color2; } else if (calculationType == ColorCalculationType.SubtractRight) { intResult = color2 - color1; } else if (calculationType == ColorCalculationType.Difference) { intResult = Math.Abs(color1 - color2); } else if (calculationType == ColorCalculationType.Multiply) { intResult = (int)((color1 / 255.0 * color2 / 255.0) * 255.0); } else if (calculationType == ColorCalculationType.Min) { intResult = (color1 < color2 ? color1 : color2); } else if (calculationType == ColorCalculationType.Max) { intResult = (color1 > color2 ? color1 : color2); } else if (calculationType == ColorCalculationType.Amplitude) { intResult = (int)(Math.Sqrt(color1 * color1 + color2 * color2) / Math .Sqrt(2.0)); }
if (intResult < 0) { resultValue = 0; } else if (intResult > 255) { resultValue = 255; } else { resultValue = (byte)intResult; }
return resultValue; }

The bulk of the ColorCalculator.Calculate method’s implementation is set around a series of if/else if statements evaluating the method parameter passed when the method had been invoked.

Colour component values can only range from 0 to 255 inclusive. Calculations performed might result in values which do not fall within the valid range of values. Calculated values less than zero are set to zero and values exceeding 255 are set to 255, sometimes this is referred to clamping.

The following sections of this article provides an explanation of each type of Image Arithmetic implemented.

Image Arithmetic: Add

if (calculationType == ColorCalculationType.Add)
{
    intResult = color1 + color2;
}

The Add algorithm is straightforward, simply adding together the two colour component values. In other words the resulting colour component will be set to equal the sum of both source colour component, provided the total does not exceed 255.

Sample Image

ImageArithmetic_Add

Image Arithmetic: Average

if (calculationType == ColorCalculationType.Average)
{
    intResult = (color1 + color2) / 2;
}

The Average algorithm calculates a simple average by adding together the two colour components and then dividing the result by two.

Sample Image

ImageArithmetic_Average

Image Arithmetic: SubtractLeft

if (calculationType == ColorCalculationType.SubtractLeft)
{
    intResult = color1 - color2;
}

The SubtractLeft algorithm subtracts the value of the second colour component parameter from the first colour component parameter.

Sample Image

ImageArithmetic_SubtractLeft

Image Arithmetic: SubtractRight

if (calculationType == ColorCalculationType.SubtractRight)
{
    intResult = color2 - color1;
}

The SubtractRight algorithm, in contrast to SubtractLeft, subtracts the value of the first colour component parameter from the second colour component parameter.

Sample Image

ImageArithmetic_SubtractRight

Image Arithmetic: Difference

if (calculationType == ColorCalculationType.Difference)
{
    intResult = Math.Abs(color1 - color2);
}

The Difference algorithm subtracts the value of the second colour component parameter from the first colour component parameter. By passing the result of the subtraction as a parameter to the Math.Abs method the algorithm ensures only calculating absolute/positive values. In other words calculating the difference in value between colour component parameters.

Sample Image

ImageArithmetic_Difference

Image Arithmetic: Multiply

if (calculationType == ColorCalculationType.Multiply)
{
    intResult = (int)((color1 / 255.0 * color2 / 255.0) * 255.0);
}

The Multiply algorithm divides each colour component parameter by a value of 255 and the proceeds to multiply the results of the division, the result is then further multiplied by a value of 255.

Sample Image

ImageArithmetic_Multiply

Image Arithmetic: Min

if (calculationType == ColorCalculationType.Min)
{
    intResult = (color1 < color2 ? color1 : color2);
}

The Min algorithm simply compares the two colour component parameters and returns the smallest value of the two.

Sample Image

ImageArithmetic_Min

Image Arithmetic: Max

if (calculationType == ColorCalculationType.Max)
{
    intResult = (color1 > color2 ? color1 : color2);
}

The Max algorithm, as can be expected, will produce the exact opposite result when compared to the Min algorithm. This algorithm compares the two colour component parameters and returns the larger value of the two.

Sample Image

ImageArithmetic_Max

Image Arithmetic: Amplitude

 else if (calculationType == ColorCalculationType.Amplitude) 
{ 
         intResult = (int)(Math.Sqrt(color1 * color1 +
                                     color2 * color2) /
                                     Math.Sqrt(2.0)); 
} 
  

The Amplitude algorithm calculates the amplitude of the two colour component parameters by multiplying each colour component by itself and then sums the results. The last step divides the result thus far by the square root of two.

Sample Image

ImageArithmetic_Amplitude

Related Articles

34 Responses to “C# How to: Image Arithmetic”



  1. 1 C# How to: Image Convolution | Software by Default Trackback on May 1, 2013 at 5:42 PM
  2. 2 C# How to: Image filtering implemented using a ColorMatrix | Software by Default Trackback on May 1, 2013 at 9:04 PM
  3. 3 C# How to: Blending Bitmap images using colour filters | Software by Default Trackback on May 1, 2013 at 10:50 PM
  4. 4 C# How to: Decoding/Converting Base64 strings to Bitmap images | Software by Default Trackback on May 2, 2013 at 9:35 PM
  5. 5 C# How to: Image Edge Detection | Software by Default Trackback on May 11, 2013 at 1:23 PM
  6. 6 C# How to: Difference Of Gaussians | Software by Default Trackback on May 18, 2013 at 12:50 AM
  7. 7 C# How to: Image Median Filter | Software by Default Trackback on May 18, 2013 at 4:16 AM
  8. 8 C# How to: Image Unsharp Mask | Software by Default Trackback on May 18, 2013 at 12:18 PM
  9. 9 C# How to: Image Colour Average | Software by Default Trackback on May 18, 2013 at 9:48 PM
  10. 10 C# How to: Image Erosion and Dilation | Software by Default Trackback on May 19, 2013 at 10:24 AM
  11. 11 C# How to: Morphological Edge Detection | Software by Default Trackback on May 25, 2013 at 8:22 AM
  12. 12 C# How to: Boolean Edge Detection | Software by Default Trackback on June 1, 2013 at 2:09 AM
  13. 13 C# How to: Gradient Based Edge Detection | Software by Default Trackback on June 1, 2013 at 4:46 PM
  14. 14 C# How to: Image Cartoon Effect | Software by Default Trackback on June 2, 2013 at 4:13 PM
  15. 15 C# How to: Sharpen Edge Detection | Software by Default Trackback on June 7, 2013 at 5:11 AM
  16. 16 C# How to: Calculating Gaussian Kernels | Software by Default Trackback on June 8, 2013 at 10:59 AM
  17. 17 C# How to: Image Blur | Software by Default Trackback on June 9, 2013 at 10:19 PM
  18. 18 C# How to: Image Transform Rotate | Software by Default Trackback on June 16, 2013 at 10:40 AM
  19. 19 C# How to: Image Transform Shear | Software by Default Trackback on June 16, 2013 at 5:45 PM
  20. 20 C# How to: Compass Edge Detection | Software by Default Trackback on June 22, 2013 at 9:34 PM
  21. 21 C# How to: Oil Painting and Cartoon Filter | Software by Default Trackback on June 30, 2013 at 10:47 AM
  22. 22 C# How to: Stained Glass Image Filter | Software by Default Trackback on June 30, 2013 at 10:50 AM
  23. 23 C# How to: Generate a Web Service from WSDL | Software by Default Trackback on June 30, 2013 at 4:08 PM
  24. 24 C# How to: Bitmap Colour Substitution implementing thresholds | Software by Default Trackback on July 6, 2013 at 4:33 PM
  25. 25 C# How to: Swapping Bitmap ARGB Colour Channels | Software by Default Trackback on July 6, 2013 at 5:02 PM
  26. 26 C# How to: Image filtering by directly manipulating Pixel ARGB values | Software by Default Trackback on July 8, 2013 at 2:57 AM
  27. 27 C# How to: Image ASCII Art | Software by Default Trackback on July 14, 2013 at 7:22 AM
  28. 28 C# How to: Weighted Difference of Gaussians | Software by Default Trackback on July 14, 2013 at 8:11 PM
  29. 29 C# How to: Image Boundary Extraction | Software by Default Trackback on July 21, 2013 at 10:23 AM
  30. 30 C# How to: Image Abstract Colours Filter | Software by Default Trackback on July 28, 2013 at 7:41 PM
  31. 31 C# How to: Fuzzy Blur Filter | Software by Default Trackback on August 9, 2013 at 6:39 AM
  32. 32 C# How to: Image Distortion Blur | Software by Default Trackback on August 9, 2013 at 10:13 PM
  33. 33 C# How to: Standard Deviation Edge Detection | Software by Default Trackback on August 8, 2015 at 8:10 AM
  34. 34 C# How to: Min/Max Edge Detection | Software by Default Trackback on August 9, 2015 at 11:29 AM

Leave a comment




Dewald Esterhuizen

Blog Stats

  • 869,667 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.