From 1cc889c6f2357d44d5dc960f32bb0eda1bd2f779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Fri, 14 Mar 2025 01:57:54 +0800 Subject: [PATCH] to mat init --- .../GameTask/CaptureContent.cs | 6 +- .../GameTask/Common/TaskControl.cs | 11 ++-- .../GameTask/Model/Area/DesktopRegion.cs | 5 +- .../GameTask/Model/Area/GameCaptureRegion.cs | 2 +- .../GameTask/Model/Area/ImageRegion.cs | 2 +- .../GameTask/TaskTriggerDispatcher.cs | 51 +++++++-------- .../Notification/NotificationService.cs | 5 +- .../View/CaptureTestWindow.xaml.cs | 3 +- Fischless.GameCapture/BitBlt/BitBltCapture.cs | 64 +++++++++++++++---- .../DwmSharedSurface/SharedSurfaceCapture.cs | 6 +- .../Fischless.GameCapture.csproj | 2 + .../Graphics/GraphicsCapture.cs | 8 ++- Fischless.GameCapture/IGameCapture.cs | 6 +- 13 files changed, 110 insertions(+), 61 deletions(-) diff --git a/BetterGenshinImpact/GameTask/CaptureContent.cs b/BetterGenshinImpact/GameTask/CaptureContent.cs index c409ef03..4bec488f 100644 --- a/BetterGenshinImpact/GameTask/CaptureContent.cs +++ b/BetterGenshinImpact/GameTask/CaptureContent.cs @@ -1,6 +1,7 @@ using BetterGenshinImpact.GameTask.Model.Area; using System; using System.Drawing; +using OpenCvSharp; namespace BetterGenshinImpact.GameTask; @@ -11,7 +12,6 @@ namespace BetterGenshinImpact.GameTask; public class CaptureContent : IDisposable { public static readonly int MaxFrameIndexSecond = 60; - private Bitmap? SrcBitmap { get; } public int FrameIndex { get; } public double TimerInterval { get; } @@ -19,9 +19,8 @@ public class CaptureContent : IDisposable public ImageRegion CaptureRectArea { get; private set; } - public CaptureContent(Bitmap srcBitmap, int frameIndex, double interval) + public CaptureContent(Mat srcBitmap, int frameIndex, double interval) { - SrcBitmap = srcBitmap; FrameIndex = frameIndex; TimerInterval = interval; var systemInfo = TaskContext.Instance().SystemInfo; @@ -42,6 +41,5 @@ public class CaptureContent : IDisposable public void Dispose() { CaptureRectArea.Dispose(); - SrcBitmap?.Dispose(); } } diff --git a/BetterGenshinImpact/GameTask/Common/TaskControl.cs b/BetterGenshinImpact/GameTask/Common/TaskControl.cs index a819adc2..577d7270 100644 --- a/BetterGenshinImpact/GameTask/Common/TaskControl.cs +++ b/BetterGenshinImpact/GameTask/Common/TaskControl.cs @@ -7,6 +7,7 @@ using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception; using BetterGenshinImpact.GameTask.Model.Area; using Fischless.GameCapture; using Microsoft.Extensions.Logging; +using OpenCvSharp; using Vanara.PInvoke; namespace BetterGenshinImpact.GameTask.Common; @@ -177,7 +178,7 @@ public class TaskControl } } - public static Bitmap CaptureGameBitmap(IGameCapture? gameCapture) + public static Mat CaptureGameBitmap(IGameCapture? gameCapture) { var bitmap = gameCapture?.Capture(); // wgc 缓冲区设置的2 所以至少截图3次 @@ -189,7 +190,7 @@ public class TaskControl Sleep(50); } } - + if (bitmap == null) { Logger.LogWarning("截图失败!"); @@ -201,10 +202,10 @@ public class TaskControl { return bitmap; } - + Sleep(30); } - + throw new Exception("尝试多次后,截图失败!"); } else @@ -213,7 +214,7 @@ public class TaskControl } } - public static Bitmap? CaptureGameBitmapNoRetry(IGameCapture? gameCapture) + public static Mat? CaptureGameBitmapNoRetry(IGameCapture? gameCapture) { return gameCapture?.Capture(); } diff --git a/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs b/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs index 1c4607cc..1d2255cf 100644 --- a/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs +++ b/BetterGenshinImpact/GameTask/Model/Area/DesktopRegion.cs @@ -3,6 +3,7 @@ using BetterGenshinImpact.GameTask.Model.Area.Converter; using BetterGenshinImpact.Helpers; using Fischless.WindowsInput; using System.Drawing; +using OpenCvSharp; namespace BetterGenshinImpact.GameTask.Model.Area; @@ -67,8 +68,8 @@ public class DesktopRegion : Region Simulation.SendInput.Mouse.MoveMouseBy((int)dx, (int)dy); } - public GameCaptureRegion Derive(Bitmap captureBitmap, int x, int y) + public GameCaptureRegion Derive(Mat captureMat, int x, int y) { - return new GameCaptureRegion(captureBitmap, x, y, this, new TranslationConverter(x, y)); + return new GameCaptureRegion(captureMat, x, y, this, new TranslationConverter(x, y)); } } diff --git a/BetterGenshinImpact/GameTask/Model/Area/GameCaptureRegion.cs b/BetterGenshinImpact/GameTask/Model/Area/GameCaptureRegion.cs index 4e497304..975b05df 100644 --- a/BetterGenshinImpact/GameTask/Model/Area/GameCaptureRegion.cs +++ b/BetterGenshinImpact/GameTask/Model/Area/GameCaptureRegion.cs @@ -11,7 +11,7 @@ namespace BetterGenshinImpact.GameTask.Model.Area; /// 游戏捕获区域类 /// 主要用于转换到遮罩窗口的坐标 /// -public class GameCaptureRegion(Bitmap bitmap, int initX, int initY, Region? owner = null, INodeConverter? converter = null, DrawContent? drawContent = null) : ImageRegion(bitmap, initX, initY, owner, converter, drawContent) +public class GameCaptureRegion(Mat mat, int initX, int initY, Region? owner = null, INodeConverter? converter = null, DrawContent? drawContent = null) : ImageRegion(mat, initX, initY, owner, converter, drawContent) { /// /// 在游戏捕获图像的坐标维度进行转换到遮罩窗口的坐标维度 diff --git a/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs b/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs index ffdd0c2a..47f57d98 100644 --- a/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs +++ b/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs @@ -76,7 +76,7 @@ public class ImageRegion : Region _srcBitmap = bitmap; } - public ImageRegion(Mat mat, int x, int y, Region? owner = null, INodeConverter? converter = null) : base(x, y, mat.Width, mat.Height, owner, converter) + public ImageRegion(Mat mat, int x, int y, Region? owner = null, INodeConverter? converter = null, DrawContent? drawContent = null) : base(x, y, mat.Width, mat.Height, owner, converter) { _srcMat = mat; } diff --git a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs index f7559ea6..684c4e37 100644 --- a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs +++ b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs @@ -284,13 +284,13 @@ namespace BetterGenshinImpact.GameTask { // if (!_prevGameActive) // { - maskWindow.Invoke(() => + maskWindow.Invoke(() => + { + if (maskWindow.IsExist()) { - if (maskWindow.IsExist()) - { - maskWindow.Show(); - } - }); + maskWindow.Show(); + } + }); // } } @@ -323,10 +323,10 @@ namespace BetterGenshinImpact.GameTask return; } - if (IsOnlyCacheCapture(bitmap)) - { - return; - } + // if (IsOnlyCacheCapture(bitmap)) + // { + // return; + // } // 循环执行所有触发器 有独占状态的触发器的时候只执行独占触发器 var content = new CaptureContent(bitmap, _frameIndex, _timer.Interval); @@ -336,7 +336,6 @@ namespace BetterGenshinImpact.GameTask var exclusiveTrigger = _triggers!.FirstOrDefault(t => t is { IsEnabled: true, IsExclusive: true }); if (exclusiveTrigger != null) { - exclusiveTrigger.OnCapture(content); speedTimer.Record(exclusiveTrigger.Name); } @@ -350,13 +349,12 @@ namespace BetterGenshinImpact.GameTask foreach (var trigger in runningTriggers) { - trigger.OnCapture(content); speedTimer.Record(trigger.Name); } } } - + speedTimer.DebugPrint(); content.Dispose(); } @@ -456,17 +454,17 @@ namespace BetterGenshinImpact.GameTask return _dispatcherCacheCaptureMode; } - public Bitmap GetLastCaptureBitmap() - { - lock (_bitmapLocker) - { - return new Bitmap(_bitmap); - } - } + // public Bitmap GetLastCaptureBitmap() + // { + // lock (_bitmapLocker) + // { + // return new Bitmap(_bitmap); + // } + // } public CaptureContent GetLastCaptureContent() { - var bitmap = GetLastCaptureBitmap(); + var bitmap = TaskControl.CaptureGameBitmap(GameCapture); return new CaptureContent(bitmap, _frameIndex, _timer.Interval); } @@ -497,20 +495,19 @@ namespace BetterGenshinImpact.GameTask Directory.CreateDirectory(path); } - var bitmap = GetLastCaptureBitmap(); + var bitmap = TaskControl.CaptureGameBitmap(GameCapture); var name = $@"{DateTime.Now:yyyyMMddHHmmssffff}.png"; var savePath = Global.Absolute($@"log\screenshot\{name}"); if (TaskContext.Instance().Config.CommonConfig.ScreenshotUidCoverEnabled) { - var mat = bitmap.ToMat(); var rect = TaskContext.Instance().Config.MaskWindowConfig.UidCoverRect; - mat.Rectangle(rect, Scalar.White, -1); - Cv2.ImWrite(savePath, mat); + bitmap.Rectangle(rect, Scalar.White, -1); + Cv2.ImWrite(savePath, bitmap); } else { - bitmap.Save(savePath, ImageFormat.Png); + Cv2.ImWrite(savePath, bitmap); } _logger.LogInformation("截图已保存: {Name}", name); @@ -527,4 +524,4 @@ namespace BetterGenshinImpact.GameTask } } } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/Service/Notification/NotificationService.cs b/BetterGenshinImpact/Service/Notification/NotificationService.cs index 6a33ca52..d6e18df9 100644 --- a/BetterGenshinImpact/Service/Notification/NotificationService.cs +++ b/BetterGenshinImpact/Service/Notification/NotificationService.cs @@ -1,4 +1,4 @@ -using BetterGenshinImpact.Service.Notification.Model; +using BetterGenshinImpact.Service.Notification.Model; using BetterGenshinImpact.Service.Notifier; using BetterGenshinImpact.Service.Notifier.Exception; using BetterGenshinImpact.Service.Notifier.Interface; @@ -13,6 +13,7 @@ using BetterGenshinImpact.GameTask.Common; using BetterGenshinImpact.Service.Notification.Model.Enum; using Microsoft.Extensions.Logging; using System.Text.Json; +using OpenCvSharp.Extensions; namespace BetterGenshinImpact.Service.Notification; @@ -166,7 +167,7 @@ public class NotificationService : IHostedService var bitmap = TaskControl.CaptureGameBitmapNoRetry(TaskTriggerDispatcher.GlobalGameCapture); if (bitmap != null) { - notificationData.Screenshot = (Bitmap)bitmap.Clone(); + notificationData.Screenshot = bitmap.ToBitmap(); } } } diff --git a/BetterGenshinImpact/View/CaptureTestWindow.xaml.cs b/BetterGenshinImpact/View/CaptureTestWindow.xaml.cs index 366563b5..04dd18a5 100644 --- a/BetterGenshinImpact/View/CaptureTestWindow.xaml.cs +++ b/BetterGenshinImpact/View/CaptureTestWindow.xaml.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Windows; using System.Windows.Media; using BetterGenshinImpact.Helpers; +using OpenCvSharp.WpfExtensions; using Wpf.Ui.Violeta.Controls; namespace BetterGenshinImpact.View; @@ -72,7 +73,7 @@ public partial class CaptureTestWindow : Window _captureCount++; sw.Reset(); sw.Start(); - DisplayCaptureResultImage.Source = bitmap.ToBitmapImage(); + DisplayCaptureResultImage.Source = bitmap.ToBitmapSource(); sw.Stop(); Debug.WriteLine("转换耗时:" + sw.ElapsedMilliseconds); _transferTime += sw.ElapsedMilliseconds; diff --git a/Fischless.GameCapture/BitBlt/BitBltCapture.cs b/Fischless.GameCapture/BitBlt/BitBltCapture.cs index de379344..9f763127 100644 --- a/Fischless.GameCapture/BitBlt/BitBltCapture.cs +++ b/Fischless.GameCapture/BitBlt/BitBltCapture.cs @@ -1,4 +1,6 @@ using System.Diagnostics; +using System.Runtime.InteropServices; +using OpenCvSharp; using Vanara.PInvoke; namespace Fischless.GameCapture.BitBlt; @@ -26,34 +28,74 @@ public class BitBltCapture : IGameCapture } } - public Bitmap? Capture() + public Mat? Capture() { if (_hWnd == IntPtr.Zero) { return null; } + User32.SafeReleaseHDC hdcSrc = User32.SafeReleaseHDC.Null; + Gdi32.SafeHDC hdcDest = Gdi32.SafeHDC.Null; + Gdi32.SafeHBITMAP hBitmap = Gdi32.SafeHBITMAP.Null; try { User32.GetClientRect(_hWnd, out var windowRect); - int x = default, y = default; + int x = 0, y = 0; var width = windowRect.right - windowRect.left; var height = windowRect.bottom - windowRect.top; - Bitmap bitmap = new(width, height); - using System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap); - var hdcDest = g.GetHdc(); - var hdcSrc = User32.GetDC(_hWnd == IntPtr.Zero ? User32.GetDesktopWindow() : _hWnd); + hdcSrc = User32.GetDC(_hWnd == IntPtr.Zero ? User32.GetDesktopWindow() : _hWnd); + hdcDest = Gdi32.CreateCompatibleDC(hdcSrc); + + var bmi = new Gdi32.BITMAPINFO + { + bmiHeader = new Gdi32.BITMAPINFOHEADER + { + biSize = (uint)Marshal.SizeOf(), + biWidth = width, + biHeight = -height, // Top-down image + biPlanes = 1, + biBitCount = 32, + biCompression = 0, // BI_RGB + biSizeImage = 0 + } + }; + + nint bits = 0; + hBitmap = Gdi32.CreateDIBSection(hdcDest, bmi, Gdi32.DIBColorMode.DIB_RGB_COLORS, out bits, IntPtr.Zero, 0); + var oldBitmap = Gdi32.SelectObject(hdcDest, hBitmap); + Gdi32.StretchBlt(hdcDest, 0, 0, width, height, hdcSrc, x, y, width, height, Gdi32.RasterOperationMode.SRCCOPY); - g.ReleaseHdc(); - Gdi32.DeleteDC(hdcDest); - Gdi32.DeleteDC(hdcSrc); - return bitmap; + + var mat = new Mat(height, width, MatType.CV_8UC4, bits); + Mat bgrMat = new Mat(); + Cv2.CvtColor(mat, bgrMat, ColorConversionCodes.BGRA2BGR); + + Gdi32.SelectObject(hdcDest, oldBitmap); + return bgrMat; } catch (Exception e) { Debug.WriteLine(e); } + finally + { + if (hBitmap != Gdi32.SafeHBITMAP.Null) + { + Gdi32.DeleteObject(hBitmap); + } + + if (hdcDest != Gdi32.SafeHDC.Null) + { + Gdi32.DeleteDC(hdcDest); + } + + if (_hWnd != IntPtr.Zero) + { + User32.ReleaseDC(_hWnd, hdcSrc); + } + } return null!; } @@ -63,4 +105,4 @@ public class BitBltCapture : IGameCapture _hWnd = IntPtr.Zero; IsCapturing = false; } -} +} \ No newline at end of file diff --git a/Fischless.GameCapture/DwmSharedSurface/SharedSurfaceCapture.cs b/Fischless.GameCapture/DwmSharedSurface/SharedSurfaceCapture.cs index b5f59828..a1ea064f 100644 --- a/Fischless.GameCapture/DwmSharedSurface/SharedSurfaceCapture.cs +++ b/Fischless.GameCapture/DwmSharedSurface/SharedSurfaceCapture.cs @@ -3,6 +3,8 @@ using Fischless.GameCapture.Graphics.Helpers; using SharpDX.Direct3D11; using SharpDX.DXGI; using System.Diagnostics; +using OpenCvSharp; +using OpenCvSharp.Extensions; using Vanara.PInvoke; using Device = SharpDX.Direct3D11.Device; @@ -64,7 +66,7 @@ namespace Fischless.GameCapture.DwmSharedSurface return region; } - public Bitmap? Capture() + public Mat? Capture() { if (_hWnd == nint.Zero) { @@ -78,7 +80,7 @@ namespace Fischless.GameCapture.DwmSharedSurface return null; } - return ToBitmap(phSurface); + return ToBitmap(phSurface)?.ToMat(); } private Bitmap? ToBitmap(nint phSurface) diff --git a/Fischless.GameCapture/Fischless.GameCapture.csproj b/Fischless.GameCapture/Fischless.GameCapture.csproj index 7b895bae..1e832bb0 100644 --- a/Fischless.GameCapture/Fischless.GameCapture.csproj +++ b/Fischless.GameCapture/Fischless.GameCapture.csproj @@ -19,6 +19,8 @@ + + \ No newline at end of file diff --git a/Fischless.GameCapture/Graphics/GraphicsCapture.cs b/Fischless.GameCapture/Graphics/GraphicsCapture.cs index 6113635a..7f912e48 100644 --- a/Fischless.GameCapture/Graphics/GraphicsCapture.cs +++ b/Fischless.GameCapture/Graphics/GraphicsCapture.cs @@ -5,6 +5,8 @@ using Vanara.PInvoke; using Windows.Foundation.Metadata; using Windows.Graphics.Capture; using Windows.Graphics.DirectX; +using OpenCvSharp; +using OpenCvSharp.Extensions; namespace Fischless.GameCapture.Graphics; @@ -112,7 +114,7 @@ public class GraphicsCapture : IGameCapture } } - public Bitmap? Capture() + public Mat? Capture() { if (_hWnd == IntPtr.Zero) { @@ -130,7 +132,7 @@ public class GraphicsCapture : IGameCapture return null; } - return frame.ToBitmap(_region); + return frame.ToBitmap(_region)?.ToMat(); } catch (Exception e) { @@ -146,7 +148,7 @@ public class GraphicsCapture : IGameCapture return null; } - return (Bitmap)_currentBitmap.Clone(); + return ((Bitmap)_currentBitmap.Clone()).ToMat(); } } diff --git a/Fischless.GameCapture/IGameCapture.cs b/Fischless.GameCapture/IGameCapture.cs index d6922cf2..ffb85923 100644 --- a/Fischless.GameCapture/IGameCapture.cs +++ b/Fischless.GameCapture/IGameCapture.cs @@ -1,4 +1,6 @@ -namespace Fischless.GameCapture; +using OpenCvSharp; + +namespace Fischless.GameCapture; public interface IGameCapture : IDisposable { @@ -7,7 +9,7 @@ public interface IGameCapture : IDisposable public void Start(nint hWnd, Dictionary? settings = null); - public Bitmap? Capture(); + public Mat? Capture(); public void Stop(); }