동일 이미지를 모두 찾는 멀티 이미지서치 예제 스크립트 입니다.

 

테스트 실행 GIF 이미지

 

[테스트 스크립트]

Test_멀티서치.ahk 파일을 다운로드한  'Ahk+ 전용 AutoHotkey.exe 파일'  위에 드래그해서 실행하세요.

멀티서치_테스트.zip
0.00MB

#SingleInstance Force

검색테이블 := "검색테이블.png"
검색이미지 := "검색이미지.png"

MsgBox, 이미지서치 테스트를 위해 '%검색테이블%' 이미지를`n그림판으로 열어야 합니다.
Run, mspaint.exe "%검색테이블%",,, pid

sleep, 100


if !pid {
  MsgBox, %검색테이블% 이미지를 그림판으로 여는데 실패했습니다.
  ExitApp
}
WinActivate, % "ahk_pid " pid
sleep, 300

;열려있는 그림판 윈도우에서 이미지 멀티서치 (반환 좌표는 찾은 이미지의 센터 좌표)
ImageSearchsx,sy, 0,0,800,800, *All *ResultCenter %검색이미지%, result
if ErrorLevel {
  MsgBox, 그림판 윈도우에서 '%검색이미지%' 이미지를 찾는데 실패하였습니다.
  ExitApp
}

;찾은 좌표 출력
loop % result.count
  text .= A_Index " : " result[A_Index].x "," result[A_Index].y "`n"
MsgBox % "그림판 윈도우에서 '" 검색이미지 "' 이미지를 " result.count "개 찾았습니다.`n`n" text

;그림판 윈도우에서 단축키를 이용해 채우기 툴 선택
WinActivate, % "ahk_pid " pid
Send, {Alt Down}h{Alt Up}
sleep, 100
Send, k

;찾은 좌표 마우스로 추적
loop % result.count
{
  MouseClick, Left, % result[A_Index].x, % result[A_Index].y
  sleep, 500
}
MsgBox, 멀티서치 테스트 완료

 

 

 

Posted by 와이로

텔레그램으로 메시지나 이미지를 전송하기 위한 스크립트 입니다.


(주의) 텔레그램에서 패치가 된건지 모르겠지만 현재 봇이 관리자인 채널로만 메시지 전송이 되고 개인 챗 아이디를 대상으로는 전송이 되지 않습니다.(2019-04-19)


전송결과확인 : http://t.me/telebottester



[테스트 스크립트]

Test_텔레그램이미지전송.ahk 파일을 다운로드한  'Ahk+ 전용 AutoHotkey.exe 파일'  위에 드래그해서 실행하세요.

Test_텔레그램이미지전송.zip


1. 텔레그램 메시지 전송용 봇 토큰은 메신저에서 'BotFather' 봇을 찾아 들어간 후 /newbot 명령을 입력해 생성할 수 있습니다.

 

2. 챗 아이디는 본인의 챗 아이디를 사용하거나 '@공개채널명'을 사용할 수 있습니다. 공개채널 사용시에는 1번 토큰 생성파트에서 생성한 봇을 해당 채널의 관리자로 임명한 상태여야 합니다.

 

   - 본인 챗 아이디 알아내는 법 : 메신저에서 'GetIDs Bot' 봇을 찾아 들어간 후

   /my_id 명령을 입력해 알아낼 수 있습니다.

 

   - 오픈채널에서 봇을 관리자로 초대 하는 법 : 오픈채널안에서 채널제목 터치 후

   설정 아이콘을 눌러 '채널 관리' 창으로 진입 후 관리자 메뉴의 '관리자 추가'를 눌러

   봇 이름을 찾아 초대 할 수 있습니다.

 

#SingleInstance Force

#include telegram.ahk


token := "830884232:AAFlwrJ5LSGM6pLBNjmMQtMj3ISboaDcVtg"

chat_id := "@telebottester"


;3. 메시지 전송

result := SendTelegramMessage(token, chat_id, "메시지 전송테스트 입니다.", "")

MsgBox % "텔레그램 메시지 " (result? "전송성공":"전송실패")


;4. 이미지 파일 전송

imageFile := "이미지.png"

result := SendTelegramMessage(token, chat_id, "전송이미지설명 파일전송", imageFile)

MsgBox % "텔레그램 이미지파일 " (result? "전송성공":"전송실패")


;5. 이미지 캡쳐 후 전송

ImageGet, hBitmap, 0,0,200,200,, *WH ;윈도우 스샷

result := SendTelegramMessage(token, chat_id, "전송이미지설명 캡쳐전송", hBitmap)

DllCall("DeleteObject", "UPtr",hBitmap)

MsgBox % "텔레그램 캡쳐이미지 " (result? "전송성공":"전송실패")


ExitApp



Posted by 와이로

