Skip to content

Commit

Permalink
Merge pull request #2 from machielvisser/feature/usability
Browse files Browse the repository at this point in the history
Feature/usability
  • Loading branch information
machielvisser committed Jan 7, 2018
2 parents dd22940 + 2cb11f0 commit 7ccb117
Show file tree
Hide file tree
Showing 8 changed files with 33,426 additions and 73 deletions.
12 changes: 10 additions & 2 deletions CameraCalibration.sln
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2010
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CameraCalibrationTool", "CameraCalibrationTool\CameraCalibrationTool.csproj", "{A3629EF3-3D7D-4A35-A5F4-9F7199B1706A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2669C70B-EFFB-4836-A646-AD6A039D3EC1}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -19,4 +24,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5C3BA1A0-9FFF-4996-BE24-186DC020E429}
EndGlobalSection
EndGlobal
1 change: 0 additions & 1 deletion CameraCalibrationTool/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<appSettings>
<add key="CalibrationFile" value="c:/users/mvisser/Desktop/CameraCalibration.bin" />
</appSettings>
</configuration>
116 changes: 68 additions & 48 deletions CameraCalibrationTool/CalibrationToolViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
Expand All @@ -22,11 +23,6 @@

namespace CameraCalibrationTool
{
/**
* ToDo:
* * Get calibration error to zero
* * Load calibration and multiply normalized point with inverse of camera matrix
**/
public class CalibrationToolViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
Expand All @@ -37,8 +33,6 @@ public class CalibrationToolViewModel : INotifyPropertyChanged

private const int _sampleRate = 2;

private string _calibrationFile;

private ImageSource _step1;
public ImageSource Step1
{
Expand Down Expand Up @@ -81,8 +75,8 @@ public int PatternQuality
}
}

private int _calibrationError;
public int CalibrationError
private double _calibrationError;
public double CalibrationError
{
get
{
Expand All @@ -95,15 +89,34 @@ public int CalibrationError
}
}

private double _faceAngle;
public double FaceAngle
{
get
{
return _faceAngle;
}
set
{
_faceAngle = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FaceAngle)));
}
}

private Capture _capture;
private CascadeClassifier _haarCascade;

private ISubject<Image<Bgr, byte>> _images = new Subject<Image<Bgr, byte>>();
private ISubject<int> _saveTriggers = new Subject<int>();
private ISubject<string> _saveTriggers = new Subject<string>();
private ISubject<Calibration> _calibrations = new Subject<Calibration>();

public CalibrationToolViewModel()
{
_calibrationFile = ConfigurationManager.AppSettings["CalibrationFile"];
_capture = new Capture(0);
_capture.ImageGrabbed += ImageGrabbed;
_capture.Start();

var initialCalibration = File.Exists(_calibrationFile) ? ReadCalibration(_calibrationFile) : Enumerable.Empty<Calibration>();
_haarCascade = new CascadeClassifier("haarcascade_frontalface_default.xml");

var realCorners = Observable
.Range(0, _nCornersVertical)
Expand All @@ -114,27 +127,20 @@ public CalibrationToolViewModel()
.Aggregate((x, y) => x.Concat(y).ToArray())
.GetAwaiter();

_capture = new Capture(0);
_capture.ImageGrabbed += ImageGrabbed;
_capture.Start();

var imageSize = _images
.Select(i => i.Copy())
.Select(i => i.Size)
.Take(1)
.GetAwaiter();

//_images
// .Select(i => i.Copy())
// .Subscribe(i => Application.Current.Dispatcher.Invoke(() => Step1 = ImageToImageSource(i)));

var patterns = _images
.Select(i => i.Copy())
.Sample(TimeSpan.FromMilliseconds(250))
.Select(FindPattern)
.Publish();

patterns
.Subscribe(i => Application.Current.Dispatcher.Invoke(() => Step1 = ImageToImageSource(i.Image)));
.Subscribe(i => Application.Current?.Dispatcher.Invoke(() => Step1 = ImageToImageSource(i.Image)));

patterns
.Subscribe(p => PatternQuality = 100 * (int)(p.Corners.Size / (float)(_nCornersHorizontal * _nCornersVertical)));
Expand All @@ -148,16 +154,15 @@ public CalibrationToolViewModel()
.Concat(new[] { p })
.ToArray())
.Select(s => Calibrate(s, realCorners, imageSize.Wait()))
//.Do(c => Debug.WriteLine(c.Error))
.StartWith(initialCalibration)
.Merge(_calibrations)
.Publish();

