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

Silverlight 4 Dica do dia #4 – Capturando as imagens da Webcam

By rdorta at junho 18, 2010 13:54
Filed Under: Arquitetura, Silverlight
&g

Olá,

Hoje vou mostrar para vocês como capturar as imagens camera do usuário no Silverlight.

Primeiro vamos ao XAML:

   1: <UserControl x:Class="SLWebCam.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"t; d:DesignWidth="700"
-CRLF-->
   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:             </Grid>
  15:             <Button Content="IniciarCaptura" HorizontalAlignment="Center" Click="Button_Click" />
  16:         </StackPanel>
  17:     </Grid>
  18: </UserControl>

 

Notem que temos neste XAML apenas 2 controles, 1 Rectangle, que servirá de ViewPort para a câmera ou seja, onde será exibida a imagem da camera e um obtão que irá disparar o início da captura.

Agora vamos ao código:

   1: using System.Windows;
   2: using System.Windows.Controls;
   3: using System.Windows.Media;
   4:  
   5: namespace SLWebCam
   6: {
   7:     public partial class MainPage : UserControl
   8:     {
   9:         CaptureSource cpsVideo;
  10:  
  11:         public MainPage()
  12:         {
  13:             InitializeComponent();
  14:         }
  15:  
  16:         private void UserControl_Loaded(object sender, RoutedEventArgs e)
  17:         {
  18:             // Instancia o objeto que manipula a WebCam
  19:             cpsVideo = new CaptureSource();
  20:             // Define qual webcam será o alvo do objeto, no caso a câmera padrão do Sistema
  21:             cpsVideo.VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
  22:  
  23:             //Cria o objeto que recebe os dados do video
  24:             VideoBrush vbsVideo = new VideoBrush();
  25:             vbsVideo.SetSource(cpsVideo);
  26:             // Preenche o retangulo com os dados capturados do video
  27:             Viewport.Fill = vbsVideo;
  28:         }
  29:  
  30:         private void Button_Click(object sender, RoutedEventArgs e)
  31:         {
  32:             // Efetua a requisição de acesso a WebCam
  33:             if (CaptureDeviceConfiguration.RequestDeviceAccess())
  34:             {
  35:                 cpsVideo.Start();
  36:             }
  37:         }
  38:     }
  39: }

Os grandes objetos que fazem a mágica são o CaptureSource, CaptureDeviceConfiguration e o VideoBrush.

Primeiro, instanciamos o CaptureSource e definimos qual camera ele irá utilizar atraves do CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice().

Depois criamos o VideoBrush e informamos a ele que sua fonte de imagens é o recém-criado CaptureSource.

Definimos que a saída do VideoBrush será o retangulo que criamos no XAML.

Pedimos a permissão do usuário para usar a câmera e pronto!!!

Muito easy esse tal de Silverlight.

Silverlight 4 is coming!!!

By rdorta at outubro 27, 2009 14:38
Filed Under: Silverlight

Desde o mês passado, a Microsoft tem lançado alguns spoilers referentes ao Silverlight4.

Dois deles me chamaram a atenção:

1)  A incorporação de direitos autorais sobre streaming. Ou seja, o suporte a direitos de transmissão de vídeo vai ser nativo. Isso é muito interessante, principalmente quando pensamos em um futuro próximo onde as locadoras começarão a trabalhar em ambiente virtual, fornecendo a locação de filmes via Streaming.

2)  Multicas de vídeos!!! Isso vai ser legal. Você poderá criar aplicações de conferências onde o streaming é enviado simultaneamente a diversos endereços.

Enfim, a Microsoft me parece estar atacando o mercado de RIA com soluções para uma nova geração de aplicativos baseados em vídeos.

A concorrencia com o Flash em sites de propaganda ainda me parece uma causa perdida, porem em aplicações orientadas a negócio corporativo o Silverlight deve virar preferência em breve.

Fonte: http://news.cnet.com/8301-13860_3-10346668-56.html

