Makale Özeti

Bu yazımızda Silverlight 4 Beta ile gelen yeni özelliklerden WebCam erişimine göz atarak WebCam üzerinden webde fotoğraf çekmeyle ilgili iki farklı yönteme göz atacağız.

Makale

Silverlight 2 sonrasında CLR'a geçiş ve 3 ile gelen yeni özellikler çerçevesinde en sık aldığım sorulardan biri Mikrofon ve Ses kartı erişiminin olup olmadığıydı. Silverlight 4 ile beraber her iki donanıma da doğrudan erişim geliyor. Bu erişim ile çok farklı uygulamalar geliştirmek mümkün, ister görüntülü chat sistemleri, ister Silverlight içerisinde doğrudan harici bir görüntü kaynağından gelen görüntüyü proses eden barkod okuma uygulamaları olsun çok ilginç çözümler geliştirilebilir. Biz bu yazımızda Silverlight 4 Beta içerisinden kamera erişimine göz atacağız ve kamera görüntüsünden de bir kare almaya çalışacağız. Aldığınız fotoğrafı sonrasında ister sunucuya gönderebilir ister doğrudan kullanıcıya verebilirsiniz.

Kamera'ya nasıl ulaşırız?

Silverlight içerisinden sistemde bulunan tüm kameraların bir listesini alabilir ve özelliklerine göre kamera seçebilirsiniz. Hatta söz konusu kameraların tek tek hangi çözünürlüklerde ve kalitede kayıt sağlayabileceğini de bulabilirsiniz.

[VB]

Partial Public Class MainPage

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim Kameralar = CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices

        Dim Liste = From inc In Kameralar

                    From formats In inc.SupportedFormats

                    Select New Kamera With {.Adi = inc.FriendlyName,

                                             .Format = formats.FramesPerSecond & "fps," &

                                                formats.Width & "x" & formats.Height,

                                             .Varsayilan = inc.IsDefaultDevice}

 

        myGrid.ItemsSource = Liste

    End Sub

 

    Public Class Kamera

        Property Adi As String

        Property Format As String

        Property Varsayilan As Boolean

    End Class

End Class

Yukarıdaki örnek uygulamada ekran bir DataGrid bulunuyor. Bu gride CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices ile aldığımız tüm kameraları SupportedFormats dizilerindeki sağladıkları çözünürlüklerle beraber joinleyerek aktarıyoruz. Benim test makinemde tek kamera olduğu için aşağıdaki ekran görüntüsü ile karşılaştım.

Webcam'in desteklediğini ayarlar.
Webcam'in desteklediğini ayarlar.

Peki istediğimiz webcamden görüntüyü alıp nasıl gösterebiliriz?

İlk olarak kullanıcıdan izin almamız gerek. Eğer kullanıcı webcam erişimine izin vermez ise hiçbirşey yapamayız. Session bazında saklanan bu izni kullanıcıdan istemek için kullanacağımız metodun adı RequestDeviceAccess şeklinde.

[VB]

        Dim IzinVarMi = CaptureDeviceConfiguration.AllowedDeviceAccess

        If Not IzinVarMi Then IzinVarMi = CaptureDeviceConfiguration.RequestDeviceAccess

Yukarıdaki ilk satırda AllowedDeviceAccess ile ilk olarak o anda iznimiz var mı yoksa yok mu konusunu kontrol ediyoruz. Eğer iznimiz varsa tekrar kullanıcıdan izin istemek saçma olur. Eğer yoksa hemen bir alt satırda RequestDeviceAccess ile iznimizi istiyoruz.

Kullanıcıdan kameraya bağlanma izni istiyoruz.
Kullanıcıdan kameraya bağlanma izni istiyoruz.

İznimizi aldıktan sonra rahatlık istediğimiz bir Device'ı seçerek cihazdan veri kaynağını alabiliriz. Sistemde farklı mikrofon ve kameralar olabileceği için bunların kompinasyonundan bir CaptureSource yaratabiliyorsunuz. Bizim örneğimizde sadece kameraya ulaşacağımız için yaratacağımız CaptureSource'un sadece VideoCaptureDevice özelliğini set edeceğiz.

[VB]

            Dim Cihaz = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice

            Dim Kaynak As New CaptureSource

            Kaynak.VideoCaptureDevice = Cihaz

Tüm bu ayarları yaptıktan sonra sıra geliyor görüntü alma işlemini başlatmaya ve alacağımız görüntüyü de bir yerlerde göstermeye. Bunun için herhangi bir kontrolü kullanabilirsiniz çünkü görüntüyü bir VideoBrush aracılığı ile alacağız ve bildiğiniz üzere VideoBrush'ları da istediğimiz herhangi bir SL kontrolünde normal renk fırçaları gibi kullanabiliyoruz.

[VB]

            Dim Firca As New VideoBrush

            Firca.SetSource(Kaynak)

 

            Kaynak.Start()

            Dikdortgen.Fill = Firca

Yukarıdaki kodumuzda VideoBrush'ımızı yaratarak Source olarak eldeki CaptureSource'u veriyoruz. Sonrasında CaptureSource üzerinden görüntü veya ses yakalama işlemini başlatmak için Start metodunu çağırmayı unutmamak gerek. En son olarak da eldeki VideoBrush'a adı Dikdortgen olarak bir Rectangle'a basit bir şekilde aktarabiliriz.

Kamera görüntüsü karşınızda.
Kamera görüntüsü karşınızda.

