有关 Nokia Imaging SDK 的初级使用,可以参考:Nokia Imaging SDK滤镜使用入门

本文的主题:

1、如何 PhotoCaptureDevice 类使用,以及如何在 MediaElement 控件上显示摄像头预览。

2、如何通过 Nokia Imaging SDK 提供的滤镜,运用到摄像头的预览缩略图图片流上。相片拍照完成后

,再为高像素图片运用用户选择的滤镜效果。

3、通过本工程,开发者可以快速预览 Nokia Imaging SDK 所提供 53 种滤镜 的大致效果,可以在

实际的开发过程中,快速选择相应的滤镜进行使用。

本文的内容:

1、首先提供一个基本的代码架构(basic文件夹下)。接下来的步骤是基于这个基本代码工程进行操作的。“基本代码工程”

实现了照片拍摄(使用 WP8 中的高级拍照 PhotoCaptureDevice 类)的基本功能,拍照完成后跳转到照片预览页面。

基本代码的运行如图:

注意:本文不会对讲述 PhotoCaptureDevice 类的使用。参考 MSDN

2、打开 basic 文件夹下的基本工程。在基本工程里面,已经添加好 Nokia Imaging SDK的相关类库。

工程目录及相关类和页面功能的说明:

3、因为工程完成后的代码量较大,为了更好的完成本工程,先介绍一下下面步骤将实现的功能。

1)单击屏幕,显示滤镜选择列表。包括 Nokia Imaging SDK 提供的 53个滤镜。

2)从滤镜列表选择滤镜后,摄像头取景框实时显示:

3)单击拍摄按钮,从 MainPage.xaml 页面跳转到ImagePreviewPage.xaml ,显示经过滤镜处理的图片(截图选择的是“魔术笔滤镜”):

4、在工程的根目录下新建一个文件夹“FilterComponent”,用来存储接下来的代码文件。

5、因为 MediaElement 有两个方法:

public void SetSource(MediaStreamSource mediaStreamSource);

public void SetSource(Stream stream);

这里我们使用第一个方法。

在 FilterComponent 文件夹下新建一个 CameraStreamSource类,该类继承自 MediaStreamSource类。把这个CameraStreamSource

类用来作为 MediaElement 控件的数据源。

注:这里只列出重点方法的解释,并未贴出全部代码及注释。具体代码请查看Code_Snippets文件夹下的 CameraStreamSource.cs 文件。

6、重写上面定义的CameraStreamSource类中的两个重要方法:

protected override void OpenMediaAsync()
protected override void GetSampleAsync(MediaStreamType mediaStreamType)

1)OpenMediaAsync 方法:收集实例化 MediaStreamDescription 对象的集合所需的元数据,然后对其进行实例化。可以把这个方法理解成,

当初始化为 MediaElement 视频流时会调用 OpenMediaAsync(),在这个方法里面,设置流数据信息,包括了流数据,视频宽高,视频时间,

当初始化完成后,调用 ReportOpenMediaCompleted(mediaSourceAttributes, mediaStreamDescriptions) 方法,来通知 MediaElement

控件,MediaStreamSource已经打开,并提供相关视频流信息。该方法仅会在视频信息初始化时调用一次。

具体的解释可以参考工程的代码注释。

2)GetSampleAsync 方法:导致 MediaStreamSource 准备一个 MediaStreamSample,它描述要由媒体管线呈现的下一个媒体示例。可以通过 ReportGetSampleCompleted 和 ReportGetSampleProgress 响应此方法。当为 MediaElement 控件提供视频流的每一帧时调用,此时我们能够

获得图像的帧数据,此时我们为该帧添加用户选择的滤镜效果。

7、在 FilterComponent 文件夹下,新建一个 FilterItem 类,该类有5个成员:

 public class FilterItem
{
public int Index { get; set; }
public string Name { get; set; } /// <summary>
/// 引用当前用户选择的滤镜效果
/// </summary>
public static FilterItem CurrentFilterItem { get; set; } /// <summary>
/// 创建滤镜效果
/// </summary>
/// <param name="index">当 index 不为空时,设置 index 指定的滤镜,如果为空,则指定
/// CurrentFilterItem.Index 指定的滤镜</param>
/// <returns></returns>
public static List<IFilter> CreateInstance(int? index = null)
{

} /// <summary>
/// 滤镜列表数据源
/// </summary>
public static readonly List<FilterItem> FilterSource = new List<FilterItem>
{

}
}

该类的作用是为 MainPage 页面的滤镜列表提供数据源。其中CreateInstance() 方法通过Switch 语句来创建相应的滤镜实体。

注:这里只列出重点方法的解释,并未贴出全部代码及注释。具体代码请查看Code_Snippets文件夹下的 FilterItem.cs 文件。

8、在 FilterComponet 文件夹下,新建一个 NokiaImagingSDKEffects 类,在这个类中,我们主要添加一个

