连连看不一样的玩法,利用python进行图片相似度计算

先放制作好的游戏视频链接:(纯粹是兴趣分享)

连连看不一样的玩法-图像相似度识别-python_单机游戏热门视频

https://www.ixigua.com/7076826558106698253?logTag=f2d215ea6e6372c45362

这两个视频是我本人自制投稿,感兴趣可以观看一下。下面是截图展示:

连连看不一样的玩法,利用python进行图片相似度计算

程序主要功能是先将练练看的整个大图切分成单个小图,然后进行循环遍历找出相似的图片,并在矩阵中进行记录,然后依据练练看两个图片连接的规则进行连接。直接放代码:

1.相似度计算模块(用一个算法就行了,我这里写了好几个)

import cv2
import numpy as np
import matplotlib
matplotlib.use('TkAgg')

均值哈希算法
def aHash(img):
    # 缩放为8*8
    # img = cv2.imread(img)
    img = np.asanyarray(img)
    img = cv2.resize(img, (8, 8))
    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # s为像素和初值为0,hash_str为hash值初值为''
    s = 0
    hash_str = ''
    # 遍历累加求像素和
    for i in range(8):
        for j in range(8):
            s = s+gray[i, j]
    # 求平均灰度
    avg = s/64
    # 灰度大于平均值为1相反为0生成图片的hash值
    for i in range(8):
        for j in range(8):
            if gray[i, j] > avg:
                hash_str = hash_str+'1'
            else:
                hash_str = hash_str+'0'
    return hash_str

差值哈希算法
def dHash(img):
    # 缩放8*8
    # img = cv2.imread(img) #此种方法只能用于本地图片读取
    img = np.asanyarray(img)
    img = cv2.resize(img, (9, 8))
    # 转换灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    hash_str = ''
    # 每行前一个像素大于后一个像素为1,相反为0,生成哈希
    for i in range(8):
        for j in range(8):
            if gray[i, j] > gray[i, j+1]:
                hash_str = hash_str+'1'
            else:
                hash_str = hash_str+'0'
    return hash_str

感知哈希算法
def pHash(img):
    # 缩放32*32
    # img = cv2.imread(img)
    img = np.asanyarray(img)
    img = cv2.resize(img, (32, 32))  # , interpolation=cv2.INTER_CUBIC
    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 将灰度图转为浮点型,再进行dct变换
    dct = cv2.dct(np.float32(gray))
    # opencv实现的掩码操作
    dct_roi = dct[0:8, 0:8]

    hash = []
    avreage = np.mean(dct_roi)
    for i in range(dct_roi.shape[0]):
        for j in range(dct_roi.shape[1]):
            if dct_roi[i, j] > avreage:
                hash.append(1)
            else:
                hash.append(0)
    return hash

