using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Drawing; using System.IO; using System.Text.Json; using System.Windows.Forms; namespace Test_Merge { internal class OCRDecoder { private string _configFile; private string _imagesFolder; private List _drivers; private List _mainZones; private Bitmap FullImage; public string ConfigFile { get => _configFile; private set => _configFile = value; } public string ImagesFolder { get => _imagesFolder; private set => _imagesFolder = value; } public List Drivers { get => _drivers; private set => _drivers = value; } public List MainZones { get => _mainZones; set => _mainZones = value; } //All the image infos will be deleted in not too much time when the merge with the program that recovers the images const string DEFAULT_IMAGE_NAME = "screen_"; // You will defenitely have to change this if you want to be able to see debug images public const string DEBUG_DUMP_FOLDER = @"C:\Users\Moi\Desktop\imgDump\Decode\"; const int NUMBER_OF_DRIVERS = 20; public OCRDecoder(string configFile, string imageFolder) { ConfigFile = configFile; ImagesFolder = imageFolder; Load(82); } /// /// Method that reads the JSON config file and create all the Zones and Windows /// /// The image #id on wich you want to create the zones on private void Load(int imageNumber) { MainZones = new List(); try { FullImage = (Bitmap)Image.FromFile(ImagesFolder + DEFAULT_IMAGE_NAME + imageNumber + ".png"); } catch { MessageBox.Show("Trouble reaching the image"); //Maybe a bit to harsh, Ill see what I can do to soft this a bit Application.Exit(); } Zone MainZone; try { using (var streamReader = new StreamReader(ConfigFile)) { var jsonText = streamReader.ReadToEnd(); var jsonDocument = JsonDocument.Parse(jsonText); var driversNames = jsonDocument.RootElement.GetProperty("Drivers"); Drivers = new List(); foreach (var nameElement in driversNames.EnumerateArray()) { Drivers.Add(nameElement.GetString()); } var mainProperty = jsonDocument.RootElement.GetProperty("Main"); Point MainPosition = new Point(mainProperty.GetProperty("x").GetInt32(), mainProperty.GetProperty("y").GetInt32()); Size MainSize = new Size(mainProperty.GetProperty("width").GetInt32(), mainProperty.GetProperty("height").GetInt32()); Rectangle MainRectangle = new Rectangle(MainPosition, MainSize); MainZone = new Zone(FullImage, MainRectangle); var zones = mainProperty.GetProperty("Zones"); var driverZone = zones[0].GetProperty("DriverZone"); Point FirstZonePosition = new Point(driverZone.GetProperty("x").GetInt32(), driverZone.GetProperty("y").GetInt32()); Size FirstZoneSize = new Size(driverZone.GetProperty("width").GetInt32(), driverZone.GetProperty("height").GetInt32()); var windows = driverZone.GetProperty("Windows"); //var driverPosition = windows.GetProperty("Position"); var driverPosition = windows[0].GetProperty("Position"); Size driverPositionArea = new Size(driverPosition.GetProperty("width").GetInt32(), FirstZoneSize.Height); Point driverPositionPosition = new Point(driverPosition.GetProperty("x").GetInt32(), driverPosition.GetProperty("y").GetInt32()); var driverGapToLeader = windows[0].GetProperty("GapToLeader"); Size driverGapToLeaderArea = new Size(driverGapToLeader.GetProperty("width").GetInt32(), FirstZoneSize.Height); Point driverGapToLeaderPosition = new Point(driverGapToLeader.GetProperty("x").GetInt32(), driverGapToLeader.GetProperty("y").GetInt32()); var driverLapTime = windows[0].GetProperty("LapTime"); Size driverLapTimeArea = new Size(driverLapTime.GetProperty("width").GetInt32(), FirstZoneSize.Height); Point driverLapTimePosition = new Point(driverLapTime.GetProperty("x").GetInt32(), driverLapTime.GetProperty("y").GetInt32()); var driverDrs = windows[0].GetProperty("Drs"); Size driverDrsArea = new Size(driverDrs.GetProperty("width").GetInt32(), FirstZoneSize.Height); Point driverDrsPosition = new Point(driverDrs.GetProperty("x").GetInt32(), driverDrs.GetProperty("y").GetInt32()); var driverTyres = windows[0].GetProperty("Tyres"); Size driverTyresArea = new Size(driverTyres.GetProperty("width").GetInt32(), FirstZoneSize.Height); Point driverTyresPosition = new Point(driverTyres.GetProperty("x").GetInt32(), driverTyres.GetProperty("y").GetInt32()); var driverName = windows[0].GetProperty("Name"); Size driverNameArea = new Size(driverName.GetProperty("width").GetInt32(), FirstZoneSize.Height); Point driverNamePosition = new Point(driverName.GetProperty("x").GetInt32(), driverName.GetProperty("y").GetInt32()); var driverSector1 = windows[0].GetProperty("Sector1"); Size driverSector1Area = new Size(driverSector1.GetProperty("width").GetInt32(), FirstZoneSize.Height); Point driverSector1Position = new Point(driverSector1.GetProperty("x").GetInt32(), driverSector1.GetProperty("y").GetInt32()); var driverSector2 = windows[0].GetProperty("Sector2"); Size driverSector2Area = new Size(driverSector2.GetProperty("width").GetInt32(), FirstZoneSize.Height); Point driverSector2Position = new Point(driverSector2.GetProperty("x").GetInt32(), driverSector2.GetProperty("y").GetInt32()); var driverSector3 = windows[0].GetProperty("Sector3"); Size driverSector3Area = new Size(driverSector3.GetProperty("width").GetInt32(), FirstZoneSize.Height); Point driverSector3Position = new Point(driverSector3.GetProperty("x").GetInt32(), driverSector3.GetProperty("y").GetInt32()); float offset = (((float)MainZone.ZoneImage.Height - (float)(Drivers.Count * FirstZoneSize.Height)) / (float)Drivers.Count); Bitmap MainZoneImage = MainZone.ZoneImage; List zonesToAdd = new List(); List zonesImages = new List(); for (int i = 0; i < NUMBER_OF_DRIVERS; i++) { Point tmpPos = new Point(0, FirstZonePosition.Y + i * FirstZoneSize.Height - Convert.ToInt32(i * offset)); Zone newDriverZone = new Zone(MainZoneImage, new Rectangle(tmpPos, FirstZoneSize)); zonesToAdd.Add(newDriverZone); zonesImages.Add(newDriverZone.ZoneImage); } //Parallel.For(0, NUMBER_OF_DRIVERS, i => for (int i = 0; i < NUMBER_OF_DRIVERS; i++) { Zone newDriverZone = zonesToAdd[(int)i]; Bitmap zoneImg = zonesImages[(int)i]; newDriverZone.AddWindow(new DriverPositionWindow(zoneImg, new Rectangle(driverPositionPosition, driverPositionArea))); newDriverZone.AddWindow(new DriverGapToLeaderWindow(zoneImg, new Rectangle(driverGapToLeaderPosition, driverGapToLeaderArea))); newDriverZone.AddWindow(new DriverLapTimeWindow(zoneImg, new Rectangle(driverLapTimePosition, driverLapTimeArea))); newDriverZone.AddWindow(new DriverDrsWindow(zoneImg, new Rectangle(driverDrsPosition, driverDrsArea))); newDriverZone.AddWindow(new DriverTyresWindow(zoneImg, new Rectangle(driverTyresPosition, driverTyresArea))); newDriverZone.AddWindow(new DriverNameWindow(zoneImg, new Rectangle(driverNamePosition, driverNameArea))); newDriverZone.AddWindow(new DriverSectorWindow(zoneImg, new Rectangle(driverSector1Position, driverSector1Area))); newDriverZone.AddWindow(new DriverSectorWindow(zoneImg, new Rectangle(driverSector2Position, driverSector2Area))); newDriverZone.AddWindow(new DriverSectorWindow(zoneImg, new Rectangle(driverSector3Position, driverSector3Area))); MainZone.AddZone(newDriverZone); }//); //MessageBox.Show("We have a main zone with " + MainZone.Zones.Count() + " Driver zones with " + MainZone.Zones[4].Windows.Count() + " windows each and we have " + Drivers.Count + " drivers"); MainZones.Add(MainZone); } } catch (IOException ex) { MessageBox.Show("Error reading JSON file: " + ex.Message); } catch (JsonException ex) { MessageBox.Show("Invalid JSON format: " + ex.Message); } } /// /// Changes the zones and windows to the new image /// /// The #id of the new image on wich to do OCR public void ChangeImage(int imageNumber) { Bitmap img = null; string imagePath = ImagesFolder + DEFAULT_IMAGE_NAME + imageNumber + ".png"; try { img = (Bitmap)Image.FromFile(imagePath); } catch { MessageBox.Show("Unable to reach the image at " + imagePath); } if (img != null) { FullImage = img; foreach (Zone z in MainZones) { z.Image = img; } } } /// /// Method that calls all the zones and windows to get the content they can find on the image to display them /// /// The id of the image we are working with /// a string representation of all the returns public async Task Decode(int idImage) { string result = ""; ChangeImage(idImage); List mainResults = new List(); //Decode for (int mainZoneId = 0; mainZoneId < MainZones.Count; mainZoneId++) { switch (mainZoneId) { case 0: //Main Zone foreach (Zone z in MainZones[mainZoneId].Zones) { mainResults.Add(await z.Decode(Drivers)); } break; //Next there could be a Title Zone and TrackInfoZone } } //Display foreach (DriverData driver in mainResults) { result += driver.ToString(); result += Environment.NewLine; } return result; } /// /// Method that can be used to convert an amount of miliseconds into a more readable human form /// /// The given amount of miliseconds ton convert /// A human readable string that represents the ms public static string ConvertMsToTime(int amountOfMs) { //Convert.ToInt32 would round upand I dont want that int minuts = (int)((float)amountOfMs / (1000f * 60f)); int seconds = (int)((amountOfMs - (minuts * 60f * 1000f)) / 1000); int ms = amountOfMs - ((minuts * 60 * 1000) + (seconds * 1000)); return minuts + ":" + seconds.ToString("00") + ":" + ms.ToString("000"); } /// /// Old method that can draw on an image where the windows and zones are created. mostly used for debugging /// /// the #id of the image we are working with /// the drawed bitmap public Bitmap Draw(int idImage) { Bitmap result; try { result = (Bitmap)Image.FromFile(ImagesFolder + DEFAULT_IMAGE_NAME + idImage + ".png"); } catch { MessageBox.Show("Image could not be found"); return null; } Graphics g = Graphics.FromImage(result); foreach (Zone z in MainZones) { int count = 0; foreach (Zone zz in z.Zones) { g.DrawRectangle(Pens.Red, z.Bounds); foreach (Window w in zz.Windows) { g.DrawRectangle(Pens.Blue, new Rectangle(z.Bounds.X + zz.Bounds.X, z.Bounds.Y + zz.Bounds.Y, zz.Bounds.Width, zz.Bounds.Height)); } count++; } } return result; } } }