public async Task GetNewFrameAndApplyEffect(IBuffer frameBuffer, Size frameSize)

该方法的作用是为预览视频流的帧添加滤镜。该方法的全部代码:

/// <summary>
/// 为预览视频流的帧添加滤镜
/// </summary>
/// <param name="frameBuffer">帧数据</param>
/// <param name="frameSize">帧尺寸</param>
/// <returns></returns>
public async Task GetNewFrameAndApplyEffect(IBuffer frameBuffer, Size frameSize)
{
var scanlineByteSize = (uint)frameSize.Width * ; // 4 bytes per pixel in BGRA888 mode
var bitmap = new Bitmap(frameSize, ColorMode.Bgra8888, scanlineByteSize, frameBuffer); // 通过 _photoCaptureDevice 创建一个新的 image source
_cameraPreviewImageSource = new CameraPreviewImageSource(_photoCaptureDevice); if (FilterItem.CurrentFilterItem != null)
{
_filterEffect = new FilterEffect(_cameraPreviewImageSource)
{
Filters = FilterItem.CreateInstance()
}; var renderer = new BitmapRenderer(_filterEffect, bitmap);
await renderer.RenderAsync();
}
else
{
var renderer = new BitmapRenderer(_cameraPreviewImageSource, bitmap);
await renderer.RenderAsync();
}
}

注:这里只列出重点方法的解释,并未贴出全部代码及注释。具体代码请查看Code_Snippets文件夹下的 NokiaImagingSDKEffects.cs 文件。

9、在 FilterComponent 文件夹下创建一个 MainPage_Realtime.cs 文件,该文件存放的类是 MainPage 类的分部类,使用关键字 partial

关键字把新代码和基础代码工程的 MainPage 类进行区分:

public partial class MainPage : PhoneApplicationPage
{

}

在该文件中添加三个全局变量:

private MediaElement _mediaElement = null;
private NokiaImagingSDKEffects _cameraEffect = null;
private CameraStreamSource _cameraStreamSource = null;

并添加一个 InitializeEffect() 方法来初始这些变量。

10、修改 MainPage 类。

1)为 MainPage.xaml 页面中,DataTemplate 中为 Image 控件添加一个 Loaded 事件,当该控件加载完成后,添加预览滤镜图片:

<Image Loaded="Image_Loaded"/>

MainPage_Realtime.cs 文件中添加该 Image_Loaded 方法:

/// <summary>
/// 当滤镜列表模版中的 Image 加载完成后,添加相应的滤镜预览图
/// </summary>
private async void Image_Loaded(object sender, RoutedEventArgs e)
{
Image image = sender as Image; // 读取根目录下的示例图片
Stream _imageSource = App.GetResourceStream(new Uri("Sample.jpg", UriKind.Relative)).Stream; // 获取当前 Item 的 DataContext
FilterItem item = image.DataContext as FilterItem; WriteableBitmap writeableBitmap = new WriteableBitmap(, ); // 为示例图片添加相应的滤镜效果
using (var source = new StreamImageSource(_imageSource))
using (var filterEffect = new FilterEffect(source) { Filters = FilterItem.CreateInstance(item.Index).ToArray() })
using (var renderer = new WriteableBitmapRenderer(filterEffect, writeableBitmap))
{
await renderer.RenderAsync();
} // 显示到页面中
image.Source = writeableBitmap;
}

2)在 MainPage.xaml 页面,为 ListBox 中 DataTemplate 模版中的 Border 控件添加  Tap="Border_Tap" 事件,来把用户选择的滤镜效

果设置为全局共享变量,该事件在 MainPage 的分部类中实现:

/// <summary>
/// 用户单击滤镜列表中的滤镜项
/// </summary>
private void Border_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
//e.Handled = true; FilterItem.CurrentFilterItem = (sender as Border).DataContext as FilterItem;
}

2)在 MainPage.xaml 给名为 LayoutRoot 的 grid 添加一个 Tap="LayoutRoot_Tap"   事件,来动态切换滤镜列表的显示与隐藏,

该事件在 MainPage 的分部类中实现:

/// <summary>
/// 单击屏幕时,切换滤镜列表
/// </summary>
private void LayoutRoot_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
e.Handled = true; if (listbox_preview.Visibility == System.Windows.Visibility.Collapsed)
{
listbox_preview.Visibility = System.Windows.Visibility.Visible;
}
else
{
listbox_preview.Visibility = System.Windows.Visibility.Collapsed;
}
}

3)添加完上面代码,在 MainPage.xaml.cs 文件中,修改 OnNavigatedTo() 方法,把 BackgroundVideoBrush.SetSource(_photoCaptureDevice);

替换为 MainPage 分部类种添加的 InitializeEffect(); 当页面导航到 MainPage 页面后,初始化相应的控件和滤镜。

同样,在 OnNavigatingFrom() 中,添加 MainPage分部类 中的 Uninitialize_Realtime();方法,以当页面导航离开时,释放资源。

