Add the Bitmap Comparison with CRC32 hashing
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run

This commit is contained in:
Namhyeon Go 2024-09-19 03:29:43 +09:00
parent 12ce97c385
commit 0742f17f2a
4 changed files with 47 additions and 19 deletions

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.IO.Hashing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.ServiceProcess; using System.ServiceProcess;
using System.Text; using System.Text;
@ -14,6 +15,7 @@ using System.Windows.Forms;
using System.Linq; using System.Linq;
using Tesseract; using Tesseract;
using WelsonJS.Service; using WelsonJS.Service;
using System.Security.Cryptography;
public class ScreenMatch public class ScreenMatch
{ {
@ -114,12 +116,12 @@ public class ScreenMatch
private List<string> _params = new List<string>(); private List<string> _params = new List<string>();
private bool isSearchFromEnd = false; private bool isSearchFromEnd = false;
private bool isSaveToFile = false; private bool isSaveToFile = false;
private bool isUseSampleClipboard = false;
private bool isUseSampleOCR = false;
private Size sampleSize; private Size sampleSize;
private int sampleAdjustX = 0; private int sampleAdjustX;
private int sampleAdjustY = 0; private int sampleAdjustY;
private List<string> sampleAny; private List<string> sampleAny;
private List<string> sampleClipboard;
private List<string> sampleOcr;
private List<string> sampleNodup; private List<string> sampleNodup;
private Size sampleNodupSize; private Size sampleNodupSize;
private Queue<Bitmap> sampleOutdated; private Queue<Bitmap> sampleOutdated;
@ -133,13 +135,20 @@ public class ScreenMatch
templateDirectoryPath = Path.Combine(workingDirectory, "app/assets/img/_templates"); templateDirectoryPath = Path.Combine(workingDirectory, "app/assets/img/_templates");
outputDirectoryPath = Path.Combine(workingDirectory, "app/assets/img/_captured"); outputDirectoryPath = Path.Combine(workingDirectory, "app/assets/img/_captured");
templateImages = new List<Bitmap>(); templateImages = new List<Bitmap>();
// Initialize variables for sampling process
sampleSize = new Size sampleSize = new Size
{ {
Width = 128, Width = 128,
Height = 128 Height = 128
}; };
sampleAdjustX = 0;
sampleAdjustY = 0;
sampleAny = new List<string>();
sampleClipboard = new List<string>();
sampleOcr = new List<string>();
sampleNodup = new List<string>();
sampleNodupSize = new Size sampleNodupSize = new Size
{ {
Width = 128, Width = 128,
@ -212,8 +221,7 @@ public class ScreenMatch
case "sample_clipboard": case "sample_clipboard":
{ {
isUseSampleClipboard = true; sampleClipboard = new List<string>(config_value.Split(':'));
this.parent.Log($"Use Clipboard within a {sampleSize.Width}x{sampleSize.Height} pixel range around specific coordinates.");
break; break;
} }
@ -221,8 +229,7 @@ public class ScreenMatch
{ {
tesseractDataPath = Path.Combine(workingDirectory, "app/assets/tessdata_best"); tesseractDataPath = Path.Combine(workingDirectory, "app/assets/tessdata_best");
tesseractLanguage = "eng"; tesseractLanguage = "eng";
isUseSampleOCR = true; sampleOcr = new List<string>(config_value.Split(':'));
this.parent.Log($"Use OCR within a {sampleSize.Width}x{sampleSize.Height} pixel range around specific coordinates.");
break; break;
} }
@ -395,7 +402,7 @@ public class ScreenMatch
} }
List<Point> matchPositions = FindTemplate(_mainImage, (Bitmap)image.Clone()); List<Point> matchPositions = FindTemplate(_mainImage, (Bitmap)image.Clone());
matchPositions.ForEach((matchPosition) => foreach (Point matchPosition in matchPositions)
{ {
try try
{ {
@ -409,12 +416,14 @@ public class ScreenMatch
Position = matchPosition, Position = matchPosition,
Text = text Text = text
}); });
break; // Only one
} }
catch (Exception ex) catch (Exception ex)
{ {
parent.Log($"Ignore the match. {ex.Message}"); parent.Log($"Ignore the match. {ex.Message}");
} }
}); }
} }
if (results.Count > 0) if (results.Count > 0)
@ -431,7 +440,7 @@ public class ScreenMatch
return results; return results;
} }
public Bitmap cropBitmap(Bitmap bitmap, Point matchPosition, Size templateSize, Size sampleSize, int dx = 0, int dy = 0) public Bitmap CropBitmap(Bitmap bitmap, Point matchPosition, Size templateSize, Size sampleSize, int dx = 0, int dy = 0)
{ {
// Adjust coordinates to the center // Adjust coordinates to the center
int x = matchPosition.X + (templateSize.Width / 2); int x = matchPosition.X + (templateSize.Width / 2);
@ -464,14 +473,15 @@ public class ScreenMatch
string text = ""; string text = "";
// Crop image // Crop image
Bitmap croppedBitmap = cropBitmap(bitmap, matchPosition, templateSize, sampleSize, sampleAdjustX, sampleAdjustY); Bitmap croppedBitmap = CropBitmap(bitmap, matchPosition, templateSize, sampleSize, sampleAdjustX, sampleAdjustY);
// Save to the outdated samples // Save to the outdated samples
if (sampleNodup.Contains(templateName)) if (sampleNodup.Contains(templateName))
{ {
Bitmap croppedNodupBitmap = cropBitmap(bitmap, matchPosition, templateSize, sampleNodupSize); Bitmap croppedNodupBitmap = CropBitmap(bitmap, matchPosition, templateSize, sampleNodupSize);
int bitmapHash = croppedNodupBitmap.GetHashCode(); uint bitmapCrc32 = ComputeBitmapCrc32(croppedNodupBitmap);
bool bitmapExists = sampleOutdated.Any(x => x.GetHashCode() == bitmapHash); parent.Log($"bitmapCrc32: {bitmapCrc32}");
bool bitmapExists = sampleOutdated.Any(x => ComputeBitmapCrc32(x) == bitmapCrc32);
if (bitmapExists) if (bitmapExists)
{ {
throw new InvalidOperationException($"This may be a duplicate request. {templateName}"); throw new InvalidOperationException($"This may be a duplicate request. {templateName}");
@ -484,7 +494,7 @@ public class ScreenMatch
} }
// if use Clipboard // if use Clipboard
if (isUseSampleClipboard) if (sampleClipboard.Contains(templateName))
{ {
Thread th = new Thread(new ThreadStart(() => Thread th = new Thread(new ThreadStart(() =>
{ {
@ -503,7 +513,7 @@ public class ScreenMatch
} }
// if use OCR // if use OCR
if (isUseSampleOCR) if (sampleOcr.Contains(templateName))
{ {
try try
{ {
@ -755,4 +765,18 @@ public class ScreenMatch
return binaryImage; return binaryImage;
} }
private uint ComputeBitmapCrc32(Bitmap bitmap)
{
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
byte[] bitmapBytes = ms.ToArray();
Crc32 crc32 = new Crc32();
crc32.Append(bitmapBytes);
return BitConverter.ToUInt32(crc32.GetCurrentHash(), 0);
}
}
} }

View File

@ -142,6 +142,9 @@
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll</HintPath> <HintPath>..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.IO.Hashing, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Hashing.8.0.0\lib\net462\System.IO.Hashing.dll</HintPath>
</Reference>
<Reference Include="System.Management" /> <Reference Include="System.Management" />
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> <Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath> <HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>

View File

@ -15,6 +15,7 @@
<package id="RestSharp" version="112.0.0" targetFramework="net48" /> <package id="RestSharp" version="112.0.0" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" /> <package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Diagnostics.DiagnosticSource" version="8.0.1" targetFramework="net48" /> <package id="System.Diagnostics.DiagnosticSource" version="8.0.1" targetFramework="net48" />
<package id="System.IO.Hashing" version="8.0.0" targetFramework="net48" />
<package id="System.Memory" version="4.5.5" targetFramework="net48" /> <package id="System.Memory" version="4.5.5" targetFramework="net48" />
<package id="System.Net.Http.WinHttpHandler" version="8.0.2" targetFramework="net48" /> <package id="System.Net.Http.WinHttpHandler" version="8.0.2" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" /> <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />

View File

@ -13,7 +13,7 @@ DISABLE_SCREEN_TIME=true
DISABLE_FILE_MONITOR=true DISABLE_FILE_MONITOR=true
; window or screen ; window or screen
SCREEN_TIME_MODE=screen SCREEN_TIME_MODE=screen
; backward,save,sample_ocr,sample_clipboard,sample_width=128,sample_height=128,sample_adjust_x=0,sample_adjust_y=0,sample_only=button.png:message.png,sample_nodup=message.png,process_name=notepad.exe ; backward,save,sample_width=128,sample_height=128,sample_adjust_x=0,sample_adjust_y=0,sample_any=button.png:message.png:like.png,sample_ocr=like.png,sample_clipboard=button.png,sample_nodup=message.png,process_name=notepad.exe
SCREEN_TIME_PARAMS= SCREEN_TIME_PARAMS=
; default: http://localhost:50051 ; default: http://localhost:50051
GRPC_HOST=http://localhost:50051 GRPC_HOST=http://localhost:50051