Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

Sepia Custom Effect (Nokia Imaging SDK)

From Wiki
Jump to: navigation, search

This article explains how to create a Sepia Effect similar to the SepiaFilter in the Nokia Imaging SDK. It is provided for educational purposes rather than developer re-use, if you want the sepia look provided by the SDK.

SignpostIcon XAML 40.png
WP Metro Icon WP8.png
Article Metadata
Tested with
Devices(s): Nokia Lumia 920
Compatibility
Platform(s):
Windows Phone 8
Dependencies: Nokia Imaging SDK 1.0
Article
Created: Rob.Kachmar (08 Feb 2014)
Last edited: Rob.Kachmar (18 Feb 2014)

Contents

Introduction

The SepiaEffect allows you to change an image into a sepia look, like an old weathered picture. It produces a speia look similar to the Nokia Imaging SDK's inbuilt SepiaFilter. The main differences are that it is implemented as a custom effect, it is less efficient, and you can use your own sepia intensity factor.

Warning.pngWarning: If you want the sepia look provided by the SDK, the SepiaEffect should not be used in place of the inbuilt SepiaFilter. It is provided for educational purposes - to make it easier to understand the techniques used so that more complex filters can be created.

The article provides links to the filter source code and test code, an explanation of how the filter works, and code snippets showing how it is used.

Source code

Full source code for the SepiaEffect custom effect is provided below (toggle "Expand") and also in a ready-to-use file here: SepiaEffect.cs.

SepiaEffect.cs (08 Feb 2014)

  1. // ============================================================================
  2. // DATE        AUTHOR                   DESCRIPTION
  3. // ----------  -----------------------  ---------------------------------------
  4. // 2014.02.01  Rob.Kachmar              Initial creation
  5. // 2014.02.08  Rob.Kachmar              Added parameter for sepia intensity
  6. // ============================================================================
  7.  
  8. using Nokia.Graphics.Imaging;
  9. using System;
  10.  
  11. namespace NISDKExtendedEffects.ImageEffects
  12. {
  13.     public class SepiaEffect : CustomEffectBase
  14.     {
  15.         // http://www.aforgenet.com/framework/docs/html/10a0f824-445b-dcae-02ef-349d4057da45.htm
  16.         // 920--> 19-20 FPS with inbuilt filter and 6-7 FPS with the custom effect
  17.         uint m_Intensity = 42; // 42 seems to be the closest to the SDK
  18.  
  19.         public SepiaEffect(IImageProvider source, double intensity = 0.42) : base(source)
  20.         {
  21.             // Self correct negative percentages to just zero them out and ensure no percentage goes above 1.0 (100%)
  22.             m_Intensity = (uint)((intensity < 0.00) ? 0.00 : (intensity > 1.00) ? 1.00 : intensity * 100);
  23.         }
  24.  
  25.         protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
  26.         {
  27.             var sourcePixels = sourcePixelRegion.ImagePixels;
  28.             var targetPixels = targetPixelRegion.ImagePixels;
  29.  
  30.             sourcePixelRegion.ForEachRow((index, width, position) =>
  31.             {
  32.                 for (int x = 0; x < width; ++x, ++index)
  33.                 {
  34.                     uint currentPixel = sourcePixels[index]; // get the current pixel
  35.                     uint red = (currentPixel & 0x00ff0000) >> 16; // red color component
  36.                     uint green = (currentPixel & 0x0000ff00) >> 8; // green color component
  37.                     uint blue = currentPixel & 0x000000ff; // blue color component
  38.  
  39.  
  40.                     // RGB to YIQ
  41.                     uint Y = (uint)Math.Min((0.299 * red + 0.587 * green + 0.114 * blue), 255);
  42.                     uint I = (uint)Math.Min((0.596 * red - 0.274 * green - 0.322 * blue), 255);
  43.                     uint Q = (uint)Math.Min((0.212 * red - 0.523 * green + 0.311 * blue), 255);
  44.  
  45.                     // Update for Brown Sepia look
  46.                     I = m_Intensity;
  47.                     Q = 0;
  48.  
  49.                     // YIQ to RGB
  50.                     red = (uint)Math.Min((1.0 * Y + 0.956 * I + 0.621 * Q), 255);
  51.                     green = (uint)Math.Min((1.0 * Y - 0.272 * I - 0.647 * Q), 255);
  52.                     blue = (uint)Math.Min((1.0 * Y - 1.105 * I + 1.702 * Q), 255);
  53.  
  54.  
  55.                     // Reassembling each component back into a pixel and assigning it to the output location 
  56.                     targetPixels[index] = 0xff000000 | (red << 16) | (green << 8) | blue;
  57.                 }
  58.             });
  59.         }
  60.     }
  61. }

