3131210 发表于 2025-4-5 12:13:23

【已解决】纯AU3模糊找图,求帮忙提高效率 汇编找图 模糊找图 后台找图

本帖最后由 3131210 于 2025-4-18 23:33 编辑

关于AU3本身实现模糊找图的问题,有没有大神可以帮提高一下找图的效率,下面的代码,在小范围内找一张小图都要十几秒       附件里面的图片要搜索200多秒。。。不是死机

附件里面有测试图片      AU3有没有可能实现毫秒级的模糊找图





#include <GDIPlus.au3>
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>

; 初始化GDI+
_GDIPlus_Startup()

;~ ; 查找单个匹配(精确匹配)
$aResult = _FindPicture("sub.bmp", "parent.bmp", Default, 5, 0.9, False)

; 查找所有匹配(90%匹配率,5像素容错)
;~ $aResult = _FindPicture("sub.bmp", "parent.bmp", Default, 5, 0.9, True)

; 在指定区域内查找
;~ $aSearchRect = ; x, y, width, height
;~ $aResult = _FindPicture("sub.bmp", "parent.bmp", $aSearchRect, 0, 1.0, False)

_GDIPlus_Shutdown()

; 找图函数
; @param $sSubPic 子图路径
; @param $sParPic 父图路径
; @param $aSearchRect 搜索区域 ,默认为空数组则搜索整图
; @param $iErrorRange 容错值 (0-255)
; @param $fMatchRate 匹配率 (0.0-1.0),默认0.9
; @param $bFindAll 是否查找所有匹配,默认False
; @return 包含所有匹配点的二维数组 ,每行是找到的中心点坐标
Func _FindPicture($sSubPic, $sParPic, $aSearchRect = Default, $iErrorRange = 0, $fMatchRate = 0.9, $bFindAll = False)
      Local $aPoints ; 存储结果的数组

      ; 加载图片 - 先用默认格式加载
      Local $hSubBitmap = _GDIPlus_BitmapCreateFromFile($sSubPic)
      Local $hParBitmap = _GDIPlus_BitmapCreateFromFile($sParPic)

      ; 获取图片尺寸
      Local $iSubWidth = _GDIPlus_ImageGetWidth($hSubBitmap)
      Local $iSubHeight = _GDIPlus_ImageGetHeight($hSubBitmap)
      Local $iParWidth = _GDIPlus_ImageGetWidth($hParBitmap)
      Local $iParHeight = _GDIPlus_ImageGetHeight($hParBitmap)

      ; 确定搜索区域
      Local $iSearchX = 0, $iSearchY = 0, $iSearchWidth = $iParWidth, $iSearchHeight = $iParHeight
      If IsArray($aSearchRect) And UBound($aSearchRect) >= 4 Then
                $iSearchX = $aSearchRect
                $iSearchY = $aSearchRect
                $iSearchWidth = $aSearchRect
                $iSearchHeight = $aSearchRect
      EndIf

      ; 使用24位BGR格式锁定位图数据
      Local $tSubBitmapData = _GDIPlus_BitmapLockBits($hSubBitmap, 0, 0, $iSubWidth, $iSubHeight, $GDIP_ILMREAD, $GDIP_PXF24RGB)
      Local $tParBitmapData = _GDIPlus_BitmapLockBits($hParBitmap, 0, 0, $iParWidth, $iParHeight, $GDIP_ILMREAD, $GDIP_PXF24RGB)

      ; 获取扫描行宽度和指针
      Local $iSubStride = DllStructGetData($tSubBitmapData, "Stride")
      Local $pSubScan0 = DllStructGetData($tSubBitmapData, "Scan0")
      Local $iParStride = DllStructGetData($tParBitmapData, "Stride")
      Local $pParScan0 = DllStructGetData($tParBitmapData, "Scan0")

      ; 获取子图第一个像素颜色作为起始匹配点 (24位BGR格式)
      Local $tStartPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pSubScan0)
      Local $iStartB = DllStructGetData($tStartPixel, "B")
      Local $iStartG = DllStructGetData($tStartPixel, "G")
      Local $iStartR = DllStructGetData($tStartPixel, "R")

      ; 计算搜索范围
      Local $iMaxY = $iSearchY + $iSearchHeight - $iSubHeight
      Local $iMaxX = $iSearchX + $iSearchWidth - $iSubWidth

      ; 开始计时
      Local $hTimer = TimerInit()

      ; 开始搜索
      Local $iPointX = -1, $iPointY = -1
      ConsoleWrite("子图尺寸: " & $iSubWidth & "x" & $iSubHeight & @CRLF)
      ConsoleWrite("父图尺寸: " & $iParWidth & "x" & $iParHeight & @CRLF)
      ConsoleWrite("搜索区域: X=" & $iSearchX & ", Y=" & $iSearchY & ", 宽=" & $iSearchWidth & ", 高=" & $iSearchHeight & @CRLF)

      For $i = $iSearchY To $iMaxY
                For $j = $iSearchX To $iMaxX
                        ; 获取父图当前位置的像素 (24位BGR)
                        Local $pParPixel = $pParScan0 + $i * $iParStride + $j * 3
                        Local $tParPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pParPixel)
                        Local $iParB = DllStructGetData($tParPixel, "B")
                        Local $iParG = DllStructGetData($tParPixel, "G")
                        Local $iParR = DllStructGetData($tParPixel, "R")

                        ; 检查起始像素是否匹配
                        If _ColorBGREqualBGR($iParB, $iParG, $iParR, $iStartB, $iStartG, $iStartR, $iErrorRange) Then
                              ; 起始像素匹配,对整个子图进行匹配
                              Local $iSum = 0 ; 总像素数
                              Local $iMatch = 0 ; 匹配的像素数

                              For $m = 0 To $iSubHeight - 1
                                        For $n = 0 To $iSubWidth - 1
                                                ; 子图像素位置 (24位BGR)
                                                Local $pSubPixel = $pSubScan0 + $m * $iSubStride + $n * 3
                                                Local $tSubPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pSubPixel)
                                                Local $iSubB = DllStructGetData($tSubPixel, "B")
                                                Local $iSubG = DllStructGetData($tSubPixel, "G")
                                                Local $iSubR = DllStructGetData($tSubPixel, "R")

                                                ; 对应的父图像素位置
                                                Local $y2 = $i + $m
                                                Local $x2 = $j + $n
                                                Local $pParRelPixel = $pParScan0 + $y2 * $iParStride + $x2 * 3
                                                Local $tParRelPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pParRelPixel)
                                                Local $iParRelB = DllStructGetData($tParRelPixel, "B")
                                                Local $iParRelG = DllStructGetData($tParRelPixel, "G")
                                                Local $iParRelR = DllStructGetData($tParRelPixel, "R")

                                                $iSum += 1

                                                ; 比较颜色 (BGR格式)
                                                If _ColorBGREqualBGR($iParRelB, $iParRelG, $iParRelR, $iSubB, $iSubG, $iSubR, $iErrorRange) Then
                                                      $iMatch += 1
                                                EndIf
                                        Next
                              Next

                              ; 计算匹配率
                              Local $fCurrentMatch = $iMatch / $iSum

                              ; 如果匹配率超过阈值,添加到结果
                              If $fCurrentMatch >= $fMatchRate Then
                                        $iPointX = $j
                                        $iPointY = $i

                                        ConsoleWrite("找到匹配点(左上角): X=" & $iPointX & ", Y=" & $iPointY & ", 匹配率: " & $fCurrentMatch & @CRLF)

                                        ; 检查是否已存在相似的点(避免重复)
                                        If Not _ListContainsPoint($aPoints, $iPointX, $iPointY, 10) Then
                                                ReDim $aPoints
                                                $aPoints = $iPointX
                                                $aPoints = $iPointY
                                        EndIf

                                        ; 如果不需要找所有匹配,直接退出
                                        If Not $bFindAll Then
                                                ExitLoop 2
                                        EndIf
                              EndIf
                        EndIf
                Next
      Next

      ; 解锁位图并释放资源
      _GDIPlus_BitmapUnlockBits($hSubBitmap, $tSubBitmapData)
      _GDIPlus_BitmapUnlockBits($hParBitmap, $tParBitmapData)
      _GDIPlus_BitmapDispose($hSubBitmap)
      _GDIPlus_BitmapDispose($hParBitmap)

      ; 报告搜索时间
      ConsoleWrite("搜索时间: " & TimerDiff($hTimer) & " 毫秒" & @CRLF)
      ConsoleWrite("找到 " & UBound($aPoints) & " 个匹配" & @CRLF)

      Return $aPoints
