Nokia Imaging SDK 的高級使用—實時濾鏡拍照

 

 

有關 Nokia Imaging SDK 的初級使用,能夠參考:Nokia Imaging SDK濾鏡使用入門html

 

本文的主題:windows

一、 如何 PhotoCaptureDevice 類使用,以及如何在 MediaElement 控件上顯示攝像頭預覽架構

二、 如何經過 Nokia Imaging SDK 提供的濾鏡,運用到攝像頭的預覽縮略圖圖片流上。相片拍照完成後async

爲高像素圖片運用用戶選擇的濾鏡效果。ide

三、經過本工程,開發者能夠快速預覽 Nokia Imaging SDK 所提供 53 種濾鏡 的大體效果,能夠在post

實際的開發過程當中,快速選擇相應的濾鏡進行使用。ui

 

 

本文的內容:url

一、首先提供一個基本的代碼架構(basic文件夾下)。接下來的步驟是基於這個基本代碼工程進行操做的。「基本代碼工程」spa

實現了照片拍攝(使用 WP8 中的高級拍照 PhotoCaptureDevice 類)的基本功能,拍照完成後跳轉到照片預覽頁面。調試

基本代碼的運行如圖:

注意:本文不會對講述 PhotoCaptureDevice 類的使用。參考 MSDN

 

 

二、打開 basic 文件夾下的基本工程。在基本工程裏面,已經添加好 Nokia Imaging SDK的相關類庫。

工程目錄及相關類和頁面功能的說明:

 

三、由於工程完成後的代碼量較大,爲了更好的完成本工程,先介紹一下下面步驟將實現的功能。

1)單擊屏幕,顯示濾鏡選擇列表。包括 Nokia Imaging SDK 提供的 53個濾鏡。

 

2)從濾鏡列表選擇濾鏡後,攝像頭取景框實時顯示:

 

3)單擊拍攝按鈕,從 MainPage.xaml 頁面跳轉到ImagePreviewPage.xaml ,顯示通過濾鏡處理的圖片(截圖選擇的是「魔術筆濾鏡」):

 

 

四、在工程的根目錄下新建一個文件夾「FilterComponent」,用來存儲接下來的代碼文件。

五、由於 MediaElement 有兩個方法:

public void SetSource(MediaStreamSource mediaStreamSource);

public void SetSource(Stream stream);

 

這裏咱們使用第一個方法。

在 FilterComponent 文件夾下新建一個 CameraStreamSource類,該類繼承自 MediaStreamSource類。把這個CameraStreamSource

類用來做爲 MediaElement 控件的數據源。

注:這裏只列出重點方法的解釋,並未貼出所有代碼及註釋。具體代碼請查看Code_Snippets文件夾下的 CameraStreamSource.cs 文件。

 

六、重寫上面定義的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 控件提供視頻流的每一幀時調用,此時咱們可以

得到圖像的幀數據,此時咱們爲該幀添加用戶選擇的濾鏡效果。

 

 

七、在 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 文件。

 

八、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; // 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 文件。

 

九、在 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() 方法來初始這些變量。

 

十、修改 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(100, 100);

     // 爲示例圖片添加相應的濾鏡效果
     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 文件。

 

十一、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(0, 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 

 

 

提示:

一、由於本實驗會使用到手機攝像頭,因此建議經過真機調試

二、在運行源代碼時,會出現一個編譯錯誤: 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

相關文章
相關標籤/搜索