특정 체크박스나 라디오버튼의 하위 콘트롤로 등록된 모든 콘트롤들을 일괄적으로 활성화시키거나 비활성 시키는 좀더 편한 방법을 찾다가 만든 유틸리티 입니다.



1. #include CGuiVLabelLink.ahk  헬퍼 클래스를 인클루드 시킵니다.


2. Gui, Add, Checkbox, vCheckA1 gCheckA1, 체크박스  처럼 v라벨과 g라벨의 이름이 동일해야 합니다.


3. GetGuiChildList(label, conValue) 사용자 함수를 생성합니다. 

- root 는 v라벨의 연결 상태를 반영한 오브젝트이며 노드는 체크박스나 라디오 박스만 사용해야 합니다.

- _CheckA3 이나 _CheckB3 처럼 라벨 이름 앞에 '_' 기호를 붙인 경우 하위 콘트롤의 활성화 동작을 역으로 수행합니다.

- CheckA2:{"":"show_hide"} 나 _CheckA3:{"":"show_hide"} 처럼 특정 노드에 'show_hide' 옵션을 넣을시 하위 콘트롤의 활성화 동작이 show/hide 동작을 수행합니다.


GetGuiChildList(label, conValue)

{

  static cls

  if !cls {

    ;주황색 부분을 현재 GUI상 콘트롤의 v라벨 연결 상태에 맞게 수정해야 합니다.

    root := {Check:{CheckA1:{}, CheckB1:{}}}

    root.Check.CheckA1 := {CheckA2:{"":"show_hide", _CheckA3:{"":"show_hide", CheckA4:{CheckA5:0}}}}

    root.Check.CheckB1 := {CheckB2:{_CheckB3:{CheckB4:{CheckB5:0}, CheckC1:{CheckC2:0}}}}

    cls := new CGuiVLabelLink(root)

  }

  return cls.GetGuiChildList(label, conValue)

}


4. g라벨 수행부에 아래 코드를 넣어주면 해당 콘트롤을 체크하거나 해제할때 하위 콘트롤을 활성/비활성 시킬 수 있습니다.

  GuiControlGet, conValue,, % A_ThisLabel

  for k,v in GetGuiChildList(A_ThisLabel, conValue)

    GuiControl, % v.cmd, % v.name



[테스트 스크립트]


Test_GUI콘트롤_일괄비활성.ahk 파일을 다운로드한  'Ahk+ 전용 AutoHotkey.exe 파일'  위에 드래그해서 실행하세요.

Test_GUI콘트롤_일괄비활성.zip


1. Test_GUI콘트롤_일괄비활성1.ahk


#SingleInstance, force

#include CGuiVLabelLink.ahk


;1. v라벨과 g라벨의 이름은 동일해야 합니다.

Gui, new

Gui, Add, Checkbox, xm     vCheck   gCheck  , 체크

Gui, Add, Checkbox, xm     vCheckA1 gCheckA1, 체크A1

Gui, Add, Checkbox, xp+70  vCheckA2 gCheckA2, 체크A2

Gui, Add, Checkbox, xp+70  vCheckA3 gCheckA3, 체크A3

Gui, Add, Checkbox, xp+70  vCheckA4 gCheckA4, 체크A4

Gui, Add, Checkbox, xp+70  vCheckA5 gCheckA5, 체크A5

Gui, Add, Checkbox, xm     vCheckB1 gCheckB1, 체크B1

Gui, Add, Checkbox, xp+70  vCheckB2 gCheckB2, 체크B2

Gui, Add, Checkbox, xp+70  vCheckB3 gCheckB3, 체크B3

Gui, Add, Checkbox, xp+70  vCheckB4 gCheckB4, 체크B4

Gui, Add, Checkbox, xp+70  vCheckB5 gCheckB5, 체크B5

Gui, Add, Checkbox, xm+140 vCheckC1 gCheckC1, 체크C1

Gui, Add, Checkbox, xm+140 vCheckC2 gCheckC2, 체크C2

Gui, Show


;3. GUI 생성 후 초기화 작업이며, 체크박스나 라디오버튼의 값에 따라 하위 콘트롤을 enable/disable 또는 show/hide 시킵니다.

  for k,v in GetGuiChildList("","")

    GuiControl, % v.cmd, % v.name

return


;2. v라벨 연결 상태를 반영한 오브젝트이며 노드는 체크박스나 라디오 박스만 사용해야 합니다.

;ㄴ _CheckA3 이나 _CheckB3 처럼 라벨 이름 앞에 '_' 기호를 붙인 경우 하위 콘트롤의 활성화 동작을 역으로 수행합니다.

;ㄴ CheckA2:{"":"show_hide"} 이나 _CheckA3:{"":"show_hide"} 처럼 특정 노드에 'show_hide' 옵션을 넣을시 하위 콘트롤의 활성화 동작이 show/hide 동작을 수행합니다.