EndFunc   ;==>_FindPicture

; 24位BGR格式颜色比较函数
Func _ColorBGREqualBGR($iB1, $iG1, $iR1, $iB2, $iG2, $iR2, $iErrorRange)
      Return (Abs($iB1 - $iB2) <= $iErrorRange) And _
                        (Abs($iG1 - $iG2) <= $iErrorRange) And _
                        (Abs($iR1 - $iR2) <= $iErrorRange)
EndFunc   ;==>_ColorBGREqualBGR

; 检查点列表中是否已包含某个点(或在指定距离内的点)
Func _ListContainsPoint($aList, $iX, $iY, $iDistance)
      For $i = 0 To UBound($aList) - 1
                If Sqrt(($aList[$i] - $iX) ^ 2 + ($aList[$i] - $iY) ^ 2) <= $iDistance Then
                        Return True
                EndIf
      Next
      Return False
EndFunc   ;==>_ListContainsPoint



3131210 发表于 昨天 23:33

本帖最后由 3131210 于 2025-4-18 23:35 编辑

AU3 纯汇编找图 支持后台 模糊找图

效果非常好 速度可以到毫秒级别

重要的还是快    2500*1500的图片,只要16毫秒

使用方法是 先绑定句柄,然后要查找的图片通过 _LoadBMPPTR 按照指定格式写到内存,然后调用_FindPic 找图。有什么其他需求的可以自己改 逻辑已经很简单了


