查看完整视频
小黑屋思过中,禁止观看!
评论并刷新后可见

您需要在视频最下面评论并刷新后,方可查看完整视频

积分观看

支付积分后查看完整视频

{{user.role.value}}
付费视频

支付完成后查看完整视频

¥{{user.role.value}}
专属视频

只允许以下等级用户查看该视频

升级
会员专享

视频选集

AHK调用opencv(应用) qq连连看 – ahk_v2_beta3

  • 视频介绍
  • 视频选集
  • 交流讨论

借助群友研究的COM 调用opencv方法,用ahk翻译了一个qq连连看自动辅助

使用方法参照视频

主脚本代码

#include <log4ahk>
#include cv2.ah2
#include <Gdip_All>

SetWorkingDir A_ScriptDir
CoordMode "ToolTip", "Screen"
CoordMode("Mouse", "Screen")

dllcall("SetDllDirectory", "Str", A_ScriptDir)
hOpencv := DllCall("LoadLibrary", "str", "opencv_world455.dll", "ptr")
hOpencvCom := DllCall("LoadLibrary", "str", "autoit_opencv_com455.dll", "ptr")
DllCall("autoit_opencv_com455.dll\DllInstall", "int", 1, "wstr", A_IsAdmin = 0 ? "user" : "", "cdecl")

changeArrayIndexToZeroBased()
log.is_out_console := true
log.is_out_file := false
log.info("f3 开始, f5退出")
MsgBox("F3 开始, F5 重启")

;游戏配置信息

;图片左上角坐标
left_x := 13
left_y :=  180
;图片长宽
pic_w :=  590
pic_h :=  386
;每个小方块长宽
block_x := 31
block_y := 35

cv := ComObject("OpenCV.cv")
mat := ComObject("OpenCV.cv.Mat")

; 将图片转化为数字矩阵,方便处理
picturemap := make_2d_array(20, 20)

;统计每种图片有多少个(最多的即为空白部分)
blank := []
loop(300)
    blank.Push(0)
;搜索的标记及其方向,不懂的可以查一查BFS(广度优先搜索)
bfsflag := 0
dirary := [[1, 0], [-1, 0], [0, 1], [0, -1]]
searchmap := make_2d_array(20, 20)
ifok := false


f3::
{
	main()
}

f5::
{
    Reload
}
main()
{
	global mat, cv
	;因为我这里切片处理不太好,小方块比对不一定完全匹配,所以就将这个过程设置了五次
	;欢迎大佬们来优化
	times := 5
	while (times--)
	{
		;找到游戏窗口,将游戏放在左上角方便定位,然后截图
        hq := WinExist("QQ游戏 - 连连看角色版")
        WinGetClientPos(&X, &Y, &W, &H, hq)
        WinMove(0, 0,,, hq)
		Sleep(1000)

        wid := A_ScreenWidth
        hei := A_ScreenHeight
        pBits:=0x00000000
        pToken := Gdip_StartUp()
        chdc := CreateCompatibleDC(GetDC(0))
        hbm := CreateDIBSection(wid, hei, chdc, 24, &pBits)
        obm := SelectObject(chdc, hbm)
        hhdc := GetDC(0)
        BitBlt(chdc, 0, 0, wid, hei, hhdc, 0, 0, 0xCC0020)
        val:= (wid * 3 + 3) & -4
        src := mat.create(hei, wid, 16, pBits, val) 
        src := cv.flip(src, 0)

        imgROI := ComObject("OpenCV.cv.Mat").create(src, ComArrayMake([left_x, left_y, pic_w, pic_h]))
		;cv.imshow("src", imgROI)
		picture_process(src)
		;进行500次匹配,防止出错
		temp := 500
		while (temp--)
		{
			log.info(a_index)
			match()
		}
		Sleep(3000)
		cnt := 0
		;如果这时检测到还有出了空白之外的图片,就用道具重置,继续完成上面步骤
        i := 0
        loop(300)
		{
			if (blank[i] != 0)
			{
				cnt++
			}
            i++
		}
		if (cnt == 1)
			break
        MouseMove 653, 199
        MouseClick("left")
		Sleep(1000)

		cv.destroyAllWindows()
		SelectObject(chdc, obm)
		ReleaseDC(hhdc)    
		DeleteObject(hbm)
		DeleteDC(chdc)
		Gdip_Shutdown(pToken)
	}
	return 0
}

