找回密码
 加入
搜索
查看: 153|回复: 10

[效率算法] 【未解决】纯AU3模糊找图,求帮忙提高效率

[复制链接]
发表于 2025-4-5 12:13:23 | 显示全部楼层 |阅读模式
本帖最后由 3131210 于 2025-4-5 12:28 编辑

关于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 = [100, 100, 200, 200] ; x, y, width, height
;~ $aResult = _FindPicture("sub.bmp", "parent.bmp", $aSearchRect, 0, 1.0, False)

_GDIPlus_Shutdown()

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

        ; 加载图片 - 先用默认格式加载
        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[0]
                $iSearchY = $aSearchRect[1]
                $iSearchWidth = $aSearchRect[2]
                $iSearchHeight = $aSearchRect[3]
        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[UBound($aPoints) + 1][2]
                                                $aPoints[UBound($aPoints) - 1][0] = $iPointX
                                                $aPoints[UBound($aPoints) - 1][1] = $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][0] - $iX) ^ 2 + ($aList[$i][1] - $iY) ^ 2) <= $iDistance Then
                        Return True
                EndIf
        Next
        Return False
EndFunc   ;==>_ListContainsPoint


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
 楼主| 发表于 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[0][2] ; 存储结果的数组

        ; 加载图片
        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[0]
                $iSearchY = $aSearchRect[1]
                $iSearchWidth = $aSearchRect[2]
                $iSearchHeight = $aSearchRect[3]
        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] ; [x, y, R, G, B] - 5行5列
        $aFeaturePoints[0][0] = 0
        $aFeaturePoints[0][1] = 0
        $aFeaturePoints[0][2] = $iStartR
        $aFeaturePoints[0][3] = $iStartG
        $aFeaturePoints[0][4] = $iStartB

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

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

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

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

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

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

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

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

        ; 第一阶段:快速跳跃扫描
        Local $aCandidates[0][2] ; 存储候选点
        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][0]
                                Local $fy = $aFeaturePoints[$f][1]
                                Local $fR = $aFeaturePoints[$f][2]
                                Local $fG = $aFeaturePoints[$f][3]
                                Local $fB = $aFeaturePoints[$f][4]

                                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[UBound($aCandidates) + 1][2]
                                $aCandidates[UBound($aCandidates) - 1][0] = $j
                                $aCandidates[UBound($aCandidates) - 1][1] = $i
                        EndIf
                Next
        Next

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

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

                ; 更精确地检查候选区域周围的像素
                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[UBound($aPoints) + 1][2]
                                                                        $aPoints[UBound($aPoints) - 1][0] = $checkX
                                                                        $aPoints[UBound($aPoints) - 1][1] = $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

发表于 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[0]+10,$Mouse[1]+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[0], $aPos[1], $aPos[2], $aPos[3])
        ;~         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)
                                        ;[url]http://www.autoitx.com/thread-20592-1-3.html[/url]
                                #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[5]
        $aBmpData[1] = _GDIPlus_ImageGetWidth ($hBitmap)
        $aBmpData[2] = _GDIPlus_ImageGetHeight ($hBitmap)
        Local $BitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $aBmpData[1], $aBmpData[2], $GDIP_ILMREAD, $GDIP_PXF24RGB)
        $aBmpData[3] = Abs(DllStructGetData($BitmapData, "Stride"))
        $aBmpData[4] = DllStructGetData($BitmapData, "Scan0");
        _GDIPlus_BitmapUnlockBits($hBitmap, $BitmapData)
        Local $tBuff, $iH
        Switch $iType;已测试比StringRegExp快
                Case -1
                        Return $aBmpData
                Case 0
                        For $iH = 1 To $aBmpData[2]
                                $tBuff = DllStructCreate("byte[" & ($aBmpData[1]*3) & "]", $aBmpData[4] + ($iH-1)*$aBmpData[3])
                                $aBmpData[0] &= StringTrimLeft(DllStructGetData($tBuff, 1),2)
                        Next
                        Return $aBmpData
                Case Else
                        Local $aRet[$aBmpData[2]]
                        For $iH = 1 To $aBmpData[2]
                                $tBuff = DllStructCreate("byte[" & ($aBmpData[1]*3) & "]", $aBmpData[4] + ($iH-1)*$aBmpData[3])
                                $aRet[$iH-1] = StringTrimLeft(DllStructGetData($tBuff, 1), 2)
                        Next
                        Return $aRet
        EndSwitch
EndFunc
发表于 2025-4-7 09:23:36 | 显示全部楼层
模糊找图... Au3单线程干这事不会快
 楼主| 发表于 2025-4-7 14:18:14 | 显示全部楼层
kemyliu 发表于 2025-4-7 08:30
阿福找图你值得拥有!!
例子:
$a1Result = search_pic(0,0,@DesktopWidth - 1,@DesktopHeight - 1,@Scrip ...

阿福是只能1比1找图,不能有半点误差啊
 楼主| 发表于 2025-4-7 14:19:20 | 显示全部楼层
afan 发表于 2025-4-7 09:23
模糊找图... Au3单线程干这事不会快

那估计得有汇编大神,通过汇编开启多线程才能追得上其他语言的步伐了
发表于 4 天前 | 显示全部楼层
好像听说按键精灵有DLL调用速度好像还可以,我以前试的时候感觉也不快,但不知现在的效果怎么样了
发表于 3 天前 | 显示全部楼层
试试这个UDF:
_ImageSearch_UDF.au3

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
 楼主| 发表于 前天 08:10 | 显示全部楼层
echo88 发表于 2025-4-13 16:45
试试这个UDF:
_ImageSearch_UDF.au3

这个效率很低 而且不支持后台和窗口句柄的截图对比 不灵活
发表于 20 小时前 | 显示全部楼层
本帖最后由 繁星 于 2025-4-16 02:49 编辑

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


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2025-4-16 22:36 , Processed in 0.097745 second(s), 21 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表