Física com Silverlight: YES WE CAN!!! – By William Machado

By rdorta at outubro 22, 2009 09:37
Filed Under: Arquitetura, Silverlight

Olá pessoal, abaixo segue um tutorial muito bom do meu colega de Makesys Willian, que tem se dedicado aos estudo de Silverlight. A equipe da Makesys vem melhorado muito seu conhecimento em Silverlight. Show!!! Obrigado William!!!!

Você vai precisar dos seguinte arquivo para trabalhar com física no Blend:

PhysicsHelper.3.0.0.3.zip (3,60 mb)

Abaixo o código fonte final:

Silverlight_Carro_Fisica.zip (521,23 kb)

By William Machado:

Tutorial: Desenvolvimento em Silverlight 3 utilizando física

No mundo do desenvolvimento de aplicativos baseados na Web, os usuários estão exigindo experiências de aplicativos cada vez mais aprimoradas.

Este tutorial mostra como podemos criar uma aplicação simples em SilverLight utilizando as leis da física. No nosso caso será um carro.

Bom antes de começar vamos entender como funciona. Farseer Physics Engine é um motor de física 2D

que suporta varias plataformas como o XNA da Microsoft, o Silverlight, WPF. Uma das características do Farseer Physics Engine é a simplicidade que permite a criação de diversas aplicações e jogos dinâmicos.

o Farseer Physics Engine é projetado para controlar a posição e rotação de objetos.
No mundo real, as coisas se movem e giram devido as forças aplicadas e torques. Em Farseer, é a mesma coisa. Objetos representam as coisas do mundo real. As forças e torques são aplicados e os organismos reagem de acordo com as leis da física 2D.

Crie um novo projeto selecionando “Silverlight 3 Application”.

clip_image002

Mude o tipo do “LayoutRoot” de “Grid” para “Canvas”.

clip_image004

Adicione o controle “PhysicsControllerBehavior” no LayoutRoot

clip_image006

Ative a propriedade: “MousePickEnabled” para manipular os objetos da tala com o mouse

clip_image008

Agora ou você pode desenhar o carro no próprio Blend ou adicionar uma imagem, no meu caso eu desenhei o carro e adicionei a imagem da roda.

clip_image010

Agrupar as imagens em “Canvas”

clip_image012

Para utilizar o recurso de física temos que incluir a “FarseerPhysics.dll” em nosso projeto.

clip_image014

Agora o projeto deve ser compilado para que os controles de física sejam adicionados no Blend.

clip_image016

Os novos controles que foram adicionados:

clip_image018

Clique e arraste o controle “PhysicsObjectBehavior” nos objetos que terão massa, nesse caso utilizei três uma para o Carro(Path) e outros dois para as rodas(Canvas).

Obs.: aplicar o “PhysicsObjectBehavior” somente nos Canvas das rodas e não nas imagens.

clip_image020

Desenhe um “Rectangle” para ser o chão e aplique o controle de física “PhysicsObjectBehavior”, mas ative a propriedade “IsStatic” do “PhysicsObjectBehavior” para que seja um objeto estático.

clip_image022

Para fazer um “Join” das rodas com o carro precisamos de um objeto intermediário para que possamos utilizar o controle “PhysicsJointBehavior” para isso vamos criar um circulo no meio da roda.

clip_image024

Arraste e solte o controle no circulo.

clip_image026

As propriedades do controle devem ficar assim:

clip_image028

Para isso você pode simplesmente clicar aqui arrastar e soltar encima do carro:

clip_image030

Ok, depois de ter feito o “Join” das rodas com o carro vamos aplicar força na roda para simular o funcionamento motor do carro, para isso precisamos do controle “PhysicsApplyTorqueBehavior”.

Clique arraste e solte o controle encima da roda

clip_image032

Nas propriedades clique em “New”, na seguinte janela escolha o evento “PhysicsKeyTrigger” (para utilizar os eventos do teclado)

