Что нового

Поиск изображений BMP

mr.Gbabak

Осваивающий
Сообщения
257
Репутация
23
т.к. в настоящее время не существует поиска изображений с небольшими вариациями (изменение оттенка отдельных пикселей), то решил попробовать склеить вместе два способа.

Имеем изображение на экране : темный фон и белый текст (это игра, поэтому оттенки некоторых пикселей могут изменяться). Поэтому BMPsearch.au3 работает не стабильно.
Поэтому была модифицирована картинка для поиска. В ней осталось два цвета пикселей: черный (0x000000) и зеленый (0x00FF00).
Далее делаем скриншот участка окна, также модифицируем окно, оставляя (точнее заменяя), все светлые пиксели на зеленый цвет, а все темные на черный цвет.
После этого уже используем библиотеку BMPsearch.au3

Темный фон на экране может отличаться по яркости (чуть-темнее, чуть светлее), на подготовленных изображениях разницы нет, но поиск уже не работает.

Подготовка файла шаблона:
Код:
Func _modfile($picture)
    $__g_iBMPFormat = $GDIP_PXF04INDEXED
    _GDIPlus_Startup()
    $hImage = _GDIPlus_ImageLoadFromFile($picture)
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    $hClone = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iW, $iH, $__g_iBMPFormat)
    $tBits = _GDIPlus_BitmapLockBits($hClone, 0, 0, $iW, $iH, BitOR($GDIP_ILMWRITE, $GDIP_ILMREAD))
    $iScan0 = DllStructGetData($tBits, "Scan0")
    $tPixel = DllStructCreate("int[" & $iW * $iH & "];", $iScan0)
    For $iY = 0 To $iH - 1
        $iOffset = $iY * $iW + 1
        For $iX = 0 To $iW - 1
            $iColor = DllStructGetData($tPixel, 1, $iOffset + $iX)
            $iR = BitAND(BitShift($iColor, 16), 0xFF)
            $iG = BitAND(BitShift($iColor, 8), 0xFF)
            $iB = BitAND($iColor, 0xFF)
            If $iR > 70 And $iG > 70 And $iB > 70 Then DllStructSetData($tPixel, 1, 0x00FF00, $iOffset + $iX)
            If $iR <= 70 And $iG <= 70 And $iB <= 70 Then DllStructSetData($tPixel, 1, 0x000000, $iOffset + $iX)
        Next
    Next
    _GDIPlus_BitmapUnlockBits($hClone, $tBits)
    _GDIPlus_ImageSaveToFile($hClone, 'images\temp.bmp')
    _GDIPlus_ImageDispose($hClone)
    _GDIPlus_Shutdown()
EndFunc   ;==>_modfile


Собственно сам поиск:
Код:
Func _search ($picture, $x1, $y1, $x2, $y2)
$__g_iBMPFormat = $GDIP_PXF04INDEXED
    _GDIPlus_Startup()
    $hBitmap = _ScreenCapture_CaptureWnd('', WinGetHandle($Win), $x1, $y1, $x2, $y2)

    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    $hClone = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iW, $iH, $__g_iBMPFormat)

    $tBits = _GDIPlus_BitmapLockBits($hClone, 0, 0, $iW, $iH, BitOR($GDIP_ILMWRITE, $GDIP_ILMREAD))
    $iScan0 = DllStructGetData($tBits, "Scan0")
    $tPixel = DllStructCreate("int[" & $iW * $iH & "];", $iScan0)
    For $iY = 0 To $iH - 1
        $iOffset = $iY * $iW + 1
        For $iX = 0 To $iW - 1
            $iColor = DllStructGetData($tPixel, 1, $iOffset + $iX)
            $iR = BitAND(BitShift($iColor, 16), 0xFF)
            $iG = BitAND(BitShift($iColor, 8), 0xFF)
            $iB = BitAND($iColor, 0xFF)
            If $iR > 90 And $iG > 90 And $iB > 90 Then DllStructSetData($tPixel, 1, 0x00FF00, $iOffset + $iX)
            If $iR <= 90 And $iG <= 90 And $iB <= 90 Then DllStructSetData($tPixel, 1, 0x000000, $iOffset + $iX)
        Next
    Next
    _GDIPlus_BitmapUnlockBits($hClone, $tBits)
    ;_GDIPlus_ImageSaveToFile($hClone, "images\temp.bmp")
    $hSource = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hClone)
    ;_GDIPlus_ImageDispose($hClone)
    ;_GDIPlus_Shutdown()
    $hBmp = _GDIPlus_BitmapCreateFromFile($picture)
    $hFind = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp)

    $aCoords = _BmpSearch($hSource, $hFind, 5)
    If @error Then
        ConsoleWrite("Ne naydeno" & @CRLF)
        _WinAPI_DeleteObject($hBitmap)
        _WinAPI_DeleteObject($hFind)
        _GDIPlus_Shutdown()
        Return SetError(-1)
    Else
        Local $coord[2]
        $coord[0] = $aCoords[1][2] - 1 + $x1
        $coord[1] = $aCoords[1][3] - 33 + $y1
        ConsoleWrite("X:" & $coord[0] & " Y:" & $coord[1] & " time:" & @extended & @CRLF)
        _WinAPI_DeleteObject($hBitmap)
        _WinAPI_DeleteObject($hFind)
        _GDIPlus_Shutdown()
        Return $coord
    EndIf
EndFunc


Поиск происходит в области
temp.bmp
файл 1.bmp находит
файл 2.bmp не находит.
Сообщение автоматически объединено:

Как всегда, после описания проблемы, пришло озарение.
Тема закрыта.
Модераторы, удалите тему.
 