picture_process(src)
{
	;用vector储存每个小方块
	log.in()
	vec := make_2d_array(11, 19)
	img := []
	x_pos := left_x, y_pos := left_y
    i := 0
    loop(11)
	{
        j := 0
        loop(19)
		{
            pic := ComObject("OpenCV.cv.Mat").create(src, ComArrayMake([x_pos, y_pos, block_x, block_y]))
			vec[i][j] := ComObject("OpenCV.cv.Mat").create(pic, ComArrayMake([3, 3, block_x - 6, block_y - 6]))
			x_pos += block_x
			if (img.Length == 0)
			{
				img.push(vec[i][j])
				picturemap[i][j] := 1
				blank[0]++
			}
			else
			{
				flag := 0
                k := 0
                loop(img.Length)
				{
					if (imgcompare(img[k], vec[i][j]) > 0.99)
					{
						picturemap[i][j] := k + 1
						flag := 1
						blank[k]++
						break
					}
                    k++
				}
				if (flag == 0)
				{
					img.push(vec[i][j])
					picturemap[i][j] := img.Length
					blank[img.Length - 1]++
				}
			}
            j++
		}
		x_pos := left_x
		y_pos += block_y
        i++
	}
	pos := 0, num := 0
    i := 0
    loop(img.Length)
	{
		if (blank[i] > num)
		{
			num := blank[i]
			pos := i + 1
		}
        i++
	}
    i := 0
    loop(11)
	{
        j := 0
        loop(19)
		{
			if (picturemap[i][j] == pos)
			{
				picturemap[i][j] := 0
			}
            j++
		}
        i++
	}
	log.out()
}

;直方图比较,结果为0到1的一个数,越大越准确
imgcompare(img1, img2)
{
	hsv_img1 := ComObject("OpenCV.cv.Mat")
    hsv_img2 := ComObject("OpenCV.cv.Mat")

	hsv_img1 := cv.cvtColor(img1, cv2.CV_COLOR_BGR2HSV)
	hsv_img2 := cv.cvtColor(img2, cv2.CV_COLOR_BGR2HSV)
	;cv.imshow("1", hsv_img1)
	;cv.imshow("2", hsv_img2)
	cv.waitKey()
 
	h_bins := 50, s_bins := 60
	histSize := [h_bins, s_bins]
	h_ranges := [0, 256]
	s_ranges := [0, 180]
 
	ranges := [h_ranges[0], h_ranges[1], s_ranges[0], s_ranges[1]]

	channels := ComArrayMake([0, 1])
	hist_test1 := cv.calcHist(ComArrayMake([hsv_img1]), channels, ComObject("OpenCV.cv.Mat"), ComArrayMake(histSize), ComArrayMake(ranges))
	cv.normalize(hist_test1, hist_test1, 0, 1, cv2.CV_NORM_MINMAX)
 
	hist_test2 := cv.calcHist(ComArrayMake([hsv_img2]), channels, ComObject("OpenCV.cv.Mat"), ComArrayMake(histSize), ComArrayMake(ranges))
	cv.normalize(hist_test2, hist_test2, 0, 1, cv2.CV_NORM_MINMAX)
 
	ans := cv.compareHist(hist_test1, hist_test2, 0)
	return ans
}

match()
{
	global ifok
	global bfsflag
	global searchmap
    i := 0
    loop(11)
	{
        j := 0
        loop(19)
		{
			if (picturemap[i][j] == 0)
			{
				j++
				continue
			}
            m := i
            loop(11)
            {
                if(m >= 11)
                    break
                n := 0
                loop(19)
				{
					if (picturemap[m][n] == 0)
					{
						n++
						continue
					}
					if (m == i && n == j)
					{
						n++
						continue
					}
					if (picturemap[i][j] == picturemap[m][n])
					{
                        array2d_clean(searchmap)
						searchmap[i][j] := 1
						bfsflag := 0
						ifok := false
						;用广度优先搜索检测两个相同的块能不能连通,能就true不能false
						bfs(i, j, m, n, searchmap, 0, 0)
						if (ifok)
						{
							;鼠标操作
                            MouseMove((left_x + j * block_x) + 10, (left_y + i * block_y) + 10)
                            MouseClick("left")
                            Sleep(200)
							MouseMove((left_x + n * block_x) + 10, (left_y + m * block_y) + 10)
                            MouseClick("left")
							picturemap[i][j] := 0
							picturemap[m][n] := 0
						}
					}
                    n++
				}
                m++
			}
            j++
		}
        i++
	}
}

