Add code and project files

This commit is contained in:
Oliver Whyte 2016-07-08 00:24:00 -07:00
parent 86e5e91a41
commit 53c5ec11be
34 changed files with 23993 additions and 2 deletions

4
.gitattributes vendored Normal file
View file

@ -0,0 +1,4 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

253
.gitignore vendored Normal file
View file

@ -0,0 +1,253 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml

45
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,45 @@
Contributing to Microsoft Cognitive Services Client Libraries & Samples
===============================================
So, you want to contribute on a client library or sample for one of the Microsoft Cognitive Services.
Here's what you need to know.
1. Each SDK should include both a client library and a sample showing the API in
action
2. When working on an SDK, it's important that we are consistent from project to project, so we ask you to follow the coding guidelines below:
- Windows [(Coding guidelines for C#)](https://msdn.microsoft.com/en-us/library/ff926074.aspx) -- also reference our [common Windows code](https://github.com/Microsoft/Cognitive-common-windows) for building samples
- Android [(Coding guidelines for
Java)](<http://source.android.com/source/code-style.html>)
- iOS Objective-C [(Coding guidelines for
Cocoa)](<https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html>)
- Optional: Client Javascript ([Coding guidelines for
npm](<https://docs.npmjs.com/misc/coding-style>))
3. Samples are important for illustrating how to actually call into the API.
Samples should be as visual and reusable as possible.
- Do:
- Create a UI sample when possible.
- Make your sample user friendly. Expect that developers will want to try
different mainline scenarios and key APIs.
- Create code that's easy for other developers to copy/paste into their
own solutions
- Consider:
- Adding UI to allow devs to quickly copy/paste subscription keys, instead
of updating them in the code or using a config file. The
FaceAPI-WPF-Samples.sln provides an example.
- Don't:
- Leave your subscription key in the source of samples. You do not want your key to be abused by others.
Happy coding!

12
LICENSE.md Normal file
View file

@ -0,0 +1,12 @@
Microsoft Cognitive Services Samples
Copyright (c) Microsoft Corporation
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,2 +1,63 @@
# Cognitive-Samples-VideoFrameAnalysis
A library with sample apps for continuous analysis of live video, using the Microsoft Cognitive Services Computer Vision APIs.
# Video Frame Analysis Sample
This sample contains a library, along with two applications, for analyzing video frames from a webcam in near-real-time using APIs from [Microsoft Cognitive Services][]. The library and applications are implemented in C#, and use the [OpenCvSharp][] package for webcam support.
[Microsoft Cognitive Services]: https://www.microsoft.com/cognitive-services
[OpenCvSharp]: https://github.com/shimat/opencvsharp
## Getting Started
1. Get API keys for the Vision APIs from [microsoft.com/cognitive][Sign-Up]. For video frame analysis, the applicable APIs are:
- [Computer Vision API][]
- [Emotion API][]
- [Face API][]
2. Open the sample in Visual Studio 2015, build and run the sample applications:
- For BasicConsoleSample, the Face API key is hard-coded directly in [BasicConsoleSample/Program.cs](Windows/BasicConsoleSample/Program.cs).
- For LiveCameraSample, the keys should be entered into the Settings pane of the app. They will be persisted across sessions as user data.
3. Reference the VideoFrameAnalyzer library from your own projects.
[Sign-Up]: https://www.microsoft.com/cognitive-services/en-us/sign-up
[Computer Vision API]: https://www.microsoft.com/cognitive-services/en-us/computer-vision-api
[Emotion API]: https://www.microsoft.com/cognitive-services/en-us/emotion-api
[Face API]: https://www.microsoft.com/cognitive-services/en-us/face-api
## Using the VideoFrameAnalyzer Library
You can start using the library with only a few lines of code:
```csharp
// Create Face API Client.
FaceServiceClient faceClient = new FaceServiceClient("<subscription key>");
// Create grabber, with analysis type Face[].
FrameGrabber<Face[]> grabber = new FrameGrabber<Face[]>();
// Set up Face API call, which returns a Face[]. Simply encodes image and submits to Face API.
grabber.AnalysisFunction = async frame => return await faceClient.DetectAsync(frame.Image.ToMemoryStream(".jpg"));
// Tell grabber to call the Face API every 3 seconds.
grabber.TriggerAnalysisOnInterval(TimeSpan.FromMilliseconds(3000));
// Start running.
await grabber.StartProcessingCameraAsync();
```
## Contributing
We welcome contributions. Feel free to file issues and pull requests on the repo and we'll address them as we can. Learn more about how you can help on our [Contribution Rules & Guidelines](CONTRIBUTING.md).
You can reach out to us anytime with questions and suggestions using our communities below:
- **Support questions:** [StackOverflow][]
- **Feedback & feature requests:** [Cognitive Services UserVoice Forum][]
This project has adopted the [Microsoft Open Source Code of Conduct][]. For more information see the [Code of Conduct FAQ][] or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
[StackOverflow]: https://stackoverflow.com/questions/tagged/microsoft-cognitive
[Cognitive Services UserVoice Forum]: https://cognitive.uservoice.com
[Microsoft Open Source Code of Conduct]: https://opensource.microsoft.com/codeofconduct/
[Code of Conduct FAQ]: https://opensource.microsoft.com/codeofconduct/faq/
## License
All Microsoft Cognitive Services SDKs and samples are licensed with the MIT License. For more details, see [LICENSE](LICENSE.md).
## Developer Code of Conduct
The image, voice, video or text understanding capabilities of VideoFrameAnalyzer use Microsoft Cognitive Services. Microsoft will receive the images, audio, video, and other data that you upload (via this app) for service improvement purposes. To report abuse of the Microsoft Cognitive Services to Microsoft, please visit the Microsoft Cognitive Services website at https://www.microsoft.com/cognitive-services, and use the "Report Abuse" link at the bottom of the page to contact Microsoft. For more information about Microsoft privacy policies please see their privacy statement here: https://go.microsoft.com/fwlink/?LinkId=521839.
Developers using Cognitive Services, including this sample, are expected to follow the "Developer Code of Conduct for Microsoft Cognitive Services", found at http://go.microsoft.com/fwlink/?LinkId=698895.

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View file

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props" Condition="Exists('..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{0638DEF8-9613-4599-9335-7A2438B447DA}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BasicConsoleSample</RootNamespace>
<AssemblyName>BasicConsoleSample</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.ProjectOxford.Face, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ProjectOxford.Face.1.1.0\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Microsoft.ProjectOxford.Face.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp.Blob, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.Blob.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp.UserInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.UserInterface.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VideoFrameAnalyzer\VideoFrameAnalyzer.csproj">
<Project>{bec7da78-c953-4a72-924f-2749d1f9f18b}</Project>
<Name>VideoFrameAnalyzer</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,119 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// MIT License
//
// Copyright (c) 2016 Microsoft Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
using System;
using VideoFrameAnalyzer;
using Microsoft.ProjectOxford.Face;
using Microsoft.ProjectOxford.Face.Contract;
namespace BasicConsoleSample
{
internal class Program
{
private static void Main(string[] args)
{
// Create grabber.
FrameGrabber<Face[]> grabber = new FrameGrabber<Face[]>();
// Create Face API Client.
FaceServiceClient faceClient = new FaceServiceClient("<subscription key>");
// Set up a listener for when we acquire a new frame.
grabber.NewFrameProvided += (s, e) =>
{
Console.WriteLine("New frame acquired at {0}", e.Frame.Metadata.Timestamp);
};
// Set up Face API call.
grabber.AnalysisFunction = async frame =>
{
Console.WriteLine("Submitting frame acquired at {0}", frame.Metadata.Timestamp);
// Encode image and submit to Face API.
return await faceClient.DetectAsync(frame.Image.ToMemoryStream(".jpg"));
};
// Set up a listener for when we receive a new result from an API call.
grabber.NewResultAvailable += (s, e) =>
{
if (e.TimedOut)
Console.WriteLine("API call timed out.");
else if (e.Exception != null)
Console.WriteLine("API call threw an exception.");
else
Console.WriteLine("New result received for frame acquired at {0}. {1} faces detected", e.Frame.Metadata.Timestamp, e.Analysis.Length);
};
// Tell grabber when to call API.
// See also TriggerAnalysisOnPredicate
grabber.TriggerAnalysisOnInterval(TimeSpan.FromMilliseconds(3000));
// Start running in the background.
grabber.StartProcessingCameraAsync().Wait();
// Wait for keypress to stop
Console.WriteLine("Press any key to stop...");
Console.ReadKey();
// Stop, blocking until done.
grabber.StopProcessingAsync().Wait();
}
}
}

View file

@ -0,0 +1,69 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BasicConsoleSample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BasicConsoleSample")]
[assembly: AssemblyCopyright("Copyright \u00A9 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0638def8-9613-4599-9335-7a2438b447da")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.ProjectOxford.Face" version="1.1.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
<package id="OpenCvSharp3-AnyCPU" version="3.1.0.20160622" targetFramework="net452" />
</packages>

View file

@ -0,0 +1,81 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ProjectOxford.Emotion.Contract;
using Microsoft.ProjectOxford.Face.Contract;
namespace LiveCameraSample
{
internal class Aggregation
{
public static Tuple<string, float> GetDominantEmotion(Scores scores)
{
float maxScore = 0;
string dominant = "";
if (scores.Anger > maxScore) { maxScore = scores.Anger; dominant = "Anger"; }
if (scores.Contempt > maxScore) { maxScore = scores.Contempt; dominant = "Contempt"; }
if (scores.Disgust > maxScore) { maxScore = scores.Disgust; dominant = "Disgust"; }
if (scores.Fear > maxScore) { maxScore = scores.Fear; dominant = "Fear"; }
if (scores.Happiness > maxScore) { maxScore = scores.Happiness; dominant = "Happiness"; }
if (scores.Neutral > maxScore) { maxScore = scores.Neutral; dominant = "Neutral"; }
if (scores.Sadness > maxScore) { maxScore = scores.Sadness; dominant = "Sadness"; }
if (scores.Surprise > maxScore) { maxScore = scores.Surprise; dominant = "Surprise"; }
return new Tuple<string, float>(dominant, maxScore);
}
public static string SummarizeEmotion(Scores scores)
{
var bestEmotion = Aggregation.GetDominantEmotion(scores);
return string.Format("{0}: {1:N1}", bestEmotion.Item1, bestEmotion.Item2);
}
public static string SummarizeFaceAttributes(FaceAttributes attr)
{
List<string> attrs = new List<string>();
if (attr.Gender != null) attrs.Add(attr.Gender);
if (attr.Age > 0) attrs.Add(attr.Age.ToString());
if (attr.HeadPose != null)
{
// Simple rule to estimate whether person is facing camera.
bool facing = Math.Abs(attr.HeadPose.Yaw) < 25;
attrs.Add(facing ? "facing camera" : "not facing camera");
}
return string.Join(", ", attrs);
}
}
}

View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="LiveCameraSample.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="LiveCameraSample.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.ProjectOxford.Common" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.308.0" newVersion="1.0.308.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<userSettings>
<LiveCameraSample.Properties.Settings>
<setting name="FaceAPIKey" serializeAs="String">
<value />
</setting>
<setting name="EmotionAPIKey" serializeAs="String">
<value />
</setting>
<setting name="VisionAPIKey" serializeAs="String">
<value />
</setting>
<setting name="SettingsPanelVisibility" serializeAs="String">
<value>Visible</value>
</setting>
<setting name="AnalysisInterval" serializeAs="String">
<value>00:00:03</value>
</setting>
<setting name="FaceAPICallCount" serializeAs="String">
<value>0</value>
</setting>
<setting name="EmotionAPICallCount" serializeAs="String">
<value>0</value>
</setting>
<setting name="VisionAPICallCount" serializeAs="String">
<value>0</value>
</setting>
<setting name="AutoStopEnabled" serializeAs="String">
<value>True</value>
</setting>
</LiveCameraSample.Properties.Settings>
</userSettings>
<applicationSettings>
<LiveCameraSample.Properties.Settings>
<setting name="AutoStopTime" serializeAs="String">
<value>00:05:00</value>
</setting>
</LiveCameraSample.Properties.Settings>
</applicationSettings>
</configuration>

View file

@ -0,0 +1,11 @@
<Application x:Class="LiveCameraSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LiveCameraSample"
xmlns:props="clr-namespace:LiveCameraSample.Properties"
Exit="Application_Exit"
StartupUri="MainWindow.xaml">
<Application.Resources>
<props:Settings x:Key="Settings" />
</Application.Resources>
</Application>

View file

@ -0,0 +1,54 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace LiveCameraSample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private void Application_Exit(object sender, ExitEventArgs e)
{
LiveCameraSample.Properties.Settings.Default.Save();
}
}
}

View file

@ -0,0 +1,54 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ProjectOxford.Vision.Contract;
namespace LiveCameraSample
{
public class CelebritiesResult
{
public Celebrity[] Celebrities { get; set; }
}
public class Celebrity
{
public string Name { get; set; }
public FaceRectangle FaceRectangle { get; set; }
public float Confidence { get; set; }
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LiveCameraSample
{
// Class to hold all possible result types.
public class LiveCameraResult
{
public Microsoft.ProjectOxford.Face.Contract.Face[] Faces { get; set; } = null;
public Microsoft.ProjectOxford.Emotion.Contract.Scores[] EmotionScores { get; set; } = null;
public string[] CelebrityNames { get; set; } = null;
public Microsoft.ProjectOxford.Vision.Contract.Tag[] Tags { get; set; } = null;
}
}

View file

@ -0,0 +1,180 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props" Condition="Exists('..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5B40977E-E8FA-41BC-8F0A-6D6FDE237571}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>LiveCameraSample</RootNamespace>
<AssemblyName>LiveCameraSample</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.ProjectOxford.Common, Version=1.0.308.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ProjectOxford.Common.1.0.308\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.ProjectOxford.Common.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.ProjectOxford.Emotion, Version=1.0.310.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ProjectOxford.Emotion.1.0.310\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.ProjectOxford.Emotion.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.ProjectOxford.Face, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ProjectOxford.Face.1.1.0\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Microsoft.ProjectOxford.Face.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.ProjectOxford.Vision, Version=1.0.354.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ProjectOxford.Vision.1.0.354\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.ProjectOxford.Vision.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp.Blob, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.Blob.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp.UserInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.UserInterface.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Aggregation.cs" />
<Compile Include="CelebritiesResult.cs" />
<Compile Include="LiveCameraResult.cs" />
<Compile Include="Visualization.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="Data\haarcascade_frontalface_alt2.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VideoFrameAnalyzer\VideoFrameAnalyzer.csproj">
<Project>{bec7da78-c953-4a72-924f-2749d1f9f18b}</Project>
<Name>VideoFrameAnalyzer</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
<Error Condition="!Exists('..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,67 @@
<Window x:Class="LiveCameraSample.MainWindow"
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"
xmlns:local="clr-namespace:LiveCameraSample"
mc:Ignorable="d"
Title="LiveCameraSample" Height="550" Width="725">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="*" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0" Name="ButtonBar">
<ComboBox x:Name="CameraList" Width="100" Margin="5,5,0,5" Loaded="CameraList_Loaded" />
<Button Content="Start Camera" Padding="5,0" Margin="5,5,0,5" Click="StartButton_Click" />
<Button Content="Stop Camera" Padding="5,0" Margin="5,5,0,5" Click="StopButton_Click" />
<TextBlock VerticalAlignment="Center" Margin="15,5,0,5" Text="Mode:" />
<ComboBox x:Name="ModeList" Width="100" Margin="5,5,0,5" Loaded="ModeList_Loaded" SelectionChanged="ModeList_SelectionChanged" />
</StackPanel>
<Button Content="Show/Hide Settings" Padding="5,0" Margin="5" Click="SettingsButton_Click" HorizontalAlignment="Right" />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image x:Name="LeftImage" Grid.Column="0" Margin="5" />
<Image x:Name="RightImage" Grid.Column="1" Margin="5" Panel.ZIndex="1" />
<StackPanel Visibility="{Binding Source={StaticResource Settings}, Path=Default.SettingsPanelVisibility, Mode=TwoWay}" Grid.Column="1" Panel.ZIndex="2" Name="SettingsPanel" Background="LightGray" VerticalAlignment="Top" Margin="5">
<TextBlock Margin="5" Grid.Row="0" FontWeight="Bold" Text="Settings"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Margin="5" Grid.Row="0" Grid.Column="0" Text="Face API Key:" />
<TextBox Margin="5" Grid.Row="0" Grid.Column="1" Text="{Binding Source={StaticResource Settings}, Path=Default.FaceAPIKey, Mode=TwoWay}" />
<TextBlock Margin="5" Grid.Row="1" Grid.Column="0" Text="Emotion API Key:" />
<TextBox Margin="5" Grid.Row="1" Grid.Column="1" Text="{Binding Source={StaticResource Settings}, Path=Default.EmotionAPIKey, Mode=TwoWay}" />
<TextBlock Margin="5" Grid.Row="2" Grid.Column="0" Text="Vision API Key:" />
<TextBox Margin="5" Grid.Row="2" Grid.Column="1" Text="{Binding Source={StaticResource Settings}, Path=Default.VisionAPIKey, Mode=TwoWay}" />
<TextBlock Margin="5" Grid.Row="3" Grid.ColumnSpan="2" TextWrapping="Wrap"><Run Text="Get API keys at "/><Hyperlink NavigateUri="http://www.microsoft.com/cognitive" RequestNavigate="Hyperlink_RequestNavigate"><Run Text="microsoft.com/cognitive"/></Hyperlink></TextBlock>
<TextBlock Margin="5" Grid.Row="4" Grid.Column="0" Text="API Call Interval:" />
<TextBox Margin="5" Grid.Row="4" Grid.Column="1" Text="{Binding Source={StaticResource Settings}, Path=Default.AnalysisInterval, Mode=TwoWay}" />
<TextBlock Margin="5" Grid.Row="5" Grid.ColumnSpan="2" TextWrapping="Wrap"><Run FontWeight="Bold" Text="Caution"/><Run Text=": Each video frame submitted to an API will count towards your transaction limit."/></TextBlock>
</Grid>
<TextBlock Margin="5,0,5,5">
<Run Text="Face API calls made = "/><Run Text="{Binding Source={StaticResource Settings}, Path=Default.FaceAPICallCount}"/><LineBreak />
<Run Text="Emotion API calls made = "/><Run Text="{Binding Source={StaticResource Settings}, Path=Default.EmotionAPICallCount}"/><LineBreak />
<Run Text="Vision API calls made = "/><Run Text="{Binding Source={StaticResource Settings}, Path=Default.VisionAPICallCount}"/>
</TextBlock>
<CheckBox Margin="5" IsChecked="{Binding Source={StaticResource Settings}, Path=Default.AutoStopEnabled}" ContentStringFormat="Automatically stop after {0}" Content="{Binding Source={StaticResource Settings}, Path=Default.AutoStopTime}" />
<Button Margin="5" Content="Save" Click="SaveSettingsButton_Click" />
</StackPanel>
</Grid>
<TextBlock Name="MessageArea" Margin="5" Grid.Row="2" VerticalAlignment="Center" />
</Grid>
</Window>

View file

@ -0,0 +1,489 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using Newtonsoft.Json;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Microsoft.ProjectOxford.Emotion;
using Microsoft.ProjectOxford.Emotion.Contract;
using Microsoft.ProjectOxford.Face;
using Microsoft.ProjectOxford.Face.Contract;
using Microsoft.ProjectOxford.Vision;
using VideoFrameAnalyzer;
namespace LiveCameraSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : System.Windows.Window
{
private EmotionServiceClient _emotionClient = null;
private FaceServiceClient _faceClient = null;
private VisionServiceClient _visionClient = null;
private readonly FrameGrabber<LiveCameraResult> _grabber = null;
private static readonly ImageEncodingParam[] s_jpegParams = {
new ImageEncodingParam(ImwriteFlags.JpegQuality, 60)
};
private readonly CascadeClassifier _localFaceDetector = new CascadeClassifier();
private bool _fuseClientRemoteResults;
private LiveCameraResult _latestResultsToDisplay = null;
private AppMode _mode;
private DateTime _startTime;
public enum AppMode
{
Faces,
Emotions,
EmotionsWithClientFaceDetect,
Tags,
Celebrities
}
public MainWindow()
{
InitializeComponent();
// Create grabber.
_grabber = new FrameGrabber<LiveCameraResult>();
// Set up a listener for when the client receives a new frame.
_grabber.NewFrameProvided += (s, e) =>
{
if (_mode == AppMode.EmotionsWithClientFaceDetect)
{
// Local face detection.
var rects = _localFaceDetector.DetectMultiScale(e.Frame.Image);
// Attach faces to frame.
e.Frame.UserData = rects;
}
// The callback may occur on a different thread, so we must use the
// MainWindow.Dispatcher when manipulating the UI.
this.Dispatcher.BeginInvoke((Action)(() =>
{
// Display the image in the left pane.
LeftImage.Source = e.Frame.Image.ToBitmapSource();
// If we're fusing client-side face detection with remote analysis, show the
// new frame now with the most recent analysis available.
if (_fuseClientRemoteResults)
{
RightImage.Source = VisualizeResult(e.Frame);
}
}));
// See if auto-stop should be triggered.
if (Properties.Settings.Default.AutoStopEnabled && (DateTime.Now - _startTime) > Properties.Settings.Default.AutoStopTime)
{
_grabber.StopProcessingAsync();
}
};
// Set up a listener for when the client receives a new result from an API call.
_grabber.NewResultAvailable += (s, e) =>
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
if (e.TimedOut)
{
MessageArea.Text = "API call timed out.";
}
else if (e.Exception != null)
{
string apiName = "";
string message = e.Exception.Message;
var faceEx = e.Exception as FaceAPIException;
var emotionEx = e.Exception as Microsoft.ProjectOxford.Common.ClientException;
var visionEx = e.Exception as Microsoft.ProjectOxford.Vision.ClientException;
if (faceEx != null)
{
apiName = "Face";
message = faceEx.ErrorMessage;
}
else if (emotionEx != null)
{
apiName = "Emotion";
message = emotionEx.Error.Message;
}
else if (visionEx != null)
{
apiName = "Computer Vision";
message = visionEx.Error.Message;
}
MessageArea.Text = string.Format("{0} API call failed on frame {1}. Exception: {2}", apiName, e.Frame.Metadata.Index, message);
}
else
{
_latestResultsToDisplay = e.Analysis;
// Display the image and visualization in the right pane.
if (!_fuseClientRemoteResults)
{
RightImage.Source = VisualizeResult(e.Frame);
}
}
}));
};
// Create local face detector.
_localFaceDetector.Load("Data/haarcascade_frontalface_alt2.xml");
}
/// <summary> Function which submits a frame to the Face API. </summary>
/// <param name="frame"> The video frame to submit. </param>
/// <returns> A <see cref="Task{LiveCameraResult}"/> representing the asynchronous API call,
/// and containing the faces returned by the API. </returns>
private async Task<LiveCameraResult> FacesAnalysisFunction(VideoFrame frame)
{
// Encode image.
var jpg = frame.Image.ToMemoryStream(".jpg", s_jpegParams);
// Submit image to API.
var attrs = new List<FaceAttributeType> { FaceAttributeType.Age,
FaceAttributeType.Gender, FaceAttributeType.HeadPose };
var faces = await _faceClient.DetectAsync(jpg, returnFaceAttributes: attrs);
// Count the API call.
Properties.Settings.Default.FaceAPICallCount++;
// Output.
return new LiveCameraResult { Faces = faces };
}
/// <summary> Function which submits a frame to the Emotion API. </summary>
/// <param name="frame"> The video frame to submit. </param>
/// <returns> A <see cref="Task{LiveCameraResult}"/> representing the asynchronous API call,
/// and containing the emotions returned by the API. </returns>
private async Task<LiveCameraResult> EmotionAnalysisFunction(VideoFrame frame)
{
// Encode image.
var jpg = frame.Image.ToMemoryStream(".jpg", s_jpegParams);
// Submit image to API.
Emotion[] emotions = null;
// See if we have local face detections for this image.
var localFaces = (OpenCvSharp.Rect[])frame.UserData;
if (localFaces != null)
{
// If we have local face detections, we can call the API with them.
// First, convert the OpenCvSharp rectangles.
var rects = localFaces.Select(
f => new Microsoft.ProjectOxford.Common.Rectangle
{
Left = f.Left,
Top = f.Top,
Width = f.Width,
Height = f.Height
});
emotions = await _emotionClient.RecognizeAsync(jpg, rects.ToArray());
}
else
{
// If not, the API will do the face detection.
emotions = await _emotionClient.RecognizeAsync(jpg);
}
// Count the API call.
Properties.Settings.Default.EmotionAPICallCount++;
// Output.
return new LiveCameraResult
{
Faces = emotions.Select(e => CreateFace(e.FaceRectangle)).ToArray(),
// Extract emotion scores from results.
EmotionScores = emotions.Select(e => e.Scores).ToArray()
};
}
/// <summary> Function which submits a frame to the Computer Vision API for tagging. </summary>
/// <param name="frame"> The video frame to submit. </param>
/// <returns> A <see cref="Task{LiveCameraResult}"/> representing the asynchronous API call,
/// and containing the tags returned by the API. </returns>
private async Task<LiveCameraResult> TaggingAnalysisFunction(VideoFrame frame)
{
// Encode image.
var jpg = frame.Image.ToMemoryStream(".jpg", s_jpegParams);
// Submit image to API.
var analysis = await _visionClient.GetTagsAsync(jpg);
// Count the API call.
Properties.Settings.Default.VisionAPICallCount++;
// Output.
return new LiveCameraResult { Tags = analysis.Tags };
}
/// <summary> Function which submits a frame to the Computer Vision API for celebrity
/// detection. </summary>
/// <param name="frame"> The video frame to submit. </param>
/// <returns> A <see cref="Task{LiveCameraResult}"/> representing the asynchronous API call,
/// and containing the celebrities returned by the API. </returns>
private async Task<LiveCameraResult> CelebrityAnalysisFunction(VideoFrame frame)
{
// Encode image.
var jpg = frame.Image.ToMemoryStream(".jpg", s_jpegParams);
// Submit image to API.
var result = await _visionClient.AnalyzeImageInDomainAsync(jpg, "celebrities");
// Count the API call.
Properties.Settings.Default.VisionAPICallCount++;
// Output.
var celebs = JsonConvert.DeserializeObject<CelebritiesResult>(result.Result.ToString()).Celebrities;
return new LiveCameraResult
{
// Extract face rectangles from results.
Faces = celebs.Select(c => CreateFace(c.FaceRectangle)).ToArray(),
// Extract celebrity names from results.
CelebrityNames = celebs.Select(c => c.Name).ToArray()
};
}
private BitmapSource VisualizeResult(VideoFrame frame)
{
// Draw any results on top of the image.
BitmapSource visImage = frame.Image.ToBitmapSource();
var result = _latestResultsToDisplay;
if (result != null)
{
// See if we have local face detections for this image.
var clientFaces = (OpenCvSharp.Rect[])frame.UserData;
if (clientFaces != null && result.Faces != null)
{
// If so, then the analysis results might be from an older frame. We need to match
// the client-side face detections (computed on this frame) with the analysis
// results (computed on the older frame) that we want to display.
MatchAndReplaceFaceRectangles(result.Faces, clientFaces);
}
visImage = Visualization.DrawFaces(visImage, result.Faces, result.EmotionScores, result.CelebrityNames);
visImage = Visualization.DrawTags(visImage, result.Tags);
}
return visImage;
}
/// <summary> Populate CameraList in the UI, once it is loaded. </summary>
/// <param name="sender"> Source of the event. </param>
/// <param name="e"> Routed event information. </param>
private void CameraList_Loaded(object sender, RoutedEventArgs e)
{
int numCameras = _grabber.GetNumCameras();
if (numCameras == 0)
{
MessageArea.Text = "No cameras found!";
}
var comboBox = sender as ComboBox;
comboBox.ItemsSource = Enumerable.Range(0, numCameras).Select(i => string.Format("Camera {0}", i + 1));
comboBox.SelectedIndex = 0;
}
/// <summary> Populate ModeList in the UI, once it is loaded. </summary>
/// <param name="sender"> Source of the event. </param>
/// <param name="e"> Routed event information. </param>
private void ModeList_Loaded(object sender, RoutedEventArgs e)
{
var modes = (AppMode[])Enum.GetValues(typeof(AppMode));
var comboBox = sender as ComboBox;
comboBox.ItemsSource = modes.Select(m => m.ToString());
comboBox.SelectedIndex = 0;
}
private void ModeList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Disable "most-recent" results display.
_fuseClientRemoteResults = false;
var comboBox = sender as ComboBox;
var modes = (AppMode[])Enum.GetValues(typeof(AppMode));
_mode = modes[comboBox.SelectedIndex];
switch (_mode)
{
case AppMode.Faces:
_grabber.AnalysisFunction = FacesAnalysisFunction;
break;
case AppMode.Emotions:
_grabber.AnalysisFunction = EmotionAnalysisFunction;
break;
case AppMode.EmotionsWithClientFaceDetect:
// Same as Emotions, except we will display the most recent faces combined with
// the most recent API results.
_grabber.AnalysisFunction = EmotionAnalysisFunction;
_fuseClientRemoteResults = true;
break;
case AppMode.Tags:
_grabber.AnalysisFunction = TaggingAnalysisFunction;
break;
case AppMode.Celebrities:
_grabber.AnalysisFunction = CelebrityAnalysisFunction;
break;
default:
_grabber.AnalysisFunction = null;
break;
}
}
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
if (!CameraList.HasItems)
{
MessageArea.Text = "No cameras found; cannot start processing";
return;
}
// Clean leading/trailing spaces in API keys.
Properties.Settings.Default.FaceAPIKey = Properties.Settings.Default.FaceAPIKey.Trim();
Properties.Settings.Default.EmotionAPIKey = Properties.Settings.Default.EmotionAPIKey.Trim();
Properties.Settings.Default.VisionAPIKey = Properties.Settings.Default.VisionAPIKey.Trim();
// Create API clients.
_faceClient = new FaceServiceClient(Properties.Settings.Default.FaceAPIKey);
_emotionClient = new EmotionServiceClient(Properties.Settings.Default.EmotionAPIKey);
_visionClient = new VisionServiceClient(Properties.Settings.Default.VisionAPIKey);
// How often to analyze.
_grabber.TriggerAnalysisOnInterval(Properties.Settings.Default.AnalysisInterval);
// Reset message.
MessageArea.Text = "";
// Record start time, for auto-stop
_startTime = DateTime.Now;
await _grabber.StartProcessingCameraAsync(CameraList.SelectedIndex);
}
private async void StopButton_Click(object sender, RoutedEventArgs e)
{
await _grabber.StopProcessingAsync();
}
private void SettingsButton_Click(object sender, RoutedEventArgs e)
{
SettingsPanel.Visibility = 1 - SettingsPanel.Visibility;
}
private void SaveSettingsButton_Click(object sender, RoutedEventArgs e)
{
SettingsPanel.Visibility = Visibility.Hidden;
Properties.Settings.Default.Save();
}
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
private Face CreateFace(FaceRectangle rect)
{
return new Face
{
FaceRectangle = new FaceRectangle
{
Left = rect.Left,
Top = rect.Top,
Width = rect.Width,
Height = rect.Height
}
};
}
private Face CreateFace(Microsoft.ProjectOxford.Vision.Contract.FaceRectangle rect)
{
return new Face
{
FaceRectangle = new FaceRectangle
{
Left = rect.Left,
Top = rect.Top,
Width = rect.Width,
Height = rect.Height
}
};
}
private Face CreateFace(Microsoft.ProjectOxford.Common.Rectangle rect)
{
return new Face
{
FaceRectangle = new FaceRectangle
{
Left = rect.Left,
Top = rect.Top,
Width = rect.Width,
Height = rect.Height
}
};
}
private void MatchAndReplaceFaceRectangles(Face[] faces, OpenCvSharp.Rect[] clientRects)
{
// Use a simple heuristic for matching the client-side faces to the faces in the
// results. Just sort both lists left-to-right, and assume a 1:1 correspondence.
// Sort the faces left-to-right.
var sortedResultFaces = faces
.OrderBy(f => f.FaceRectangle.Left + 0.5 * f.FaceRectangle.Width)
.ToArray();
// Sort the clientRects left-to-right.
var sortedClientRects = clientRects
.OrderBy(r => r.Left + 0.5 * r.Width)
.ToArray();
// Assume that the sorted lists now corrrespond directly. We can simply update the
// FaceRectangles in sortedResultFaces, because they refer to the same underlying
// objects as the input "faces" array.
for (int i = 0; i < Math.Min(faces.Length, clientRects.Length); i++)
{
// convert from OpenCvSharp rectangles
OpenCvSharp.Rect r = sortedClientRects[i];
sortedResultFaces[i].FaceRectangle = new FaceRectangle { Left = r.Left, Top = r.Top, Width = r.Width, Height = r.Height };
}
}
}
}

View file

@ -0,0 +1,88 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("LiveCameraSample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LiveCameraSample")]
[assembly: AssemblyCopyright("Copyright \u00A9 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace LiveCameraSample.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LiveCameraSample.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View file

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -0,0 +1,143 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace LiveCameraSample.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string FaceAPIKey {
get {
return ((string)(this["FaceAPIKey"]));
}
set {
this["FaceAPIKey"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string EmotionAPIKey {
get {
return ((string)(this["EmotionAPIKey"]));
}
set {
this["EmotionAPIKey"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string VisionAPIKey {
get {
return ((string)(this["VisionAPIKey"]));
}
set {
this["VisionAPIKey"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Visible")]
public global::System.Windows.Visibility SettingsPanelVisibility {
get {
return ((global::System.Windows.Visibility)(this["SettingsPanelVisibility"]));
}
set {
this["SettingsPanelVisibility"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("00:00:03")]
public global::System.TimeSpan AnalysisInterval {
get {
return ((global::System.TimeSpan)(this["AnalysisInterval"]));
}
set {
this["AnalysisInterval"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int FaceAPICallCount {
get {
return ((int)(this["FaceAPICallCount"]));
}
set {
this["FaceAPICallCount"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int EmotionAPICallCount {
get {
return ((int)(this["EmotionAPICallCount"]));
}
set {
this["EmotionAPICallCount"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int VisionAPICallCount {
get {
return ((int)(this["VisionAPICallCount"]));
}
set {
this["VisionAPICallCount"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool AutoStopEnabled {
get {
return ((bool)(this["AutoStopEnabled"]));
}
set {
this["AutoStopEnabled"] = value;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("00:05:00")]
public global::System.TimeSpan AutoStopTime {
get {
return ((global::System.TimeSpan)(this["AutoStopTime"]));
}
}
}
}

View file

@ -0,0 +1,36 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="LiveCameraSample.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="FaceAPIKey" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="EmotionAPIKey" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="VisionAPIKey" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="SettingsPanelVisibility" Type="System.Windows.Visibility" Scope="User">
<Value Profile="(Default)">Visible</Value>
</Setting>
<Setting Name="AnalysisInterval" Type="System.TimeSpan" Scope="User">
<Value Profile="(Default)">00:00:03</Value>
</Setting>
<Setting Name="FaceAPICallCount" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="EmotionAPICallCount" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="VisionAPICallCount" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="AutoStopEnabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="AutoStopTime" Type="System.TimeSpan" Scope="Application">
<Value Profile="(Default)">00:05:00</Value>
</Setting>
</Settings>
</SettingsFile>

View file

@ -0,0 +1,172 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.ProjectOxford.Emotion.Contract;
using Microsoft.ProjectOxford.Face.Contract;
using Microsoft.ProjectOxford.Vision.Contract;
namespace LiveCameraSample
{
public class Visualization
{
private static SolidColorBrush s_lineBrush = new SolidColorBrush(new System.Windows.Media.Color { R = 255, G = 185, B = 0, A = 255 });
private static Typeface s_typeface = new Typeface(new FontFamily("Segoe UI"), FontStyles.Normal, FontWeights.Bold, FontStretches.Normal);
private static BitmapSource DrawOverlay(BitmapSource baseImage, Action<DrawingContext, double> drawAction)
{
double annotationScale = baseImage.PixelHeight / 320;
DrawingVisual visual = new DrawingVisual();
DrawingContext drawingContext = visual.RenderOpen();
drawingContext.DrawImage(baseImage, new Rect(0, 0, baseImage.Width, baseImage.Height));
drawAction(drawingContext, annotationScale);
drawingContext.Close();
RenderTargetBitmap outputBitmap = new RenderTargetBitmap(
baseImage.PixelWidth, baseImage.PixelHeight,
baseImage.DpiX, baseImage.DpiY, PixelFormats.Pbgra32);
outputBitmap.Render(visual);
return outputBitmap;
}
public static BitmapSource DrawTags(BitmapSource baseImage, Tag[] tags)
{
if (tags == null)
{
return baseImage;
}
Action<DrawingContext, double> drawAction = (drawingContext, annotationScale) =>
{
double y = 0;
foreach (var tag in tags)
{
// Create formatted text--in a particular font at a particular size
FormattedText ft = new FormattedText(tag.Name,
CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typeface,
42 * annotationScale, Brushes.Black);
// Instead of calling DrawText (which can only draw the text in a solid colour), we
// convert to geometry and use DrawGeometry, which allows us to add an outline.
var geom = ft.BuildGeometry(new Point(10 * annotationScale, y));
drawingContext.DrawGeometry(s_lineBrush, new Pen(Brushes.Black, 2 * annotationScale), geom);
// Move line down
y += 42 * annotationScale;
}
};
return DrawOverlay(baseImage, drawAction);
}
public static BitmapSource DrawFaces(BitmapSource baseImage, Microsoft.ProjectOxford.Face.Contract.Face[] faces, Scores[] emotionScores, string[] celebName)
{
if (faces == null)
{
return baseImage;
}
Action<DrawingContext, double> drawAction = (drawingContext, annotationScale) =>
{
for (int i = 0; i < faces.Length; i++)
{
var face = faces[i];
if (face.FaceRectangle == null) { continue; }
Rect faceRect = new Rect(
face.FaceRectangle.Left, face.FaceRectangle.Top,
face.FaceRectangle.Width, face.FaceRectangle.Height);
string text = "";
if (face.FaceAttributes != null)
{
text += Aggregation.SummarizeFaceAttributes(face.FaceAttributes);
}
if (emotionScores?[i] != null)
{
text += Aggregation.SummarizeEmotion(emotionScores[i]);
}
if (celebName?[i] != null)
{
text += celebName[i];
}
faceRect.Inflate(6 * annotationScale, 6 * annotationScale);
double lineThickness = 4 * annotationScale;
drawingContext.DrawRectangle(
Brushes.Transparent,
new Pen(s_lineBrush, lineThickness),
faceRect);
if (text != "")
{
FormattedText ft = new FormattedText(text,
CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typeface,
16 * annotationScale, Brushes.Black);
var pad = 3 * annotationScale;
var ypad = pad;
var xpad = pad + 4 * annotationScale;
var origin = new Point(
faceRect.Left + xpad - lineThickness / 2,
faceRect.Top - ft.Height - ypad + lineThickness / 2);
var rect = ft.BuildHighlightGeometry(origin).GetRenderBounds(null);
rect.Inflate(xpad, ypad);
drawingContext.DrawRectangle(s_lineBrush, null, rect);
drawingContext.DrawText(ft, origin);
}
}
};
return DrawOverlay(baseImage, drawAction);
}
}
}

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net452" />
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net452" />
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net452" />
<package id="Microsoft.ProjectOxford.Common" version="1.0.308" targetFramework="net452" />
<package id="Microsoft.ProjectOxford.Emotion" version="1.0.310" targetFramework="net452" />
<package id="Microsoft.ProjectOxford.Face" version="1.1.0" targetFramework="net452" />
<package id="Microsoft.ProjectOxford.Vision" version="1.0.354" targetFramework="net452" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
<package id="OpenCvSharp3-AnyCPU" version="3.1.0.20160622" targetFramework="net452" />
</packages>

View file

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiveCameraSample", "LiveCameraSample\LiveCameraSample.csproj", "{5B40977E-E8FA-41BC-8F0A-6D6FDE237571}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoFrameAnalyzer", "VideoFrameAnalyzer\VideoFrameAnalyzer.csproj", "{BEC7DA78-C953-4A72-924F-2749D1F9F18B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicConsoleSample", "BasicConsoleSample\BasicConsoleSample.csproj", "{0638DEF8-9613-4599-9335-7A2438B447DA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5B40977E-E8FA-41BC-8F0A-6D6FDE237571}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B40977E-E8FA-41BC-8F0A-6D6FDE237571}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B40977E-E8FA-41BC-8F0A-6D6FDE237571}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B40977E-E8FA-41BC-8F0A-6D6FDE237571}.Release|Any CPU.Build.0 = Release|Any CPU
{BEC7DA78-C953-4A72-924F-2749D1F9F18B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEC7DA78-C953-4A72-924F-2749D1F9F18B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEC7DA78-C953-4A72-924F-2749D1F9F18B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEC7DA78-C953-4A72-924F-2749D1F9F18B}.Release|Any CPU.Build.0 = Release|Any CPU
{0638DEF8-9613-4599-9335-7A2438B447DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0638DEF8-9613-4599-9335-7A2438B447DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0638DEF8-9613-4599-9335-7A2438B447DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0638DEF8-9613-4599-9335-7A2438B447DA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,70 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace VideoFrameAnalyzer
{
public static class ConcurrentLogger
{
private readonly static SemaphoreSlim s_printMutex = new SemaphoreSlim(1);
private readonly static BlockingCollection<string> s_messageQueue = new BlockingCollection<string>();
public static void WriteLine(string message)
{
var timestamp = DateTime.Now;
// Push the message on the queue
s_messageQueue.Add(timestamp.ToString("o") + ": " + message);
// Start a new task that will dequeue one message and print it. The tasks will not
// necessarily run in order, but since each task just takes the oldest message and
// prints it, the messages will print in order.
Task.Run(async () =>
{
// Wait to get access to the queue.
await s_printMutex.WaitAsync();
try
{
string msg = s_messageQueue.Take();
Console.WriteLine(msg);
}
finally
{
s_printMutex.Release();
}
});
}
}
}

View file

@ -0,0 +1,554 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Uncomment this to enable the LogMessage function, which can with debugging timing issues.
// #define TRACE_GRABBER
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using OpenCvSharp;
namespace VideoFrameAnalyzer
{
/// <summary> A frame grabber. </summary>
/// <typeparam name="AnalysisResultType"> Type of the analysis result. This is the type that
/// the AnalysisFunction will return, when it calls some API on a video frame. </typeparam>
public class FrameGrabber<AnalysisResultType>
{
#region Types
/// <summary> Additional information for new frame events. </summary>
/// <seealso cref="T:System.EventArgs"/>
public class NewFrameEventArgs : EventArgs
{
public NewFrameEventArgs(VideoFrame frame)
{
Frame = frame;
}
public VideoFrame Frame { get; }
}
/// <summary> Additional information for new result events, which occur when an API call
/// returns. </summary>
/// <seealso cref="T:System.EventArgs"/>
public class NewResultEventArgs : EventArgs
{
public NewResultEventArgs(VideoFrame frame)
{
Frame = frame;
}
public VideoFrame Frame { get; }
public AnalysisResultType Analysis { get; set; } = default(AnalysisResultType);
public bool TimedOut { get; set; } = false;
public Exception Exception { get; set; } = null;
}
#endregion Types
#region Properties
/// <summary> Gets or sets the analysis function. The function can be any asynchronous
/// operation that accepts a <see cref="VideoFrame"/> and returns a
/// <see cref="Task{AnalysisResultType}"/>. </summary>
/// <value> The analysis function. </value>
/// <example> This example shows how to provide an analysis function using a lambda expression.
/// <code>
/// var client = new EmotionServiceClient("subscription key");
/// var grabber = new FrameGrabber();
/// grabber.AnalysisFunction = async (frame) =&gt; { return await client.RecognizeAsync(frame.Image.ToMemoryStream(".jpg")); };
/// </code></example>
public Func<VideoFrame, Task<AnalysisResultType>> AnalysisFunction { get; set; } = null;
/// <summary> Gets or sets the analysis timeout. When executing the
/// <see cref="AnalysisFunction"/> on a video frame, if the call doesn't return a
/// result within this time, it is abandoned and no result is returned for that
/// frame. </summary>
/// <value> The analysis timeout. </value>
public TimeSpan AnalysisTimeout { get; set; } = TimeSpan.FromMilliseconds(5000);
public bool IsRunning { get { return _analysisTaskQueue != null; } }
public double FrameRate
{
get { return _fps; }
set
{
_fps = value;
if (_timer != null)
{
_timer.Change(TimeSpan.Zero, TimeSpan.FromSeconds(1.0 / _fps));
}
}
}
public int Width { get; protected set; }
public int Height { get; protected set; }
#endregion Properties
#region Fields
protected Predicate<VideoFrame> _analysisPredicate = null;
protected VideoCapture _reader = null;
protected Timer _timer = null;
protected readonly SemaphoreSlim _timerMutex = new SemaphoreSlim(1);
protected readonly AutoResetEvent _frameGrabTimer = new AutoResetEvent(false);
protected bool _stopping = false;
protected Task _producerTask = null;
protected Task _consumerTask = null;
protected BlockingCollection<Task<NewResultEventArgs>> _analysisTaskQueue = null;
protected bool _resetTrigger = true;
protected int _numCameras = -1;
protected int _currCameraIdx = -1;
protected double _fps = 0;
#endregion Fields
#region Methods
public FrameGrabber()
{
}
/// <summary> (Only available in TRACE_GRABBER builds) logs a message. </summary>
/// <param name="format"> Describes the format to use. </param>
/// <param name="args"> Event information. </param>
[Conditional("TRACE_GRABBER")]
protected void LogMessage(string format, params object[] args)
{
ConcurrentLogger.WriteLine(String.Format(format, args));
}
/// <summary> Starts processing frames from a live camera. Stops any current video source
/// before starting the new source. </summary>
/// <returns> A Task. </returns>
public async Task StartProcessingCameraAsync(int cameraIndex = 0, double overrideFPS = 0)
{
// Check to see if we're re-opening the same camera.
if (_reader != null && _reader.CaptureType == CaptureType.Camera && cameraIndex == _currCameraIdx)
{
return;
}
await StopProcessingAsync().ConfigureAwait(false);
_reader = new VideoCapture(cameraIndex);
_fps = overrideFPS;
if (_fps == 0)
{
_fps = 30;
}
Width = _reader.FrameWidth;
Height = _reader.FrameHeight;
StartProcessing(TimeSpan.FromSeconds(1 / _fps), () => DateTime.Now);
_currCameraIdx = cameraIndex;
}
/// <summary> Starts capturing and processing video frames. </summary>
/// <param name="frameGrabDelay"> The frame grab delay. </param>
/// <param name="timestampFn"> Function to generate the timestamp for each frame. This
/// function will get called once per frame. </param>
protected void StartProcessing(TimeSpan frameGrabDelay, Func<DateTime> timestampFn)
{
OnProcessingStarting();
_resetTrigger = true;
_frameGrabTimer.Reset();
_analysisTaskQueue = new BlockingCollection<Task<NewResultEventArgs>>();
var timerIterations = 0;
// Create a background thread that will grab frames in a loop.
_producerTask = Task.Factory.StartNew(() =>
{
var frameCount = 0;
while (!_stopping)
{
LogMessage("Producer: waiting for timer to trigger frame-grab");
// Wait to get released by the timer.
_frameGrabTimer.WaitOne();
LogMessage("Producer: grabbing frame...");
var startTime = DateTime.Now;
// Grab single frame.
var timestamp = timestampFn();
Mat image = new Mat();
bool success = _reader.Read(image);
LogMessage("Producer: frame-grab took {0} ms", (DateTime.Now - startTime).Milliseconds);
if (!success)
{
// If we've reached the end of the video, stop here.
if (_reader.CaptureType == CaptureType.File)
{
LogMessage("Producer: null frame from video file, stop!");
// This will call StopProcessing on a new thread.
var stopTask = StopProcessingAsync();
// Break out of the loop to make sure we don't try grabbing more
// frames.
break;
}
else
{
// If failed on live camera, try again.
LogMessage("Producer: null frame from live camera, continue!");
continue;
}
}
// Package the image for submission.
VideoFrameMetadata meta;
meta.Index = frameCount;
meta.Timestamp = timestamp;
VideoFrame vframe = new VideoFrame(image, meta);
// Raise the new frame event
LogMessage("Producer: new frame provided, should analyze? Frame num: {0}", meta.Index);
OnNewFrameProvided(vframe);
if (_analysisPredicate(vframe))
{
LogMessage("Producer: analyzing frame");
// Call the analysis function on a threadpool thread
var analysisTask = DoAnalyzeFrame(vframe);
LogMessage("Producer: adding analysis task to queue {0}", analysisTask.Id);
// Push the frame onto the queue
_analysisTaskQueue.Add(analysisTask);
}
else
{
LogMessage("Producer: not analyzing frame");
}
LogMessage("Producer: iteration took {0} ms", (DateTime.Now - startTime).Milliseconds);
++frameCount;
}
LogMessage("Producer: stopping, destroy reader and timer");
_analysisTaskQueue.CompleteAdding();
// We reach this point by breaking out of the while loop. So we must be stopping.
_reader.Dispose();
_reader = null;
// Make sure the timer stops, then get rid of it.
var h = new ManualResetEvent(false);
_timer.Dispose(h);
h.WaitOne();
_timer = null;
LogMessage("Producer: stopped");
}, TaskCreationOptions.LongRunning);
_consumerTask = Task.Factory.StartNew(async () =>
{
while (!_analysisTaskQueue.IsCompleted)
{
LogMessage("Consumer: waiting for task to get added");
// Get the next processing task.
Task<NewResultEventArgs> nextTask = null;
// Blocks if m_analysisTaskQueue.Count == 0
// IOE means that Take() was called on a completed collection.
// Some other thread can call CompleteAdding after we pass the
// IsCompleted check but before we call Take.
// In this example, we can simply catch the exception since the
// loop will break on the next iteration.
// See https://msdn.microsoft.com/en-us/library/dd997371(v=vs.110).aspx
try
{
nextTask = _analysisTaskQueue.Take();
}
catch (InvalidOperationException) { }
if (nextTask != null)
{
// Block until the result becomes available.
LogMessage("Consumer: waiting for next result to arrive for task {0}", nextTask.Id);
var result = await nextTask;
// Raise the new result event.
LogMessage("Consumer: got result for frame {0}. {1} tasks in queue", result.Frame.Metadata.Index, _analysisTaskQueue.Count);
OnNewResultAvailable(result);
}
}
LogMessage("Consumer: stopped");
}, TaskCreationOptions.LongRunning);
// Set up a timer object that will trigger the frame-grab at a regular interval.
_timer = new Timer(async s /* state */ =>
{
await _timerMutex.WaitAsync();
try
{
// If the handle was not reset by the producer, then the frame-grab was missed.
bool missed = _frameGrabTimer.WaitOne(0);
_frameGrabTimer.Set();
if (missed)
{
LogMessage("Timer: missed frame-grab {0}", timerIterations - 1);
}
LogMessage("Timer: grab frame num {0}", timerIterations);
++timerIterations;
}
finally
{
_timerMutex.Release();
}
}, null, TimeSpan.Zero, frameGrabDelay);
OnProcessingStarted();
}
/// <summary> Stops capturing and processing video frames. </summary>
/// <returns> A Task. </returns>
public async Task StopProcessingAsync()
{
OnProcessingStopping();
_stopping = true;
_frameGrabTimer.Set();
if (_producerTask != null)
{
await _producerTask;
_producerTask = null;
}
if (_consumerTask != null)
{
await _consumerTask;
_consumerTask = null;
}
if (_analysisTaskQueue != null)
{
_analysisTaskQueue.Dispose();
_analysisTaskQueue = null;
}
_stopping = false;
OnProcessingStopped();
}
/// <summary> Trigger analysis on an arbitrary predicate. </summary>
/// <param name="predicate"> The predicate to use to decide whether or not to analyze a
/// particular <see cref="VideoFrame"/>. The function must accept two arguments: the
/// <see cref="VideoFrame"/> in question, and a boolean flag that indicates the
/// trigger should be reset (e.g. on the first frame, or when the predicate has
/// changed). </param>
public void TriggerAnalysisOnPredicate(Func<VideoFrame, bool, bool> predicate)
{
_resetTrigger = true;
_analysisPredicate = (VideoFrame frame) =>
{
bool shouldCall = predicate(frame, _resetTrigger);
_resetTrigger = false;
return shouldCall;
};
}
/// <summary> Trigger analysis at a regular interval. </summary>
/// <param name="interval"> The time interval to wait between analyzing frames. </param>
public void TriggerAnalysisOnInterval(TimeSpan interval)
{
_resetTrigger = true;
// Keep track of the next timestamp to trigger.
DateTime nextCall = DateTime.MinValue;
_analysisPredicate = (VideoFrame frame) =>
{
bool shouldCall = false;
// If this is the first frame, then trigger and initialize the timer.
if (_resetTrigger)
{
_resetTrigger = false;
nextCall = frame.Metadata.Timestamp;
shouldCall = true;
}
else
{
shouldCall = frame.Metadata.Timestamp > nextCall;
}
// Return.
if (shouldCall)
{
nextCall += interval;
return true;
}
return false;
};
}
/// <summary> Gets the number of cameras available. Caution, the first time this function
/// is called, it opens each camera. Thus, it should be called before starting any
/// camera. </summary>
/// <returns> The number cameras. </returns>
public int GetNumCameras()
{
// Count cameras manually
if (_numCameras == -1)
{
_numCameras = 0;
while (_numCameras < 100)
{
using (var vc = VideoCapture.FromCamera(_numCameras))
{
if (vc.IsOpened())
++_numCameras;
else
break;
}
}
}
return _numCameras;
}
/// <summary> Raises the processing starting event. </summary>
protected void OnProcessingStarting()
{
ProcessingStarting?.Invoke(this, null);
}
/// <summary> Raises the processing started event. </summary>
protected void OnProcessingStarted()
{
ProcessingStarted?.Invoke(this, null);
}
/// <summary> Raises the processing stopping event. </summary>
protected void OnProcessingStopping()
{
ProcessingStopping?.Invoke(this, null);
}
/// <summary> Raises the processing stopped event. </summary>
protected void OnProcessingStopped()
{
ProcessingStopped?.Invoke(this, null);
}
/// <summary> Raises the new frame provided event. </summary>
/// <param name="frame"> The frame. </param>
protected void OnNewFrameProvided(VideoFrame frame)
{
NewFrameProvided?.Invoke(this, new NewFrameEventArgs(frame));
}
/// <summary> Raises the new result event. </summary>
/// <param name="args"> Event information to send to registered event handlers. </param>
protected void OnNewResultAvailable(NewResultEventArgs args)
{
NewResultAvailable?.Invoke(this, args);
}
/// <summary> Executes the analysis operation asynchronously, then returns either the
/// result, or any exception that was thrown. </summary>
/// <param name="frame"> The frame. </param>
/// <returns> A Task&lt;NewResultEventArgs&gt; </returns>
protected async Task<NewResultEventArgs> DoAnalyzeFrame(VideoFrame frame)
{
CancellationTokenSource source = new CancellationTokenSource();
// Make a local reference to the function, just in case someone sets
// AnalysisFunction = null before we can call it.
var fcn = AnalysisFunction;
if (fcn != null)
{
NewResultEventArgs output = new NewResultEventArgs(frame);
var task = fcn(frame);
LogMessage("DoAnalysis: started task {0}", task.Id);
try
{
if (task == await Task.WhenAny(task, Task.Delay(AnalysisTimeout, source.Token)))
{
output.Analysis = await task;
source.Cancel();
}
else
{
output.TimedOut = true;
}
}
catch (Exception ae)
{
output.Exception = ae;
}
LogMessage("DoAnalysis: returned from task {0}", task.Id);
return output;
}
else
{
return null;
}
}
#endregion Methods
#region Events
public event EventHandler ProcessingStarting;
public event EventHandler ProcessingStarted;
public event EventHandler ProcessingStopping;
public event EventHandler ProcessingStopped;
public event EventHandler<NewFrameEventArgs> NewFrameProvided;
public event EventHandler<NewResultEventArgs> NewResultAvailable;
#endregion Events
}
}

View file

@ -0,0 +1,69 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("VideoFrameAnalyzer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VideoFrameAnalyzer")]
[assembly: AssemblyCopyright("Copyright \u00A9 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("bec7da78-c953-4a72-924f-2749d1f9f18b")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,72 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services: http://www.microsoft.com/cognitive
//
// Microsoft Cognitive Services Github:
// https://github.com/Microsoft/Cognitive
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using OpenCvSharp;
namespace VideoFrameAnalyzer
{
/// <summary> Metadata for a VideoFrame. </summary>
public struct VideoFrameMetadata
{
public DateTime Timestamp;
public int Index;
}
/// <summary> A video frame produced by the <see cref="FrameGrabber{AnalysisResultType}"/>.
/// This class encapsulates the image, any metadata, and also allows the user to attach
/// some arbitrary data to each frame as it flows through the pipeline. </summary>
public class VideoFrame
{
/// <summary> Constructor. </summary>
/// <param name="image"> The image captured by the camera. </param>
/// <param name="metadata"> The metadata. </param>
public VideoFrame(Mat image, VideoFrameMetadata metadata)
{
Image = image;
Metadata = metadata;
}
/// <summary> Gets the image for the frame. </summary>
/// <value> The image. </value>
public Mat Image { get; }
/// <summary> Gets the frame's metadata. </summary>
/// <value> The metadata. </value>
public VideoFrameMetadata Metadata { get; }
/// <summary> Gets or sets the frame's "user data". </summary>
/// <value> Any additional data that the user would like to attach to a video frame. </value>
public object UserData { get; set; } = null;
}
}

View file

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props" Condition="Exists('..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BEC7DA78-C953-4A72-924F-2749D1F9F18B}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VideoFrameAnalyzer</RootNamespace>
<AssemblyName>VideoFrameAnalyzer</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp.Blob, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.Blob.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenCvSharp.UserInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\lib\net45\OpenCvSharp.UserInterface.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="ConcurrentLogger.cs" />
<Compile Include="FrameGrabber.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VideoFrame.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OpenCvSharp3-AnyCPU.3.1.0.20160622\build\OpenCvSharp3-AnyCPU.props'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
<package id="OpenCvSharp3-AnyCPU" version="3.1.0.20160622" targetFramework="net452" />
</packages>