Skip to content

Commit

Permalink
Working version
Browse files Browse the repository at this point in the history
  • Loading branch information
StanleySweet committed Jan 18, 2018
1 parent c111132 commit 419574b
Show file tree
Hide file tree
Showing 126 changed files with 1,003 additions and 548 deletions.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace MediaFrameQrProcessing.Entities
using Windows.Media.Ocr;

namespace MediaFrameQrProcessing.Entities
{
public class ActiDetectedWord
{
Expand All @@ -18,6 +20,16 @@ public ActiDetectedWord(string originalText, double posX, double posY, double wi
_width = width;
_exactMatch = exactMatch;
}

public ActiDetectedWord(OcrWord word, bool exactMatch = false)
{
_originalText = word.Text;
_posX = word.BoundingRect.X;
_posY = word.BoundingRect.Y;
_height = word.BoundingRect.Height;
_width = word.BoundingRect.Width;
_exactMatch = exactMatch;
}
public string DetectedWord => _originalText;
public bool IsExactMatch() => _exactMatch;
public float PosX => (float)_posX;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace MediaFrameQrProcessing.Processors
{
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using VideoDeviceFinders;
using Windows.Devices.Enumeration;
Expand All @@ -10,73 +11,121 @@

public abstract class MediaCaptureFrameProcessor : IDisposable
{
protected MediaCaptureFrameProcessor(
MediaFrameSourceFinder mediaFrameSourceFinder,
DeviceInformation videoDeviceInformation,
string mediaEncodingSubtype,
MediaCaptureMemoryPreference memoryPreference = MediaCaptureMemoryPreference.Cpu)
#region Attributes
private Action<VideoDeviceController> videoDeviceControllerInitialiser;
private readonly string mediaEncodingSubtype;
private readonly MediaFrameSourceFinder mediaFrameSourceFinder;
private readonly DeviceInformation videoDeviceInformation;
private readonly MediaCaptureMemoryPreference memoryPreference;
public MediaFrameReader mediaFastFrameReader { get; private set; }
private MediaCapture mediaCapture;
#endregion

protected MediaCaptureFrameProcessor(MediaFrameSourceFinder mediaFrameSourceFinder, DeviceInformation videoDeviceInformation, string mediaEncodingSubtype, MediaCaptureMemoryPreference memoryPreference = MediaCaptureMemoryPreference.Cpu)
{
this.mediaFrameSourceFinder = mediaFrameSourceFinder;
this.videoDeviceInformation = videoDeviceInformation;
this.mediaEncodingSubtype = mediaEncodingSubtype;
this.memoryPreference = memoryPreference;
this.mediaFastFrameReader = null;
}
public void SetVideoDeviceControllerInitialiser(
Action<VideoDeviceController> initialiser)

public void SetVideoDeviceControllerInitialiser(Action<VideoDeviceController> initialiser)
{
this.videoDeviceControllerInitialiser = initialiser;
}

protected abstract Task<bool> ProcessFrameAsync(MediaFrameReference frameReference);

/// <summary>
/// Note: the natural thing to do here is what I used to do which is to create the
/// MediaCapture inside of a using block.
/// Problem is, that seemed to cause a situation where I could get a crash (AV) in
///
/// Windows.Media.dll!Windows::Media::Capture::Frame::MediaFrameReader::CompletePendingStopOperation
///
/// Which seemed to be related to stopping/disposing the MediaFrameReader and then
/// disposing the media capture immediately after.
///
/// Right now, I've promoted the media capture to a member variable and held it around
/// and instead of creating/disposing an instance each time one instance is kept
/// indefinitely.
/// It's not what I wanted...
/// </summary>
/// <param name="timeout"></param>
/// <returns></returns>
public async Task ProcessFramesAsync(TimeSpan timeout)
{
// Note: the natural thing to do here is what I used to do which is to create the
// MediaCapture inside of a using block.
// Problem is, that seemed to cause a situation where I could get a crash (AV) in
//
// Windows.Media.dll!Windows::Media::Capture::Frame::MediaFrameReader::CompletePendingStopOperation
//
// Which seemed to be related to stopping/disposing the MediaFrameReader and then
// disposing the media capture immediately after.
//
// Right now, I've promoted the media capture to a member variable and held it around
// and instead of creating/disposing an instance each time one instance is kept
// indefinitely.
// It's not what I wanted...

await Task.Run(async () =>
try
{
await Task.Run(async () =>
{
var startTime = DateTime.Now;
if (this.mediaCapture == null)
this.mediaCapture = await this.CreateMediaCaptureAsync();

var mediaFrameSource = this.mediaCapture.FrameSources[this.mediaFrameSourceFinder.FrameSourceInfo.Id];
using (var frameReader = await this.mediaCapture.CreateFrameReaderAsync(mediaFrameSource, this.mediaEncodingSubtype))
{
await frameReader.StartAsync();
await this.ProcessFramesAsyncLoop(frameReader, timeout, startTime);
await frameReader.StopAsync();
}
});
}catch(Exception ex)
{
var startTime = DateTime.Now;
Debug.WriteLine("Erreur : lors du traitement lent des images : " + ex);
}

if (this.mediaCapture == null)
this.mediaCapture = await this.CreateMediaCaptureAsync();
}

var mediaFrameSource = this.mediaCapture.FrameSources[this.mediaFrameSourceFinder.FrameSourceInfo.Id];
using (var frameReader = await this.mediaCapture.CreateFrameReaderAsync(mediaFrameSource, this.mediaEncodingSubtype))
{
bool done = false;
public async Task CreateMediaFastFrameReader()
{
if (this.mediaCapture == null) this.mediaCapture = await this.CreateMediaCaptureAsync();
var mediaFrameSource = this.mediaCapture.FrameSources[this.mediaFrameSourceFinder.FrameSourceInfo.Id];

if (mediaFastFrameReader == null)
{
mediaFastFrameReader = await this.mediaCapture.CreateFrameReaderAsync(mediaFrameSource, this.mediaEncodingSubtype);
await mediaFastFrameReader.StartAsync();
}
}

await frameReader.StartAsync();
public async Task DisposeMediaFastFrameReader()
{
if (mediaFastFrameReader != null)
{
await mediaFastFrameReader.StopAsync();
mediaFastFrameReader.Dispose();
mediaFastFrameReader = null;
}
}

while (!done)
/// <summary>
/// Iterates until a result is found or timeout
/// </summary>
/// <param name="timeout"></param>
/// <param name="startTime"></param>
/// <returns></returns>
public async Task ProcessFramesAsyncLoop(MediaFrameReader frameReader, TimeSpan timeout, DateTime startTime)
{
bool done = false;
while (!done)
{
using (var frame = frameReader.TryAcquireLatestFrame())
{
if (frame != null)
{
using (var frame = frameReader.TryAcquireLatestFrame())
{
if (frame != null)
{
done = await this.ProcessFrameAsync(frame);
}
}
if (!done)
{
done = (DateTime.Now - startTime) > timeout;
}
done = await this.ProcessFrameAsync(frame);
}
await frameReader.StopAsync();
}
if (!done)
{
done = (DateTime.Now - startTime) > timeout;
}
}
);
}

async Task<MediaCapture> CreateMediaCaptureAsync()
{
var settings = new MediaCaptureInitializationSettings()
Expand Down Expand Up @@ -108,13 +157,8 @@ protected virtual void Dispose(bool disposing)
this.mediaCapture.Dispose();
this.mediaCapture = null;
}
}

Action<VideoDeviceController> videoDeviceControllerInitialiser;
readonly string mediaEncodingSubtype;
readonly MediaFrameSourceFinder mediaFrameSourceFinder;
readonly DeviceInformation videoDeviceInformation;
readonly MediaCaptureMemoryPreference memoryPreference;
MediaCapture mediaCapture;
DisposeMediaFastFrameReader().Wait();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ await Task.Run(() =>
{
try
{
this.Result = null;
Result zxingResult = ZXingQRCodeDecoder.DecodeBufferToQRCode(bitmap);

if (zxingResult != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,20 @@

public class WordFrameProcessor : MediaCaptureFrameProcessor
{
public List<ActiDetectedWord> Result { get; private set; }
public readonly string RequestWord;
private OcrEngine m_OcrEngine;
public HashSet<ActiDetectedWord> Result { get; private set; }
public string RequestWord { get; }
private static OcrEngine m_OcrEngine = OcrEngine.TryCreateFromUserProfileLanguages();

public WordFrameProcessor(string requestWord, MediaFrameSourceFinder mediaFrameSourceFinder, DeviceInformation videoDeviceInformation, string mediaEncodingSubtype, MediaCaptureMemoryPreference memoryPreference = MediaCaptureMemoryPreference.Cpu) : base(mediaFrameSourceFinder, videoDeviceInformation, mediaEncodingSubtype, memoryPreference)
{
Result = new List<ActiDetectedWord>();
Result = new HashSet<ActiDetectedWord>();
this.RequestWord = requestWord;
}

protected override async Task<bool> ProcessFrameAsync(MediaFrameReference frameReference)
{
bool success = false;
Result?.Clear();

Boolean success = false;
// Takes at worst 60ms
await Task.Run(async () =>
{
// doc here https://msdn.microsoft.com/en-us/library/windows/apps/xaml/windows.media.capture.frames.videomediaframe.aspx
Expand All @@ -38,28 +37,29 @@ await Task.Run(async () =>
{
try
{
if (this.m_OcrEngine == null)
this.m_OcrEngine = OcrEngine.TryCreateFromUserProfileLanguages();

OcrResult ocrResult = await this.m_OcrEngine.RecognizeAsync(bitmap);

OcrResult ocrResult = await m_OcrEngine.RecognizeAsync(bitmap);
Result?.Clear();

if (ocrResult == null)
throw new NullReferenceException("Ocr Result is null");
return;

foreach (OcrWord word in ocrResult.Lines.SelectMany(l => l.Words))
foreach (OcrLine line in ocrResult.Lines)
{
if ("quarante deux".Equals(RequestWord.ToLower()))
Result.Add(new ActiDetectedWord(word.Text, word.BoundingRect.X, word.BoundingRect.Y, word.BoundingRect.Width, word.BoundingRect.Height, false));
else if (word.Text.ToLower().Equals(RequestWord.ToLower()))
Result.Add(new ActiDetectedWord(word.Text, word.BoundingRect.X, word.BoundingRect.Y, word.BoundingRect.Width, word.BoundingRect.Height, true));
else if (word.Text.ToLower().Contains(RequestWord.ToLower()))
Result.Add(new ActiDetectedWord(word.Text, word.BoundingRect.X, word.BoundingRect.Y, word.BoundingRect.Width, word.BoundingRect.Height, true));
else if (RequestWord.ToLower().Contains(word.Text.ToLower()))
Result.Add(new ActiDetectedWord(word.Text, word.BoundingRect.X, word.BoundingRect.Y, word.BoundingRect.Width, word.BoundingRect.Height, true));
else if (LevenshteinDistance.Compute(RequestWord.ToLower(), word.Text.ToLower()) <= 2)
Result.Add(new ActiDetectedWord(word.Text, word.BoundingRect.X, word.BoundingRect.Y, word.BoundingRect.Width, word.BoundingRect.Height, false));
foreach (OcrWord word in line.Words)
{
if ("quarante deux".Equals(RequestWord.ToLower()))
Result.Add(new ActiDetectedWord(word, false));
else if (word.Text.ToLower().Equals(RequestWord.ToLower()))
Result.Add(new ActiDetectedWord(word, true));
else if (word.Text.ToLower().Contains(RequestWord.ToLower()))
Result.Add(new ActiDetectedWord(word, true));
else if (RequestWord.ToLower().Contains(word.Text.ToLower()))
Result.Add(new ActiDetectedWord(word, true));
else if (LevenshteinDistance.Compute(RequestWord.ToLower(), word.Text.ToLower()) <= 2)
Result.Add(new ActiDetectedWord(word, false));
}
}

success = Result.Count > 0;
}
catch (Exception ex)
Expand Down
43 changes: 22 additions & 21 deletions FullScreen-Version/MediaFrameQrProcessing/Wrappers/WordScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,26 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Media.MediaProperties;

public static class WordScanner
{
private static WordFrameProcessor m_FrameProcessor;

/// <summary>
///
/// Note - I keep this frame processor around which means keeping the
/// underlying MediaCapture around because when I didn't keep it
/// around I ended up with a crash in Windows.Media.dll related
/// to disposing of the MediaCapture.
/// So...this isn't what I wanted but it seems to work better :-(
/// </summary>
/// <param name="resultCallback"></param>
/// <param name="timeout"></param>
/// <param name="requestWord"></param>
public static async Task ScanFirstCameraForWords(Action<List<ActiDetectedWord>> resultCallback, TimeSpan timeout, string requestWord)
public static async Task ScanFirstCameraForWords(Action<HashSet<ActiDetectedWord>> resultCallback, TimeSpan timeout, string requestWord)
{

List<ActiDetectedWord> result = null;

// Note - I keep this frame processor around which means keeping the
// underlying MediaCapture around because when I didn't keep it
// around I ended up with a crash in Windows.Media.dll related
// to disposing of the MediaCapture.
// So...this isn't what I wanted but it seems to work better :-(
// We still need to update it case the word has changed, else it w
// We still need to update it case the word has changed, else it will keep the same word at each call
if (m_FrameProcessor == null || !requestWord.Equals(m_FrameProcessor.RequestWord))
{
var mediaFrameSourceFinder = new MediaFrameSourceFinder();
Expand Down Expand Up @@ -72,19 +68,24 @@ public static async Task ScanFirstCameraForWords(Action<List<ActiDetectedWord>>
// every frame that return something will bring us
// back in this loop. so we call the call back to display what we found.
// and we continue iterating until all time has run out.
await m_FrameProcessor.CreateMediaFastFrameReader();
while (!done)
{
// Get data from the frames
await m_FrameProcessor.ProcessFramesAsync(currentTimeout);
// See what result we got.
result = m_FrameProcessor.Result;
// Call back with whatever result we got.
resultCallback(result);
// If we timed out just leave.
done = (DateTime.Now - startTime) > timeout;
// Continue scanning with the time we have left
currentTimeout = (DateTime.Now - startTime);
await Task.Run(async () =>
{
// Get data from the frames
await m_FrameProcessor.ProcessFramesAsyncLoop(m_FrameProcessor.mediaFastFrameReader, currentTimeout, DateTime.Now);
// See what result we got.
// Call back with whatever result we got.
resultCallback(m_FrameProcessor.Result);
// If we timed out just leave.
done = (DateTime.Now - startTime) > timeout;
// Continue scanning with the time we have left
currentTimeout = (DateTime.Now - startTime);
});
}
// Dispose the frame reader
await m_FrameProcessor.DisposeMediaFastFrameReader();
}
}
}
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@ E:\Users\dolci\Documents\ESILV\PI² A5\Repos\Actimage-OCR-PISquare\FullScreen-Ve
E:\Users\dolci\Documents\ESILV\PI² A5\Repos\Actimage-OCR-PISquare\FullScreen-Version\MediaFrameQrProcessing\obj\Debug\qualifiers.txt
E:\Users\dolci\Documents\ESILV\PI² A5\Repos\Actimage-OCR-PISquare\FullScreen-Version\MediaFrameQrProcessing\obj\Debug\qualifiers.txt.intermediate
E:\Users\dolci\Documents\ESILV\PI² A5\Repos\Actimage-OCR-PISquare\FullScreen-Version\MediaFrameQrProcessing\obj\Debug\MultipleQualifiersPerDimensionFound.txt
E:\Users\dolci\Documents\ESILV\PI² A5\Repos\Actimage-OCR-PISquare\FullScreen-Version\MediaFrameQrProcessing\obj\Debug\MediaFrameQrProcessing.csprojResolveAssemblyReference.cache
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5688c3fa9c0491888d37226058446d90bf3ab0cd
1614477a5834299d972670cb71ea103bb9378a77
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1614477a5834299d972670cb71ea103bb9378a77
Loading

0 comments on commit 419574b

Please sign in to comment.