×
Namespaces

Variants
Actions
Revision as of 12:23, 11 December 2012 by galazzo (Talk | contribs)

Enabling wallet payment by face recognition

From Nokia Developer Wiki
Jump to: navigation, search

This article, the second of a series based on DSP project and focused on face recognition, shows step by step how to implement a way to process wallet payment authorization.

WP Metro Icon Multimedia.png
SignpostIcon XAML 40.png
WP Metro Icon WP8.png
Article Metadata
Tested with
Devices(s): Nokia Lumia
Compatibility
Platform(s): Windows Phone 8
Windows Phone 8
Article
Keywords: Wallet, Payment, Face Recognition
Created: galazzo (11 Dec 2012)
Last edited: galazzo (11 Dec 2012)

Contents

Introduction

A new interesting feature of Windows Phone 8 is certainly the Wallet and Deals APIs which allows users to do the following:

  • Collect coupons, credit cards, memberships, loyalty cards, and more in one place.
  • Manage the payment instruments that they use in the app and music store.
  • Link items in the Wallet to apps on their phone.
  • Make contactless transactions, using Near-Field Communication (NFC), in some markets.

The Wallet API offers full programmatic access to the Wallet. It allows you to create, read, update, and delete Wallet items to implement Deals or Payments.
Deals are useful to manage coupons, loyalty cards, Payment instrument manage a balance on an account maintained by your backend.
The sample application we will create first acquires the face sample to compare and store it int oa file. Throught RootFrame.UriMapper rewriting when the app is called from Wallet before to process payment is required to compare your face with the one saved into the system. If there is a match payment process can continue else is stopped.

Required capabilities

In order to use Wallet API in Windows Phone 8 you need to specify in the WMAppManifest.xml the following reqiored capabilities otherwise your app might not work correctly or it might fail the process of submission to the Store.

Capability API that requires this capability
ID_CAP_WALLET Required for all Wallet API, which is anything in Microsoft.Phone.Wallet or Microsoft.Phone.SecureElement.
ID_CAP_WALLET_PAYMENTINSTRUMENTS Required for PaymentInstrument and OnlinePaymentInstrument.
ID_CAP_WALLET_SECUREELEMENT Required for SecureElementSession, SecureElementChannel and SecureElementReader.

Warning.pngWarning: To deploy or submit an app that uses ID_CAP_WALLET_SECUREELEMENT or ID_CAP_WALLET_PAYMENTINSTRUMENTS, you must request special permissions and have that permission applied to your developer account.

Creating the UI

The following code create the object to display the camera video flow and the snap button to save the captured image, compute or save it. Besides MainPage.xml the same code is needed for the secondary screen called Wallet.xaml we need to create to be opened when the application is called from the wallet.

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.Background>
<VideoBrush x:Name="viewfinderBrush">
<VideoBrush.RelativeTransform>
<CompositeTransform CenterY="0.5" CenterX="0.5" Rotation="-90"/>
</VideoBrush.RelativeTransform>
</VideoBrush>
</Grid.Background>
</Grid>
<Button Content="Snap Picture" Click="SaveImage" Margin="0,624,0,0" Grid.Row="1" />
<!--Application progress bar.-->
<ProgressBar Height="10" Name="progressBar" Width="460" Visibility="Collapsed" Margin="12,365,8,286" Grid.Row="1" IsIndeterminate="True" />

Remapping URI

Into App.xaml.cs add the following code:

class MyAppUriMapper : UriMapperBase
{
public override Uri MapUri(Uri uri)
{
string tempUri = uri.ToString();
if (tempUri.Contains("PaymentInstrument"))
{
return new Uri("/Wallet.xaml", UriKind.Relative);
}
else
{
return uri;
}
}
}
 
public partial class App : Application
{
..........
 
public App()
{
..........
RootFrame.UriMapper = new MyAppUriMapper();
}
}

Camera

In common with Wallet.xaml.

public partial class MainPage : PhoneApplicationPage
{
PhotoCamera cam;
MediaLibrary library = new MediaLibrary();
 
public MainPage()
{
InitializeComponent();
this.Loaded += Page_Loaded;
}
 
void Page_Loaded(object sender, RoutedEventArgs e)
{
if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
{
cam = new Microsoft.Devices.PhotoCamera(CameraType.FrontFacing);
cam.CaptureImageAvailable += cam_CaptureImageAvailable;
viewfinderBrush.SetSource(cam);
} else
if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
{
cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);
 
cam.CaptureImageAvailable += cam_CaptureImageAvailable;
viewfinderBrush.SetSource(cam);
}
}
 