GetGuiChildList(label, conValue)

{

  static cls

  if !cls {

    root := {Check:{CheckA1:{}, CheckB1:{}}}

    root.Check.CheckA1 := {CheckA2:{"":"show_hide", _CheckA3:{"":"show_hide", CheckA4:{CheckA5:0}}}}

    root.Check.CheckB1 := {CheckB2:{_CheckB3:{CheckB4:{CheckB5:0}, CheckC1:{CheckC2:0}}}}

    cls := new CGuiVLabelLink(root)

  }

  return cls.GetGuiChildList(label, conValue)

}


Check:

CheckA1:

CheckA2:

CheckA3:

CheckA4:

CheckA5:

CheckB1:

CheckB2:

CheckB3:

CheckB4:

CheckB5:

CheckC1:

CheckC2:

 

  GuiControlGet, conValue,, % A_ThisLabel

  for k,v in GetGuiChildList(A_ThisLabel, conValue)

    GuiControl, % v.cmd, % v.name

return



2. Test_GUI콘트롤_일괄비활성2.ahk


#SingleInstance, force
#include CGuiVLabelLink.ahk


;1. v라벨과 g라벨의 이름은 동일해야 합니다.
Gui, new
Gui, Add, Checkbox, xm         vCheck  gCheck   , 체크

Gui, Add, Checkbox, xp+70     vCheck1 gCheck1 , 선택1
Gui, Add, Text        , xp+70    vText1  gText1      , 에디트1
Gui, Add, Edit        , x+3 yp-3 vEdit1  gEdit1
Gui, Add, Text        , xm+140  vText2  gText2      , 에디트2
Gui, Add, Edit        , x+3 yp-3 vEdit2  gEdit2

Gui, Add, Checkbox, xm+70    vCheck2 gCheck2 , 선택2
Gui, Add, Text        , xp+70    vText3  gText3     , 에디트3
Gui, Add, Edit        , x+3 yp-3 vEdit3  gEdit3
Gui, Add, Text        , xm+140  vText4  gText4    , 에디트4
Gui, Add, Edit        , x+3 yp-3 vEdit4  gEdit4
Gui, Show

;3. GUI 생성 후 초기화 작업이며, 체크박스나 라디오버튼의 값에 따라 하위 콘트롤을 enable/disable 또는 show/hide 시킵니다.
  for k,v in GetGuiChildList("","")
    GuiControl, % v.cmd, % v.name
return

;2. v라벨 연결 상태를 반영한 오브젝트이며 노드는 체크박스나 라디오 박스만 사용해야 합니다.
;ㄴ _Check2 처럼 라벨 이름 앞에 '_' 기호를 붙일경우 하위 콘트롤의 활성화 동작을 역으로 수행합니다.
;ㄴ _Check2:{"":"show_hide"} 처럼 특정 노드에 'show_hide' 옵션을 넣을시 하위 콘트롤의 활성화 동작이 show/hide 동작을 수행합니다.
GetGuiChildList(label, conValue)
{
  static cls
  if !cls {
    root := {Check:{Check1:{}, _Check2:{}}}
    root.Check.Check1 := {Text1:0, Edit1:0, Text2:0, Edit2:0}
    root.Check._Check2 := {Text3:0, Edit3:0, Text4:0, Edit4:0, "":"show_hide"}
    cls := new CGuiVLabelLink(root)
  }
  return cls.GetGuiChildList(label, conValue)
}

Check:

Check1:
Text1:
Edit1:
Text2:
Edit2:

Check2:
Text3:
Edit3:
Text4:
Edit4:

  GuiControlGet, conValue,, % A_ThisLabel
  for k,v in GetGuiChildList(A_ThisLabel, conValue)
    GuiControl, % v.cmd, % v.name
return




Posted by 와이로

ADB shell screencap 명령으로 디바이스 내부에 별도이미지파일 저장없이 바로 HBITMAP 이미지로 가져오는 방법 (32비트 오토핫키용)


테스트 에뮬레이터 - [MOMO]앱플레이어




;--------------------------------------------------------------------

#SingleInstance Force

#include Gdip.ahk  ;https://autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/


;MCode Func

AdjustScreencapData := MCode("2,x86:VVdWU4tsJBSLRCQYjXQF/zn1d1ONfv6NTQGJ6usRZpCJyIPCAYhZ/4PBATnydyI51w+2GnbqgPsNdeWAegENdd8PtloCgPsKdBa7DQAAAOvPKehbXl9dw5CNtCYAAAAAiciDwgPrvjHA6+iQkJCQkA==")