bfs(i, j, m, n, searchmap, dir, temp)
{
	global bfsflag
	global ifok
	if (bfsflag == 1)
		return
	if (temp > 2)
		return
	if ((i == m) && (j == n))
	{
		bfsflag := 1
		ifok := true
		return
	}
    ii := 0
    loop(4)
	{
		xx := i + dirary[ii][0]
		yy := j + dirary[ii][1]
		if (xx < 0 || xx > 10 || yy < 0 || yy > 18 || searchmap[xx][yy] == 1)
		{
			ii++
			continue
		}
		searchmap[xx][yy] := 1
		if ((picturemap[xx][yy] == 0) || (picturemap[xx][yy] == picturemap[m][n]))
		{
			if (dir == 0)
			{
				bfs(xx, yy, m, n, searchmap, ii + 1, temp)
			}
			else
			{
				if (ii + 1 != dir)
					bfs(xx, yy, m, n, searchmap, ii + 1, temp + 1)
				else
					bfs(xx, yy, m, n, searchmap, ii + 1, temp)
			}
			searchmap[xx][yy] := 0
		}
        ii++
	}
	return
}
;r rows
;c cols
make_2d_array(r, c)
{
    arr := []
    arr.Length := r
    for k, v in arr
    {
        arr[k] := []
        arr[k].Length := c
        for i, j in arr
            arr[k][i] := 0
    }
    return arr
}
array2d_clean(in_array)
{
    for k,v in in_array
        for i,j in v
            in_array[k][i] := 0
}
ComArrayMake(inputArray)
{
	arr := ComObjArray(VT_VARIANT:=12, inputArray.Length)
	Loop inputArray.Length
	{
		arr[A_Index - 1] := inputArray[A_Index - 1]
	}
	return arr
}

/************************************************************************
 * @file: array_zero_based_index.ah2
 * @description: 使Array数组对象以0为第一个元素
 * @author thqby
 * @date 11/23/2020
 * @version 1.0
 ***********************************************************************/
changeArrayIndexToZeroBased() {
    static init := (() => (
        __enum := Array.Prototype.GetOwnPropDesc("__Enum").call,
        __item := Array.Prototype.GetOwnPropDesc("__Item"),
        __set := __item.set, __get := __item.get,
        Array.Prototype.DefineProp("__Item", {
            get: (s, i) => __get(s, i + 1),
                set: (s, v, i) => __set(s, v, i + 1)
        }),
        Array.Prototype.DefineProp("__Enum", { call:
                (s, n := 1) => (n != 2 ? __enum(s, n) :
                        (n := s.Length, i := 0, (&k, &v) => (
                            i < n ? (k := i++, v := __get(s, i), true) : false
                        ))
                ) })
    ))()
}
changeComArrayIndexToOneBased() {
    static init := (() => (
        __enum := (Object.GetOwnPropDesc)(ComObjArray.Prototype, "__Enum").call,
        __item := (Object.GetOwnPropDesc)(ComObjArray.Prototype, "__Item"),
        __set := __item.set, __get := __item.get,
        (Object.DefineProp)(ComObjArray.Prototype, "__Item", {
            get: (s, i) => __get(s, i - 1),
                set: (s, v, i) => __set(s, v, i - 1)
        }),
        (Object.DefineProp)(ComObjArray.Prototype, "__Enum", { call:
                (s, n := 1) => (n != 2 ? __enum(s, n) :
                        (n := s.MaxIndex(), i := 0, (&k, &v) => (
                            i <= n ? (v := __get(s, i), k := ++i, true) : false
                        ))
                ) })
    ))()
}

给TA捐赠
共{{data.count}}人
人已捐赠
9 条回复 A文章作者 M管理员
  1. hexuren

    视频格式转下mp4

  2. dbgba
    dbgba给您打赏了¥10
  3. dbgba

    过来支持一波,另外视频的图像挂了

  4. hexuren

    视频单独发我吧!我这里你这个视频就播放不了

  5. random
    random给您打赏了¥5
  6. 慕英名

    好厉害

  7. dzeanah

    Ive been looking for something like this..! not sure were to find the dependancies? (log4ahk, cv2.ah2)?

    • ahker

      附件有隐藏链接

  8. AHK奇巧淫技

    越来越强大了

个人中心
购物车
优惠劵
有新私信 私信列表
搜索