×
Namespaces

Variants
Actions

Implementations of Custom Filter for the Nokia Imaging SDK

From Nokia Developer Wiki
Jump to: navigation, search

This article explains how to implement Custom Filters for the Nokia Imaging SDK.

SignpostIcon XAML 40.png
WP Metro Icon WP8.png
Article Metadata
Code ExampleTested with
SDK: Windows Phone 8.0 SDK, Nokia Imaging SDK v1.0
Compatibility
Platform(s):
Windows Phone 8
Dependencies: Nokia Imaging SDK
Article
Created: Engin Kırmacı (15 Dec 2013)
Last edited: hamishwillee (08 Jan 2014)

Contents

Introduction

After Nokia Imaging SDK graduates from beta, custom filter introduced. This is most exciting feature, that allow us to create our own filters. In this article, I'll be explaining how to implement custom filters for different purposes by comparing differences in implemantation that described in Core Concepts document.

Note.pngNote: Sample Filters are implemented for my framework which is described in "Filter and Custom Filter Management Framework for The Nokia Imaging SDK". So that some of complex filters may not be working well without my framework. But it's simple to fix, I'll be explaining in the article.

How to implement custom filters?

I'm categorizing my sample custom filters in 3 category; calculation purpose, simple ones and complex ones. I'll try to explain over sample filters.

Custom Filter for Calculation Purpose

HistogramFilter is the only sample for this type of filter. This filters calculates Red, Green, Blue and Luminance of image. These parameters can be used as filter parameters then.

Trick is here, IsInPlace property in base constructor is set to true, so that no need to set targetPixelRegion.ImagePixels.