ScreencapToDIB := MCode("2,x86:VVdWU4PsDItEJCiLdCQkhcB+fY0EtQAAAACLVCQsxwQkAAAAAMdEJAQAAAAA99iJRCQIi0QkKIPoAQ+vxo08goX2fjuLRCQgi0wkBDHbjSyIi0SdDInCweoQD7bKicIlAP8AAMHiEIHiAAD/AAnKCdCJBJ+DwwE53nXWAXQkBIMEJAEDfCQIiwQkOUQkKHWwg8QMW15fXcOQkJCQkJCQkA==")



^\::ExitApp


F1::

  RegRead, MomoDir, HKCU, Software\NOXGAMES\MOMO, InstallDir

  adb_path = %MomoDir%adb.exe

  Runwait, "%adb_path%" devices


  sCmd = "%adb_path%" -s "127.0.0.1:5555" shell screencap  ;127.0.0.1:5555 = MoMo 기본 앱플레이어

  if hBitmap := ADBScreenCapStdOutToHBitmap( sCmd )

  {

    SaveHBITMAPToFile(hBitmap, "_testImage.bmp")

    DllCall("DeleteObject", Ptr,hBitmap)

  }

  MsgBox, % hBitmap? "screen cap 이미지 추출성공":"실패"

return


;--------------------------------------------------------------------

;https://autohotkey.com/board/topic/96903-simplified-versions-of-seans-stdouttovar/

ADBScreenCapStdOutToHBitmap( sCmd ) {

  global AdjustScreencapData, ScreencapToDIB


  DllCall( "CreatePipe", UIntP,hPipeRead, UIntP,hPipeWrite, UInt,0, UInt,0 )

  DllCall( "SetHandleInformation", UInt,hPipeWrite, UInt,1, UInt,1 )


  VarSetCapacity( STARTUPINFO, 68,  0 )      ; STARTUPINFO          ;  http://goo.gl/fZf24

  NumPut( 68,         STARTUPINFO,  0 )      ; cbSize

  NumPut( 0x100,      STARTUPINFO, 44 )      ; dwFlags    =>  STARTF_USESTDHANDLES = 0x100 

  NumPut( hPipeWrite, STARTUPINFO, 60 )      ; hStdOutput

  NumPut( hPipeWrite, STARTUPINFO, 64 )      ; hStdError


  VarSetCapacity( PROCESS_INFORMATION, 16 )  ; PROCESS_INFORMATION  ;  http://goo.gl/b9BaI      


  If ! DllCall( "CreateProcess", UInt,0, UInt,&sCmd, UInt,0, UInt,0 ;  http://goo.gl/USC5a

              , UInt,1, UInt,0x08000000, UInt,0, UInt,0

              , UInt,&STARTUPINFO, UInt,&PROCESS_INFORMATION ) 

    Return "" 

    , DllCall( "CloseHandle", UInt,hPipeWrite ) 

    , DllCall( "CloseHandle", UInt,hPipeRead )

    , DllCall( "SetLastError", Int,-1 )


  hProcess := NumGet( PROCESS_INFORMATION, 0 )                 

  hThread  := NumGet( PROCESS_INFORMATION, 4 )                      


  DllCall( "CloseHandle", UInt,hPipeWrite )


  block := {}, blockIndex := 0, allSize := 0, nPipeAvail := 4096

  loop

  {

    ++blockIndex

    block[blockIndex] := {data:"", size:0, addr:0}

    ObjSetCapacity(block[blockIndex], "data", nPipeAvail)

    block[blockIndex].addr := ObjGetAddress(block[blockIndex], "data")

    

    nSz := 0

    if !DllCall( "ReadFile", UInt,hPipeRead, UInt,block[blockIndex].addr, UInt,nPipeAvail, UIntP,nSz, UInt,0 )

      break

    block[blockIndex].size := nSz, allSize += nSz

  }


  DllCall( "GetExitCodeProcess", UInt,hProcess, UIntP,ExitCode )

  DllCall( "CloseHandle", UInt,hProcess  )

  DllCall( "CloseHandle", UInt,hThread   )

  DllCall( "CloseHandle", UInt,hPipeRead )


  if allSize

  {

    VarSetCapacity( bin, allSize, 0 ), tar := &bin

    for k,v in block

      if v.size

        DllCall("RtlMoveMemory", "UPTR",tar, "UPTR",v.addr, "UInt",v.size), tar += v.size

    allSize := DllCall(AdjustScreencapData, "UPTR",&bin, "UInt",allSize, "cdecl")

    width  := NumGet(&bin, 0, "uint"), height := NumGet(&bin, 4, "uint")

    hBM := CreateDIBSection(width, height,"",32, ppvBits)  

    DllCall(ScreencapToDIB, "UPtr",&bin, "UInt",width, "UInt",height, "UPtr",ppvBits, "cdecl")

    return hBM

  }

  

}

 