clip_image034

 

Selecione uma tecla para acionar o controle

clip_image036

Adicione um valor para “ToqueValue” ex: -5000 para que a roda gire para a esquerda

clip_image038

Repita o mesmo procedimento adicione mais um controle “PhysicsApplyTorqueBehavior”, mas com o valor de “ToqueValue” 5000 para que a roda gire para a direita

clip_image040

Salve a aplicação (CTRL + S) compile (CTRL + SHIFT + B) e execute (F5)

Pronto temos um carro utilizando as leis da física em Silverlight.

Silverlight + Deep Zoom = RIA Experiences Parte 2 – Deep Zoom Dinamico – YES WE CAN

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

No meu post anterior, Silverlight + DeepZoom = RIA Experiences Parte 1 - Utilizando o Deep Zoom Composer, mostrei como podemos criar experiências simples com o Deep Zoom Composer.

Uma das grandes reclamações que eu costumo ouvir sobre o deep zoom é que não conseguimos criar experiências onde os dados sejam dinamicos, e a obrigatoriedade de utilizar o Deep Zoom Composer.

Esse meu post é dedicado a acabar com essa “crença”. Deep Zoom dinamico? YES WE CAN!!!

Criando o projeto

Para começar vamos precisar das seguintes ferramentas:

Siverlight 2 + Tools (também funciona com o 3, só estou usando o 2 porque estou finalizando um projeto que começou com ele)

Um pouco de conhecimento sobre imagens e tratamento de imagens com C# (google it!!!)

Deep Zoom Composer ( Leitor diz: nããããããõ!!!!…. Dorta diz: Calma!! é só pra pegar uma dll!!!!)

DeepZoomTools.dll

Bom, pra começar, vamos falar dessa dll. Você não vai achar praticamente nenhuma documentação sobre essa dll.

Ela foi criada pela própria equipe do Expression e foi divulgada nesse post do blog deles. Essa dll foi divulgada para que os desenvolvedores pudessem simular o funcionamento do Deep Zoom Composer em suas aplicações.

Abaixo segue os objetos que vamos utilizar e sua função:

ImageCreator: É o objeto de imagem utilizado pelo Deep Zoom.
CollectionCreator: Objeto responsável por criar aquelas diversas imagens para cada nível de zoom do nosso Deep Zoom

O que eu preciso saber de Deep Zoom?

Você deve ter conhecimento de como o Deep Zoom Composer trabalha, sugiro seguir meu post anterior Silverlight + DeepZoom = RIA Experiences Parte 1 - Utilizando o Deep Zoom Composer e criar algumas aplicações estáticas para entender alguns conceitos como:

Ao criar uma composição de Deep Zoom, são gerados inúmeros arquivos, com imagens e xmls que definem o comportamento de zoom da composição. (Pasta GeneratedImages)

Os xmls que são gerados definem os caminhos das imagens que serão utilizadas a cada nível de zoom

Vamos ao que interessa.

Crie um projeto do tipo Silverlight Application no VS 2008 e Peça para que seja criada uma aplicação WEB de testes. (Arquitetura em Siverlight vai dar um excelente post em breve).

image

Adiciona a sua pasta ClientBin do projeto WEB uma pasta chamada Generated Images

Adicione ao seu projeto WEB uma referencia a dll do DeepZoomTools : [Program Files]\Microsoft Expression\Deep Zoom Composer\DeepZoomTools.dll

O serviço que cria as imagens e xmls

Adicione ao seu projeto web, na pasta ClientBin, um Generic Handler, vamos chama-lo de ImageHandler:

image

 

Nosso serviço, vai ler as imagens de uma pasta (poderia ler qualquer imagem) e utiliza-las para montar um composição deep zoom.

O código que utilizei para buscar as imagens é bem simples:

private static List<string> ObterImagensDiretorio(DirectoryInfo pdiInformacaoDiretorio)
        {
            List<string> lstImagens = new List<string>();
            foreach (var finInformacaoImagem in pdiInformacaoDiretorio.GetFiles("*.jpg"))
            {
                lstImagens.Add(finInformacaoImagem.FullName);
            }
            return lstImagens;
        }

Agora no método ProcessRequest do nosso serviço, vamos inicializar as nossas variáveis:

1)Caminho para onde serão enviadas as imagens e XMLs

string strCaminhoImagensGeradas = context.Server.MapPath("~/ClientBin/GeneratedImages/");

2) Imagens que serão utilizadas no DeepZoom

           List<string> lstImagens = ObterImagensDiretorio(new DirectoryInfo(context.Server.MapPath("~/Imagem/")));

3) Lista de XMLs que serão gerados

          List<string> lstXMLs = new List<string>();

Por fim, mas não menos importante, criamos os objetos de imagem do Deep Zoom e a coleção:

O objeto ImageCreator e o objeto CollectionCreator possuem propriedades muito parecidas entre as quais podemos destacar:

TileSize – O tamanho que cada “tira” da composição deve assumir
TileFormat – O formato de arquivo de  cada “tira” (PNG, JPG, etc…)
ImageQuality – Como qualquer bom editor de imagem, você pode editar qual a qualidade de exportação da imagem, sendo 1 = 100%.

Ambos os objetos também possuem o método create:

ImageCreator.Create([Caminho original da imagem], [Caminho onde a imagem deve ser criada]);  - Cria as imagens e xmls referentes as imagens
ColectionCreator.Create([Lista dos caminhos dos xmls que contém as informações das imagens], [Caminho onde ele deve gerar a coleção completa]); Cria a estrutura completa de XML e imagens da composição

Segue o código abaixo:

foreach (string strImagem in lstImagens)
            {

                ImageCreator ic = new ImageCreator();

                ic.TileSize = 256;

                ic.TileFormat = ImageFormat.Jpg;

                ic.ImageQuality = 1;

                string target = strCaminhoImagensGeradas + "output_images\\" + Path.GetFileNameWithoutExtension(strImagem);

                ic.Create(strImagem, target);

                lstXMLs.Add(Path.ChangeExtension(target, ".xml"));

            }

            cc.TileSize = 256;

            cc.TileFormat = ImageFormat.Jpg;

            cc.MaxLevel = 8;

            cc.ImageQuality = 1;

            cc.Create(lstXMLs, strCaminhoImagensGeradas + "output");

WELL DONE!!! NOSSO SERVIÇO ESTA PRONTO!!! Agora vamos ao Silverlight:

DE VOLTA AO SILVERLIGHT

Agora vamos criar o DeepZoom utilizando o MultiScaleImage, no Silverlight.

Dentro dos seu LayoutRoot na sua Page.xaml crie os seguintes componentes:

<MultiScaleImage x:Name="msi" Height="Auto" Width="589"/>
        <Button Content="Embaralhar" HorizontalAlignment="Center" VerticalAlignment="Top" Click="Button_Click"/>

E agora no código Page.xaml.cs no método construtor, vamos invocar nosso serviço de geração de imagens:

WebClient wbc = new WebClient();
            wbc.OpenReadAsync(new Uri(“
http://localhost:3585/ClientBin/ImageHandler.ashx”));
            wbc.OpenReadCompleted += new OpenReadCompletedEventHandler(wbc_OpenReadCompleted);

E ao terminar o serviço vamos popular o nosso MultiScaleImage:

this.msi.Source = new DeepZoomImageTileSource(new Uri("http://localhost:3585/ClientBin/GeneratedImages/output.xml"));

DONE!!!

Espero que essas dicas ajudem a iluminar os passos para nova experiências com Silverlight e Deep Zoom.

Aqui está o link para o código fonte com imagens, um evento para capturar Mouse Wheel muito bom e um efeito de embaralhamento randomico nota 100000:

DeepZoomDinamico.zip (13,36 mb)

Nos vemos na 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.