public class HistogramFilter : CustomEffectBase
{
public int[] Red { get; set; }
 
public int[] Green { get; set; }
 
public int[] Blue { get; set; }
 
public int[] Luminance { get; set; }
 
public HistogramFilter(IImageProvider source, out int[] red, out int[] green, out int[] blue, out int[] luminance)
: base(source, true)
{
Red = new int[byte.MaxValue + 1];
Green = new int[byte.MaxValue + 1];
Blue = new int[byte.MaxValue + 1];
Luminance = new int[byte.MaxValue + 1];
 
red = Red;
green = Green;
blue = Blue;
luminance = Luminance;
}
 
protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
{
sourcePixelRegion.ForEachRow((index, width, pos) =>
{
for (int x = 0; x < width; ++x, ++index)
{
Color c = ToColor(sourcePixelRegion.ImagePixels[index]);
 
Red[c.R]++;
Green[c.G]++;
Blue[c.B]++;
 
double luminance = 0.299 * c.R + 0.587 * c.G + 0.114 * c.B;
if (luminance < byte.MinValue)
luminance = byte.MinValue;
else if (luminance > byte.MaxValue)
luminance = byte.MaxValue;
 
Luminance[(byte)luminance]++;
}
});
}

Note.pngNote: IsInPlace property is true here. Which means sourcePixel and targetPixel is same array. Documentation says that it's more efficient. But you have to be careful if you want to process pixel and don't want to change source pixel.

Simple Custom Filter

ThresholdFilter is one of the sample for this type of filter. It's the same implementation as described here

public class ThresholdFilter : CustomEffectBase
{
private byte _thresholdR = 0;
private byte _thresholdG = 0;
private byte _thresholdB = 0;
 
public ThresholdFilter(IImageProvider source, byte R, byte G, byte B)
: base(source)
{
_thresholdR = R;
_thresholdG = G;
_thresholdB = B;
}
 
protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
{
sourcePixelRegion.ForEachRow((index, width, pos) =>
{
for (int x = 0; x < width; ++x, ++index)
{
Color c = ToColor(sourcePixelRegion.ImagePixels[index]);
 
if (c.R < _thresholdR)
c.R = 0;
 
if (c.G < _thresholdG)
c.G = 0;
 
if (c.B < _thresholdB)
c.B = 0;
targetPixelRegion.ImagePixels[index] = FromColor(c);
}
});
}
}

Note.pngNote: IsInPlace property didn't set here. Default value of it is false. Which means sourcePixel, targetPixel is different array and you have to get pixel from sourcePixel, process it and set to targetPixel. Also note that If you don't set targetPixel, you'll see black image.

Complex Custom Filter

PixelInterpolation is one of the sample for this type of filter. This filter pixelates image without changing the image size. It divides to image to rectangles like table and get top left pixel of each cell. Then changes every pixels in cell to corner.
For that purpose, iteration every pixels with ForEachRow is not efficient. First of all, use following to get width and height of an image.

int width = (int)sourcePixelRegion.Bounds.Width;
int height = (int)sourcePixelRegion.Bounds.Height;

Then, it iterates only corner pixels.

int offsetX = _pixelSize / 2;
int offsetY = _pixelSize / 2;
 
for (int x = 0; x < width; x += _pixelSize)
{
for (int y = 0; y < height; y += _pixelSize)
{
//calculation here
}
}

Final code looks as below

public class PixelInterpolation : CustomEffectBase
{
private int _pixelSize = 0;
 
public PixelInterpolation(IImageProvider source, int PixelSize)
: base(source)
{
_pixelSize = PixelSize;
}
 
protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
{
int offsetX = _pixelSize / 2;
int offsetY = _pixelSize / 2;
 
int width = (int)sourcePixelRegion.Bounds.Width;
int height = (int)sourcePixelRegion.Bounds.Height;
 
for (int x = 0; x < width; x += _pixelSize)
{
for (int y = 0; y < height; y += _pixelSize)
{
// make sure that the offset is within the boundry of the image
while (x + offsetX >= width) offsetX--;
while (y + offsetY >= height) offsetY--;
 
// get the pixel color in the center of the soon to be pixelated area
var pixel = sourcePixelRegion.ImagePixels[DimensionConverter.To1D(x + offsetX, y + offsetY, width)];
 
// for each pixel in the pixelate size, set it to the center color
for (int i = x; i < x + _pixelSize && i < width; i++)
for (int j = y; j < y + _pixelSize && j < height; j++)
targetPixelRegion.ImagePixels[DimensionConverter.To1D(i, j, width)] = pixel;
}
}
}
}

Note.pngNote: ForEachRow method in PixelRegion class used for iterate over the pixels consecutively. If you want to iterate every pixels consecutively, don't use for loop, ForEachRow method is the most efficient way. Unless you want to iterate some pixels, not all of them or multiple iteration for each pixel as shown in the code above, use for loop.

Note.pngNote: IsInPlace property didn't set here. Default value of it is false. Which means sourcePixel, targetPixel is different array and you have to get pixel from sourcePixel, process it and set to targetPixel. Also note that If you don't set targetPixel, you'll see black image.

Use Complex Custom Filter without my Framework

QuadTransformation filter is transforms quadratic shape to rectangular form.

QuadTransformation.png

As you seen in the image, result will be smaller than input image. But custom filter implementation doesn't allow us to change output size. I solved that problem in my framework by using IPreProcess and IPostProcess interfaces.

public class QuadTransformation : CustomEffectBase, IPostProcess
{
.
.
protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
{
.
.
}
 
public FactoryBase PostProcessFactory()
{
var factory = new NokiaFilterFactory(null);
factory.Filters.Add(new ReframingFilter(new Rect(0, 0, Size.Width, Size.Height), 0));
 
return factory;
}
}

With this implemantation, after QuadTranformation processed, ReframingFilter applied to image.

To use this custom filter without my framework, you've to build pipeline between QuadTranformation and ReframingFilter as below.The result will be the as same as with using my framework.

var customFilter = new QuadTransformation(source, new Windows.Foundation.Size(300, 300), QuadDirection.QuadToRect, EdgePoints);
 
var effects = new FilterEffect(customFilter);
effects.Filters = new IFilter[]
{
new ReframingFilter(new Rect(0, 0, Size.Width, Size.Height), 0))
};
 
var renderer = new WriteableBitmapRenderer(effects, outputBitmap);
await renderer.RenderAsync();

Sample Filters

  • HistogramFilter (calculates Red, Green, Blue and Luminance data for histogram of image)

Note.pngNote: Histogram filter doesn't render image, it's for calculation purpose.

Summary

As you've seen in article, it's easy to implement your own custom filters. I implemented some filters which are used for image processing and I'll constantly adding new filters for that purpose. If you request me a custom filter implementation, please add a comment. I'll try my best and also you can contribute to project, follow github page.

This page was last modified on 8 January 2014, at 06:57.
108 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.

×