全程可以不生成任何缓存,速度极快

3131210 发表于 2025-4-5 12:24:58

本帖最后由 3131210 于 2025-4-5 12:28 编辑

再贴一个快速版本 但是还是不够快   上面提供的图片,能在1秒内找到,但是还是太慢了




; 高效率版本的找图函数
Func _FindPicture_Fast($sSubPic, $sParPic, $aSearchRect = Default, $iErrorRange = 0, $fMatchRate = 0.9, $bFindAll = False)
      Local $aPoints ; 存储结果的数组

      ; 加载图片
      Local $hSubBitmap = _GDIPlus_BitmapCreateFromFile($sSubPic)
      Local $hParBitmap = _GDIPlus_BitmapCreateFromFile($sParPic)

      ; 获取图片尺寸
      Local $iSubWidth = _GDIPlus_ImageGetWidth($hSubBitmap)
      Local $iSubHeight = _GDIPlus_ImageGetHeight($hSubBitmap)
      Local $iParWidth = _GDIPlus_ImageGetWidth($hParBitmap)
      Local $iParHeight = _GDIPlus_ImageGetHeight($hParBitmap)

      ; 确定搜索区域
      Local $iSearchX = 0, $iSearchY = 0, $iSearchWidth = $iParWidth, $iSearchHeight = $iParHeight
      If IsArray($aSearchRect) And UBound($aSearchRect) >= 4 Then
                $iSearchX = $aSearchRect
                $iSearchY = $aSearchRect
                $iSearchWidth = $aSearchRect
                $iSearchHeight = $aSearchRect
      EndIf

      ; 使用24位BGR格式锁定位图数据
      Local $tSubBitmapData = _GDIPlus_BitmapLockBits($hSubBitmap, 0, 0, $iSubWidth, $iSubHeight, $GDIP_ILMREAD, $GDIP_PXF24RGB)
      Local $tParBitmapData = _GDIPlus_BitmapLockBits($hParBitmap, 0, 0, $iParWidth, $iParHeight, $GDIP_ILMREAD, $GDIP_PXF24RGB)

      ; 获取扫描行宽度和指针
      Local $iSubStride = DllStructGetData($tSubBitmapData, "Stride")
      Local $pSubScan0 = DllStructGetData($tSubBitmapData, "Scan0")
      Local $iParStride = DllStructGetData($tParBitmapData, "Stride")
      Local $pParScan0 = DllStructGetData($tParBitmapData, "Scan0")

      ; 获取子图第一个像素颜色作为起始匹配点
      Local $tStartPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pSubScan0)
      Local $iStartB = DllStructGetData($tStartPixel, "B")
      Local $iStartG = DllStructGetData($tStartPixel, "G")
      Local $iStartR = DllStructGetData($tStartPixel, "R")

      ; 修改特征像素数组定义
      Local $aFeaturePoints ; - 5行5列
      $aFeaturePoints = 0
      $aFeaturePoints = 0
      $aFeaturePoints = $iStartR
      $aFeaturePoints = $iStartG
      $aFeaturePoints = $iStartB

      ; 中心点
      $aFeaturePoints = Int($iSubWidth / 2)
      $aFeaturePoints = Int($iSubHeight / 2)
      Local $pCenterPixel = $pSubScan0 + $aFeaturePoints * $iSubStride + $aFeaturePoints * 3
      Local $tCenterPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pCenterPixel)
      $aFeaturePoints = DllStructGetData($tCenterPixel, "R")
      $aFeaturePoints = DllStructGetData($tCenterPixel, "G")
      $aFeaturePoints = DllStructGetData($tCenterPixel, "B")

      ; 右下角
      $aFeaturePoints = $iSubWidth - 1
      $aFeaturePoints = $iSubHeight - 1
      Local $pCornerPixel = $pSubScan0 + $aFeaturePoints * $iSubStride + $aFeaturePoints * 3
      Local $tCornerPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pCornerPixel)
      $aFeaturePoints = DllStructGetData($tCornerPixel, "R")
      $aFeaturePoints = DllStructGetData($tCornerPixel, "G")
      $aFeaturePoints = DllStructGetData($tCornerPixel, "B")

      ; 左下角
      $aFeaturePoints = 0
      $aFeaturePoints = $iSubHeight - 1
      Local $pBottomLeftPixel = $pSubScan0 + $aFeaturePoints * $iSubStride + $aFeaturePoints * 3
      Local $tBottomLeftPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pBottomLeftPixel)
      $aFeaturePoints = DllStructGetData($tBottomLeftPixel, "R")
      $aFeaturePoints = DllStructGetData($tBottomLeftPixel, "G")
      $aFeaturePoints = DllStructGetData($tBottomLeftPixel, "B")

      ; 右上角
      $aFeaturePoints = $iSubWidth - 1
      $aFeaturePoints = 0
      Local $pTopRightPixel = $pSubScan0 + $aFeaturePoints * $iSubStride + $aFeaturePoints * 3
      Local $tTopRightPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pTopRightPixel)
      $aFeaturePoints = DllStructGetData($tTopRightPixel, "R")
      $aFeaturePoints = DllStructGetData($tTopRightPixel, "G")
      $aFeaturePoints = DllStructGetData($tTopRightPixel, "B")

      ; 优化2: 采用跳跃式扫描 - 先每隔几个像素检查一次
      Local $iStepSize = 4 ; 可以根据图像大小调整

      ; 计算搜索范围
      Local $iMaxY = $iSearchY + $iSearchHeight - $iSubHeight
      Local $iMaxX = $iSearchX + $iSearchWidth - $iSubWidth

      ; 开始计时
      Local $hTimer = TimerInit()

      ; 开始搜索
      ConsoleWrite("开始快速搜索..." & @CRLF)

      ; 第一阶段:快速跳跃扫描
      Local $aCandidates ; 存储候选点
      For $i = $iSearchY To $iMaxY Step $iStepSize
                For $j = $iSearchX To $iMaxX Step $iStepSize
                        ; 检查特征点是否匹配
                        Local $bFeatureMatch = True

                        For $f = 0 To UBound($aFeaturePoints) - 1
                              Local $fx = $aFeaturePoints[$f]
                              Local $fy = $aFeaturePoints[$f]
                              Local $fR = $aFeaturePoints[$f]
                              Local $fG = $aFeaturePoints[$f]
                              Local $fB = $aFeaturePoints[$f]

                              Local $px = $j + $fx
                              Local $py = $i + $fy

                              ; 检查特征点坐标是否在有效范围内
                              If $px >= 0 And $px < $iParWidth And $py >= 0 And $py < $iParHeight Then
                                        Local $pParPixel = $pParScan0 + $py * $iParStride + $px * 3
                                        Local $tParPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pParPixel)
                                        Local $pR = DllStructGetData($tParPixel, "R")
                                        Local $pG = DllStructGetData($tParPixel, "G")
                                        Local $pB = DllStructGetData($tParPixel, "B")

                                        If Not _ColorBGREqualBGR($pB, $pG, $pR, $fB, $fG, $fR, $iErrorRange) Then
                                                $bFeatureMatch = False
                                                ExitLoop
                                        EndIf
                              Else
                                        $bFeatureMatch = False
                                        ExitLoop
                              EndIf
                        Next

                        ; 如果特征点匹配,加入候选列表
                        If $bFeatureMatch Then
                              ReDim $aCandidates
                              $aCandidates = $j
                              $aCandidates = $i
                        EndIf
                Next
      Next

      ConsoleWrite("找到 " & UBound($aCandidates) & " 个候选位置" & @CRLF)

      ; 第二阶段:详细检查候选点
      For $c = 0 To UBound($aCandidates) - 1
                Local $j = $aCandidates[$c]
                Local $i = $aCandidates[$c]

                ; 更精确地检查候选区域周围的像素
                For $offsetY = -$iStepSize + 1 To 0
                        For $offsetX = -$iStepSize + 1 To 0
                              Local $checkX = $j + $offsetX
                              Local $checkY = $i + $offsetY

                              ; 确保在搜索范围内
                              If $checkX >= $iSearchX And $checkX <= $iMaxX And $checkY >= $iSearchY And $checkY <= $iMaxY Then
                                        ; 获取父图当前位置的像素
                                        Local $pParPixel = $pParScan0 + $checkY * $iParStride + $checkX * 3
                                        Local $tParPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pParPixel)
                                        Local $iParB = DllStructGetData($tParPixel, "B")
                                        Local $iParG = DllStructGetData($tParPixel, "G")
                                        Local $iParR = DllStructGetData($tParPixel, "R")

                                        ; 检查起始像素是否匹配
                                        If _ColorBGREqualBGR($iParB, $iParG, $iParR, $iStartB, $iStartG, $iStartR, $iErrorRange) Then
                                                ; 优化3: 采样匹配 - 不检查所有像素,只检查部分
                                                Local $iSampleStep = 2 ; 可以根据需要调整
                                                Local $iSum = 0 ; 总采样数
                                                Local $iMatch = 0 ; 匹配的采样数

                                                For $m = 0 To $iSubHeight - 1 Step $iSampleStep
                                                      For $n = 0 To $iSubWidth - 1 Step $iSampleStep
                                                                ; 子图像素位置
                                                                Local $pSubPixel = $pSubScan0 + $m * $iSubStride + $n * 3
                                                                Local $tSubPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pSubPixel)
                                                                Local $iSubB = DllStructGetData($tSubPixel, "B")
                                                                Local $iSubG = DllStructGetData($tSubPixel, "G")
                                                                Local $iSubR = DllStructGetData($tSubPixel, "R")

                                                                ; 对应的父图像素位置
                                                                Local $y2 = $checkY + $m
                                                                Local $x2 = $checkX + $n

                                                                ; 确保在父图范围内
                                                                If $x2 < $iParWidth And $y2 < $iParHeight Then
                                                                        Local $pParRelPixel = $pParScan0 + $y2 * $iParStride + $x2 * 3
                                                                        Local $tParRelPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pParRelPixel)
                                                                        Local $iParRelB = DllStructGetData($tParRelPixel, "B")
                                                                        Local $iParRelG = DllStructGetData($tParRelPixel, "G")
                                                                        Local $iParRelR = DllStructGetData($tParRelPixel, "R")

                                                                        $iSum += 1

                                                                        ; 比较颜色
                                                                        If _ColorBGREqualBGR($iParRelB, $iParRelG, $iParRelR, $iSubB, $iSubG, $iSubR, $iErrorRange) Then
                                                                              $iMatch += 1
                                                                        EndIf
                                                                EndIf
                                                      Next
                                                Next

                                                ; 如果采样匹配率高,进行全像素匹配
                                                If $iSum > 0 And $iMatch / $iSum >= $fMatchRate Then
                                                      $iSum = 0
                                                      $iMatch = 0

                                                      For $m = 0 To $iSubHeight - 1
                                                                For $n = 0 To $iSubWidth - 1
                                                                        ; 子图像素位置
                                                                        Local $pSubPixel = $pSubScan0 + $m * $iSubStride + $n * 3
                                                                        Local $tSubPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pSubPixel)
                                                                        Local $iSubB = DllStructGetData($tSubPixel, "B")
                                                                        Local $iSubG = DllStructGetData($tSubPixel, "G")
                                                                        Local $iSubR = DllStructGetData($tSubPixel, "R")

                                                                        ; 对应的父图像素位置
                                                                        Local $y2 = $checkY + $m
                                                                        Local $x2 = $checkX + $n
                                                                        Local $pParRelPixel = $pParScan0 + $y2 * $iParStride + $x2 * 3
                                                                        Local $tParRelPixel = DllStructCreate("BYTE B;BYTE G;BYTE R", $pParRelPixel)
                                                                        Local $iParRelB = DllStructGetData($tParRelPixel, "B")
                                                                        Local $iParRelG = DllStructGetData($tParRelPixel, "G")
                                                                        Local $iParRelR = DllStructGetData($tParRelPixel, "R")

                                                                        $iSum += 1

                                                                        ; 比较颜色
                                                                        If _ColorBGREqualBGR($iParRelB, $iParRelG, $iParRelR, $iSubB, $iSubG, $iSubR, $iErrorRange) Then
                                                                              $iMatch += 1
                                                                        EndIf
                                                                Next
                                                      Next

                                                      ; 计算匹配率
                                                      Local $fCurrentMatch = $iMatch / $iSum

                                                      ; 如果匹配率超过阈值,添加到结果
                                                      If $fCurrentMatch >= $fMatchRate Then
                                                                ConsoleWrite("找到匹配点(左上角): X=" & $checkX & ", Y=" & $checkY & ", 匹配率: " & $fCurrentMatch & @CRLF)

                                                                ; 检查是否已存在相似的点(避免重复)
                                                                If Not _ListContainsPoint($aPoints, $checkX, $checkY, 10) Then
                                                                        ReDim $aPoints
                                                                        $aPoints = $checkX
                                                                        $aPoints = $checkY
                                                                EndIf

                                                                ; 如果不需要找所有匹配,直接退出
                                                                If Not $bFindAll Then
                                                                        ExitLoop 3
                                                                EndIf
                                                      EndIf
                                                EndIf
                                        EndIf
                              EndIf
                        Next
                Next
      Next

      ; 解锁位图并释放资源
      _GDIPlus_BitmapUnlockBits($hSubBitmap, $tSubBitmapData)
      _GDIPlus_BitmapUnlockBits($hParBitmap, $tParBitmapData)
      _GDIPlus_BitmapDispose($hSubBitmap)
      _GDIPlus_BitmapDispose($hParBitmap)

      ; 报告搜索时间
      ConsoleWrite("搜索时间: " & TimerDiff($hTimer) & " 毫秒" & @CRLF)
      ConsoleWrite("找到 " & UBound($aPoints) & " 个匹配" & @CRLF)

      Return $aPoints