Вложения

  • images.zip
    2.9 КБ · Просмотры: 13
Последнее редактирование:

InnI

AutoIT Гуру
Сообщения
4,922
Репутация
1,432
в настоящее время не существует поиска изображений с небольшими вариациями (изменение оттенка отдельных пикселей)
Ну, почему же... Есть некая ImageSearch.dll с одноимённой UDF, позволяющая искать с допуском цвета. Только их много разных версий и не все работают. Но найти рабочую можно даже на этом форуме.
Кстати, вот на днях выложили очередную вариацию на тему
Я попробовал - не заработала. Разбираться не стал - удалил. Но, может у вас получится разобраться.
 

Cytrus

Новичок
Сообщения
110
Репутация
3
Сколько в одном пикселе байт? Три байта. RGB. Какие вариации? Какие оттенки?
Имеется ввиду цветные изображения.
Или вы работаете с чёрно-белыми изображениями?
 

InnI

AutoIT Гуру
Сообщения
4,922
Репутация
1,432
Сколько в одном пикселе байт? Три байта. RGB.
Ну, вообще-то, четыре: ARGB. Хотя, конечно, бывают картинки, определяемые собственной палитрой... но не в этом случае.

Какие вариации? Какие оттенки?
Сохраните одну и ту же картинку (например, из буфера обмена) в формате BMP и JPG. Теперь сравните файлы попиксельно и посмотрите на вариации и оттенки.
 
Последнее редактирование:

Cytrus

Новичок
Сообщения
110
Репутация
3
Мне кажется, что это не вариации, а потеря качества для JPEG-файла. Меньше пикселей на дюйм. DPI.
 

InnI

AutoIT Гуру
Сообщения
4,922
Репутация
1,432
потеря качества для JPEG-файла. Меньше пикселей на дюйм. DPI.
Вы бы википедию почитали за счёт чего у JPG качество ухудшается. Тогда больше будет уверенности и меньше будет казаться...
 
Автор
M

mr.Gbabak

Осваивающий
Сообщения
257
Репутация
23
Может кому интересно будет...
Написал скрипт на Python + Opencv, позволяет найти все похожие изображения. (Уточню: похожие т.е. с небольшими вариациями в цветах и оттенках отдельных пикселей! Это не значит, что если изменить размер картинки, перекрасить ее, повернуть то он ее найдет) В моем случае же нужен поиск только одного совпадения, поэтому возвращает координаты последнего найденного.
Позволяет найти картинку с допуском.

Для работы скрипта нужен установленный Python.
Код для Autoit (производит запуск python скрипта и чтение результата из консоли)
P/S скрипт не расчесан, не является UDF , т.к. писал исключительно для себя в академических целях.
Код:
;#include <Array.au3>
;#include <Constants.au3>
$image = 'search.bmp'
search_python($image)

Func search_python($nFail)
    $sPath = ' search.py ' & @ScriptDir & '/images/' & $nFail
    $sPath1 = 'C:\Users\Andrey\AppData\Local\Programs\Python\Python36-32\python.exe'
    $hTimer = TimerInit()
    $iPID = Run($sPath1 & $sPath, @ScriptDir, @SW_HIDE, $STDOUT_CHILD)
    If @error Then
        ConsoleWrite(@CR & 'ERROR1')
    EndIf
    $sStdOutRead = ''
    While 1
        $sStdOutRead &= StdoutRead($iPID)
        If @error Then ExitLoop
    WEnd
    $iDiff = TimerDiff($hTimer)

    ConsoleWrite(@CR & $sStdOutRead)
    $coord = StringSplit($sStdOutRead, ' ', 2)
    If @error Then Return SetError(-1)
    ConsoleWrite(@CR & 'Spead : ' & $iDiff & @CR)
    Return $coord
EndFunc   ;==>search_python


код для Python
Код:
import subprocess
import sys
import argparse
import numpy as np
import pyautogui
import cv2 # Импортируем модуль OpenCV (cv2) под именем cv


def createParser ():
    parser = argparse.ArgumentParser()
    parser.add_argument ('name', nargs='?')

    return parser

if __name__ == '__main__':
    parser = createParser()
    namespace = parser.parse_args()

    if namespace.name:
        shablon_img = format (namespace.name)
    #    print("Привет, {}!".format(namespace.name))
     #   print (shablon_img)

    else:
        print ("@error")

#shablon_img= 'C:/Users/Andrey/Desktop/virtual/FW_Mission/images/vybrannyj_object.bmp'

def Opredelenie_coordinat(shablon):
    image = pyautogui.screenshot()
    img_bgr = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)

    #img_bgr = cv2.imread(cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR))
    img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

    #output = subprocess.check_output('ipconfig')
    #print (output)
    template = cv2.imread(shablon,0)# Загружаем изображение
    w, h = template.shape[::-1]

    res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
    threshold = 0.9
    loc = np.where( res >= threshold)

    location = 0

    for pt in zip(*loc[::-1]):
     location +=1
     x=pt[0]
     y=pt[1]
     cv2.rectangle(img_bgr, pt, (pt[0]+w, pt[1]+h),(0,255,0),2)

    if location>0:
      print (x,y)
    else:
      print ('@error')
    #cv2.imshow('detected', img_bgr)
    #cv2.imshow('detected',imutils.resize(img_bgr, height = 650))
    #cv2.waitKey() # Ожидаем нажатия любой клавиши для

Opredelenie_coordinat(shablon_img)

Поиск картинки размером 98х8 пикселей, на экране 1920х1080 занимает 0.3 сек
 
Последнее редактирование:
Верх