我应该如何在患有红绿色盲的情况下通过 CF2214H Double Vision?

· · 休闲·娱乐

观察题目描述可知,本题主要考察选手是不是色盲。由生物学常识可知,最常见的色盲是红绿色盲,因此不难想到题目考察选手对红色与绿色的区分能力。

因此下载题目中唯一一张图片,并在目录下运行如下 Python 代码:

from PIL import Image
import numpy as np

# 读取图像
img = Image.open('filename.png') # 请将 filename.png 改为你的文件名

# 转换为RGB模式(确保图像是RGB格式)
if img.mode != 'RGB':
    img = img.convert('RGB')

# 将图像转换为numpy数组
img_array = np.array(img)

# 提取RGB三个通道
r_channel = img_array[:, :, 0]  # R通道
g_channel = img_array[:, :, 1]  # G通道
b_channel = img_array[:, :, 2]  # B通道

# 保存为图像文件
Image.fromarray(r_channel).save('R_channel.png')
Image.fromarray(g_channel).save('G_channel.png')
Image.fromarray(b_channel).save('B_channel.png')

# 可选:保存为文本文件(显示数值)
# np.savetxt('R_channel.txt', r_channel, fmt='%d')
# np.savetxt('G_channel.txt', g_channel, fmt='%d')
# np.savetxt('B_channel.txt', b_channel, fmt='%d')

print("RGB通道已提取并保存为:")
print("- R_channel.png")
print("- G_channel.png")
print("- B_channel.png")

可得如下三张图像(分别为 R、G、B 通道)。

不难观察到重复出现 13 次的 74 字样,因此输出 74 74 74 74 74 74 74 74 74 74 74 74 74 即可。

#include <cstdio>
using namespace std;
int main() {
    printf("74 74 74 74 74 74 74 74 74 74 74 74 74");
    return 0;
}

欸?我为什么没有通过此题?

再次观察题面,注意到题目名 Double Vision,不难联想到一种需要将两眼视觉错位叠加的图片:Autostereogram。

为了看出在 Autostereogram 中隐藏的信息,我们需要将两眼的焦平面移动至屏幕的前方或后方,达到将图像错位叠加的效果。

因此,我们需要将图像平移一段距离,求出与原图片的差,存储于新图片中。考虑到 Autostereogram 的平移量一般为一个重复单元的长度,我们需要求出其长度。

上图为原图的 R 通道,放大 6 倍,蓝色虚线长方形的长边即为一个重复单元的长度。观察图片最下方的信息栏,我们知道一个重复单元长 171 像素。因此在图片目录下运行如下 Python 代码:

from PIL import Image
import numpy as np

def shift_and_difference(image_path, shift_amount=100):
    # 读取图像
    img = Image.open(image_path)

    # 转换为RGB模式(确保有三通道)
    if img.mode != 'RGB':
        img = img.convert('RGB')

    # 获取图像尺寸
    width, height = img.size

    # 转换为numpy数组
    img_array = np.array(img)

    # 创建平移后的图像数组(用黑色填充移出的部分)
    shifted_array = np.zeros_like(img_array)

    # 向左平移:原图像的右侧部分移动到左侧
    if shift_amount < width:
        shifted_array[:, :width - shift_amount] = img_array[:, shift_amount:]

    # 计算差值(绝对值差)
    diff_array = np.abs(img_array.astype(np.int16) - shifted_array.astype(np.int16))
    diff_array = diff_array.astype(np.uint8)  # 转换回uint8类型

    # 转换为PIL图像
    diff_img = Image.fromarray(diff_array)

    # 保存结果
    diff_img.save('difference.png')

    # 可选:保存平移后的图像用于调试
    shifted_img = Image.fromarray(shifted_array)
    shifted_img.save('shifted_left_' + str(shift_amount) + '.png')

    return diff_img, shifted_img

# 执行平移和差分
shift = 171 # 定义平移量
difference_image, shifted_image = shift_and_difference('filename.png', shift_amount=shift) # 请将 filename.png 改为你的文件名

print("已完成操作:")
print("- 原始图像向左平移" + str(shift) + "像素")
print("- 计算原始图像与平移图像的差值")
print("- 结果保存为 difference.png")
print("- 平移图像保存为 shifted_left_" + str(shift) + ".png(用于调试)")

得到如下图片(difference.png):

不难读出文字内容:YU5zV2VS,输出该字符串即可。

参考代码:

#include <cstdio>
using namespace std;
int main() {
    printf("YU5zV2VS");
    return 0;
}