EndFunc   ;==>_FindPicture_Fast

kemyliu 发表于 2025-4-7 08:30:04

阿福找图你值得拥有!!
例子:
$a1Result = search_pic(0,0,@DesktopWidth - 1,@DesktopHeight - 1,@ScriptDir & "\system\SAP\Input1.png")
                                If $a1Result<>"" Then
                                        $Mouse=StringSplit ($a1Result,",",2)
                                        MouseClick('left',$Mouse+10,$Mouse+5)
                                        Sleep(500)
                              endif

#include <GdiPlus.au3>
;#include <myOcrFunc.au3>
#include <ScreenCapture.au3>
#include <Clipboard.au3>

Global $x1,$y1,$x2,$y2,$pic,$aPosMsg

Func search_pic($x1,$y1,$x2,$y2,$pic,$type=0) ;当前屏幕找图,说明:$x1:屏幕上的左上角X坐标,$y1:屏幕上的左上角Y坐标,$x2:屏幕上的右下角X坐标,$y2:屏幕上的右下角Y坐标,$pic:要找图的路径及名称,$aPosMsg:返回坐标值(X坐标,Y坐标,长,高)
        _GDIPlus_Startup ()
        $s_dir = @ScriptDir
        If $type==0 Then
                _ScreenCapture_Capture ( $s_dir & "\Source.bmp",$x1,$y1,$x2,$y2 )
                ConsoleWrite("X1="&$x1&@CRLF&"X2="&$x2&@CRLF&"Y1="&$y1&@CRLF&"Y2="&$y1&@CRLF)
                $hBitmap1 = _GDIPlus_BitmapCreateFromFile($s_dir & "\Source.bmp")
        Else
                ClipPut("")
                Send("{PRINTSCREEN}")
                $Timer = TimerInit()
                While TimerDiff($Timer) < 1000
                        _ClipBoard_Open(0)
                        $hBitmap = _ClipBoard_GetDataEx($CF_BITMAP)
                        _ClipBoard_Close()
                        If $hBitmap Then ExitLoop
                        Sleep(10)
                WEnd
                $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
                _GDIPlus_ImageSaveToFile($hImage, $s_dir & "\Source.bmp")
                $hBitmap1 = _GDIPlus_BitmapCreateFromFile($s_dir & "\Source.bmp")
        EndIf
        $array1 = _myReadBitmapMsg($hBitmap1, 1)
        $search_pic=$pic
        $hBitmap2 = _GDIPlus_BitmapCreateFromFile($search_pic)
        $array2 = _myReadBitmapMsg($hBitmap2, 1)
       
        $iMax = _GDIPlus_ImageGetWidth ($hBitmap1) / _GDIPlus_ImageGetWidth ($hBitmap2)
       
       $t=TimerInit()
       $aPosMsg = _ArrayComp($array1, $array2, False, $iMax)
       ;ConsoleWrite("找到一个图片块用去时间:"&TimerDiff($t)&'毫秒,位置信息(为空未找到):'&$aPosMsg&@CRLF)
       
        ;$t=TimerInit()
        ;$aPosMsg = _ArrayComp($array1, $array2, True, $iMax)
        ;ConsoleWrite("找到所有图片块用去时间:"&TimerDiff($t)&'毫秒,位置信息(为空未找到):'&$aPosMsg&@CRLF)
       
        ;~ If $aPosMsg<>"" Then
        ;~         Local $aPos, $i, $hGraphics = _GDIPlus_ImageGetGraphicsContext ($hBitmap1)
        ;~         $aPosMsg = StringSplit($aPosMsg,"|",2)
        ;~         For $i = 0 To UBound($aPosMsg)-1
        ;~               $aPos = StringSplit($aPosMsg[$i],",",2)
        ;~               _GDIPlus_GraphicsDrawRect($hGraphics, $aPos, $aPos, $aPos, $aPos)
        ;~         Next
        ;~         ;_GDIPlus_ImageSaveToFile($hBitmap1, $s_dir&"\Target.bmp")
        ;~         _GDIPlus_GraphicsDispose ($hGraphics)
        ;~ EndIf
        _GDIPlus_ImageDispose ($hBitmap1)
        _WinAPI_DeleteObject ($hBitmap1)
        _GDIPlus_ImageDispose ($hBitmap2)
        _WinAPI_DeleteObject ($hBitmap2)
        _GDIPlus_ShutDown ()
        Return $aPosMsg
        Exit