calibrations
.Subscribe(c => CalibrationError = (int)c.Error);
.Subscribe(c => CalibrationError = c.Error);

_saveTriggers
.WithLatestFrom(calibrations, (t, c) => c)
.Subscribe(c => SaveCalibration(c.CameraMatrix, c.DistortionCoefficients));
.WithLatestFrom(calibrations, (f, c) => new { File = f, Calibration = c })
.Subscribe(t => SaveCalibration(t.Calibration.CameraMatrix, t.Calibration.DistortionCoefficients, t.File));

_images
.Select(i => i.Copy())
Expand All @@ -168,12 +173,15 @@ public CalibrationToolViewModel()
CvInvoke.Undistort(d.Image, output, d.Calibration.CameraMatrix, d.Calibration.DistortionCoefficients);
return output;
})
.Subscribe(i => Application.Current.Dispatcher.Invoke(() => Step2 = ImageToImageSource(i)));
.Subscribe(i => Application.Current?.Dispatcher.Invoke(() => Step2 = ImageToImageSource(i)));

var faces = _images
.Select(i => i.Copy())
.SelectMany(i => _haarCascade.DetectMultiScale(i, 1.3, 5, new ImageSize(150, 150)))
.WithLatestFrom(calibrations, (r, c) => new { Rectangle = r, Calibration = c })
.Select(x => Angle(new PointF(x.Rectangle.X + x.Rectangle.Width / 2, 240), x.Calibration))
.Subscribe(a => Application.Current?.Dispatcher.Invoke(() => FaceAngle = a));

calibrations
.Select(c => Angle(new PointF(640, 240), c))
.Subscribe(a => Debug.WriteLine(a));

patterns.Connect();
calibrations.Connect();
}
Expand All @@ -183,26 +191,38 @@ public CalibrationToolViewModel()
_capture.Stop();
}

public void SaveCalibration()
public void SaveCalibration(string file)
{
_saveTriggers.OnNext(0);
_saveTriggers.OnNext(file);
}

public void OpenCalibration(string file)
{
try
{
_calibrations.OnNext(ReadCalibration(file));
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}

private void SaveCalibration(Mat cameraMatrix, Mat distCoeffs)
private void SaveCalibration(Mat cameraMatrix, Mat distCoeffs, string file)
{
var fs = new FileStorage(_calibrationFile, FileStorage.Mode.Write);
var fs = new FileStorage(file, FileStorage.Mode.Write);
fs.Write(cameraMatrix, "cameraMatrix");
fs.Write(distCoeffs, "distCoeffs");
}

private IEnumerable<Calibration> ReadCalibration(string file)
private Calibration ReadCalibration(string file)
{
var fs = new FileStorage(file, FileStorage.Mode.Read);
var calibration = new Calibration();
fs.GetNode("cameraMatrix").ReadMat(calibration.CameraMatrix);
fs.GetNode("distCoeffs").ReadMat(calibration.DistortionCoefficients);

yield return calibration;
return calibration;
}

private double Angle(PointF point, Calibration calibration)
Expand All @@ -215,14 +235,8 @@ private double Angle(PointF point, Calibration calibration)
CvInvoke.ConvertPointsToHomogeneous(undistorted, homogeneous);

// Calculate angle
var angle = Math.Acos(1 / homogeneous[0].Norm) * 180 / Math.PI;
return angle;

// Calculate area in camera coordinates

// Calculate area in world coordinates

// Look for possible matches in tracking
var sign = homogeneous[0].X / Math.Abs(homogeneous[0].X);
return sign * Math.Acos(1 / homogeneous[0].Norm) * 180 / Math.PI;
}