注:这里只列出重点方法的解释,并未贴出全部代码及注释。具体代码请查看Code_Snippets文件夹下的 MainPage_Realtime.cs 文件。

11、ImagePreviewPage.xaml.cs 页面中,为 PhotoCaptureDevice 类捕获的高分辨率图片添加用户选择的滤镜效果。因为高分辨率图片保存在了 ImageDataContext.Singleton.ImageStream  属性中,所以直接对它添加滤镜效果,然后显示在页面上:

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
ImageDataContext dataContext = ImageDataContext.Singleton; if (dataContext.ImageStream != null)
{
// 显示默认没有滤镜效果的图片
//BitmapImage bi = new BitmapImage();
//bi.SetSource(dataContext.ImageStream);
//image.Source = bi; dataContext.ImageStream.Seek(, SeekOrigin.Begin);//严重注意!!!!!!!! using (var source = new StreamImageSource(dataContext.ImageStream))
using (var filterEffect = new FilterEffect(source) { Filters = FilterItem.CreateInstance() })
using (var renderer = new JpegRenderer(filterEffect))
{
Windows.Storage.Streams.IBuffer buf = await renderer.RenderAsync(); Stream stream = System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.AsStream(buf);
BitmapImage bi = new BitmapImage();
bi.SetSource(stream);
image.Source = bi;
}
} base.OnNavigatedTo(e);
}

代码工程完成后,运行效果:

上面的 gif 图片快速演示了 Nokia Imging SDK 中的 53 种滤镜,并且给取景器快速运用其中对比比较明显的几个滤镜,拍照

后,即可得到经过滤镜处理的全像素照片。

总结:

本实验代码量比较多,没有全部粘贴工程代码,而是先在 basic 文件夹下提供一个用 PhotoCaptureDeVice类实现的拍

照功能的基本代码工程,然后在该文件夹下的 Code_Snippets 文件夹中,提供相应的代码片段。动手实验文档中主要讲解了重点代码的作用,

并且 Nokia Imaging SDK 提供的 全部 53种滤镜,都只是设置了默认值,具体参数的调整已经添加到工程的代码注释上。

有关 Nokia Imaging SDK 滤镜使用流程,请参考相关文档

代码工程下载:http://pan.baidu.com/s/1sj4RKo1

提示:

1、因为本实验会使用到手机摄像头,所以建议通过真机调试

2、在运行源代码时,会出现一个编译错误: Nokia Imaging SDK does not support the AnyCPU target platform.

因为 Nokia Imaging SDK 支持托管代码和本地代码,所以在编译前需要进行设置:

1)在模拟器上运行时:菜单 -> 生成 -> 配置管理器 -> 活动解决方案平台 -> x86 2)在真机上运行时:  菜单 -> 生成 -> 配置管理器 -> 活动解决方案平台 -> ARM

更多有关说明请参考: http://developer.nokia.com/Resources/Library/Lumia/#!nokia-imaging-sdk/adding-libraries-to-the-project.html

最新文章

  1. ASP.NET Core 中文文档 第二章 指南(8) 使用 dotnet watch 开发 ASP.NET Core 应用程序
  2. SQL中EXISTS的使用
  3. Windows 2008 R2 强制删除Cluster
  4. java与mysql连接
  5. 【BZOJ-4173】数学 欧拉函数 + 关于余数的变换
  6. ASP.NET Global Application_Error事件中访问Session报错 解决
  7. 正向代理与反向代理的区别【Nginx读书笔记】(zz)
  8. PHP 简单处理--文件下载--文件上传
  9. NSString的常见方法
  10. Json lib集成stucts2的使用方法 抛出 NestableRuntimeException异常的解决办法
  11. jq中 offset()方法, scrollTop()方法以及scrollLeft()方法
  12. Spring Data Solr教程(翻译)
  13. e2e 自动化集成测试 架构 实例 WebStorm Node.js Mocha WebDriverIO Selenium Step by step (一) 京东 商品搜索
  14. sulime-text 3 安装以及使用
  15. 反射(学习整理)----Class类和加载器ClassLoader类的整理
  16. rhel6.4 using centos source
  17. 新浪微博iOS SDK UIImage+WBSDKResize.o
  18. 用js来实现那些数据结构(栈01)
  19. windows eclipse安装lombok插件
  20. 一脸懵逼学习HBase的搭建(注意HBase的版本)

热门文章

  1. java Class的 getSuperclass与getGenericSuperclass区别
  2. linux、mac的bash和zsh如何切换
  3. OpenRISC自定义指令GCC修改
  4. 数学图形(1.25)cassini曲线
  5. Informatica 常用组件Source Qualifier之四 SQL Query
  6. JS-得到屏幕宽高、页面宽高
  7. HUD Text 学习
  8. android 程序更新(没有sdcard)
  9. Python list添加新元素
  10. [Swift A] - Welcome to Swift