Silverlight 4 Dica do Dia #5 - Realidade Aumentada – YES WE CAN!!!

By rdorta at junho 21, 2010 16:43
Filed Under: Arquitetura, Silverlight

Após meu último post, sobre integração com WebCam recebi muitas perguntas referentes a Realidade Aumentada.

Portanto, resolvi escrever este post sobre o assunto como forma de iniciar as pessoas que querem aprender mais sobre o assunto.

Sugiro que quem ainda não leu meu último post, que comece por ele, porque neste post vou assumir que você já sabe como capturar as imagens vindas da sua WebCam.

Depois de ler o post anterior, imprima a imagem abaixo:

image

Essa imagem é a que vamos identificar dentro da nossa aplicação.

Bom, partindo do programa gerado no último post, temos uma aplicação que captura os dados da webcam e exibe na tela.

Vamos utilizar o SLARToolkit, como nosso framework de identificação de padrão de imagem e substituição.

Adicione as referências das 2 dlls do toolkit no projeto.

Agora baixe o arquivo Pattern que representa a imagem acima: http://blogs.makesys.com.br/dorta/makesys.pat. Adicione ela ao projeto, clique em cima dela, vá até a aba propriedades e troque a sua Build Action para Resource.

Adicione o pattern no projeto.

Agora, a partir do projeto que criamos no meu último post, vamos adicionar um canvas após o Rectangle que serviu como ViewPort, dentro deste canvas, vou adicionar uma imagem, mas pode ser adicionado qualquer outro objeto Silverlight, eis o XAML completo:

   1: <UserControl x:Class="SLRealidadeAumentada.MainPage"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:     mc:Ignorable="d"
   7:     d:DesignHeight="550" d:DesignWidth="700"
   8:     Loaded="UserControl_Loaded">
   9:  
  10:     <Grid x:Name="LayoutRoot" Background="White">
  11:         <StackPanel>
  12:             <Grid Width="640" Height="480">
  13:                 <Rectangle Name="Viewport" Stroke="Black" StrokeThickness="2" />
  14:                 <Canvas>
  15:                     <Grid Background="White" x:Name="imgMakesys" Visibility="Collapsed"  >
  16:                         <Image Source="logo_makesys.png" Height="91" Width="261"/>
  17:                     </Grid>
  18:                 </Canvas>
  19:             </Grid>
  20:             <Button Content="IniciarCaptura" HorizontalAlignment="Center" Click="Button_Click" />
  21:         </StackPanel>
  22:     </Grid>
  23: </UserControl>

Abaixo o código final:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Net;
   5: using System.Windows;
   6: using System.Windows.Controls;
   7: using System.Windows.Documents;
   8: using System.Windows.Input;
   9: using System.Windows.Media;
">  10: using System.Windows.Media.Animation;
  11: using System.Windows.Shapes;
  12: using SLARToolKit;
  13: using System.Windows.Media.Media3D;
  14:  
  15: namespace SLRealidadeAumentada
  16: {
  17:     public partial class MainPage : UserControl
  18:     {
  19:  
  20:         CaptureSource cpsVideo;
  21:         CaptureSourceMarkerDetector cmkDetectorPattern;
  22:  
  23:         public MainPage()
  24:         {
  25:             InitializeComponent();
  26:         }
  27:  
  28:         private void UserControl_Loaded(object sender, RoutedEventArgs e)
  29:         {
  30:             // Instancia o objeto que manipula a WebCam
  31:             cpsVideo = new CaptureSource();
  32:             // Define qual webcam será o alvo do objeto, no caso a câmera padrão do Sistema
  33:             cpsVideo.VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
  34:  
  35:             //Cria o objeto que recebe os dados do video
  36:             var vbsVideo = new VideoBrush();
  37:             vbsVideo.SetSource(cpsVideo);
  38:             // Preenche o retangulo com os dados capturados do video
  39:             Viewport.Fill = vbsVideo;
  40:  
  41:             //  Initialize the o detector
  42:             cmkDetectorPattern = new CaptureSourceMarkerDetector();
  43:             // Carrega o pattern que deve ser procurado, ele tem 64 segmentos e 80 milimetros de 
  44:             var patPattern = Marker.LoadFromResource("makesys.pat", 64, 64, 80);
  45:             // Cria a parspectiva com planos de 1 a 4000
  46:             cmkDetectorPattern.Initialize(cpsVideo, 1, 4000, patPattern);
  47:  
  48:             // Vincula o handler de captura do pattern
  49:             // O evento é disparado se pelo menos um pattern é identificado na imagem
  50:             cmkDetectorPattern.MarkersDetected += (senderDelegate, eDelegate) =>
  51:             {
  52:                 // Cria uma nova tread para manipular a projeção do objeto que está no canvas
  53:                 Dispatcher.BeginInvoke(() =>
  54:                 {
  55:                     // Calcula a matrix de projeção
  56:                     var dreResultado = eDelegate.DetectionResults;
  57:                     if (dreResultado.HasResults)
  58:                     {
  59:                         // Centro do Objeto
  60:                         Matrix3D mtdCentro = Matrix3DFactory.CreateTranslation(-imgMakesys.ActualWidth * 0.5, -imgMakesys.ActualHeight * 0.5, 0);
  61:                         // Troca o eixo Y e diminui a escala pela metade
  62:                         Matrix3D mtdEscala = Matrix3DFactory.CreateScale(0.5, -0.5, 0.5);
  63:                         // Calcula a matriz final de transformação baseada no ponto centro original
  64:                         Matrix3D mtdFinal = mtdCentro * mtdEscala * dreResultado[0].Transformation;
  65:  
  66:                         // Calcula a projeção utilizando o SLARToolkit
  67:                         Matrix3D mtdViewPort = Matrix3DFactory.CreateViewportTransformation(Viewport.ActualWidth, Viewport.ActualHeight);
  68:                         Matrix3D mtdProjecao = Matrix3DFactory.CreateViewportProjection(mtdFinal, Matrix3D.Identity, cmkDetectorPattern.Projection, mtdViewPort);
  69:  
  70:                         // Aplicaca a transformação 3D ao objeto final
  71:                         imgMakesys.Projection = new Matrix3DProjection { ProjectionMatrix = mtdProjecao };
  72:                         imgMakesys.Visibility = Visibility.Visible;
  73:                     }
  74:                 });
  75:             };
  76:         }
  77:  
  78:         private void Button_Click(object sender, RoutedEventArgs e)
  79:         {
  80:             // Efetua a requisição de acesso a WebCam
  81:             if (CaptureDeviceConfiguration.RequestDeviceAccess())
  82:             {
  83:                 cpsVideo.Start();
  84:             }
  85:         }
  86:     }
  87: }

