private void HandleHotkey(object sender, KeyPressedEventArgs e) { // Capture the primary screen Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); Graphics graphics = Graphics.FromImage(bitmap); graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size); // Save the image as jpg for possible upload later bitmap.Save(@"img\screenshot.jpg", ImageFormat.Jpeg); Image <Bgr, byte> image = new Image <Bgr, byte>(bitmap); // Apply an adaptive threshold to improve OCR recognition image = image .Convert <Gray, byte>() .ThresholdAdaptive( new Gray(255), AdaptiveThresholdType.GaussianC, Emgu.CV.CvEnum.ThresholdType.Binary, 51, new Gray(-10) ).Convert <Bgr, byte>(); bool errors = false; var platvalues = new int[4] { -1, -1, -1, -1 }; var subimages = new Image <Bgr, byte> [8]; for (int i = 0; i < 8; i++) { // Extract the subimage containing the item name // this has to be done sequentially and not in parallel // TODO: multiline names subimages[i] = image.Copy(rectangles[i]); } // returns a funtion that tries to recognize item i // if big is true, considers a 2-line item name Action <int> recognize(bool big) { return((i) => { var subimage = subimages[big ? 4 + i : i]; // Save the image as jpg for possible upload later subimage.ToBitmap().Save($@"img\{i}.jpg", ImageFormat.Jpeg); // Only one OCR instance per thread or runtime errors happen var ocr = new Tesseract( @".\tessdata", "weng", OcrEngineMode.TesseractOnly, // Fun fact: no Q or J appears on any name "ABCDEFGHIJKLMNOPRSTUVWXYZ&" ); ocr.SetImage(subimage); ocr.Recognize(); var str = ocr.GetUTF8Text().Trim(); // Save the originally recognized text reportStrings[i, 0] = str; var item = EditDistance.BestMatch(str); // Save the fixed name reportStrings[i, 1] = item; if (item == "NOT RECOGNIZED") { if (big) { errors = true; } else { recognize(true)(i); } } else { platvalues[i] = GetWarframeMarketPrice(item); } }); } // We run both the OCR and the warframe.market query in parallel Parallel.For(0, 4, recognize(false)); // Labels can only be edited in the main thread for (int i = 0; i < 4; i++) { var name = reportStrings[i, 1]; labels[i, 0].Text = Items.Normalize(name); if (platvalues[i] >= 0) { labels[i, 1].Text = Items.Ducats[name] + ""; labels[i, 2].Text = platvalues[i] + ""; } else { labels[i, 1].Text = labels[i, 2].Text = "???"; } } // Minimize and restore window to bring it to the front WindowState = FormWindowState.Minimized; WindowState = FormWindowState.Normal; if (errors && Properties.Settings.Default.submit_errors) { SubmitErrorAsync(); } else { submitErrorButton.Enabled = true; } }