From 910b0cd8c4aa52247c26b5891423b058938d14ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Myhre?= <71138449+gruble@users.noreply.github.com> Date: Thu, 2 Nov 2023 17:54:45 +0100 Subject: [PATCH 01/10] Utkast til sny service --- .../Models/ICustomVistionDecodeResult.cs | 22 ++++++++++ SnowProfileScanner/Program.cs | 1 + .../Services/SymbolRecognitionService.cs | 41 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 SnowProfileScanner/Models/ICustomVistionDecodeResult.cs create mode 100644 SnowProfileScanner/Services/SymbolRecognitionService.cs diff --git a/SnowProfileScanner/Models/ICustomVistionDecodeResult.cs b/SnowProfileScanner/Models/ICustomVistionDecodeResult.cs new file mode 100644 index 0000000..e5b589d --- /dev/null +++ b/SnowProfileScanner/Models/ICustomVistionDecodeResult.cs @@ -0,0 +1,22 @@ +namespace SnowProfileScanner.Models +{ + /** + * Resultat fra klassifisering av et symbol + */ + public interface ICustomVistionDecodeResult + { + string id { get; set; } + string project { get; set; } + string iteration { get; set; } + string created { get; set; } + IPrediction[] predictions { get; set; } + } + + public interface IPrediction + { + double Probability { get; set; } + string TagId { get; set; } + string TagName { get; set; } + } + +} diff --git a/SnowProfileScanner/Program.cs b/SnowProfileScanner/Program.cs index cd081ec..5c4eca2 100644 --- a/SnowProfileScanner/Program.cs +++ b/SnowProfileScanner/Program.cs @@ -10,6 +10,7 @@ builder.Services.AddRazorPages(); builder.Services.AddControllersWithViews(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddHttpClient(); var app = builder.Build(); diff --git a/SnowProfileScanner/Services/SymbolRecognitionService.cs b/SnowProfileScanner/Services/SymbolRecognitionService.cs new file mode 100644 index 0000000..059609c --- /dev/null +++ b/SnowProfileScanner/Services/SymbolRecognitionService.cs @@ -0,0 +1,41 @@ +using Newtonsoft.Json; +using SnowProfileScanner.Models; + +namespace SnowProfileScanner.Services +{ + public class SymbolRecognitionService + { + private string url, predictionKey; + private ILogger logger; + + public SymbolRecognitionService(IConfiguration configuration, ILogger logger) + { + url = configuration["CustomVisionUrl"]; + predictionKey = configuration["CustomVisionPredictionKey"]; + this.logger = logger; + } + + public async Task ClassifyImage(byte[] image) + { + using var client = new HttpClient(); + client.DefaultRequestHeaders.Add("Content-Type", "application/octet-stream"); + client.DefaultRequestHeaders.Add("Prediction-Key", predictionKey); + var body = new ByteArrayContent(image); + HttpResponseMessage response = await client.PostAsync(url, body); + if (response.StatusCode.Equals(200)) + { + var result = JsonConvert.DeserializeObject (response.Content.ToString()); + logger.LogDebug("ClassifyImage: Fikk OK" + response.StatusCode, result); + if (result.predictions.Length > 0) { + var prediction = result.predictions[0]; + return prediction.TagName; + } + return ":-|"; + } else + { + logger.LogError("ClassifyImage: Fikk HTTP-respons-kode: " + response.StatusCode); + return ":-("; + } + } + } +} From 99cf31c3a9138fe796b36e92b8e22018fc919da7 Mon Sep 17 00:00:00 2001 From: Erik Edin Date: Thu, 2 Nov 2023 17:55:41 +0100 Subject: [PATCH 02/10] Image extraction --- .gitignore | 5 ++ .../Controllers/UploadController.cs | 54 ++++++++++++++++--- SnowProfileScanner/SnowProfileScanner.csproj | 1 + 3 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ddecdb --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/CroppedImages diff --git a/SnowProfileScanner/Controllers/UploadController.cs b/SnowProfileScanner/Controllers/UploadController.cs index e775b05..2dc4d3f 100644 --- a/SnowProfileScanner/Controllers/UploadController.cs +++ b/SnowProfileScanner/Controllers/UploadController.cs @@ -9,6 +9,11 @@ using SnowProfileScanner.Services.Caaml; using System.Text; using System.Net; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Formats; +using System.IO; public class UploadController : Controller { @@ -67,10 +72,13 @@ public async Task Upload( AnalyzeResult result = operation.Value; var numberOfTables = result.Tables.Count(); + + Image image = Image.Load(memoryStream.ToArray()); + var snowProfile = new SnowProfile { SnowTemp = numberOfTables > 1 ? DecodeSnowTemperature(result.Tables[1]) : new(), - Layers = numberOfTables > 0 ? DecodeSnowProfile(result.Tables[0]) : new(), + Layers = numberOfTables > 0 ? DecodeSnowProfile(image, result.Tables[0]) : new(), AirTemp = numberOfTables > 1 ? DecodeAirTemperature(result.Tables[1]) : null, }; @@ -81,8 +89,26 @@ public async Task Upload( return View("Result", snowProfileEntity); } - - + + + private Image CropImageToBoundingBox(Image image, IReadOnlyList boundingBox) + { + var rectangle = ConvertBoundingBoxToRectangle(boundingBox); + return image.Clone(x => x.Crop(rectangle)); + } + + + private Rectangle ConvertBoundingBoxToRectangle(IReadOnlyList boundingBox) + { + + var topLeft = new Point((int)boundingBox[0].X, (int)boundingBox[0].Y); + var bottomRight = new Point((int)boundingBox[2].X, (int)boundingBox[2].Y); + var width = bottomRight.X - topLeft.X; + var height = bottomRight.Y - topLeft.Y; + return new Rectangle(topLeft.X, topLeft.Y, width, height); + } + + private List DecodeSnowTemperature(DocumentTable tbl1) { @@ -117,13 +143,19 @@ public async Task Upload( return temps; } - private static List DecodeSnowProfile(DocumentTable tbl1) + private List DecodeSnowProfile(Image image, DocumentTable tbl1) { var snowProfiles = new List(); var rowsCount = tbl1.Cells .Where(cell => cell.ColumnIndex == 0 && !string.IsNullOrWhiteSpace(cell.Content)) .Max(cell => cell.RowIndex); + + string imagesDirectory = Path.Combine("C:/NVE/Prosjektmappe/Regobs-ocr", "CroppedImages"); + if (!Directory.Exists(imagesDirectory)) + { + Directory.CreateDirectory(imagesDirectory); + } for (int rowIndex = 1; rowIndex <= rowsCount; rowIndex++) { var row = tbl1.Cells.Where(cell => cell.RowIndex == rowIndex); @@ -157,7 +189,8 @@ public async Task Upload( .OrderBy(vh => -vh.Length) .FirstOrDefault(); - var grainTypeText = ToString(row.SingleOrDefault(cell => cell.ColumnIndex == 3)) + var grainCell = row.SingleOrDefault(cell => cell.ColumnIndex == 3); + var grainTypeText = ToString(grainCell) .Replace("t", "f") .Replace("I", "l") .Replace("1", "l") @@ -172,6 +205,14 @@ public async Task Upload( .Where(vg => vg.Length <= grainTypeText.Length && vg.ToUpper() == grainTypeText[..vg.Length]) .OrderBy(vg => -vg.Length) .FirstOrDefault(); + if (grainTypeText == null || grainTypeText == string.Empty) + { + var polygon = grainCell.BoundingRegions[0].BoundingPolygon; + var croppedImage = CropImageToBoundingBox(image, polygon); + var filePath = Path.Combine(imagesDirectory, $"CroppedImage_Cell_{rowIndex}.png"); + croppedImage.Save(filePath); + } + var grainType = grainTypeText?.GetPrimaryGrainForm(); if (grainType?.Count() == 4) { @@ -182,7 +223,7 @@ public async Task Upload( { grainTypeSec = grainTypeSec.Substring(0, 2) + grainTypeSec.Substring(2).ToLower(); } - + var grainSizeText = row.SingleOrDefault(cell => cell.ColumnIndex == 4)?.Content ?? ""; var grainSizeSplit = grainSizeText.Split(new Char[] { '-', '–', '—', '_' }); @@ -192,6 +233,7 @@ public async Task Upload( { grainSizeMax = ToDouble(grainSizeSplit.Last()); } + var snowProfile = new SnowProfile.Layer { diff --git a/SnowProfileScanner/SnowProfileScanner.csproj b/SnowProfileScanner/SnowProfileScanner.csproj index 99ff26d..24e0a90 100644 --- a/SnowProfileScanner/SnowProfileScanner.csproj +++ b/SnowProfileScanner/SnowProfileScanner.csproj @@ -10,6 +10,7 @@ + From 80e54721b9ffb351b31d2318a6aea138b3b0affb Mon Sep 17 00:00:00 2001 From: Erik Edin Date: Thu, 2 Nov 2023 21:53:06 +0100 Subject: [PATCH 03/10] Progress --- .../Controllers/UploadController.cs | 21 ++++++++--- .../Services/SymbolRecognitionService.cs | 36 +++++++++---------- SnowProfileScanner/SnowProfileScanner.csproj | 1 + 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/SnowProfileScanner/Controllers/UploadController.cs b/SnowProfileScanner/Controllers/UploadController.cs index 2dc4d3f..a1de408 100644 --- a/SnowProfileScanner/Controllers/UploadController.cs +++ b/SnowProfileScanner/Controllers/UploadController.cs @@ -14,12 +14,15 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Formats; using System.IO; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Advanced; public class UploadController : Controller { private readonly IConfiguration _configuration; private readonly SnowProfileService _snowProfileService; + private readonly SymbolRecognitionService _symbolRecognitionService; private readonly HttpClient _httpClient; private const string RECAPTCHA_URL = "https://www.google.com/recaptcha/api/siteverify"; private static readonly HashSet VALID_LWC = ValidLwc(); @@ -31,11 +34,13 @@ public class UploadController : Controller public UploadController( IConfiguration configuration, SnowProfileService snowProfileService, - HttpClient httpClient + HttpClient httpClient, + SymbolRecognitionService symbolService ) { _httpClient = httpClient; _configuration = configuration; _snowProfileService = snowProfileService; + _symbolRecognitionService = symbolService; } public IActionResult Index() @@ -78,7 +83,7 @@ public async Task Upload( var snowProfile = new SnowProfile { SnowTemp = numberOfTables > 1 ? DecodeSnowTemperature(result.Tables[1]) : new(), - Layers = numberOfTables > 0 ? DecodeSnowProfile(image, result.Tables[0]) : new(), + Layers = numberOfTables > 0 ? await DecodeSnowProfile(image, result.Tables[0]) : new(), AirTemp = numberOfTables > 1 ? DecodeAirTemperature(result.Tables[1]) : null, }; @@ -143,7 +148,7 @@ private Rectangle ConvertBoundingBoxToRectangle(IReadOnlyList DecodeSnowProfile(Image image, DocumentTable tbl1) + private async Task> DecodeSnowProfile(Image image, DocumentTable tbl1) { var snowProfiles = new List(); var rowsCount = tbl1.Cells @@ -209,8 +214,14 @@ private Rectangle ConvertBoundingBoxToRectangle(IReadOnlyList logger) { url = configuration["CustomVisionUrl"]; predictionKey = configuration["CustomVisionPredictionKey"]; this.logger = logger; + predictionClient = AuthenticatePrediction(url, predictionKey); } - public async Task ClassifyImage(byte[] image) + public async Task ClassifyImage(Stream image) { - using var client = new HttpClient(); - client.DefaultRequestHeaders.Add("Content-Type", "application/octet-stream"); - client.DefaultRequestHeaders.Add("Prediction-Key", predictionKey); - var body = new ByteArrayContent(image); - HttpResponseMessage response = await client.PostAsync(url, body); - if (response.StatusCode.Equals(200)) - { - var result = JsonConvert.DeserializeObject (response.Content.ToString()); - logger.LogDebug("ClassifyImage: Fikk OK" + response.StatusCode, result); - if (result.predictions.Length > 0) { - var prediction = result.predictions[0]; - return prediction.TagName; - } - return ":-|"; - } else + var value = await predictionClient.DetectImageAsync(new Guid("e05d2a8c-6fd0-4c44-820b-e9aa43785aae"), "Regobs-Image-Recognition", image); + return value.Predictions[0].TagName; + } + private static CustomVisionPredictionClient AuthenticatePrediction(string endpoint, string predictionKey) + { + // Create a prediction endpoint, passing in the obtained prediction key + CustomVisionPredictionClient predictionApi = new CustomVisionPredictionClient(new Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction.ApiKeyServiceClientCredentials(predictionKey)) { - logger.LogError("ClassifyImage: Fikk HTTP-respons-kode: " + response.StatusCode); - return ":-("; - } + Endpoint = endpoint + }; + return predictionApi; } } } diff --git a/SnowProfileScanner/SnowProfileScanner.csproj b/SnowProfileScanner/SnowProfileScanner.csproj index 24e0a90..1dcf930 100644 --- a/SnowProfileScanner/SnowProfileScanner.csproj +++ b/SnowProfileScanner/SnowProfileScanner.csproj @@ -10,6 +10,7 @@ + From 262305d87a85088f838a26be220f2e5c8a232d15 Mon Sep 17 00:00:00 2001 From: Erik Edin Date: Thu, 2 Nov 2023 22:43:11 +0100 Subject: [PATCH 04/10] Works!! --- SnowProfileScanner/Controllers/UploadController.cs | 9 ++++----- SnowProfileScanner/Services/SymbolRecognitionService.cs | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/SnowProfileScanner/Controllers/UploadController.cs b/SnowProfileScanner/Controllers/UploadController.cs index a1de408..a1783ae 100644 --- a/SnowProfileScanner/Controllers/UploadController.cs +++ b/SnowProfileScanner/Controllers/UploadController.cs @@ -16,6 +16,7 @@ using System.IO; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; +using Microsoft.AspNetCore.WebUtilities; public class UploadController : Controller { @@ -214,11 +215,9 @@ private Rectangle ConvertBoundingBoxToRectangle(IReadOnlyList ClassifyImage(Stream image) + public async Task ClassifyImage(MemoryStream image) { - var value = await predictionClient.DetectImageAsync(new Guid("e05d2a8c-6fd0-4c44-820b-e9aa43785aae"), "Regobs-Image-Recognition", image); + var value = await predictionClient.ClassifyImageAsync(Guid.Parse("e05d2a8c-6fd0-4c44-820b-e9aa43785aae"), "Iteration2", image); return value.Predictions[0].TagName; } private static CustomVisionPredictionClient AuthenticatePrediction(string endpoint, string predictionKey) From 275b55874a09fe1573229fd8141dcbda1db5f55b Mon Sep 17 00:00:00 2001 From: Erik Edin Date: Fri, 3 Nov 2023 15:17:46 +0100 Subject: [PATCH 05/10] Adjustment --- .../Services/SymbolRecognitionService.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/SnowProfileScanner/Services/SymbolRecognitionService.cs b/SnowProfileScanner/Services/SymbolRecognitionService.cs index 0d7d54c..8548c7b 100644 --- a/SnowProfileScanner/Services/SymbolRecognitionService.cs +++ b/SnowProfileScanner/Services/SymbolRecognitionService.cs @@ -7,7 +7,7 @@ namespace SnowProfileScanner.Services { public class SymbolRecognitionService { - private string url, predictionKey; + private string url, predictionKey, projectId; private ILogger logger; private CustomVisionPredictionClient predictionClient; @@ -15,14 +15,28 @@ public SymbolRecognitionService(IConfiguration configuration, ILogger ClassifyImage(MemoryStream image) { - var value = await predictionClient.ClassifyImageAsync(Guid.Parse("e05d2a8c-6fd0-4c44-820b-e9aa43785aae"), "Iteration2", image); - return value.Predictions[0].TagName; + var value = await predictionClient.ClassifyImageAsync(Guid.Parse(projectId), "Iteration2", image); + if (value.Predictions[0].Probability > 0.30) + { + if(value.Predictions[0].TagName == "MDcr") + { + return "MFcr"; + } + return value.Predictions[0].TagName; + } + else + { + return null; + } + } private static CustomVisionPredictionClient AuthenticatePrediction(string endpoint, string predictionKey) { From ada205d197d363e647fc712ebd1ef2b4d609eab6 Mon Sep 17 00:00:00 2001 From: Erik Edin Date: Fri, 3 Nov 2023 15:30:49 +0100 Subject: [PATCH 06/10] Removed local folder path:) --- SnowProfileScanner/Controllers/UploadController.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/SnowProfileScanner/Controllers/UploadController.cs b/SnowProfileScanner/Controllers/UploadController.cs index a1783ae..7d200a5 100644 --- a/SnowProfileScanner/Controllers/UploadController.cs +++ b/SnowProfileScanner/Controllers/UploadController.cs @@ -155,13 +155,7 @@ private Rectangle ConvertBoundingBoxToRectangle(IReadOnlyList cell.ColumnIndex == 0 && !string.IsNullOrWhiteSpace(cell.Content)) .Max(cell => cell.RowIndex); - - string imagesDirectory = Path.Combine("C:/NVE/Prosjektmappe/Regobs-ocr", "CroppedImages"); - if (!Directory.Exists(imagesDirectory)) - { - Directory.CreateDirectory(imagesDirectory); - } for (int rowIndex = 1; rowIndex <= rowsCount; rowIndex++) { var row = tbl1.Cells.Where(cell => cell.RowIndex == rowIndex); @@ -219,8 +213,6 @@ private Rectangle ConvertBoundingBoxToRectangle(IReadOnlyList Date: Fri, 3 Nov 2023 16:35:37 +0100 Subject: [PATCH 07/10] Fixed orientation problem --- SnowProfileScanner/Controllers/UploadController.cs | 1 + SnowProfileScanner/Services/SymbolRecognitionService.cs | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/SnowProfileScanner/Controllers/UploadController.cs b/SnowProfileScanner/Controllers/UploadController.cs index 7d200a5..b3cea44 100644 --- a/SnowProfileScanner/Controllers/UploadController.cs +++ b/SnowProfileScanner/Controllers/UploadController.cs @@ -99,6 +99,7 @@ public async Task Upload( private Image CropImageToBoundingBox(Image image, IReadOnlyList boundingBox) { + image.Mutate(x => x.AutoOrient()); var rectangle = ConvertBoundingBoxToRectangle(boundingBox); return image.Clone(x => x.Crop(rectangle)); } diff --git a/SnowProfileScanner/Services/SymbolRecognitionService.cs b/SnowProfileScanner/Services/SymbolRecognitionService.cs index 8548c7b..8150d96 100644 --- a/SnowProfileScanner/Services/SymbolRecognitionService.cs +++ b/SnowProfileScanner/Services/SymbolRecognitionService.cs @@ -23,13 +23,9 @@ public SymbolRecognitionService(IConfiguration configuration, ILogger ClassifyImage(MemoryStream image) { - var value = await predictionClient.ClassifyImageAsync(Guid.Parse(projectId), "Iteration2", image); + var value = await predictionClient.ClassifyImageAsync(Guid.Parse(projectId), "Iteration3", image); if (value.Predictions[0].Probability > 0.30) { - if(value.Predictions[0].TagName == "MDcr") - { - return "MFcr"; - } return value.Predictions[0].TagName; } else From e9a4d4265652e48ea6902ca809254073988e9e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Myhre?= <71138449+gruble@users.noreply.github.com> Date: Fri, 3 Nov 2023 22:39:08 +0100 Subject: [PATCH 08/10] =?UTF-8?q?Ny=20modellkj=C3=B8ring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SnowProfileScanner/Pages/Shared/Result.cshtml | 2 +- SnowProfileScanner/Services/SymbolRecognitionService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SnowProfileScanner/Pages/Shared/Result.cshtml b/SnowProfileScanner/Pages/Shared/Result.cshtml index 60efb20..6dd4e5a 100644 --- a/SnowProfileScanner/Pages/Shared/Result.cshtml +++ b/SnowProfileScanner/Pages/Shared/Result.cshtml @@ -70,7 +70,7 @@ } else { -

Ingen snø temperaturer funnet.

+

Fant ingen temperaturprofil

} Bilde tatt av brukeren diff --git a/SnowProfileScanner/Services/SymbolRecognitionService.cs b/SnowProfileScanner/Services/SymbolRecognitionService.cs index 8150d96..c870ada 100644 --- a/SnowProfileScanner/Services/SymbolRecognitionService.cs +++ b/SnowProfileScanner/Services/SymbolRecognitionService.cs @@ -23,7 +23,7 @@ public SymbolRecognitionService(IConfiguration configuration, ILogger ClassifyImage(MemoryStream image) { - var value = await predictionClient.ClassifyImageAsync(Guid.Parse(projectId), "Iteration3", image); + var value = await predictionClient.ClassifyImageAsync(Guid.Parse(projectId), "Iteration5", image); if (value.Predictions[0].Probability > 0.30) { return value.Predictions[0].TagName; From 5e62efd1f43ad7f5b06a1a95680967f165fb24f4 Mon Sep 17 00:00:00 2001 From: Erik Edin Date: Thu, 9 Nov 2023 12:21:18 +0100 Subject: [PATCH 09/10] Earlier auto rotation --- SnowProfileScanner/Controllers/UploadController.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SnowProfileScanner/Controllers/UploadController.cs b/SnowProfileScanner/Controllers/UploadController.cs index b3cea44..1628dbd 100644 --- a/SnowProfileScanner/Controllers/UploadController.cs +++ b/SnowProfileScanner/Controllers/UploadController.cs @@ -80,7 +80,7 @@ public async Task Upload( var numberOfTables = result.Tables.Count(); Image image = Image.Load(memoryStream.ToArray()); - + image.Mutate(x => x.AutoOrient()); var snowProfile = new SnowProfile { SnowTemp = numberOfTables > 1 ? DecodeSnowTemperature(result.Tables[1]) : new(), @@ -99,7 +99,6 @@ public async Task Upload( private Image CropImageToBoundingBox(Image image, IReadOnlyList boundingBox) { - image.Mutate(x => x.AutoOrient()); var rectangle = ConvertBoundingBoxToRectangle(boundingBox); return image.Clone(x => x.Crop(rectangle)); } From 3ab677f67dcecb1359580d3026249394a6bf69f6 Mon Sep 17 00:00:00 2001 From: Erik Edin Date: Tue, 13 Feb 2024 16:33:59 +0100 Subject: [PATCH 10/10] Lagt til Arons endringer --- .../Controllers/UploadController.cs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/SnowProfileScanner/Controllers/UploadController.cs b/SnowProfileScanner/Controllers/UploadController.cs index 1628dbd..4901931 100644 --- a/SnowProfileScanner/Controllers/UploadController.cs +++ b/SnowProfileScanner/Controllers/UploadController.cs @@ -95,28 +95,29 @@ public async Task Upload( return View("Result", snowProfileEntity); } - - private Image CropImageToBoundingBox(Image image, IReadOnlyList boundingBox) - { - var rectangle = ConvertBoundingBoxToRectangle(boundingBox); - return image.Clone(x => x.Crop(rectangle)); - } + private Image CropImageToBoundingBox(Image image, IReadOnlyList boundingBox) + { + image.Mutate(x => x.AutoOrient()); + var rectangle = ConvertBoundingBoxToRectangle(boundingBox); + return image.Clone(x => x.Crop(rectangle)); + } - private Rectangle ConvertBoundingBoxToRectangle(IReadOnlyList boundingBox) - { - var topLeft = new Point((int)boundingBox[0].X, (int)boundingBox[0].Y); - var bottomRight = new Point((int)boundingBox[2].X, (int)boundingBox[2].Y); - var width = bottomRight.X - topLeft.X; - var height = bottomRight.Y - topLeft.Y; - return new Rectangle(topLeft.X, topLeft.Y, width, height); - } + private Rectangle ConvertBoundingBoxToRectangle(IReadOnlyList boundingBox) + { + + var topLeft = new Point((int)boundingBox.Select(p => p.X).Min(), (int)boundingBox.Select(p => p.Y).Min()); + var bottomRight = new Point((int)boundingBox.Select(p => p.X).Max(), (int)boundingBox.Select(p => p.Y).Max()); + var width = bottomRight.X - topLeft.X; + var height = bottomRight.Y - topLeft.Y; + return new Rectangle(topLeft.X, topLeft.Y, width, height); + } - private List DecodeSnowTemperature(DocumentTable tbl1) + private List DecodeSnowTemperature(DocumentTable tbl1) { var rows = tbl1.Cells .Where(cell => cell.RowIndex > 1 && !string.IsNullOrWhiteSpace(cell.Content))