EndFunc        
        ;一般来说,当$hBitmap2是小图时$iType=1, 较大时$iType=0, 如果已知$array2哪个元素进行搜索比较合理,直接指定为$iY
Func _ArrayComp($array1, $array2, $SearchAll=False, $iMax=0, $iY=0, $iType=0)
        Local $iExtended=0
        If $iMax>0 And $iY=0 Then
                Local $t=TimerInit()
                Local $sBmpData1 = ""
                For $i = 0 To UBound($array1)-1;相当于_ArrayToString或_myReadBitmapMsg($hBitmap,0),但更快
                        $sBmpData1 &= $array1[$i]
                Next;===>当多个$array2搜索时,这个内容考虑在udf外执行,_ArrayComp($sBmpData1, $array1, $array2, $SearchAll=False, $iMax=0, $iY=0, $iType=0)
                For $i = 0 To UBound($array2)-1
                        If StringReplace($array2[$i], StringLeft($array2[$i],6),"")="" Then ContinueLoop
                        Select
                                Case $iType = 0
                                        $iY = $i
                                        ExitLoop
                                #cs
                                Case $iType = 1 And Not @AutoItX64 ;pusofalse提供的多线程方法
                                        ;该方法中映射文件到内容部分 $pBaseAddress 暂用本段代替
                                        Local $tBuff = DllStructCreate("char ["&StringLen($sBmpData1)+1&"]")
                                        DllStructSetData($tBuff, 1, $sBmpData1)
                                        $pBaseAddress = DllStructGetPtr($tBuff)
                                        ;http://www.autoitx.com/thread-20592-1-3.html
                                #ce
                                Case Else
                                        StringReplace($sBmpData1,$array2[$i],"",0, 1)
                                        If $iExtended=0 Or $iExtended>@extended Then
                                                $iExtended=@extended
                                                If $iExtended=0 Then Return "";没有匹配的图块
                                                $iY = $i
                                                If $iExtended<=$iMax Then ExitLoop
                                        EndIf
                        EndSelect
                Next
                ;ConsoleWrite("获取最佳搜索串"&TimerDiff($t)&','&$iExtended&@CRLF)
        EndIf
        ;Local $t=TimerInit()
        If UBound($array1)<UBound($array2) Then Return ""
        Local $s_re="", $y, $y2, $iW2=StringLen($array2[$iY]), $iPos;, $iSearchPos
        For $y = $iy To UBound($array1)-1
                $iPos = 0;$iSearchPos = 1
                While $y+UBound($array2)<=UBound($array1)
                        $iPos = StringInStr($array1[$y], $array2[$iY], 1, 1, $iPos+1);$iPos = StringInStr($array1[$y], $array2[$iY], 1, 1, $iSearchPos)
                        Select
                                Case $iPos = 0
                                        ContinueLoop(2)
                                Case Mod($iPos-1,6)<>0 ;Or $y<$iy
                                        ;$iSearchPos = $iPos+1
                                        ContinueLoop
                        EndSelect
                        For $y2 = $iY To UBound($array2)-1
                                If StringMid($array1[$y+$y2-$iy], $iPos, $iW2)<>$array2[$y2] Then
                                        ;$iSearchPos = $iPos+1
                                        ContinueLoop(2)
                                EndIf
                        Next
                        For $y2 = 0 To $iY-1
                                If StringMid($array1[$y+$y2-$iy], $iPos, $iW2)<>$array2[$y2] Then
                                        ;$iSearchPos = $iPos+1
                                        ContinueLoop(2)
                                EndIf
                        Next
                        $s_re &= ($iPos-1)/6&','&$y-$iy&','&$iW2/6&','&UBound($array2)&"|"
                        StringReplace($s_re,"|","")
                        If (Not $SearchAll) Or ($iExtended>0 And @extended>=$iExtended) Then ExitLoop(2)
                        ;$iSearchPos = $iPos+1
                WEnd
        Next
        If StringRight($s_re,1)="|" Then $s_re = StringTrimRight($s_re,1)
        ;ConsoleWrite(TimerDiff($t)&@CRLF);18
        Return $s_re