;--------------------------------------------------------------------

MCode(mcode) {

static e := {1:4, 2:1}, c := (A_PtrSize=8) ? "x64" : "x86"

if (!regexmatch(mcode, "^([0-9]+),(" c ":|.*?," c ":)([^,]+)", m))

return

if (!DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", 0, "uint*", s, "ptr", 0, "ptr", 0))

return

p := DllCall("GlobalAlloc", "uint", 0, "ptr", s, "ptr")

if (c="x64")

DllCall("VirtualProtect", "ptr", p, "ptr", s, "uint", 0x40, "uint*", op)

if (DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", p, "uint*", s, "ptr", 0, "ptr", 0))

return p

DllCall("GlobalFree", "ptr", p)

    return

}


SaveHBITMAPToFile(hBitmap, sFile)

{

  VarSetCapacity(DIBSECTION, A_PtrSize=8? 104:84, 0)

  NumPut(40, DIBSECTION, A_PtrSize=8? 32:24,"UInt") ;dsBmih.biSize

  DllCall("GetObject", "UPTR", hBitmap, "int", A_PtrSize=8? 104:84, "UPTR", &DIBSECTION)

  hFile:= DllCall("CreateFile", "UPTR", &sFile, "Uint", 0x40000000, "Uint", 0, "Uint", 0, "Uint", 2, "Uint", 0, "Uint", 0)

  DllCall("WriteFile", "UPTR", hFile, "int64P", 0x4D42|14+40+(biSizeImage:=NumGet(DIBSECTION, A_PtrSize=8? 52:44, "UInt"))<<16, "Uint", 6, "UintP", 0, "Uint", 0)

  DllCall("WriteFile", "UPTR", hFile, "int64P", 54<<32, "Uint", 8, "UintP", 0, "Uint", 0)

  DllCall("WriteFile", "UPTR", hFile, "UPTR", &DIBSECTION + (A_PtrSize=8? 32:24), "Uint", 40, "UintP", 0, "Uint", 0)

  DllCall("WriteFile", "UPTR", hFile, "Uint", NumGet(DIBSECTION, A_PtrSize=8? 24:20, "UPtr"), "Uint", biSizeImage, "UintP", 0, "Uint", 0)

  DllCall("CloseHandle", "UPTR", hFile)

}







Posted by 와이로

모바일게임 히트같은 경우 녹스와 블루스택에서 색상이 다르게 나옵니다. 이 때문에 한쪽에서 추출한 이미지를 다른쪽에서 활용 할 수가 없더군요.

 

1. 녹스 이미지

 

2. 블루스택 이미지

 

 

해결 방법을 찾던 중... 색상을 회색톤으로 바꾸니 녹스에서 추출한 이미지로 블루스택상의 이미지에서 이미지서치에 성공을 했습니다. 대부분 공차값 50 내에서 찾아지더군요.

 

3. 녹스이미지를 회색톤으로 바꾼 것

 

4. 블루스택 이미지를 회색톤으로 바꾼 것

 

 

이렇게 테스트한 결과를 가지고 ImageSearch 명령에서 쉽게 사용할 수 있도록 *FilterGray 옵션으로 추가 했습니다.

 


 

아래 스크립트는 녹스에서 추출한 '우편함' 이미지를 사용해 블루스택상의 이미지에서 검색하는 스크립트입니다.

 

 

 

Test.ahk 파일을 다운로드한  'Ahk+ 전용 AutoHotkey.exe 파일'  위에 드래그해서 실행하세요.

ImageSearch_FilterGray옵션.zip

 

 

<스크립트>

 

imgFind = image검색.bmp
img녹스 = image녹스.bmp
img블택 = image블택.bmp

공차 = 30

 

text := "녹스 스샷에서 추출한 이미지로 이미지서치 한 결과`n`n"
text .= "`n[*FilterGray 옵션 사용 전]`n"
ImageSearch, sx,sy, 0,0,0,0, *TargetFile<%img녹스%> *%공차% %imgFind%
if !ErrorLevel
  text .= "녹스 스샷에서 검색성공 : " sx "," sy "`n"
ImageSearch, sx,sy, 0,0,0,0, *TargetFile<%img블택%> *%공차% %imgFind%
if !ErrorLevel
  text .= "블택 스샷에서 검색성공 : " sx "," sy "`n"

 

text .= "`n[*FilterGray 옵션 사용 후]`n"
ImageSearch, sx,sy, 0,0,0,0, *FilterGray *TargetFile<%img녹스%> *%공차% %imgFind%
if !ErrorLevel
  text .= "녹스 스샷에서 검색성공 : " sx "," sy "`n"
ImageSearch, sx,sy, 0,0,0,0, *FilterGray *TargetFile<%img블택%> *%공차% %imgFind%
if !ErrorLevel
  text .= "블택 스샷에서 검색성공 : " sx "," sy "`n"

 

MsgBox % text

 

 

 

 

 

 

Posted by 와이로

오토핫키 ImageFilter 명령어로 이미지에 그레이필터 적용

 

1. 원본 이미지

 

2. 절반만 그레이필터 적용

 

 

Test.ahk 파일을 다운로드한  'Ahk+ 전용 AutoHotkey.exe 파일'  위에 드래그해서 실행하세요.

Gray필터테스트.zip

 

 

<스크립트>


imgFile = 1.bmp

ImageGet, hBitmap,,,,, imgFile  ;이미지파일 로드

ImageFilter, Gray, hBitmap, hBitmap, 0,0,800,900  ;그레이필터 적용

SaveHBITMAPToFile(hBitmap, "2.bmp")

DllCall("DeleteObject", "Ptr",hBitmap)



 

 

 

 

 

 

 

Posted by 와이로

 

 

;이미지 파일에서 메모리로 이미지 로딩하기

bmpFile = %A_ScriptDir%\Image\IL_Other.bmp

hBitmap := DllCall("USER32\LoadImage", Ptr,0, Str,bmpFile, Uint,0, Int,0, Int,0, Uint,0x10 | 0x2000, Ptr)


;----------------------------------------------------------------------------------
;클립보드에서 비트맵 복사 후 HBitmap 핸들로 반환

;www.autohotkey.com/forum/viewtopic.php?t=35242
CreateHBitmapFromClipboard()
{
  If DllCall("IsClipboardFormatAvailable", UInt,2 )
    DllCall( "OpenClipboard", UInt,0 ), tBM := DllCall("GetClipboardData", UInt,2 )
    , hBM := DllCall( "CopyImage", UInt,tBM, UInt,0, Int,0,Int,0, UInt,0x2000, UInt )
    , DllCall( "CloseClipboard" )
  return hBM ? hBM : 0
}

 

;----------------------------------------------------------------------------------

;메모리에 로딩된 BMP파일을 읽어 HBitmap핸들로 반환
CreateHBitmapFromVar(ByRef bmpVar)
{
  WinGet, hwnd, ID, ahk_class Progman
  hDC := DllCall("USER32\GetDC", Ptr,hwnd, Ptr)
  hBMP := DllCall( "CreateDIBitmap", UInt,hDC, UInt,(bmiHAddr:=&bmpVar+14)
       ,UInt,(CBM_INIT:=4), UInt,&bmpVar+NumGet(&bmpVar,10), UInt,&bmpVar+14, UInt,(DIB_PAL_COLORS:=1) )
  DllCall("ReleaseDC", Ptr,hwnd, Ptr,hDC, Uint)
  return hBMP
}

 

;----------------------------------------------------------------------------------

;메모리에 로딩된 BMP파일을 읽어 pBitmap핸들로 반환 (Gdip 라이브러리 필요)
CreateBitmapFromVar(ByRef bmpVar)
{
  WinGet, hwnd, ID, ahk_class Progman
  hDC := DllCall("USER32\GetDC", Ptr,hwnd, Ptr)
  hBMP := DllCall( "CreateDIBitmap", UInt,hDC, UInt,(bmiHAddr:=&bmpVar+14)
       ,UInt,(CBM_INIT:=4), UInt,&bmpVar+NumGet(&bmpVar,10), UInt,&bmpVar+14, UInt,(DIB_PAL_COLORS:=1) )
  pBitmap := Gdip_CreateBitmapFromHBITMAP(hBMP)
  DllCall("ReleaseDC", Ptr,hwnd, Ptr,hDC, Uint)
  DllCall("DeleteObject", Ptr,hBMP, Uint)
  return pBitmap
}

 

;----------------------------------------------------------------------------------

;비트맵을 파일로 저장
SaveHBITMAPToFile(hBitmap, sFile)
{
  VarSetCapacity(DIBSECTION, A_PtrSize=8? 104:84, 0)
  NumPut(40, DIBSECTION, A_PtrSize=8? 32:24,"UInt") ;dsBmih.biSize
  DllCall("GetObject", "UPTR", hBitmap, "int", A_PtrSize=8? 104:84, "UPTR", &DIBSECTION)
  hFile:= DllCall("CreateFile", "UPTR", &sFile, "Uint", 0x40000000, "Uint", 0, "Uint", 0, "Uint", 2, "Uint", 0, "Uint", 0)
  DllCall("WriteFile", "UPTR", hFile, "int64P", 0x4D42|14+40+(biSizeImage:=NumGet(DIBSECTION, A_PtrSize=8? 52:44, "UInt"))<<16, "Uint", 6, "UintP", 0, "Uint", 0)
  DllCall("WriteFile", "UPTR", hFile, "int64P", 54<<32, "Uint", 8, "UintP", 0, "Uint", 0)
  DllCall("WriteFile", "UPTR", hFile, "UPTR", &DIBSECTION + (A_PtrSize=8? 32:24), "Uint", 40, "UintP", 0, "Uint", 0)
  DllCall("WriteFile", "UPTR", hFile, "Uint", NumGet(DIBSECTION, A_PtrSize=8? 24:20, "UPtr"), "Uint", biSizeImage, "UintP", 0, "Uint", 0)
  DllCall("CloseHandle", "UPTR", hFile)
}

 

Posted by 와이로

 

ImageSearch 명령어 확장기능 설명 바로가기

 

 

이번 예제 스크립트는 '다음팟 플레이어' 를 이용한 동영상 속 이미지를 검색하는 방법입니다. 팟플레이어는 단축키(Ctrl+C)로 현재 프레임의 원본 이미지를 클립보드에 저장 할 수 있습니다. 이걸 이용해 동영상에서 검색할 이미지를 찾는 방법을 알아보겠습니다.

 

간혹 단축키가 다를 수 있습니다.

단축키 확인 방법 : 메뉴 -> 영상 -> 영상 캡쳐 -> 현재 화면 복사(원본크기)  Ctrl+C

 

 

 

 

찾아야할 이미지 만드는 법 : 동영상 재생 후 이미지가 있는 프레임에서 '현재 화면 복사' 단축키를 사용해 이미지를 캡춰 한 후 그림판에 붙여넣기 후 필요한 이미지를 잘라내면 됩니다.

 

1. 이 스샷은 동영상에서 찾아낼 이미지를 표시 한 스샷입니다.

 

 

 

2. 아래 스샷은 동영상 재생 중 검색대상 이미지를 발견에 성공했을때를 찍은 스샷입니다. 검색성공시 '스페이스' 키로 바로 재생을 멈추게 해봤습니다.

 

검색대상 위치가 비어있는 이유는 클립보드를 통한 이미지서치가 동영상 재생보다 더 빨라서 입니다. 다시 재생 시키면 바로 해당위치에 검색대상이미지가 나타나는걸 볼수 있습니다.

 

 

 

Test.ahk 파일을 다운로드한  'Ahk+ 전용 AutoHotkey.exe 파일'  위에 드래그해서 실행하세요.

팟플레이어_동영상이미지서치_Test.zip

 

 

 

<스크립트>

 

searchImg = 찾는이미지.bmp
movieFile = TestMovie.avi

 

;매크로 종료
F2::ExitApp

 

;동영상 감시 시작
F1::
  ;레지스트리에서 팟플레이어 설치경로 얻기
  RegRead, player_path, HKCU, Software\DAUM\PotPlayer, ProgramPath
  if !player_path
  {
    MsgBox, 팟플레이어 등록정보를 찾을 수 없어 프로그램을 종료합니다.
    ExitApp
  }
  
  ;팟플레이어 실행
  Run, "%player_path%" "%movieFile%"
  sleep, 2000

 

  loop
  {
    ;팟플레이어 체크
    IfWinNotActive, ahk_class PotPlayer
    {
      sleep, 100
      WinActivate, ahk_class PotPlayer
      continue
    }
    
    ;팟플레이어 '현재프레임 클립보드로 복사' 단축키 체크하세요 : Ctrl+C
    Send, ^c
    
    ;압축률 또는 해상도가 높은 동영상은 sleep을 충분히 걸어줘야 팟플레이어에 렉이 안생깁니다.
    sleep, 100
   
    hBitmap := CreateHBitmapFromClipboard()

 

    ;*TargetHBmp 옵션은 HBITMAP 핸들의 비트맵을 이미지서치 대상으로 설정하며

    ;이미지서치 명령 후 비트맵 핸들을 자동 초기화 시키는 옵션입니다.
    ImageSearch, sx,sy, 0,0,0,0, *TargetHBmp%hBitmap% *50 %searchImg%
    if !ErrorLevel
    {
      ;이미지서치 성공시 팟플레이어 일시정지
      Send, {Space}
     
      MsgBox % "found = " sx "," sy
      ExitApp
    }
  }
return

 

;클립보드 이미지를 HBITMAP 으로 반환

CreateHBitmapFromClipboard()
{
  If DllCall("IsClipboardFormatAvailable", UInt,2 )
    DllCall( "OpenClipboard", UInt,0 ), tBM := DllCall("GetClipboardData", UInt,2 )
    , hBM := DllCall( "CopyImage", UInt,tBM, UInt,0, Int,0,Int,0, UInt,0x2000, UInt )
    , DllCall( "CloseClipboard" )
  return hBM ? hBM : 0
}

 

 

 

 

 

 

 

 

 

Posted by 와이로

ImageListSearch 명령어 설명 바로가기

 

이 샘플 스크립트는 설명의 편의를 위해 검색대상을 화면이 아닌 이미지파일로 했습니다.

SearchTarget_....bmp : 일련의 숫자 이미지가 들어있는 이미지 파일

imglist_number.bmp : 0~9까지의 파트이미지가 세로로 연결된 이미지리스트(파트사이즈 5x8)

 

 

 

Test.ahk 파일을 다운로드한  'Ahk+ 전용 AutoHotkey.exe 파일'  위에 드래그해서 실행하세요.

ImageListSearch숫자추출_테스트.zip

 

 

 

<스크립트 : SearchTarget_오랜지컬러숫자추출.ahk>

 

color := 0xFFB400                  ;오랜지색 RGB
imageList = imglist_number.bmp   ;이미지리스트 경로 (흰색의 5x8 픽셀로된 10개의 숫자 이미지리스트)
searchTarget = SearchTarget_오랜지컬러숫자추출.bmp     ;검색대상 경로


;검색대상에 있는 숫자컬러와 이미지리스트의 숫자컬러가 다르므로
;이미지리스트의 숫자컬러를 검색대상의 숫자컬러로 교체해 줍니다.

ImageGet, hImgList,,,,, imageList   ;이미지리스트파일을 로딩

ColorReplace, hImgList, hImgList, 0xFFFFFF, color   ;흰색(0xFFFFFF) -> 오랜지색(0xFFB400) 교체

 

;검색시작좌표와 마지막좌표 설정
ImageGet,,,,,, searchTarget,,size
curx := 0  ,  cury := 0
endx := size.width - 1  ,  endy := size.height - 1

loop
{
  ;x축 검색영역 벗어날시 루프 종료
  if (curx>endx)
    break
  
  ;5x8 픽셀사이즈의 파트이미지 10개로 구성된 이미지리스트로 대상 검색
  ;이미지리스트파일 대신 이미지리스트비트맵핸들을 사용하므로 *HBmpNotDel 옵션 추가
  ImageListSearch, sx,sy,si, curx,cury,endx,endy, *UseZeroIndex *Listmax10 *TransBlack *Transnot%color% *FixW *ValidW *Obj *TargetFile<%searchTarget%> *HBmpNotDel %hImgList%
  if !ErrorLevel
  {
    str .= si.index
    curx := si.validx + si.validw
  }
  ++curx
}

 

;이미지리스트 비트맵 핸들의 사용이 끝났으므로 핸들을 초기화합니다.
DllCall("DeleteObject", Ptr,hImgList)

 

;찾은숫자 메시지박스로 표시

MsgBox % "찾은숫자 = " str

 


/*


 < ImageListSearch 명령에 사용된 옵션 설명 >

 

*UseZeroIndex : 이미지리스트의 시작인덱스를 1이 아닌 0을 사용한다.

*Listmax10 : 이미지리스트가 10개의 파트이미지로 구성되있음을 표시합니다.

*TransBlack : 이미지리스트의 배경색이 검은색임을 표시합니다.(검색제외 색상)

*Transnot%color% : 각 파트이미지로 검색할시 파트이미지의 검은색 영역에 color 변수의 색값이 없어야 함을 표시합니다.

*FixW : 검색영역을 검색시작좌표에서 파트이미지의 가로사이즈(W)만큼으로 제한합니다.

검색영역을 무시하고 일정영역 만큼만 각 파트이미지를 대조해 보고 서치를 끝내는 옵션입니다.

*ValidW : 파트이미지의 가로영역의 유효이미지를 제외한 부분을 최대한 제거합니다.

숫자 1의 경우 가로 5픽셀이지만 이 옵션 효과로 인해 가로 유효영역인 2픽셀만 검색에 사용됩니다. *Trans 옵션도 투명영역을 배제하고 유효영역만 검색하는데 뭐가 다르냐고 의문을 품는 분들을 위해 설명하자면 *Trans 옵션은 실제 검색용으로 쓰는 이미지 사이즈를 줄여주지는 않지만 *Valid 옵션은 이미지 크기가 바뀐다고 보면됩니다.

*Obj : 출력변수 si 를 Object 출력변수로 설정합니다.

*TargetFile<%searchTarget%> : searchTarget 변수의 파일을 대상으로 검색합니다.

파일대상일때는 경로를 < > 로 둘러싸줘야 합니다.

*HBmpNotDel : 검색소스파일대신 비트맵핸들값으로 검색한다는 것을 표시하는 옵션입니다. (*HBmp옵션과 동일하지만 핸들을 소멸시키지 않습니다.)
 

*/

 


 

 

 

 

 

 

 

 

Posted by 와이로