别眨眼!用Python实现“大家来找茬”游戏自动化

148 阅读5分钟

别眨眼!用Python实现“大家来找茬”游戏自动化

哎你小时候玩过“大家来找茬”没?就两张看起来一模一样的图,让你挑错。那时候谁要是能一分钟找出五个不同点,直接神级操作。 现在咱们直接让python帮我们来找 😏

image.png


我们从最基础的讲起,别急,一步步来

我知道你看到“图像处理”四个字,脑子就嗡了对吧……想着会不会用到一堆你没见过的库,操作系统层的API,甚至要学OpenCV高级函数?别慌!聪明的你一定会发现,其实很多复杂的事情换个思路,就没那么吓人了。尤其是我们这种“能偷懒就偷懒”的人,嘿嘿。


首先,咱要有两张图片

这是我从网上随便找的一个用来测试:

image.png

你可能在想:那咱直接逐像素对比不就得了?

是啊……听起来很简单,但图像对比最大的问题不是“做不到”,而是——误差太多。哪怕两个图只是格式转换了下,压缩算法不一样,那些像素也会飘一丢丢,结果就可想而知了。


正确思路:结构相似性比较(SSIM)

不是“逐像素比”,而是“比感觉”。也就是 结构相似性(SSIM)算法。这玩意儿说人话就是:它模仿人眼的判断方式,比图像的结构、亮度、对比度等等,算出来一张“相似度图”。

SSIM 的输出是一张灰度图,越黑的地方差异越大。

先安装需要的库

pip install opencv-python scikit-image

opencv-python 这个库是 OpenCV 的 Python 版本,你可以拿它打开图片、改尺寸、加滤镜、找轮廓、画图、读视频,甚至接摄像头,堪称图像届全能型选手。大部分图像处理活儿,它都能搞定,效率还高——因为底层是 C++ 写的,跑起来飞快。

scikit-image scikit-image 是 Python 图像处理领域的“学霸型选手”,它不像 OpenCV 那样啥都管,它更专注于“图像分析”。你要比两张图有多像?识别某个纹理结构?提取边缘细节?找图像差异?它特别擅长干这些高阶操作,尤其是咱们这次用的 SSIM 算法,就是它家的主打。

先上代码——咱慢慢拆解

from skimage.metrics import structural_similarity as ssim
import cv2
import numpy as np

# 读取图像
img1 = cv2.imread('01.png')
img2 = cv2.imread('02.png')

# 转灰度图(SSIM只吃灰度)
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

# 计算相似度和差异图
score, diff = ssim(gray1, gray2, full=True)
diff = (1 - diff) * 255
diff = diff.astype("uint8")

print(f"相似度得分:{score:.4f}")

# 相似度得分:0.8865

一看代码居然这么少。是不是突然觉得“图像处理”其实挺简单的?


找不同,怎么圈出来?

上面那段代码生成的是一张“差异图”——黑白灰图,灰度越高代表差异越明显。那么我们接下来要干的事很简单:

  • 把“差异图”二值化
  • 找轮廓
  • 在原图上画个圈圈!

继续看👇

# 二值化
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

# 找轮廓
contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 在原图上画红圈
for c in contours:
    if cv2.contourArea(c) < 50:  # 忽略一些小噪点
        continue
    (x, y, w, h) = cv2.boundingRect(c)
    cv2.rectangle(img2, (x, y), (x + w, y + h), (0, 0, 255), 2)

cv2.imwrite('result.png', img2)

就是这么简单粗暴。图就出来了!红圈一圈一圈地把不同的地方都包了出来。


好多地方都标记错了怎么办

问题一:圈的位置不准,标记偏

大多数时候,这个锅其实是 图片尺寸没统一

哪怕你肉眼看是一样大小,像素对不上,图像对比就全歪了。

✅ 解决办法:对齐尺寸!
img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

你必须保证两张图的尺寸一模一样,不能信“看起来差不多”,必须用代码硬对齐。


问题二:乱圈?误圈?干扰项太多!

这通常是 SSIM 算法太敏感了

有时候压缩格式、亮度对比度不一致、图中有一些小噪点,它都当成“不同”来圈出来。

特别是那种微小的颜色过渡、阴影、jpg压缩痕迹,人类根本不觉得有差别,但 SSIM 觉得有差别。于是它就啪地给你画一圈。

✅ 解决办法:阈值过滤 + 图像预处理

下面这一句就是重点过滤机制:

if cv2.contourArea(c) < 50:
    continue  # 小面积忽略

你可以把 50 调大点,比如 100 或 200,看着来。 另外,可以提前对图像做模糊处理,减小那些细碎变化:

gray1 = cv2.GaussianBlur(gray1, (5, 5), 0)
gray2 = cv2.GaussianBlur(gray2, (5, 5), 0)

模糊一波再比,就像你眼睛眯起来再看图,反而清晰了😂


问题三:漏圈了!有不同但没标记!

这种情况其实也挺常见的——特别是差异不明显的时候。

比如:把“红色”改成“稍暗红”,或图里某个小细节被抹掉了,这种如果 SSIM 差异不够大,就不会触发阈值。

✅ 怎么办?

方法一:手动提高敏感度(不推荐,容易误报) 方法二:改用别的图像差异算法,比如 图像减法像素级差异百分比过滤

举个简单的“像素差异”粗暴算法:

diff = cv2.absdiff(gray1, gray2)
_, thresh = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)

这个虽然不如 SSIM 优雅,但真·能找到“变了”的地方。很多时候我们会结合两种方法一起用。


进阶建议:混合判断法(SSIM + 像素差)

ssim_diff = ssim(gray1, gray2, full=True)[1]
ssim_diff = (1 - ssim_diff) * 255
ssim_diff = ssim_diff.astype("uint8")

pixel_diff = cv2.absdiff(gray1, gray2)

# 合并两种差异结果
combined_diff = cv2.addWeighted(ssim_diff, 0.5, pixel_diff, 0.5, 0)

别问,问就是——混合比纯SSIM聪明。 人也是要“听觉 + 视觉 + 嗅觉”来判断世界嘛,算法也一样!


最后说2句

这类找出图片不同的功能,说简单它确实几行就能跑。但想圈得准、圈得少、圈得对,真的得调几轮。每张图的内容、光线、颜色都不一样,得出来的结果就千差万别。

聪明的你一定会调教出最适合自己需求的“找茬神器”💪

当然为了方便演示大家也可以在一张图片上面画几个点点然后让程序帮你找出来