Deixei o código bem comentado, note que estamos utilizando o objeto Matrix3D para adicionar uma projeção ao nosso grid que contém a imagem.

A grande mágica na realidade é realizada pelo SLARToolkit que identifica a imagem e dispara o delegate que criamos na linha 50.

Notem também que estamos utilizando Multi-Threading para renderizar a projeção, isso evita que a aplicação trave com o processamento.

Abaixo uma imagem minha(galã!!!) utilizando o código acima.

image

Agora o código final para você brincarem :)

 

Get Microsoft Silverlight

 

 

Segue o fonte: SLRealidadeAumentada.zip (618,51 kb)

Até a próxima

Custom Loading no Silverlight

By rdorta at setembro 30, 2009 11:12
Filed Under: Silverlight

Olá amigos, já repararam que toda aplicação em Silverlight sempre tem o mesmo Loading? Esse loading vem do próprio Silverlight e por já existir dificilmente nós desenvolvedores mudamos essa animação.

Mas para os intrépidos designers que não se conformam com isso (inclusive o que trabalha comigo) segue abaixo a forma como você pode trocar seu loading e ainda por cima como você pode manipular objetos via Javascript, muito necessário quando você está utilizando Silverlight em páginas que não são criadas com .Net (aspx).

Abaixo segue o código HTML do Silverlight:

<script type="text/javascript" src="Splash/SplashScreen.js"></script> 
...
...
<object id="Xaml1" data="data:application/x-silverlight-2," 
type="application/x-silverlight-2" width="100%" height="100%"> ...
<param name="splashscreensource" value="Splash/SplashScreen.xaml"/>
<param name="onSourceDownloadProgressChanged" value="onSourceDownloadProgressChanged" />
 

Agora em sua aplicação crie uma página SplashScreen.XAML:

<StackPanel xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
VerticalAlignment="Center" Margin="0,100,0,0">
<Image Source="../Splash/slc-watermark.png"
Height="47" Width="343"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="10" />
<Grid HorizontalAlignment="Center">
<Rectangle x:Name="rectBorder" StrokeThickness="1" Stroke="#FFC8C8C8"
Height="7" Width="200" HorizontalAlignment="Left"/>
<Rectangle x:Name="rectBar" Fill="#FFC8C8C8"
Height="7" Width="0" HorizontalAlignment="Left" />
</Grid>
</StackPanel>

 

E por fim, segue o código javascript para movimentar a barra de loading:

function onSourceDownloadProgressChanged(sender, eventArgs) {
var myHost = document.getElementById("Xaml1");
var rectBar = myHost.content.findName("rectBar");
var rectBorder = myHost.content.findName("rectBorder");
if(eventArgs.progress)
rectBar.Width = eventArgs.progress * rectBorder.Width;
else
rectBar.Width = eventArgs.get_progress() * rectBorder.Width;
}

 

Me perdoem amigos desenvolvedores por dar armas ao seus designers e fazer com que eles atormentem a vida de vocês, mas uma aplicação Silverlight bem feita envolve sempre um bom designer :)

Até a próxima Arqinovação!!!

Sobre mim

Ricardo Dorta

Ricardo Dorta

Arquiteto de sistemas da Makesys, atua na área de desenvolvimento de aplicações .NET há 5 anos.
MCP, MCAD e MCSD.