EndFunc
       
Func _myReadBitmapMsg($hBitmap, $iType=1);
        Local $aBmpData
        $aBmpData = _GDIPlus_ImageGetWidth ($hBitmap)
        $aBmpData = _GDIPlus_ImageGetHeight ($hBitmap)
        Local $BitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $aBmpData, $aBmpData, $GDIP_ILMREAD, $GDIP_PXF24RGB)
        $aBmpData = Abs(DllStructGetData($BitmapData, "Stride"))
        $aBmpData = DllStructGetData($BitmapData, "Scan0");
        _GDIPlus_BitmapUnlockBits($hBitmap, $BitmapData)
        Local $tBuff, $iH
        Switch $iType;已测试比StringRegExp快
                Case -1
                        Return $aBmpData
                Case 0
                        For $iH = 1 To $aBmpData
                                $tBuff = DllStructCreate("byte[" & ($aBmpData*3) & "]", $aBmpData + ($iH-1)*$aBmpData)
                                $aBmpData &= StringTrimLeft(DllStructGetData($tBuff, 1),2)
                        Next
                        Return $aBmpData
                Case Else
                        Local $aRet[$aBmpData]
                        For $iH = 1 To $aBmpData
                                $tBuff = DllStructCreate("byte[" & ($aBmpData*3) & "]", $aBmpData + ($iH-1)*$aBmpData)
                                $aRet[$iH-1] = StringTrimLeft(DllStructGetData($tBuff, 1), 2)
                        Next
                        Return $aRet
        EndSwitch
