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.

Wide Angle Lens Effect

From Wiki
Jump to: navigation, search
Featured Article
18 Aug
2014

This article explains how to implement a Wide Angle Lens effect.


WP Metro Icon WP8.png
Article Metadata
Code ExampleTested with
SDK: Windows Phone 8.0, 8.1
Devices(s): Nokia Lumia 920, 625 , 620
Compatibility
Platform(s):
Windows Phone 8
Article
Created: Loukt (21 Jun 2014)
Last edited: croozeus (18 Aug 2014)


Contents

Introduction

A wide-angle lens refers to a lens with a focal length substantially smaller than the normal lens focal length, this lens allows more of the scene to be included in the picture.

This lens is usually used to emphasize the difference in size or distance between objects in the foreground and the background, nearby objects appear very large and objects at a moderate distance would appear small and far away.

Wide Angle Effect

Basically, to go from a normal picture to a Wide-Angle is clearly impossible as we need to retrieve more data around the image, in this article we'll try to simulate the Effect giving an illusion of a Wide Angle Effect.

normal image without distortion
Like the FishEye Lens, the Wide Angle also applies some distortions on the image, we'll try to reproduce those distortions and try to bring in the emphasis done by the lens on the image.
image with distortion applied
We can easily define these distortions as a gradual stretching in both the width and height, having as a start points the center vertical line of the image.



Creating the effect

Before creating a custom effect, we recommend you read Custom Filter QuickStart for Nokia Imaging SDK.

How to calculate the numerical distortion values

Wide Angle Carreau F1.jpg
as stated before, there is a gradual stretching in both the width and the height, starting from the central vertical line points to the edges of the image, we can perform this "gradual" distortions effect mathematically using Numerical Series, widening the distortions at each iteration.
Un+1 = Un + Distortion


Before we start the calculating the distortions, to make the computing easy we start by normalizing all the pixels to a range of [-1 1] for both height and width, and then Starting from the center of the first row we start with left side, then the right side.

Wide Angle Carreau - F2.jpg
There is also a case where we could leave a portion of the center untouched in which we simply specify the percentage to ignore.

In the normal case, the distortion will start from the center (blue vertical line) and will increase gradually till the edges of the image (orange vertical lines), as for the second case, a rectangle equals to the specified percentage will be ignored (blue rectangle) and will not be affected, the distortion will start at the edges of this rectangle to the orange vertical lines.

we set two constants for the Height and Width distortion and then we divide the image into 3 parts, the left side, the center (which could be one line) and the right side

// two constant values to controle the distortion for the height and width
const double HeightDistortion = 0.0005;
const double WidthDistortion = 0.0001;
//we calculate according the CenterDistance to be ignored, the starting
//points from the left and the right
int startLeft = (int)(halfwidth - halfwidth * CenterDistance);
int startRight = (int)(halfwidth + halfwidth * CenterDistance);
 
// apply the distortion for the left side of the image
for (int x = startLeft-1; x >= 0 ; x--)
{...
widthDist = widthDist + WidthDistortion;
heightDist = heightDist + HeightDistortion;
}
// leave the center unchanged
for (int x = startLeft; x < startRight; x++, index++)
{
targetPixels[index] = sourcePixels[index];
}
//apply the distortion to the right side
for (int x = startRight; x < width; x++)
{...
widthDist = widthDist + WidthDistortion;
heightDist = heightDist + HeightDistortion;
}

The code

const double HeightDistortion = 0.0005;
const double WidthDistortion = 0.0001;
 
protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
{
var sourcePixels = sourcePixelRegion.ImagePixels;
var targetPixels = targetPixelRegion.ImagePixels;
int rowindex = 0;
int halfwidth = (int)targetPixelRegion.ImageSize.Width / 2;
 
int startLeft = (int)(halfwidth - halfwidth * CenterDistance);
int startRight = (int)(halfwidth + halfwidth * CenterDistance);
 
double widthDist = 0;
double heightDist = 0;
double resizeH = 0;
sourcePixelRegion.ForEachRow((index, width, position) =>
{
double ny = ((2 * rowindex) / sourcePixelRegion.ImageSize.Height) - 1;
 
 
widthDist = heightDist = 0;
for (int x = startLeft-1; x >= 0 && index < width * sourcePixelRegion.ImageSize.Height; x--)
{
resizeH = heightDist / startLeft;
double newSize = resizeH * (startLeft - x) + 1;
double nx = ((2 * x) / sourcePixelRegion.ImageSize.Width) - 1;
//compute new x,y
double nyn = ny / newSize;
double nxn = nx + widthDist;
 
//
if (nxn <= 1 && nxn >= -1 && nyn >= -1 && nyn <= 1)
{
int x2 = (int)(((nxn + 1) * sourcePixelRegion.ImageSize.Width) / 2);
int y2 = (int)(((nyn + 1) * sourcePixelRegion.ImageSize.Height) / 2);
// find (x2,y2) position from source pixels
int srcpos = (int)(y2 * sourcePixelRegion.ImageSize.Width + x2);
// make sure that position stays within arrays
if (srcpos >= 0 &
srcpos < sourcePixelRegion.ImageSize.Width * sourcePixelRegion.ImageSize.Height)
{
targetPixels[index + x] = sourcePixels[srcpos];
}
}
widthDist = widthDist + WidthDistortion;
heightDist = heightDist + HeightDistortion;
}
 
index = rowindex * width + startLeft;
 
// if we are in the Center, don't distort
for (int x = startLeft; x < startRight; x++, index++)
{
targetPixels[index] = sourcePixels[index];
}
 
widthDist = heightDist = 0;
for (int x = startRight; x < width; x++)
{
resizeH = heightDist / startLeft;
double newSize = resizeH * (startRight - x) + 1;
double nyn = ny * newSize;
double nx = ((2 * x) / sourcePixelRegion.ImageSize.Width) - 1;
double nxn = nx - widthDist;
 
if (nxn <= 1 && nxn >= -1 && nyn >= -1 && nyn <= 1)
{
int x2 = (int)(((nxn + 1) * sourcePixelRegion.ImageSize.Width) / 2);
int y2 = (int)(((nyn + 1) * sourcePixelRegion.ImageSize.Height) / 2);
int srcpos = (int)(y2 * sourcePixelRegion.ImageSize.Width + x2);
// make sure that position stays within arrays
if (srcpos >= 0 &
srcpos < sourcePixelRegion.ImageSize.Width * sourcePixelRegion.ImageSize.Height)
{
targetPixels[index + x - startRight] = sourcePixels[srcpos];
}
}
else break;
widthDist = widthDist + WidthDistortion;
heightDist = heightDist + HeightDistortion;
}
 
 
rowindex++;
});
}

Performance

Device WideAngleEffect
Lumia 925 4-5 FPS
Lumia 620 2-3 FPS

Using the FishEye Effect

There are multiple ways of using the filter, but here is a quick and easy way to see an example. Download the RealTimeFilterDemo solution available here.

It's recommended to read the walk-through of the solution available here too).

case xx: //replace xx with a number according the effectCount in your list
{
EffectName = String.Format(nameFormat, (_effectIndex + 1), "Wide Angle");
_customEffect = new WideAngleEffect(m_StreamImageSource, 0);
//the second parameter is the portion from center to ignore, the range is [0,1]
//0 means nothing is ignored.
//1 means all the image is ignored
}
break;

Results

Original image Result
Original image
Wide Angle
Original image
Wide Angle
Original image
Wide Angle

More information

Wide Angle Lens
Wide Angle Imaging Geometry

This page was last modified on 18 August 2014, at 11:43.
628 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.

×