Testing

The Test Apps for Viewing Custom Filters allow you to cycle through a number of different custom effects (including SepiaEffect) and apply them to the real-time camera preview or a static image.

In addition, the custom effect file can be dropped into your own project, and used as described in the section Using the filter.

Pre-requisites

Performance

The SepiaEffect is less efficient than the Nokia Imaging SDK's inbuilt SepiaFilter.

Device SepiaEffect SepiaFilter
Lumia 920 6-7 FPS 19-20 FPS

The SepiaEffect class runs at about 6-7 FPS (frames per second). The inbuilt SepiaFilter runs at around 19-20 FPS.

The Real Time Filter Demo test project is configured so that the inbuilt and custom effect run side-by-side for easy comparison.

Code walkthrough

The technique for changing a color image into a sepia look, like an old weathered picture, involves converting from the RGB color scheme to the YIQ color scheme. Then you zero out the "Q" component and adjust the "I" component by the level of intensity you want for the sepia look. Finally, you convert back from YIQ to RGB.

  1. // RGB to YIQ
  2. uint Y = (uint)Math.Min((0.299 * red + 0.587 * green + 0.114 * blue), 255);
  3. uint I = (uint)Math.Min((0.596 * red - 0.274 * green - 0.322 * blue), 255);
  4. uint Q = (uint)Math.Min((0.212 * red - 0.523 * green + 0.311 * blue), 255);
  5.  
  6. // Update for Sepia look
  7. I = 42;
  8. Q = 0;
  9.  
  10. // YIQ to RGB
  11. red = (uint)Math.Min((1.0 * Y + 0.956 * I + 0.621 * Q), 255);
  12. green = (uint)Math.Min((1.0 * Y - 0.272 * I - 0.647 * Q), 255);
  13. blue = (uint)Math.Min((1.0 * Y - 1.105 * I + 1.702 * Q), 255);

Note.pngNote: This technique above comes from the AForge.Net Project and actually produces a slightly different look than the SDK, but a value of 42 for the "I" component seems to match it the closest. As soon as we figure out an algorithm that matches the SDK, we'll update the default.

To go beyond the SDK, we simply added a parameter to the class to allow adjusting the intensity of the sepia look. Now you can choose your own customized sepia look.

  1. uint m_Intensity = 42; 
  2.  
  3. public SepiaEffect(IImageProvider source, double intensity = 0.42) : base(source)
  4. {
  5.     // Self correct negative percentages to just zero them out and ensure no percentage goes above 1.0 (100%)
  6.     m_Intensity = (uint)((intensity < 0.00) ? 0.00 : (intensity > 1.00) ? 1.00 : intensity * 100);
  7. }
  8. ...
  9.     // Update for Sepia look
  10.     I = m_Intensity;
  11. ...


Using the filter

Drop an image control into your XAML.

  1. <Image x:Name="FilterEffectImage" Width="800" Height="480" Stretch="Fill" Grid.RowSpan="2" />

Use this code to apply the filter effect to your chosen image and assign it to the XAML image control.

  1. // Initialize a WriteableBitmap with the dimensions of the XAML image control
  2. WriteableBitmap writeableBitmap = new WriteableBitmap((int)FilterEffectImage.Width, (int)FilterEffectImage.Height);
  3.  
  4. // Example: Accessing an image stream within a standard photo chooser task callback
  5. // http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh394019(v=vs.105).aspx
  6. //using (var imageStream = new StreamImageSource(e.ChosenPhoto))
  7.  
  8. // Example: Accessing an image stream from a sample picture loaded with the project in a folder called "Pictures"
  9. var resource = App.GetResourceStream(new Uri(string.Concat("Pictures/", "sample_photo_08.jpg"), UriKind.Relative));
  10. using (var imageStream = new StreamImageSource(resource.Stream))
  11. {
  12.     // Applying the custom filter effect to the image stream
  13.     using (var customEffect = new SepiaEffect(imageStream, 0.42))
  14.     {
  15.         // Rendering the resulting image to a WriteableBitmap
  16.         using (var renderer = new WriteableBitmapRenderer(customEffect, writeableBitmap))
  17.         {
  18.             // Applying the WriteableBitmap to our xaml image control
  19.             FilterEffectImage.Source = await renderer.RenderAsync();
  20.         }
  21.     }
  22. }


License

The code has been released with the standard MIT License, and can be viewed in the Github project here.


Summary

Hopefully you've enjoyed seeing how this custom effect implementation unlocks some of the mystery behind the amazing Nokia Imaging SDK.

As with all articles on the wiki, you are welcome to contribute any changes to this code that would improve the quality, whether it be additional features or improving its efficiency.

This page was last modified on 18 February 2014, at 06:40.
196 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×