EndFunc

afan 发表于 2025-4-7 09:23:36

模糊找图... Au3单线程干这事不会快

3131210 发表于 2025-4-7 14:18:14

kemyliu 发表于 2025-4-7 08:30
阿福找图你值得拥有!!
例子:
$a1Result = search_pic(0,0,@DesktopWidth - 1,@DesktopHeight - 1,@Scrip ...

阿福是只能1比1找图,不能有半点误差啊

3131210 发表于 2025-4-7 14:19:20

afan 发表于 2025-4-7 09:23
模糊找图... Au3单线程干这事不会快

那估计得有汇编大神,通过汇编开启多线程才能追得上其他语言的步伐了

msold5 发表于 7 天前

好像听说按键精灵有DLL调用速度好像还可以,我以前试的时候感觉也不快,但不知现在的效果怎么样了

echo88 发表于 6 天前

试试这个UDF:
_ImageSearch_UDF.au3

3131210 发表于 5 天前

echo88 发表于 2025-4-13 16:45
试试这个UDF:
_ImageSearch_UDF.au3

这个效率很低 而且不支持后台和窗口句柄的截图对比 不灵活

繁星 发表于 3 天前

本帖最后由 繁星 于 2025-4-16 02:49 编辑

试试我写的这个库,不喜欢带库可以从内存加载,你提供的实例图片找到5毫秒,我自己测试4K图片找个地方截个小图找到也就50毫秒


3131210 发表于 前天 07:23

好像WIN11用不了




zhaoceshi 发表于 前天 09:28

3131210 发表于 2025-4-17 07:23
好像WIN11用不了

我win11运行了,没有报错。返回Found 1: X=268   Y=31    Conf=100.00% Time=2.35ms

繁星 发表于 前天 23:15

3131210 发表于 2025-4-17 07:23
好像WIN11用不了

vc运行库https://aka.ms/vs/17/release/vc_redist.x64.exe
页: [1]
查看完整版本: 【已解决】纯AU3模糊找图,求帮忙提高效率 汇编找图 模糊找图 后台找图