Yukarıda gördüğünüz üzere kamera görüntüsünü almakla kalmayıp Silverlight'taki Transformasyon ve PixelShader özelliklerini de rahatlıkla bu görüntüler üzerine uygulayabiliyoruz. Uygulamanın tam kodlarını aşağıda bulabilirsiniz.

[VB]

    Private Sub btnTikla_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnTikla.Click

        Dim IzinVarMi = CaptureDeviceConfiguration.AllowedDeviceAccess

        If Not IzinVarMi Then IzinVarMi = CaptureDeviceConfiguration.RequestDeviceAccess

 

        If IzinVarMi Then

            Dim Cihaz = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice

            Dim Kaynak As New CaptureSource

            Kaynak.VideoCaptureDevice = Cihaz

 

            Dim Firca As New VideoBrush

            Firca.SetSource(Kaynak)

 

            Kaynak.Start()

            Dikdortgen.Fill = Firca

            Golge.Fill = Firca

        End If

    End Sub

[XAML]

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="SilverlightApplication25.MainPage"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   mc:Ignorable="d"

   d:DesignHeight="300" d:DesignWidth="400">

 

    <Canvas x:Name="LayoutRoot" Background="White">

        <Rectangle x:Name="Dikdortgen" Height="168" Width="249" Canvas.Left="20" Canvas.Top="19">

            <Rectangle.Effect>

                <BlurEffect Radius="15"/>

            </Rectangle.Effect>

        </Rectangle>

        <Button x:Name="btnTikla" Content="BAŞLAT" Height="25" Width="100" Canvas.Left="300" Canvas.Top="275" />

        <Rectangle x:Name="Golge" Height="67" Canvas.Left="27.207" Canvas.Top="191" Width="249" RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" d:LayoutRounding="Auto">

            <Rectangle.OpacityMask>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="Transparent" Offset="0"/>

                    <GradientStop Color="White" Offset="1"/>

                </LinearGradientBrush>

            </Rectangle.OpacityMask>

            <Rectangle.RenderTransform>

                <TransformGroup>

                    <ScaleTransform ScaleY="-1" ScaleX="1"/>

                    <SkewTransform AngleY="0" AngleX="52.651"/>

                    <RotateTransform Angle="0"/>

                    <TranslateTransform X="36.69"/>

                </TransformGroup>

            </Rectangle.RenderTransform>

        </Rectangle>

    </Canvas>

</UserControl>

Kameradan fotoğrafı nasıl yakalarız?

Kameranın görüntüsünden fotoğraf yakalayabilmeniz için hazır bir API doğrudan CaptureSource nesnesi üzerinden sunuluyor. Ama sunulan API'ın birkaç ufak sorunu var. Birincisi eğer yukarıdaki gibi görüntüye bir PixelShader eklediyseniz veya üzerine birşeyler bindirdiyseniz maalesef bunların hiçbiri aldığınız fotoğrafta yer almayacaktır. İkincisi ile eğer CaptureSource durdurulmuş ise son gelen kareyi alma şansınız olmuyor. Gelin yine de ilk önce bu API'ye bir göz atalım sonra da istersek daha farklı bir yöntem olarak ne uygulayabiliriz ona bakarız.

[VB]

    Private Sub btnTikla2_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnTikla2.Click

        If Kaynak IsNot Nothing Then

            Kaynak.AsyncCaptureImage(Sub(Foto)

                                                               Dispatcher.BeginInvoke(Sub()

                                                                                                          imgFoto.Source = Foto

                                                                                                     End Sub)

                                                         End Sub)

        End If

    End Sub

Yukarıdaki kod içerisinde Kaynak olarak geçen nesne bizim bir önceki örneğimizde başlattığımız CaptureSource nesnesi. Bu nesneyi UserControl içerisinde tanımlayarak farklı eventlarda kullanılabilir hale getirdikten sonra fotoğraf çekme işlemini yapacak düğmede nesnenin varlığını kontrol ederek işleme devam ediyoruz. CaptureSource üzerinden AsyncCaptureImage metodunu çağırdığınızda fotoğraf alma işlemini yaparak bir Callback'e düşüyor. Bu Callback'den geri veri döndürebilmek ve sahneye yeni koyduğumuz imgFoto adındaki Image nesnesine source aktarabilmek adına Dispatcher üzerinden UI Thread'e ulaşıyoruz. Tüm bunları lamdalarla yapınca iş epey kolayca halloluyor.

Fotoğrafımızı yakalayap sağa koyduk.
Fotoğrafımızı yakalayap sağa koyduk.

Gördüğünüz gibi aldığımız görüntü ana kaynaktan olduğu için Blur efekti vs uygulanmış değil. Oysa orta kısımda gördüğümüzün tam aynısını almak isterdi gönül. İşte böyle bir durumda doğrudan Silverlight 3 ile gelen WriteableBitmap sınıfını kullanabiliriz.

[VB]

    Private Sub btnTikla2_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnTikla2.Click

        Dim Goruntu As New Imaging.WriteableBitmap(Dikdortgen, Nothing)

        imgFoto.Source = Goruntu

    End Sub

Kodumuzda WriteableBitmap yaratırken ekranda hedef nesne olarak da Rectangle tipindeki Dikdortgen'imizi veriyoruz. Böylece Blur vs efektleri uygulanmış hali ile görüntüyü alabiliyoruz.

PixelShader efekti ile görüntüyü aldık.
PixelShader efekti ile görüntüyü aldık.

Artık aldığınız bu fotoğrafları işlemek veya doğrudan sunucuya bir web servisi aracılığı ile göndermek vs tamamen size kalmış. Hepinize kolay gelsin.