第十六届全国大学生信息安全竞赛创新实践能力赛-Misc-国粹

有三张图片:

a.png 、k.png 是数量相等的一串麻将,题目.png是两行麻将,像是麻将种类的列举

解题思路:“题目”作为一个坐标轴,其中第一行是坐标轴的y轴,第二行是坐标轴的x轴,“a”和“k”是两两对应的坐标点,使用脚本匹配,将其坐标点画出来,获得flag。

将题目中的图片进行切片,脚本:

from PIL import Image

pic = Image.open('E:\\题目.png')
x = 0
y = 0
for i in range(0, 42):
    # m=Image.new('RGB',(431,73))
    n = pic.crop((x, y, x + 53, y + 73))
    #将从pic对象中裁剪出一个大小为53x73的矩形图像,并将结果保存在变量n中。
    n.save(f'E:\\cuted\\{i}.png')
    x += 53

这里记得手动创建一个保存图片切片的目录cuted,否则将找不到目录进而报错。

成功后得到如下一堆图片:

 然后根据a和k图片进行匹配,匹配出坐标点,画出坐标点,脚本:

import cv2
import numpy as np
import os
import turtle as t

images = []
x = [0 for i in range(343)]
y = [0 for i in range(343)]

# 获取文件夹内的图片名称
for root, dirs, filenames in os.walk('E:\\cuted'):
    for filename in filenames:
        f = int(filename.split(".")[0])  # 将文件名转换为数字
        images.append(f)

images.sort()  # 对文件名进行排序

# 读取识别图像
img_rgb = cv2.imread('E:\\a.png')
if img_rgb is None:
    raise Exception("Failed to load image: a.png")

img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)

# 使用模板匹配进行识别
for i in range(len(images)):
    template = cv2.imread(f'E:\\cuted\\{images[i]}.png', 0)
    if template is None:
        raise Exception(f"Failed to load template: {images[i]}.png")

    h, w = template.shape[:2]
    result = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
    threshold = 0.9
    loc = np.where(result >= threshold)

    for pt in zip(*loc[::-1]):
        m = pt[0] // 53
        x[m] = images[i]
        bottom_right = (pt[0] + w, pt[1] + h)
        cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)

cv2.imwrite("E:\\x.jpg", img_rgb)

# 读取第二张识别图像
img_rgb = cv2.imread('E:\\k.png')
if img_rgb is None:
    raise Exception("Failed to load image: k.png")

img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)

# 使用模板匹配进行识别
for i in range(len(images)):
    template = cv2.imread(f'E:\\cuted\\{images[i]}.png', 0)
    if template is None:
        raise Exception(f"Failed to load template: {images[i]}.png")

    h, w = template.shape[:2]
    result = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
    threshold = 0.9
    loc = np.where(result >= threshold)

    for pt in zip(*loc[::-1]):
        m = pt[0] // 53
        y[m] = images[i]
        bottom_right = (pt[0] + w, pt[1] + h)
        cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)

cv2.imwrite("E:\\y.jpg", img_rgb)

# 打印坐标
for i in range(0, 343):
    print(f'{x[i]} {y[i]}')

# 绘制模块
t.speed(100)
t.penup()
for i in range(0, 343):
    t.goto(y[i] * 5, -x[i] * 5)
    t.pendown()
    t.circle(1, 360)
    t.penup()

t.done()

运行成功即可获取到flag:

下面再看一个“F61d”战队的脚本:

他们是先获取题目图片尺寸,保存为一个字节组,然后对a.png和k.png进行切片,再拿去对着字节组进行匹配,脚本如下:

import numpy as np                     # 导入NumPy库,用于数值计算和数组操作
from PIL import Image                  # 导入PIL库中的Image模块,用于图像处理

class test():
    def __init__(self):
        self.a = np.array(Image.open("./a.png"))   # 通过Image.open()打开并读取名为"a.png"的图像,然后转换为NumPy数组
        self.k = np.array(Image.open('./k.png'))   # 通过Image.open()打开并读取名为"k.png"的图像,然后转换为NumPy数组
        self.img = np.array(Image.open('./题目.png'))   # 通过Image.open()打开并读取名为"题目.png"的图像,然后转换为NumPy数组
        self.img_make()                            # 调用img_make()方法,用于处理图像尺寸
        self.dic()                                 # 调用dic()方法,用于创建字典映射

    def img_make(self):
        lst_img = self.img.shape                    # 获取self.img的形状(尺寸)
        self.part = (lst_img[0] // 2, lst_img[1] // 43, lst_img[2])    # 计算图像尺寸的一部分,用于后续的图像分割

    def dic(self):
        dic = {}                                    # 创建一个空字典,用于存储图像片段与索引的映射关系
        for n, x in enumerate(range(self.part[1], self.img.shape[1], self.part[1])):
            # 遍历图像中的特定区域,每次从x=self.part[1]开始,到x=self.img.shape[1]为止,以self.part[1]为步长
            # 这个循环将图像分割成若干个小片段,并将每个片段的像素值转换为字节序列,并作为键存储到字典dic中,值为n
            dic[self.img[0:self.part[0], x:x + self.part[1], :self.part[2] - 1].tobytes()] = n

        # 使用字典dic将self.a和self.k中的每个像素值转换为对应的索引值
        self.a = [dic[self.a[:, x:x + self.part[1]].tobytes()] for x in range(0, self.a.shape[1], self.part[1])]
        self.k = [dic[self.k[:, x:x + self.part[1]].tobytes()] for x in range(0, self.k.shape[1], self.part[1])]

        result = np.zeros((max(self.a), max(self.k)), dtype=np.uint8)    # 创建一个二维的全零数组,大小由self.a和self.k的最大值确定
        result[np.array(self.a) - 1, np.array(self.k) - 1] = 1          # 将数组result中对应索引位置的元素设为1
        resimg = Image.fromarray(result * 255)                          # 将二维数组result转换为PIL图像
        resimg.show()                                                    # 显示图像

if __name__ == "__main__":
    test()               # 创建test类的实例,并执行其中的代码

运行成功后可得到flag,如图:

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值