灰度直方图算法
def calculate(image1, image2):
    # 计算单通道的直方图的相似值
    # 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0
    # 三直方图算法和单通道的直方图 0-1之间,值越大,越相似。 相同图片为1
    # image1 = cv2.imread(image1)
    # image2 = cv2.imread(image2)
    image1 = np.asanyarray(image1)
    image2 = np.asanyarray(image2)
    hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
    hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
    # 计算直方图的重合度
    degree = 0
    for i in range(len(hist1)):
        if hist1[i] != hist2[i]:
            degree = degree + \
                (1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
        else:
            degree = degree + 1
    degree = degree / len(hist1)
    return degree

三通道直方图算法
def classify_calculate(image1, image2):
    # 计算单通道的直方图的相似值
    # 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0
    # 三直方图算法和单通道的直方图 0-1之间,值越大,越相似。 相同图片为1
    hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
    hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
    # 计算直方图的重合度
    degree = 0
    for i in range(len(hist1)):
        if hist1[i] != hist2[i]:
            degree = degree + \
                (1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
        else:
            degree = degree + 1
    degree = degree / len(hist1)
    return degree

RGB每个通道的直方图相似度
def classify_hist_with_split(image1, image2, size=(256, 256)):
    # 将图像resize后,分离为RGB三个通道,再计算每个通道的相似值
    image1 = np.asanyarray(image1)
    image2 = np.asanyarray(image2)
    image1 = cv2.resize(image1, size)
    image2 = cv2.resize(image2, size)
    sub_image1 = cv2.split(image1)
    sub_image2 = cv2.split(image2)
    sub_data = 0
    for im1, im2 in zip(sub_image1, sub_image2):
        sub_data += classify_calculate(im1, im2)
    sub_data = sub_data / 3
    return sub_data

Hash值对比
def cmpHash(hash1, hash2):
    # 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0
    # 三直方图算法和单通道的直方图 0-1之间,值越大,越相似。 相同图片为1
    # 算法中1和0顺序组合起来的即是图片的指纹hash。顺序不固定,但是比较的时候必须是相同的顺序。
    # 对比两幅图的指纹,计算汉明距离,即两个64位的hash值有多少是不一样的,不同的位数越小,图片越相似
    # 汉明距离:一组二进制数据变成另一组数据所需要的步骤,可以衡量两图的差异,汉明距离越小,则相似度越高。汉明距离为0,即两张图片完全一样
    n = 0
    # hash长度不同则返回-1代表传参出错
    if len(hash1) != len(hash2):
        return -1
    # 遍历判断
    for i in range(len(hash1)):
        # 不相等则n计数+1,n最终为相似度
        if hash1[i] != hash2[i]:
            n = n + 1
    return n

2.基本功能(截图,图片转换)

from PIL import ImageGrab
import numpy as np

#截图方法
#传入图片像素位置以及所需比例宽度高度 #引入自己写的模块
from LLKgame.similarFunctinos import cmpHash, pHash, classify_hist_with_split, calculate

#传入截图的左上右下坐标,宽的小图数量,长的小图数量,小图的高度和宽度
#如cutPicture(304, 271, 1226, 870,10,14,60.2,65.9)在坐标(304,271)(1226,870)处截取140个小图,小图的高是60.2,宽是65.9

def cutPicture(left,top,right,botton,pWidth,pHeight,height,width):  # 截图
    size = (left, top, right, botton)
    img = ImageGrab.grab(size)
    # img.size(200,100)
    print(img.size)
    print(img)
    # img.save("D://cut.jpg")
    # img.show()
    # 2、分切小图
    image_list = {}
    for x in range(pWidth):
        image_list[x] = {}
        for y in range(pHeight):
            # print("show",x, y)
            # exit()
            top1 = x * height
            left1 = y * width
            right1 = (y + 1) * width
            botton1 = (x + 1) * height
            # 用crop函数切割成小图标,参数为图标的左上角和右下角左边
            im = img.crop((left1, top1, right1, botton1))
            # im.show()
            # time.sleep(1)
            # 将切割好的图标存入对应的位置
            image_list[x][y] = im
    print(image_list)
    return image_list

#创造数字矩阵
#传入矩阵的宽高和初始矩阵
def makeArray(pWidth,pHeight,image_list):
    image_type_list = []
    arr = np.zeros((pWidth + 2,pHeight + 2), dtype=np.int32)  # 创建矩阵以数字代替图片
    for i in range(len(image_list)):
        for j in range(len(image_list[0])):
            im = image_list[i][j]
            # 验证当前图标是否已存入
            index = getIndex(10,0.65,im, image_type_list)
            # 不存在image_type_list
            if index < 0:
                image_type_list.append(im)
                arr[i + 1][j + 1] = len(image_type_list)
            else:
                arr[i + 1][j + 1] = index + 1
    print("&#x56FE;&#x6807;&#x6570;&#xFF1A;", len(image_type_list))
    # self.im2num_arr = arr
    return arr

&#x68C0;&#x67E5;&#x6570;&#x7EC4;&#x4E2D;&#x662F;&#x5426;&#x6709;&#x56FE;&#x6807;,&#x5982;&#x679C;&#x6709;&#x5219;&#x8FD4;&#x56DE;&#x7D22;&#x5F15;&#x4E0B;&#x8868;
#&#x4F20;&#x5165;&#x6807;&#x51C6;&#x76F8;&#x4F3C;&#x5EA6;similar1 similar2 &#x548C;&#x9700;&#x8981;&#x9A8C;&#x8BC1;&#x56FE;&#x7247;
def getIndex(similar1,similar2,im, im_list):
    global flag
    for i in range(len(im_list)):
        flag = 0
        # if self.compare_image_with_hash(im, im_list[i],6):
        #     return i
        val1 = calculate(im,im_list[i])
        val2 = classify_hist_with_split(im,im_list[i])
        val3 = cmpHash(pHash(im), pHash(im_list[i]))
        if val2 >= similar2:
            flag = 1
        if val1 >= similar2:
            flag = flag + 1
        if val3 <= 1 similar1: flag="flag" + if>= 2:
            return i
    return -1

</=>

3.连连看连接逻辑

import time
from pymouse import *

from LLKgame.baseFunctions import cutPicture, makeArray

class run_game():
    #&#x521D;&#x59CB;&#x622A;&#x56FE;&#x5DE6;&#x4E0A;&#x53F3;&#x4E0B;&#x5750;&#x6807;&#x4F4D;&#x7F6E;&#xFF0C;&#x521D;&#x59CB;&#x622A;&#x56FE;&#x603B;&#x5BBD;&#x603B;&#x9AD8;&#xFF0C;&#x521D;&#x59CB;&#x5355;&#x4E2A;&#x56FE;&#x50CF;&#x5BBD;&#x9AD8;
    def __init__(self,left,top,right,botton,pWidth,pHeight,height,width):
        self.left = left
        self.top = top
        self.right = right
        self.botton = botton
        self.pWidth = pWidth
        self.pHeight = pHeight
        self.width = width
        self.height = height
        self.im2num_arr = []

    #&#x70B9;&#x51FB;&#x4E8B;&#x4EF6;
    def pClick(self, x1, y1, x2, y2):
        m = PyMouse()
        p1_x = int(self.left + (y1) * self.width - int((self.width / 2)))
        p1_y = int(self.top + (x1) * self.height - int((self.height / 2)))
        p2_x = int(self.left + (y2) * self.width - int((self.width / 2)))
        p2_y = int(self.top + (x2) * self.height - int((self.height / 2)))

        time.sleep(0.3)#&#x6C89;&#x7761;&#x65F6;&#x95F4;
        m.click(int(p1_x / 1.25), int(p1_y / 1.25))
        time.sleep(0.3)
        m.click(int(p2_x / 1.25), int(p2_y / 1.25))
        # time.sleep(0.1)
        # &#x8BBE;&#x7F6E;&#x77E9;&#x9635;&#x503C;&#x4E3A;0
        self.im2num_arr[x1][y1] = 0
        self.im2num_arr[x2][y2] = 0
        print("&#x6D88;&#x9664;&#xFF1A;(%d, %d) (%d, %d)" % (x1, y1, x2, y2))

    # &#x662F;&#x5426;&#x4E3A;&#x540C;&#x884C;&#x6216;&#x540C;&#x5217;&#x4E14;&#x53EF;&#x8FDE;
    #X1 Y1 &#x5143;&#x7D20;&#x5750;&#x6807;x&#x503C;&#x4EE5;&#x53CA;y&#x503C; X2 Y2 &#x5143;&#x7D20;&#x5750;&#x6807;x&#x503C; y&#x503C;
    def isReachable(self, x1, y1, x2, y2):
        # 1&#x3001;&#x5148;&#x5224;&#x65AD;&#x503C;&#x662F;&#x5426;&#x76F8;&#x540C;
        if self.im2num_arr[x1][y1] != self.im2num_arr[x2][y2]:
            return False
        # &#x5224;&#x65AD;&#x6A2A;&#x5411;&#x8FDE;&#x901A;
        if self.isSameRow(x1, y1, x2, y2):
            return True
        # &#x5224;&#x65AD;&#x7EB5;&#x5411;&#x8FDE;&#x901A;
        if self.isSameCol(x1, y1, x2, y2):
            return True
        # &#x5224;&#x65AD;&#x4E00;&#x4E2A;&#x62D0;&#x70B9;&#x53EF;&#x8FDE;&#x901A;
        if self.turnOnceCheck(x1, y1, x2, y2):
            return True
        # &#x5224;&#x65AD;&#x4E24;&#x4E2A;&#x62D0;&#x70B9;&#x53EF;&#x8FDE;&#x901A;
        if self.turnTwiceCheck(x1, y1, x2, y2):
            return True
        # &#x4E0D;&#x53EF;&#x8054;&#x901A;&#x8FD4;&#x56DE;False
        return False

    #&#x662F;&#x5426;&#x4E24;&#x4E2A;&#x5143;&#x7D20;&#x540C;&#x884C;
    def isSameRow(self, x1, y1, x2, y2):
        if (abs(y1 - y2) == 1 and x1 == x2):  # &#x540C;&#x884C;&#x4E14;&#x76F8;&#x90BB;
            return True

        if (abs(y1 - y2) > 1 and x1 == x2):  # &#x540C;&#x884C;&#x4E0D;&#x76F8;&#x90BB;
            # if (x1 == 0 or x1 == (self.pHeight - 1)):  # &#x6700;&#x5916;&#x884C;
            #     return True
            flag = 0
            for i in range(min(y1, y2) + 1, max(y1, y2)):
                if self.im2num_arr[x1][i] == 0:
                    flag = flag + 0
                else:
                    flag = flag + 1
            if (flag == 0):
                return True
        return False

    #&#x662F;&#x5426;&#x540C;&#x5217;
    def isSameCol(self, x1, y1, x2, y2):
        if (abs(x1 - x2) == 1 and y1 == y2):  # &#x540C;&#x5217;&#x4E14;&#x76F8;&#x90BB;
            return True

        if (abs(x1 - x2) > 1 and y1 == y2):  # &#x540C;&#x5217;&#x4E0D;&#x76F8;&#x90BB;
            # if (y1 == 0 or y1 == (self.pWidth - 1)):  # &#x5728;&#x6700;&#x5916;&#x5217;
            #     return True
            flag = 0
            for i in range(min(x1, x2) + 1, max(x1, x2)):
                if self.im2num_arr[i][y1] == 0:
                    flag = flag + 0
                else:
                    flag = flag + 1
            if (flag == 0):
                return True
        return False

    # &#x5224;&#x65AD;&#x4E00;&#x4E2A;&#x62D0;&#x70B9;&#x53EF;&#x8054;&#x901A;
    def turnOnceCheck(self, x1, y1, x2, y2):
        if x1 == x2 or y1 == y2:
            return False
        cx = x1
        cy = y2
        dx = x2
        dy = y1
        # &#x62D0;&#x70B9;&#x4E3A;&#x7A7A;&#xFF0C;&#x4ECE;&#x7B2C;&#x4E00;&#x4E2A;&#x70B9;&#x5230;&#x62D0;&#x70B9;&#x5E76;&#x4E14;&#x4ECE;&#x62D0;&#x70B9;&#x5230;&#x7B2C;&#x4E8C;&#x4E2A;&#x70B9;&#x53EF;&#x901A;&#xFF0C;&#x5219;&#x6574;&#x6761;&#x8DEF;&#x53EF;&#x901A;&#x3002;
        if self.im2num_arr[cx][cy] == 0:
            if self.isSameRow(x1, y1, cx, cy) and self.isSameCol(cx, cy, x2, y2):
                return True
        if self.im2num_arr[dx][dy] == 0:
            if self.isSameRow(x1, y1, dx, dy) and self.isSameCol(dx, dy, x2, y2):
                return True
        return False

    # &#x5224;&#x65AD;&#x4E24;&#x4E2A;&#x62D0;&#x70B9;&#x53EF;&#x8054;&#x901A;
    def turnTwiceCheck(self, x1, y1, x2, y2):
        if x1 == x2 and y1 == y2:
            return False
        # &#x904D;&#x5386;&#x6574;&#x4E2A;&#x6570;&#x7EC4;&#x627E;&#x5408;&#x9002;&#x7684;&#x62D0;&#x70B9;
        for i in range(0, len(self.im2num_arr)):
            for j in range(0, len(self.im2num_arr[1])):
                # &#x4E0D;&#x4E3A;&#x7A7A;&#x4E0D;&#x80FD;&#x4F5C;&#x4E3A;&#x62D0;&#x70B9;
                if self.im2num_arr[i][j] != 0:
                    continue
                # &#x4E0D;&#x548C;&#x88AB;&#x9009;&#x65B9;&#x5757;&#x5728;&#x540C;&#x4E00;&#x884C;&#x5217;&#x7684;&#x4E0D;&#x80FD;&#x4F5C;&#x4E3A;&#x62D0;&#x70B9;
                if i != x1 and i != x2 and j != y1 and j != y2:
                    continue
                # &#x4F5C;&#x4E3A;&#x4EA4;&#x70B9;&#x7684;&#x65B9;&#x5757;&#x4E0D;&#x80FD;&#x4F5C;&#x4E3A;&#x62D0;&#x70B9;
                if (i == x1 and j == y2) or (i == x2 and j == y1):
                    continue
                if self.turnOnceCheck(x1, y1, i, j) and (
                        self.isSameRow(i, j, x2, y2) or self.isSameCol(i, j, x2, y2)):
                    return True
                if self.turnOnceCheck(i, j, x2, y2) and (
                        self.isSameRow(x1, y1, i, j) or self.isSameCol(x1, y1, i, j)):
                    return True
        return False

    # &#x5224;&#x65AD;&#x77E9;&#x9635;&#x662F;&#x5426;&#x5168;&#x4E3A;0
    def isAllZero(self, arr):
        for i in range(0, self.pWidth + 2):
            for j in range(0, self.pHeight + 2):
                if arr[i][j] != 0:
                    return False
        return True

    def start(self):
        # 3&#x3001;&#x904D;&#x5386;&#x67E5;&#x627E;&#x53EF;&#x4EE5;&#x76F8;&#x8FDE;&#x7684;&#x5750;&#x6807;
        global num1
        global num2
        num1 = 0#&#x5FAA;&#x73AF;&#x5224;&#x65AD;
        num2 = 0 #&#x7ED3;&#x675F;&#x7B26;
        print(self.im2num_arr)
        while not self.isAllZero(self.im2num_arr):
            if num1 == 10:
                for i in range(0, self.pWidth + 2):
                    for j in range(0, self.pHeight + 2):
                        self.im2num_arr[i][j] = 0
                num2 = 1
            for x1 in range(0, self.pWidth + 2):
                for y1 in range(0, self.pHeight + 2):
                    if self.im2num_arr[x1][y1] == 0:
                        continue
                    for x2 in range(0, self.pWidth + 2):
                        for y2 in range(0, self.pHeight + 2):
                            if self.im2num_arr[x2][y2] == 0 or (x1 == x2 and y1 == y2):
                                continue
                            if self.im2num_arr[x1][y1] == self.im2num_arr[x2][y2]:
                                if self.isReachable(x1, y1, x2, y2):
                                    self.pClick(x1, y1, x2, y2)
            num1 = num1 + 1
        return num2
if __name__ == '__main__':
    t = run_game(304, 271, 1226, 870,10,14,60.2,65.9)#&#x8BBE;&#x7F6E;&#x5143;&#x7D20;&#x5750;&#x6807;
    time.sleep(3)#&#x7B49;&#x5F85;3&#x79D2;
    image = cutPicture(304, 271, 1226, 870,10,14,60.2,65.9)#&#x622A;&#x56FE;
    arr = makeArray(10,14,image)#&#x8BBE;&#x7F6E;&#x77E9;&#x9635;
    t.im2num_arr = arr
    num = t.start()
    print("&#x6E38;&#x620F;&#x7ED3;&#x675F;!")

总结:程序难点在于两个图片之间相似度识别的精确性,不过对于练练看这个游戏来说,这个程序所使用的计算算法是够用的。

遇到问题:程序往往错误判断两个图片可以连接

解决方案:细微调整截图以及小图切分的像素位置,往往小图的切分是问题导致的关键,只要调整好切分的像素坐标,是没有问题的。

再次放视频链接:感兴趣可以看看,这是自制文章和视频,纯粹是兴趣分享,请在视频中点个赞吧!https://www.ixigua.com/7076826558106698253?logTag=f2d215ea6e6372c45362

说明:文章中引用了部分网友的知识点,不过这个程序我写的太久远的,不知道是哪篇文章了,如有引用请在评论区说明,我加个链接。

Original: https://blog.csdn.net/cqq1171422470/article/details/123965283
Author: QQ的猫好懒
Title: 连连看不一样的玩法,利用python进行图片相似度计算

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/642004/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球