private Calibration Calibrate(PointF[][] patterns, IObservable<MCvPoint3D32f[]> realCorners, ImageSize size)
Expand All @@ -241,10 +255,10 @@ private Calibration Calibrate(PointF[][] patterns, IObservable<MCvPoint3D32f[]>

private void ImageGrabbed(object sender, EventArgs e)
{
IOutputArray image = new Image<Bgr, byte>(_capture.Width, _capture.Height);
var image = new Image<Bgr, byte>(_capture.Width, _capture.Height);
_capture.Retrieve(image);
_images.OnNext((Image<Bgr, byte>)image);
((Image<Bgr, byte>)image).Dispose();
_images.OnNext(image);
image.Dispose();
}

private Pattern FindPattern(Image<Bgr, byte> image)
Expand Down Expand Up @@ -285,6 +299,12 @@ private BitmapImage ImageToImageSource(Image<Bgr, byte> image)
}
}

class Detection
{
public Rectangle Position;
public Image<Bgr, byte> Image;
}

class Pattern
{
public VectorOfPointF Corners;
Expand Down
5 changes: 5 additions & 0 deletions CameraCalibrationTool/CameraCalibrationTool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="haarcascade_frontalface_default.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
Expand Down
21 changes: 14 additions & 7 deletions CameraCalibrationTool/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,34 @@
xmlns:local="clr-namespace:CameraCalibrationTool"
mc:Ignorable="d"
Title="Camera Calibration Tool" Height="400" Width="800">
<Grid>
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"></ColumnDefinition>
<ColumnDefinition Width="4*"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="5"></RowDefinition>
</Grid.RowDefinitions>
<Image
Source="{Binding Step1}"
Stretch="Uniform"
Grid.Row="0"/>
Stretch="Uniform"/>
<Image
Source="{Binding Step2}"
Stretch="Uniform"
Grid.Row="0"
Grid.Column="1"/>
<Button Click="Button_Click" Grid.Column="2" Height="20" VerticalAlignment="Top" />
<Grid Grid.Column="2" Grid.Row="0" Grid.RowSpan="2" Margin="2">
<Grid.RowDefinitions>
<RowDefinition Height="25"></RowDefinition>
<RowDefinition Height="25"></RowDefinition>
<RowDefinition Height="25"></RowDefinition>
</Grid.RowDefinitions>
<Button Click="OpenButtonClick" Grid.Row="0" Height="20" VerticalAlignment="Top">Open</Button>
<Button Click="SaveButtonClick" Grid.Row="1" Height="20" VerticalAlignment="Top">Save</Button>
<TextBlock Grid.Row="2" Text="{Binding FaceAngle}"/>
</Grid>
<ProgressBar Minimum="0" Maximum="100" Value="{Binding PatternQuality}" Grid.Column="0" Grid.Row="1" />
<ProgressBar Minimum="0" Maximum="100" Value="{Binding CalibrationError}" Grid.Column="1" Grid.Row="1" Foreground="Red" />
<ProgressBar Minimum="0" Maximum="1" Value="{Binding CalibrationError}" Grid.Column="1" Grid.Row="1" Foreground="Red" />
</Grid>
</Window>
27 changes: 12 additions & 15 deletions CameraCalibrationTool/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
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;

namespace CameraCalibrationTool
{
Expand All @@ -29,9 +17,18 @@ public MainWindow()
DataContext = _viewModel = new CalibrationToolViewModel();
}

private void Button_Click(object sender, RoutedEventArgs e)
private void SaveButtonClick(object sender, RoutedEventArgs e)
{
_viewModel.SaveCalibration();
var dialog = new SaveFileDialog();
if (dialog.ShowDialog() ?? false)
_viewModel.SaveCalibration(dialog.FileName);
}

private void OpenButtonClick(object sender, RoutedEventArgs e)
{
var dialog = new OpenFileDialog();
if (dialog.ShowDialog() ?? false)
_viewModel.OpenCalibration(dialog.FileName);
}
}
}
Loading

0 comments on commit 7ccb117

Please sign in to comment.