public bool IsDinoInventoryVisible() { if (_screenCaptureProcess == null) { _screenCaptureProcess = Process.GetProcessesByName(screenCaptureApplicationName).FirstOrDefault(); if (_screenCaptureProcess == null) { return(false); } } if (Win32API.GetForegroundWindow() != _screenCaptureProcess.MainWindowHandle) { return(false); } Bitmap screenshotBmp = Win32API.GetScreenshotOfProcess(screenCaptureApplicationName, waitBeforeScreenCapture); if (screenshotBmp == null || !CheckResolutionSupportedByOcr(screenshotBmp)) { return(false); } const OcrTemplate.OcrLabels label = OcrTemplate.OcrLabels.Level; Rectangle rec = ocrConfig.labelRectangles[(int)label]; Bitmap bmp = SubImage(screenshotBmp, rec.X, rec.Y, rec.Width, rec.Height); string statOCR = PatternOcr.ReadImageOcr(bmp, true, Properties.Settings.Default.OCRWhiteThreshold); return(Regex.IsMatch(statOCR, @":\d+$")); }
// todo not used, remove? //private static Rectangle letterRect(Bitmap source, int hStart, int hEnd) //{ // int startWhite = -1, endWhite = -1; // for (int j = 0; j < source.Height; j++) // { // for (int i = hStart; i < hEnd; i++) // { // if (startWhite == -1 && source.GetPixel(i, j).R == 255) // { // startWhite = j; // } // if (endWhite == -1 && source.GetPixel(i, (source.Height - j) - 1).R == 255) // { // endWhite = (source.Height - j); // } // if (startWhite != -1 && endWhite != -1) // return new Rectangle(hStart, startWhite, hEnd - hStart, endWhite - startWhite); // } // } // return Rectangle.Empty; //} public double[] DoOcr(out string OCRText, out string dinoName, out string species, out string ownerName, out string tribeName, out Sex sex, string useImageFilePath = "", bool changeForegroundWindow = true) { string finishedText = string.Empty; dinoName = string.Empty; species = string.Empty; ownerName = string.Empty; tribeName = string.Empty; sex = Sex.Unknown; double[] finalValues = new double[1] { 0 }; if (ocrConfig == null) { OCRText = "Error: no ocr configured"; return(finalValues); } Bitmap screenshotbmp; _ocrControl.debugPanel.Controls.Clear(); _ocrControl.ClearLists(); if (System.IO.File.Exists(useImageFilePath)) { screenshotbmp = (Bitmap)Image.FromFile(useImageFilePath); } else { // grab screenshot from ark screenshotbmp = Win32API.GetScreenshotOfProcess(screenCaptureApplicationName, waitBeforeScreenCapture, true); } if (screenshotbmp == null) { OCRText = "Error: no image for OCR. Is ARK running?"; return(finalValues); } if (!CheckResolutionSupportedByOcr(screenshotbmp)) { OCRText = "Error while calibrating: The game-resolution is not supported by the currently loaded OCR-configuration.\n" + $"The tested image has a resolution of {screenshotbmp.Width} × {screenshotbmp.Height} px,\n" + $"the resolution of the loaded ocr-config is {ocrConfig.resolutionWidth} × {ocrConfig.resolutionHeight} px.\n\n" + "Load a ocr-config file with the resolution of the game to make it work."; return(finalValues); } // TODO resize image according to resize-factor. used for large screenshots if (ocrConfig.resize != 1 && ocrConfig.resize > 0) { Bitmap resized = new Bitmap((int)(ocrConfig.resize * ocrConfig.resolutionWidth), (int)(ocrConfig.resize * ocrConfig.resolutionHeight)); using (var graphics = Graphics.FromImage(resized)) { graphics.CompositingMode = CompositingMode.SourceCopy; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; using (var wrapMode = new ImageAttributes()) { wrapMode.SetWrapMode(WrapMode.TileFlipXY); graphics.DrawImage(screenshotbmp, new Rectangle(0, 0, 1920, 1080), 0, 0, screenshotbmp.Width, screenshotbmp.Height, GraphicsUnit.Pixel, wrapMode); } screenshotbmp?.Dispose(); screenshotbmp = resized; } } if (enableOutput && _ocrControl != null) { _ocrControl.DisplayBmpInOcrControl(screenshotbmp); } finalValues = new double[ocrConfig.labelRectangles.Length]; finalValues[8] = -1; // set imprinting to -1 to mark it as unknown and to set a difference to a creature with 0% imprinting. if (changeForegroundWindow) { Win32API.SetForegroundWindow(Application.OpenForms[0].Handle); } bool wild = false; // todo: set to true and find out if the creature is wild in the first loop int stI = -1; for (int lbI = 0; lbI < ocrConfig.labelNames.Count; lbI++) { stI++; if (lbI == 8) { stI = 8; } string statName = ocrConfig.labelNames[stI]; switch (statName) { case "NameSpecies": if (ocrConfig.RecognitionPatterns.TrainingSettings.SkipName) { dinoName = string.Empty; continue; } break; case "Tribe": if (ocrConfig.RecognitionPatterns.TrainingSettings.SkipTribe) { tribeName = string.Empty; continue; } break; case "Owner": if (ocrConfig.RecognitionPatterns.TrainingSettings.SkipOwner) { ownerName = string.Empty; continue; } break; } Rectangle rec = ocrConfig.labelRectangles[lbI]; // wild creatures don't have the xp-bar, all stats are moved one row up if (wild && stI < 9) { rec.Offset(0, ocrConfig.labelRectangles[0].Top - ocrConfig.labelRectangles[1].Top); } Bitmap testbmp = SubImage(screenshotbmp, rec.X, rec.Y, rec.Width, rec.Height); //AddBitmapToDebug(testbmp); string statOcr; try { if (statName == "NameSpecies") { statOcr = PatternOcr.ReadImageOcr(testbmp, false, 0.85f, _ocrControl); } else if (statName == "Level") { statOcr = PatternOcr.ReadImageOcr(testbmp, true, 1.1f, _ocrControl).Replace(".", ": "); } else if (statName == "Tribe" || statName == "Owner") { statOcr = PatternOcr.ReadImageOcr(testbmp, false, 0.8f, _ocrControl); } else { statOcr = PatternOcr.ReadImageOcr(testbmp, true, ocrControl: _ocrControl).Trim('.'); // statValues are only numbers } } catch (OperationCanceledException) { OCRText = "Canceled"; return(finalValues); } if (statOcr == string.Empty && (statName == "Health" || statName == "Imprinting" || statName == "Tribe" || statName == "Owner")) { if (wild && statName == "Health") { stI--; wild = false; } continue; // these can be missing, it's fine } finishedText += (finishedText.Length == 0 ? string.Empty : "\r\n") + statName + ":\t" + statOcr; // parse the OCR String var r = new Regex(@"^[_\/\\]*(.*?)[_\/\\]*$"); statOcr = r.Replace(statOcr, "$1"); if (statName == "NameSpecies") { r = new Regex(@".*?([♂♀])?[_.,-\/\\]*([^♂♀]+?)(?:[\(\[]([^\[\(\]\)]+)[\)\]]$|$)"); } else if (statName == "Owner" || statName == "Tribe") { r = new Regex(@"(.*)"); } else if (statName == "Level") { r = new Regex(@".*\D(\d+)"); } else { r = new Regex(@"(?:[\d.,%\/]*\/)?(\d+[\.,']?\d?)(%)?\.?"); // only the second numbers is interesting after the current weight is not shown anymore //if (onlyNumbers) //r = new Regex(@"((\d*[\.,']?\d?\d?)\/)?(\d*[\.,']?\d?\d?)"); //else // r = new Regex(@"([a-zA-Z]*)[:;]((\d*[\.,']?\d?\d?)\/)?(\d*[\.,']?\d?\d?)"); } MatchCollection mc = r.Matches(statOcr); if (mc.Count == 0) { if (statName == "NameSpecies" || statName == "Owner" || statName == "Tribe") { continue; } //if (statName == "Torpor") //{ // // probably it's a wild creature // // todo //} //else //{ finishedText += "error reading stat " + statName; finalValues[stI] = 0; continue; //} } if (statName == "NameSpecies" || statName == "Owner" || statName == "Tribe") { if (statName == "NameSpecies" && mc[0].Groups.Count > 0) { if (mc[0].Groups[1].Value == "♀") { sex = Sex.Female; } else if (mc[0].Groups[1].Value == "♂") { sex = Sex.Male; } dinoName = mc[0].Groups[2].Value; species = mc[0].Groups[3].Value; if (species.Length == 0) { species = dinoName; } // remove non-letter chars r = new Regex("[^a-zA-Z]"); species = r.Replace(species, string.Empty); // replace capital I with lower l (common misrecognition) r = new Regex("(?<=[a-z])I(?=[a-z])"); species = r.Replace(species, "l"); // readd spaces before capital letters r = new Regex("(?<=[a-z])(?=[A-Z])"); species = r.Replace(species, " "); finishedText += "\t→ " + sex.ToString() + ", " + species; } else if (statName == "Owner" && mc[0].Groups.Count > 0) { ownerName = mc[0].Groups[0].Value; finishedText += "\t→ " + ownerName; } else if (statName == "Tribe" && mc[0].Groups.Count > 0) { tribeName = mc[0].Groups[0].Value.Replace("Tobe", "Tribe").Replace("Tdbe", "Tribe").Replace("Tribeof", "Tribe of "); finishedText += "\t→ " + tribeName; } continue; } if (mc[0].Groups.Count > 2 && mc[0].Groups[2].Value == "%" && statName == "Weight") { // first stat with a '%' is damage, if oxygen is missing, shift all stats by one finalValues[4] = finalValues[3]; // shift food to weight finalValues[3] = finalValues[2]; // shift oxygen to food finalValues[2] = 0; // set oxygen (which wasn't there) to 0 stI++; } var splitRes = statOcr.Split('/', ',', ':'); var ocrValue = splitRes[splitRes.Length - 1] == "%" ? splitRes[splitRes.Length - 2] : splitRes[splitRes.Length - 1]; ocrValue = PatternOcr.RemoveNonNumeric(ocrValue); double.TryParse(ocrValue, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.GetCultureInfo("en-US"), out double v); // common substitutions: comma and apostrophe to dot, if (statName == "MeleeDamage" && v > 1000) { v = v / 10; } finishedText += $"\t→ {v}"; // TODO: test here that the read stat name corresponds to the stat supposed to be read finalValues[stI] = v; } OCRText = finishedText; // TODO reorder stats to match 12-stats-order return(finalValues); /* * Bitmap grab = Win32Stuff.GetSreenshotOfProcess(screenCaptureApplicationName); * AddBitmapToDebug(grab); * * //grab.Save("E:\\Temp\\Calibration8.png", ImageFormat.Png); * if (changeForegroundWindow) * Win32Stuff.SetForegroundWindow(Application.OpenForms[0].Handle); */ }
public double[] DoOcr(out string OcrText, out string dinoName, out string species, out string ownerName, out string tribeName, out Sex sex, string useImageFilePath = "", bool changeForegroundWindow = true) { string finishedText = string.Empty; dinoName = string.Empty; species = string.Empty; ownerName = string.Empty; tribeName = string.Empty; sex = Sex.Unknown; double[] finalValues = { 0 }; if (ocrConfig == null) { OcrText = "Error: OCR not configured"; return(finalValues); } Bitmap screenShotBmp; _ocrControl.debugPanel.Controls.Clear(); _ocrControl.ClearLists(); if (File.Exists(useImageFilePath)) { screenShotBmp = (Bitmap)Image.FromFile(useImageFilePath); } else { // grab screen shot from ark screenShotBmp = Win32API.GetScreenshotOfProcess(screenCaptureApplicationName, waitBeforeScreenCapture, true); } if (screenShotBmp == null) { OcrText = "Error: no image for OCR. Is ARK running?"; return(finalValues); } if (!CheckResolutionSupportedByOcr(screenShotBmp)) { OcrText = "Error while calibrating: The game-resolution is not supported by the currently loaded OCR-configuration.\n" + $"The tested image has a resolution of {screenShotBmp.Width} × {screenShotBmp.Height} px,\n" + $"the resolution of the loaded ocr-config is {ocrConfig.resolutionWidth} × {ocrConfig.resolutionHeight} px.\n\n" + "Load or create a ocr-config file with the resolution of the game to make it work."; return(finalValues); } // TODO resize image according to resize-factor. used for large screenshots if (ocrConfig.resize != 1 && ocrConfig.resize > 0) { Bitmap resized = new Bitmap((int)(ocrConfig.resize * ocrConfig.resolutionWidth), (int)(ocrConfig.resize * ocrConfig.resolutionHeight)); using (var graphics = Graphics.FromImage(resized)) { graphics.CompositingMode = CompositingMode.SourceCopy; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; using (var wrapMode = new ImageAttributes()) { wrapMode.SetWrapMode(WrapMode.TileFlipXY); graphics.DrawImage(screenShotBmp, new Rectangle(0, 0, resized.Width, resized.Height), 0, 0, screenShotBmp.Width, screenShotBmp.Height, GraphicsUnit.Pixel, wrapMode); } screenShotBmp.Dispose(); screenShotBmp = resized; } } if (enableOutput) { _ocrControl?.DisplayBmpInOcrControl(screenShotBmp); } finalValues = new double[ocrConfig.labelRectangles.Length]; finalValues[8] = -1; // set imprinting to -1 to mark it as unknown and to set a difference to a creature with 0% imprinting. if (changeForegroundWindow) { Win32API.SetForegroundWindow(Application.OpenForms[0].Handle); } HammingWeight.InitializeBitCounts(); // TODO OCR performance measurement //var sw = new Stopwatch(); //sw.Start(); var whiteThreshold = Properties.Settings.Default.OCRWhiteThreshold; bool wild = false; // todo: set to true and find out if the creature is wild in the first loop int stI = -1; var labels = (OcrTemplate.OcrLabels[])Enum.GetValues(typeof(OcrTemplate.OcrLabels)); for (int lbI = 0; lbI < labels.Length; lbI++) { stI++; if (lbI == 8) { stI = 8; } var label = labels[stI]; switch (label) { case OcrTemplate.OcrLabels.NameSpecies: if (ocrConfig.RecognitionPatterns.TrainingSettings.SkipName) { dinoName = string.Empty; continue; } break; case OcrTemplate.OcrLabels.Tribe: if (ocrConfig.RecognitionPatterns.TrainingSettings.SkipTribe) { tribeName = string.Empty; continue; } break; case OcrTemplate.OcrLabels.Owner: if (ocrConfig.RecognitionPatterns.TrainingSettings.SkipOwner) { ownerName = string.Empty; continue; } break; } Rectangle rec = ocrConfig.labelRectangles[lbI]; // wild creatures don't have the xp-bar, all stats are moved one row up if (wild && stI < 9) { rec.Offset(0, ocrConfig.labelRectangles[0].Top - ocrConfig.labelRectangles[1].Top); } Bitmap testbmp = SubImage(screenShotBmp, rec.X, rec.Y, rec.Width, rec.Height); //AddBitmapToDebug(testbmp); string statOcr; try { if (label == OcrTemplate.OcrLabels.NameSpecies) { statOcr = PatternOcr.ReadImageOcr(testbmp, false, whiteThreshold, rec.X, rec.Y, _ocrControl); } else if (label == OcrTemplate.OcrLabels.Level) { statOcr = PatternOcr.ReadImageOcr(testbmp, true, whiteThreshold, rec.X, rec.Y, _ocrControl).Replace(".", ": "); } else if (label == OcrTemplate.OcrLabels.Tribe || label == OcrTemplate.OcrLabels.Owner) { statOcr = PatternOcr.ReadImageOcr(testbmp, false, whiteThreshold, rec.X, rec.Y, _ocrControl); } else { statOcr = PatternOcr.ReadImageOcr(testbmp, true, whiteThreshold, rec.X, rec.Y, _ocrControl).Trim('.'); // statValues are only numbers } } catch (OperationCanceledException) { OcrText = "Canceled"; return(finalValues); } if (statOcr == string.Empty && (label == OcrTemplate.OcrLabels.Health || label == OcrTemplate.OcrLabels.Imprinting || label == OcrTemplate.OcrLabels.Tribe || label == OcrTemplate.OcrLabels.Owner)) { if (wild && label == OcrTemplate.OcrLabels.Health) { stI--; wild = false; } continue; // these can be missing, it's fine } finishedText += $"{(finishedText.Length == 0 ? string.Empty : "\r\n")}{label}:\t{statOcr}"; // parse the OCR String var r = new Regex(@"^[_\/\\]*(.*?)[_\/\\]*$"); statOcr = r.Replace(statOcr, "$1"); if (label == OcrTemplate.OcrLabels.NameSpecies) { r = new Regex(@".*?([♂♀])?[_.,-\/\\]*([^♂♀]+?)(?:[\(\[]([^\[\(\]\)]+)[\)\]]$|$)"); } else if (label == OcrTemplate.OcrLabels.Owner || label == OcrTemplate.OcrLabels.Tribe) { r = new Regex(@"(.*)"); } else if (label == OcrTemplate.OcrLabels.Level) { r = new Regex(@".*\D(\d+)"); } else { r = new Regex(@"(?:[\d.,%\/]*\/)?(\d+[\.,']?\d?)(%)?\.?"); // only the second numbers is interesting after the current weight is not shown anymore } MatchCollection mc = r.Matches(statOcr); if (mc.Count == 0) { if (label == OcrTemplate.OcrLabels.NameSpecies || label == OcrTemplate.OcrLabels.Owner || label == OcrTemplate.OcrLabels.Tribe) { continue; } //if (statName == "Torpor") //{ // // probably it's a wild creature // // todo //} //else //{ finishedText += $"error reading stat {label}"; finalValues[stI] = 0; continue; //} } if (label == OcrTemplate.OcrLabels.NameSpecies || label == OcrTemplate.OcrLabels.Owner || label == OcrTemplate.OcrLabels.Tribe) { if (label == OcrTemplate.OcrLabels.NameSpecies && mc[0].Groups.Count > 0) { if (mc[0].Groups[1].Value == "♀") { sex = Sex.Female; } else if (mc[0].Groups[1].Value == "♂") { sex = Sex.Male; } dinoName = mc[0].Groups[2].Value; species = mc[0].Groups[3].Value; if (species.Length == 0) { species = dinoName; } // remove non-letter chars r = new Regex(@"[^a-zA-Z]"); species = r.Replace(species, string.Empty); // replace capital I with lower l (common misrecognition) r = new Regex(@"(?<=[a-z])I(?=[a-z])"); species = r.Replace(species, "l"); // readd spaces before capital letters //r = new Regex("(?<=[a-z])(?=[A-Z])"); //species = r.Replace(species, " "); finishedText += $"\t→ {sex}, {species}"; dinoName = RemoveUnrecognizedCharacters(dinoName); species = RemoveUnrecognizedCharacters(species); } else if (label == OcrTemplate.OcrLabels.Owner && mc[0].Groups.Count > 0) { ownerName = mc[0].Groups[0].Value; finishedText += $"\t→ {ownerName}"; ownerName = RemoveUnrecognizedCharacters(ownerName); } else if (label == OcrTemplate.OcrLabels.Tribe && mc[0].Groups.Count > 0) { tribeName = mc[0].Groups[0].Value; finishedText += $"\t→ {tribeName}"; tribeName = RemoveUnrecognizedCharacters(tribeName); } continue; } if (mc[0].Groups.Count > 2 && mc[0].Groups[2].Value == "%" && label == OcrTemplate.OcrLabels.Weight) { // first stat with a '%' is damage, if oxygen is missing, shift all stats by one finalValues[4] = finalValues[3]; // shift food to weight finalValues[3] = finalValues[2]; // shift oxygen to food finalValues[2] = 0; // set oxygen (which wasn't there) to 0 stI++; } var splitRes = statOcr.Split('/', ',', ':'); var ocrValue = splitRes[splitRes.Length - 1] == "%" ? splitRes[splitRes.Length - 2] : splitRes[splitRes.Length - 1]; ocrValue = PatternOcr.RemoveNonNumeric(ocrValue); double.TryParse(ocrValue, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.GetCultureInfo("en-US"), out double v); // common substitutions: comma and apostrophe to dot, finishedText += label == OcrTemplate.OcrLabels.Level ? $"\t→ {v:F0}" : $"\t→ {v:F1}"; // TODO: test here that the read stat name corresponds to the stat supposed to be read finalValues[stI] = v; string RemoveUnrecognizedCharacters(string s) => s.Replace("�", string.Empty); } OcrText = finishedText; // TODO OCR performance output //sw.Stop(); //Debug.WriteLine($"OCR took {sw.ElapsedMilliseconds} ms."); // TODO reorder stats to match 12-stats-order return(finalValues); }