This article will show the details of implementing augmented reality in Windows Phone using Geo Augmented Reality Toolkit (GART). GART enables you to create augmented reality experiences that depend on real geographical locations. It takes care of overlaying Bing maps, your heading, picture/frames from camera and virtual elements that display information about certain points of interest.
In the last article I wrote about GART, I mentioned 6 steps necessary for creating an augmented reality app using GART. Those steps were:
- Add an ARDisplay control to your Windows Phone page
- Add the views you want as children of the ARDisplay control
- Start and stop services when navigating to and from the page
- Create a collection of ARItem objects (or your own custom type that inherits from ARItem) and include real geolocation
- Set ARDisplay.Items equal to your new collection
- Optionally, style the elements
Of course, the first step is missing (or we could call it the step 0) which is creating the Windows Phone project and adding the GART reference. GART can be downloaded here:
http://gart.codeplex.com/releases/view/75331
Windows Phone project needs to be created and GART added to references. Now we can start with the 6 steps and the result would be an app that was shown on this youtube video:
Add ARDisplay control
Besides adding the reference to the project, you need to add it on the top of the MainPage.xaml page:
|
1 |
xmlns:gart="clr-namespace:GART.Controls;assembly=GART" |
The references need to be added to the MainPage.xaml.cs code file:
|
1 2 3 |
using GART; using GART.Controls; using GART.Data; |
Adding the control is really simple. Just put it inside the main grid, usually named LayoutRoot.
|
1 2 3 4 5 |
<Grid x:Name="LayoutRoot"> <gart:ARDisplay Name="ardisplay" Tap="ardisplay_Tap"> </gart:ARDisplay> </Grid> |
And that’s it. This is just the control, but now we need the layers included, too!
Add the views you want as children of the ARDisplay control
The layers, or the views, need to be added in this specific order, otherview you might encounter problems in displaying them all correctly. Just add them as the children of ARDisplay control:
|
1 2 3 4 5 6 7 8 |
<Grid x:Name="LayoutRoot"> <gart:ARDisplay Name="ardisplay" Tap="ardisplay_Tap"> <gart:VideoPreview x:Name="videoPreview"/> <gart:OverheadMap x:Name="overheadMap" CredentialsProvider="{StaticResource BingCredentials}" /> <gart:WorldView x:Name="worldView" ItemTemplate="{StaticResource CityItem}" /> <gart:HeadingIndicator x:Name="headingIndicator" Width="300" Height="300" HorizontalAlignment="Center" VerticalAlignment="Center"/> </gart:ARDisplay> </Grid> |
You’ll notice that the OverheadMap layers needs Bing credentials – that’s because GART takes care of the Bing maps for you. VideoPreview gives you the frames from the camera, WorldView gives you the layer for virtual elements, and the HeadingIndicator indicates your heading.
To be able to switch between the layers, you should add four buttons in the ApplicationBar. You can add less in case you’re not using all the layers.
|
1 2 3 4 5 6 7 8 |
<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton x:Name="threeDButton" IconUri="/Images/appbar.3D.png" Text="3D" Click="threeDButton_Click"/> <shell:ApplicationBarIconButton x:Name="headingButton" IconUri="/Images/appbar.heading.png" Text="heading" Click="headingButton_Click"/> <shell:ApplicationBarIconButton x:Name="mapButton" IconUri="/Images/appbar.map.png" Text="map" Click="mapButton_Click"/> <shell:ApplicationBarIconButton x:Name="rotateDButton" IconUri="/Images/appbar.rotate.png" Text="rotate" Click="rotateDButton_Click"/> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> |
All the buttons have click events, so you need to implement those too. It’s great that GART offers you some helpers to turn on and off layer as easy as possible. You need this in the code behind (MainPage.xaml.cs)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
private void threeDButton_Click(object sender, EventArgs e) { UIHelper.ToggleVisibility(worldView); } private void headingButton_Click(object sender, EventArgs e) { UIHelper.ToggleVisibility(headingIndicator); } private void mapButton_Click(object sender, EventArgs e) { UIHelper.ToggleVisibility(overheadMap); } private void rotateDButton_Click(object sender, EventArgs e) { SwitchHeadingMode(); } private void SwitchHeadingMode() { if (headingIndicator.RotationSource == RotationSource.AttitudeHeading) { headingIndicator.RotationSource = RotationSource.North; overheadMap.RotationSource = RotationSource.AttitudeHeading; } else { overheadMap.RotationSource = RotationSource.North; headingIndicator.RotationSource = RotationSource.AttitudeHeading; } } |
Start and stop services when navigating to and from the page
In the code behind, the MainPage.xaml.cs, you need to start and stop the services:
|
1 2 3 4 5 6 7 8 9 10 11 |
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { ardisplay.StartServices(); base.OnNavigatedTo(e); } protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) { ardisplay.StopServices(); base.OnNavigatedFrom(e); } |
Create a collection of ARItem objects (or your own custom type)
For the demo I created (the earlier video), I created a CityPlace class that inherits from ARItem expanding it with one more property called Description – it basically just describes the city place that I’m showing.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
using GART.Data; namespace GARTdemo { public class CityPlace : ARItem { private string description; public string Description { get { return description; } set { if (description != value) { description = value; NotifyPropertyChanged(() => Description); } } } } } |
In the MainPage.xaml.cs I initialize the ObservableCollection and get data (call the method):
|
1 2 3 4 5 6 7 8 9 |
private ObservableCollection<ARItem> locationsTvrda; public MainPage() { InitializeComponent(); locationsTvrda = new ObservableCollection<ARItem>(); GetData(); } |
GetData method adds a bunch of CityPlace items with real geographical locations and descriptions to the locationsTvrda collection.
|
1 2 3 4 5 6 7 8 9 10 |
private void GetData() { locationsTvrda.Add(new CityPlace() { GeoLocation = new GeoCoordinate(45.560450422716464, 18.69576883316039), Content = "Kugin spomenik", Description = "Spomenik Presvetom Trojstvu - sa svecima Sv. Sebastionom, Sv.Rokom, Sv. Rozalijom i Sv. Katarinom - podignut je 1729. do 1730. godine u središtu Tvrđe kao zavjetni spomenik da se Bog smiluje i da odvrati kugu koja je harala u Osijeku i u cijeloj Slavoniji" }); ... ... |
This is done for all the objects. I’m showing just one, as an example. Have in mind that GeoCoordinate class has many possible constructors, so you can add the altitude of the specific objects, too. The problem may only be that they are detected only in the radius of 300 yards (around 275 meters).
Bind ARDisplay.Items to your new collection
At the end of the GetData method, I set the ItemsSource of the ARDisplay control to the ObservableCollection:
|
1 |
ardisplay.ARItems = locationsTvrda; |
And that’s it!
Optionally, style the elements
I know I said that we’re done with XAML, but in case you wish to style the virtual elements displayed over the real life objects, you can do it in XAML. For example, the styling used for this demo was this:
|
1 2 3 4 5 6 7 8 9 10 |
<phone:PhoneApplicationPage.Resources> <DataTemplate x:Key="CityItem"> <Border BorderBrush="Black" BorderThickness="4" CornerRadius="8" Background="#FF003847" Width="320"> <StackPanel Margin="4"> <TextBlock x:Name="NameBlock" TextWrapping="NoWrap" Text="{Binding Content}" FontSize="38" VerticalAlignment="Center" Margin="0,0,4,0" d:LayoutOverrides="Width" Grid.Column="1" TextTrimming="WordEllipsis"/> <TextBlock x:Name="DescriptionBlock" TextWrapping="Wrap" Text="{Binding Description}" FontSize="24" VerticalAlignment="Center" Margin="0,0,4,0" d:LayoutOverrides="Width" Grid.Column="1" TextTrimming="WordEllipsis" MaxHeight="168"/> </StackPanel> </Border> </DataTemplate> </phone:PhoneApplicationPage.Resources> |
Nothing too complicated or difficult!
That’s it! Augmented reality application in 6 easy steps! :)
Like igrali blog on Facebook! Prefer Twitter?
@Igrali Nice description of using GART!! I think you have added static content of City places and Description ??
Glad you found it useful. City places are static in my case (that includes the description, too), but that’s just a demo.
Ideally, you would get those from a web service.
Yes!! Thanks for the reply :) :) @igrali :)
Can you describe how can we include the web search results into this program or a web service that does that?
@Abhishek, you can use the Bing Maps SOAP Services for including the web results. http://msdn.microsoft.com/en-us/library/cc879136 Just go through the link…the whole documentation is provided there.
Thanks a lot I had tried executing the sample Bing example given in Gart but even after adding the DLL file in the project reference I am getting errors of linking should I have to change anything else in the project files.Sorry if it was a silly question but I am a beginner in windows phone.
The Example is fine. Just remove the GART.dll from project and try adding GART.dll again. I think, you will find a solution.
Error 1 The type or namespace name ‘Net’ does not exist in the namespace ‘System’ (are you missing an assembly reference?) C:UsersAdministratorDesktopgart-63068 (1)GeoARToolkitabhiWindowsPhoneBingARDataRestaurantItem.cs 3 14 BingAR
i am getting this error when i try to execute the sample bing program after including gart dll in the project references from the solutions explorer
http://gart.codeplex.com/SourceControl/list/changesets# download the solution from this link, and try it. If you have still problem, just send me mail to tejaswarooparukoti@gmail.com.
Thanks a ton it was a linking problem I got it.
By the way can we integrate google services in it?
Yes!! Check the Google API for that. Mostly Google API is exposed in JSON Format. Not sure. Check it!
I was thinking of combining your example with the sample Bing ar but when I create a new class outside the BingAr class the outer class is not able to access the non static methods can u help me out?
Thanks a lot!
Hi,
This toolkit is amazing and I’m trying to get into WP7 & 8 dev. I’ve followed the steps here (I think) and at the end I can’t compile and build due to three errors. The ‘CityItem’ and ‘BingCredentials’ are not resolving, and the ‘ObservableCollection’ cannot be be found.
I’ve added the refernces, and added the right ‘using …’ parts, I’m just stuck :(
Hi
GART currently doesn’t work on Windows Phone 8, only WP7. Which one are you using?
Hey, I’m using WP7.5 on a Lumia 800 and I’m using Visual Studio 2012
J
Hi
Thank you igrali for your useful article. I run the sample code quite successfully, the only problem i am facing is that my description is not visible. Only the content is visible. How to solve this issue?
Thanks
Hi, great article I got the smaple up and running in 5 min and customized it in 10 =)
but I was just wodnering can the GART toolkit accept 3d objects, just as out of curiosity? have you tried anything like this please let me know
Do you mean if it’s possible to show 3D objects on top, instead of simple name/description flat XAML items?
Actually I just noticed something there is a project template called XAML with XNA, maybe it the XNA frameworks can render the graphics, such as fbx files, and I can use the standard Xaml to implement GART, It does seem to make sense I guess Ill have to try it to find out =)
If you have any other suggestions pleaase do let me know.
Thanks
Ronak
Do you know what library nokia used for their augmented reality app? When will it be available for WP8? Thanks for great article
Hi Martin
Good question. I don’t know what they used, but if I had to guess, I’d say that they’ve built a custom solution from scratch, but functionally similar to GART.
Not sure when GART would become available for WP8, but you can follow gart.codeplex.com to get the latest updates!
Error 2 Could not load the assembly file:///D:SetupsMobileWindows PhoneGART_1_0_1GART.dll. This assembly may have been downloaded from the Web. If an assembly has been downloaded from the Web, it is flagged by Windows as being a Web file, even if it resides on the local computer. This may prevent it from being used in your project. You can change this designation by changing the file properties. Only unblock assemblies that you trust. See http://go.microsoft.com/fwlink/?LinkId=179545 for more information. AR
Why is this?
Probably when you downloaded GART, it was downloaded in a .zip file. I assume that before unpacking the .zip file, it’s necessary to right click on the zip file and select Properties and then click on Unblock to unblock the downloaded dlls.
yep thanks :) I corrected that. but now i’m getting a runtime error
How do I make it so the city item is a constant size and not variable on the distance from it.
You would have to edit the source code for that.