This ML.Net +You only look once V5(YoloV5) + RaspberryPI 4B project uploads raw camera and marked up (with searchable tags) images to Azure Storage.
My backyard test-rig consists of a Unv ADZK-10 Security Camera, Power over Ethernet(PoE) module, D-Link Switch and a Raspberry Pi 4B 8G.
{
...
"Application": {
"DeviceId": "edgecamera",
...
"PredicitionScoreThreshold": 0.7,
"PredictionLabelsOfInterest": [
"bicycle",
"person",
"car"
],
"OutputImageMarkup": true
},
...
"AzureStorage": {
"ConnectionString": "FhisIsNotTheConnectionStringYouAreLookingFor",
"ImageCameraFilenameFormat": "{0:yyyyMMdd}/camera/{0:HHmmss}.jpg",
"ImageMarkedUpFilenameFormat": "{0:yyyyMMdd}/markedup/{0:HHmmss}.jpg"
}
}
After the You Only Look Once(YOLOV5)+ML.Net+Open Neural Network Exchange(ONNX) plumbing has loaded a timer with a configurable due time and period is started.
private async void ImageUpdateTimerCallback(object state)
{
DateTime requestAtUtc = DateTime.UtcNow;
// Just incase - stop code being called while photo already in progress
if (_cameraBusy)
{
return;
}
_cameraBusy = true;
_logger.LogInformation("Image processing start");
try
{
#if CAMERA_RASPBERRY_PI
RaspberryPIImageCapture();
#endif
#if CAMERA_SECURITY
SecurityCameraImageCapture();
#endif
if (_applicationSettings.ImageCameraUpload)
{
_logger.LogTrace("Image camera upload start");
string imageFilenameCloud = string.Format(_azureStorageSettings.ImageCameraFilenameFormat, requestAtUtc);
await _imagecontainerClient.GetBlobClient(imageFilenameCloud).UploadAsync(_applicationSettings.ImageCameraFilepath, true);
_logger.LogTrace("Image camera upload done");
}
List<YoloPrediction> predictions;
using (Image image = Image.FromFile(_applicationSettings.ImageCameraFilepath))
{
_logger.LogTrace("Prediction start");
predictions = _scorer.Predict(image);
_logger.LogTrace("Prediction done");
OutputImageMarkup(image, predictions, _applicationSettings.ImageMarkedUpFilepath);
}
if (_logger.IsEnabled(LogLevel.Trace))
{
_logger.LogTrace("Predictions {0}", predictions.Select(p => new { p.Label.Name, p.Score }));
}
var predictionsOfInterest = predictions.Where(p => p.Score > _applicationSettings.PredicitionScoreThreshold).Select(c => c.Label.Name).Intersect(_applicationSettings.PredictionLabelsOfInterest, StringComparer.OrdinalIgnoreCase);
if (_logger.IsEnabled(LogLevel.Trace))
{
_logger.LogTrace("Predictions of interest {0}", predictionsOfInterest.ToList());
}
var predictionsTally = predictions.Where(p => p.Score >= _applicationSettings.PredicitionScoreThreshold)
.GroupBy(p => p.Label.Name)
.Select(p => new
{
Label = p.Key,
Count = p.Count()
});
if (_applicationSettings.ImageMarkedupUpload && predictionsOfInterest.Any())
{
_logger.LogTrace("Image marked-up upload start");
string imageFilenameCloud = string.Format(_azureStorageSettings.ImageMarkedUpFilenameFormat, requestAtUtc);
BlobUploadOptions blobUploadOptions = new BlobUploadOptions()
{
Tags = new Dictionary<string, string>()
};
foreach (var predicition in predictionsTally)
{
blobUploadOptions.Tags.Add(predicition.Label, predicition.Count.ToString());
}
BlobClient blobClient = _imagecontainerClient.GetBlobClient(imageFilenameCloud);
await blobClient.UploadAsync(_applicationSettings.ImageMarkedUpFilepath, blobUploadOptions);
_logger.LogTrace("Image marked-up upload done");
}
if (_logger.IsEnabled(LogLevel.Information))
{
_logger.LogInformation("Predictions tally {0}", predictionsTally.ToList());
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Camera image download, post procesing, image upload, or telemetry failed");
}
finally
{
_cameraBusy = false;
}
TimeSpan duration = DateTime.UtcNow - requestAtUtc;
_logger.LogInformation("Image processing done {0:f2} sec", duration.TotalSeconds);
}
A marked up image is uploaded to Azure Storage if any of the objects detected (with a score greater than PredicitionScoreThreshold) is in the PredictionLabelsOfInterest list.
I have added Tags to the images so they can be filtered with tools like Azure Storage Explorer.