×
Namespaces

Variants
Actions

Skip Pixel Custom Effect (Nokia Imaging SDK)

From Nokia Developer Wiki
Jump to: navigation, search

This article explains how to create a Skip Pixel custom effect. This copies every nth row and column to the target, skipping the others.

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 (06 Feb 2014)
Last edited: Rob.Kachmar (18 Feb 2014)

Contents

Introduction

The SkipPixelEffect copies only every nth specified row and column to the target, skipping over the other rows/columns in the source image. As the image has less pixels it is considerably less bright; the effect also allows the developer to control the brightness of those pixels which are copied.

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.

Note.pngNote: The effect is much more interesting in live camera preview than in the static images shown below.

Source code

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

SkipPixelEffect.cs (03 Feb 2014)

  1. // ============================================================================
  2. // DATE        AUTHOR                   DESCRIPTION
  3. // ----------  -----------------------  ---------------------------------------
  4. // 2014.01.20  Rob.Kachmar              Initial creation
  5. // ============================================================================
  6.  
  7. using System;
  8. using Nokia.Graphics.Imaging;
  9.  
  10. namespace NISDKExtendedEffects.ImageEffects
  11. {
  12.     public class SkipPixelEffect : CustomEffectBase
  13.     {
  14.         private int m_ProcessEveryNthRow = 1;
  15.         private int m_ProcessEveryNthColumn = 1;
  16.         private int m_RowModuloTarget = 0;
  17.         private int m_ColumnModuloTarget = 0;
  18.         private double m_BrightnessPercentage = 0;
  19.  
  20.         public SkipPixelEffect(IImageProvider source, int processEveryNthRow = 1, int processEveryNthColumn = 1, 
  21.             double brightness = 0) : base(source)
  22.         {
  23.             m_ProcessEveryNthRow = (processEveryNthRow <= 0) ? 1 : processEveryNthRow; // Protect against divide by zero
  24.             m_ProcessEveryNthColumn = (processEveryNthColumn <= 0) ? 1 : processEveryNthColumn; // Protect against divide by zero
  25.             m_RowModuloTarget = m_ProcessEveryNthRow - 1;
  26.             m_ColumnModuloTarget = m_ProcessEveryNthColumn - 1;
  27.             m_BrightnessPercentage = brightness;
  28.         }
  29.  
  30.         protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
  31.         {
  32.             var sourcePixels = sourcePixelRegion.ImagePixels;
  33.             var targetPixels = targetPixelRegion.ImagePixels;
  34.  
  35.             int rowIndex = 0;
  36.             sourcePixelRegion.ForEachRow((index, width, position) =>
  37.             {
  38.                 if ((rowIndex % m_ProcessEveryNthRow).Equals(m_RowModuloTarget)) // only process on every other Nth pixel per row
  39.                 {
  40.                     for (int x = 0; x < width; ++x, ++index)
  41.                     {
  42.                         if ((x % m_ProcessEveryNthColumn).Equals(m_ColumnModuloTarget)) // only process on every other Nth pixel per column
  43.                         {
  44.                             uint currentPixel = sourcePixels[index]; // get the current pixel
  45.                             uint red = (currentPixel & 0x00ff0000) >> 16; // red color component
  46.                             uint green = (currentPixel & 0x0000ff00) >> 8; // green color component
  47.                             uint blue = currentPixel & 0x000000ff; // blue color component
  48.  
  49.                             if (m_BrightnessPercentage < 0)
  50.                             {
  51.                                 // Dimming the image - A value of -1 or -100%, will completely reduce all colors to 0
  52.                                 // Reduce each color component by the passed in percentage of the amount of color
  53.                                 // it is currently displaying.
  54.                                 red = (uint)Math.Max(0, Math.Min(255, (red + (red * m_BrightnessPercentage))));
  55.                                 green = (uint)Math.Max(0, Math.Min(255, (green + (green * m_BrightnessPercentage))));
  56.                                 blue = (uint)Math.Max(0, Math.Min(255, (blue + (blue * m_BrightnessPercentage))));
  57.                             }
  58.                             else
  59.                             {
  60.                                 // Brightening the image - A value of 1 or 100%, will completely increase all colors to 255
  61.                                 // Increase each color component by the passed in percentage of the amount of color
  62.                                 // is has left before it reaches the max of 255.
  63.                                 red = (uint)Math.Max(0, Math.Min(255, (red + ((255 - red) * m_BrightnessPercentage))));
  64.                                 green = (uint)Math.Max(0, Math.Min(255, (green + ((255 - green) * m_BrightnessPercentage))));
  65.                                 blue = (uint)Math.Max(0, Math.Min(255, (blue + ((255 - blue) * m_BrightnessPercentage))));
  66.                             }
  67.  
  68.                             uint newPixel = 0xff000000 | (red << 16) | (green << 8) | blue; // reassembling each component back into a pixel
  69.                             targetPixels[index] = newPixel; // assign the newPixel to the equivalent location in the output image
  70.                         }
  71.                     }
  72.                 }
  73.                 rowIndex++;
  74.             });
  75.         }
  76.     }
  77. }

Testing

The Test Apps for Viewing Custom Filters allow you to cycle through a number of different custom effects (including SkipPixelEffect) 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

Device SkipPixelEffect - every 3rd row/column SkipPixelEffect - every 8th row/column SkipPixelEffect - every 13th row/column
Lumia 920 13-14 FPS 17 FPS 17-18 FPS

The SkipPixelEffect class runs 13-18 FPS (Frames Per Second) depending on how many pixels you want to skip.

Code walkthrough

Note.pngNote: This code walkthrough is borrowed from Custom Filter QuickStart for Nokia Imaging SDK

The key to skipping rows is to keep track of the row index, then take the modulo of the row index based on the rows you want to skip. You would also do the same thing with the column index, x. Let's take a look at the code below, which will only process every 3rd row and every 3rd column. Go ahead and play around with the processEveryNthRow and processEveryNthColumn parameters to see what happens.

Note.pngNote: If modulo is throwing you off, you can view many other explanations of it here.

  1. int processEveryNthRow = 3;
  2. int processEveryNthColumn = 3;
  3. processEveryNthRow = (processEveryNthRow <= 0) ? 1 : processEveryNthRow; // Protect against divide by zero
  4. processEveryNthColumn = (processEveryNthColumn <= 0) ? 1 : processEveryNthColumn; // Protect against divide by zero
  5. int rowModuloTarget = processEveryNthRow - 1;
  6. int columnModuloTarget = processEveryNthColumn - 1;
  7.  
  8. int rowIndex = 0;
  9. sourcePixelRegion.ForEachRow((index, width, position) =>
  10. {
  11.     if ((rowIndex % processEveryNthRow).Equals(rowModuloTarget)) // only process on every Nth pixel per row
  12.     {
  13.         for (int x = 0; x < width; ++x, ++index)
  14.         {
  15.             if ((x % processEveryNthColumn).Equals(columnModuloTarget)) // only process on every Nth pixel per column
  16.             {
  17.                 targetPixels[index] = sourcePixels[index];
  18.             }
  19.         }
  20.     }
  21.     rowIndex++;
  22. });


Note.pngNote: The SkipPixelEffect class code also allows you to change the brightness of the pixels that are displayed. You can read more about the brightness effect here

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 SkipPixelEffect(imageStream, 8, 8, 0.50))
  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 to skip over pixels in an image to create a fun new filtered view of your images. This is just one of many things you can do with 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 09:31.
72 page views in the last 30 days.
×