private void SaveImage(object sender, RoutedEventArgs e)
{
cam.CaptureImage();
}
}

Face Recognition Support

Add the following lines to MainPage.xaml, in common with Wallet.xaml.

public partial class MainPage : PhoneApplicationPage
{
PhotoCamera cam;
MediaLibrary library = new MediaLibrary();
 
public static WriteableBitmap CapturedImage;
private static int W = 256;
private static int H = 256;
private static int matchSamples = 25;
 
private double[] compareSignal = new Double[matchSamples];
 
private Double[] pRealIn = new Double[W * H];
private Double[] pImagIn = new Double[W * H];
private Double[] pRealOut = new Double[W * H];
private Double[] pImagOut = new Double[W * H];
private Double[] pRealOut2 = new Double[W * H];
private Double[] pImagOut2 = new Double[W * H];
 
private const string faceFileName = "face.csv";
.......

 void cam_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
{
//Take JPEG stream and decode into a WriteableBitmap object
Deployment.Current.Dispatcher.BeginInvoke(delegate()
{
MainPage.CapturedImage = PictureDecoder.DecodeJpeg(e.ImageStream, W, H);
 
//Collapse visibility on the progress bar once writeable bitmap is visible.
progressBar.Visibility = Visibility.Collapsed;
 
int[] pixel = MainPage.CapturedImage.Pixels;
 
int color = 0;
for (int y = 0; y < MainPage.CapturedImage.PixelHeight; y++)
{
for (int x = 0; x < MainPage.CapturedImage.PixelWidth; x++)
{
color = MainPage.CapturedImage.Pixels[x + (y * MainPage.CapturedImage.PixelWidth)];
pRealIn[x + (y * MainPage.CapturedImage.PixelWidth)] = DSP.Utilities.ColorToGray(color) & 0xFF;
 
}
}
 
Double[] signal;
 
System.Diagnostics.Debug.WriteLine("Using Fourier");
DSP.FourierTransform.Compute2D((uint)W, (uint)H, ref pRealIn, null, ref pRealOut, ref pImagOut, false);
signal = DSP.Utilities.triangularExtraction(ref pRealOut, (uint)W, (uint)H, (uint)matchSamples, 0);
 
DSP.Utilities.saveSignal(ref signal, faceFileName);
 
Wallet_CreateNewPaymentInstrument();
 
});
 
}

Wallet:PaymentInstruments

Include the following namespaces:

using System.Windows.Media.Imaging;
using Windows.System;
using Microsoft.Phone.Tasks;
using Microsoft.Phone.Wallet;
using System.Windows.Media;

The following code is needed to register our application into the wallet in order to be able to call it from the Wallet.
private void Wallet_CreateNewPaymentInstrument()
{
// Check if the object is already created
if ((Microsoft.Phone.Wallet.Wallet.FindItem("facedetectionwallet") as PaymentInstrument) == null)
{
var item = new PaymentInstrument()
{
IssuerName = "sebastiano.galazzo@gmail.com",
CustomerName = "Sebastiano Galazzo",
ExpirationDate = DateTime.Now.AddDays(1),
PaymentInstrumentKinds = PaymentInstrumentKinds.Debit,
DisplayName = "Face Recognition Wallet",
Logo99x99 = GetBitmapSource("99x99.png"),
Logo336x336 = GetBitmapSource("336x336.png"),
Logo159x159 = GetBitmapSource("159x159.png"),
DisplayAvailableBalance = "50€?",
DisplayBalance = "100€?",
DisplayCreditLimit = "1000€",
DisplayAvailableCredit = "1000€",
BackgroundColor = Color.FromArgb(255, 70, 150, 250),
Nickname = "Bino",
Message = "Face recognition based wallet.",
MemberSince = DateTime.Now.AddYears(-1),
AccountNumber = "12345679",
NavigationUri = new Uri("/mainpage.xaml?wallet=PaymentInstrument", UriKind.Relative)
};
item.UpdateId("facedetectionwallet");
AddWalletItemTask task = new AddWalletItemTask()
{
Item = item
};
task.Completed += (s, args) => MessageBox.Show(args.TaskResult.ToString());
task.Show();
 
} else {
MessageBox.Show("Face updated!");
}
Launcher.LaunchUriAsync(new Uri("wallet://", UriKind.RelativeOrAbsolute));
}
 
private BitmapSource GetBitmapSource(string url)
{
var bmp = new BitmapImage();
bmp.SetSource(Application.GetResourceStream(new Uri(url, UriKind.Relative)).Stream);
return bmp;
}

Wallet.xaml

This page is opened when the application is called from Wallet. Most of the code is in common with MainPage.xaml except cam_CaptureImageAvailable code and the lack of Wallet_CreateNewPaymentInstrument that is needed to register application into the wallet but unnecessary here.

using DSP;
 
namespace FaceWallet
{
public partial class Wallet : PhoneApplicationPage
{
PhotoCamera cam;
MediaLibrary library = new MediaLibrary();
 
public static WriteableBitmap CapturedImage;
private static int W = 256;
private static int H = 256;
private static int matchSamples = 25;
 
private double[] compareSignal = new Double[matchSamples];
 
private Double[] pRealIn = new Double[W * H];
private Double[] pImagIn = new Double[W * H];
private Double[] pRealOut = new Double[W * H];
private Double[] pImagOut = new Double[W * H];
private Double[] pRealOut2 = new Double[W * H];
private Double[] pImagOut2 = new Double[W * H];
 
private const string faceFileName = "face.csv";
 
public Wallet()
{
InitializeComponent();
this.Loaded += Page_Loaded;
}
 
void Page_Loaded(object sender, RoutedEventArgs e)
{
if ((compareSignal = DSP.Utilities.loadSignal(faceFileName)) == null) { MessageBox.Show("Face to recognize has not been sampled.\nPlease procedd to sampling before continue."); return; }
 
if (PhotoCamera.IsCameraTypeSupported(CameraType.FrontFacing))
{
cam = new Microsoft.Devices.PhotoCamera(CameraType.FrontFacing);
cam.CaptureImageAvailable += cam_CaptureImageAvailable;
viewfinderBrush.SetSource(cam);
}
else
if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
{
cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);
 
cam.CaptureImageAvailable += cam_CaptureImageAvailable;
viewfinderBrush.SetSource(cam);
}
}
 
void cam_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
{
Deployment.Current.Dispatcher.BeginInvoke(delegate()
{
//Take JPEG stream and decode into a WriteableBitmap object
MainPage.CapturedImage = PictureDecoder.DecodeJpeg(e.ImageStream, W, H);
 
//Collapse visibility on the progress bar once writeable bitmap is visible.
progressBar.Visibility = Visibility.Collapsed;
 
int[] pixel = MainPage.CapturedImage.Pixels;
 
int color = 0;
for (int y = 0; y < MainPage.CapturedImage.PixelHeight; y++)
{
for (int x = 0; x < MainPage.CapturedImage.PixelWidth; x++)
{
color = MainPage.CapturedImage.Pixels[x + (y * MainPage.CapturedImage.PixelWidth)];
pRealIn[x + (y * MainPage.CapturedImage.PixelWidth)] = DSP.Utilities.ColorToGray(color) & 0xFF;
}
}
 
Double[] match;
double mse = 0;
 
System.Diagnostics.Debug.WriteLine("Using Fourier");
DSP.FourierTransform.Compute2D((uint)W, (uint)H, ref pRealIn, null, ref pRealOut, ref pImagOut, false);
match = DSP.Utilities.triangularExtraction(ref pRealOut, (uint)W, (uint)H, (uint)matchSamples, 0);
 
/*System.Diagnostics.Debug.WriteLine("Using Wavelet");
DSP.Wavelet.haar2(ref pRealIn, H, W);
match = DSP.Utilities.squareExtraction(ref pRealIn, (uint)W, (uint)H, (uint)matchSamples, 0);*/

 
mse = DSP.Utilities.MSE(ref compareSignal, ref match, (int)matchSamples);
 
// Normalize Fourier result
mse /= 1000000000;
 
// Normalize Wavelet
//mse /= 100000;
 
mse = Math.Round(mse);
 
System.Diagnostics.Debug.WriteLine("MSE:" + mse);
 
if (mse < 55)
{
MessageBox.Show("You have been recognized!\nMSE:" + mse + "\nWe can proceed with payment");
}
else
{
MessageBox.Show("You have not been recognized!\nMSE:"+mse+"\nWe can't proceed with payment.\nIf you are the correct people, please retry to shoot a new photo with different environment conditions.");
}
 
});
}
 
private void SaveImage(object sender, RoutedEventArgs e)
{
cam.CaptureImage();
}
 
}
}
598 page views in the last 30 days.
×