什么是隐藏图?请在手机版小红书上打开此链接双指放大图片观看。
本人还写了一个QT程序,可以通过傻瓜式操作生成隐藏图,有兴趣可以自行体验。
主要就是根据透明度展示原理去针对一个通道列方程,然后发现把前景图的色值全部映射到 128 ~ 255
而隐藏图的色值全部映射到 0 ~ 127
,方程就刚好是必然有解的,也就是不管任何的前景图色值和隐藏图色值的组合都一定能够找到一对合法的效果图的透明度和色值。
由于每个像素点只有一个透明度但有三个颜色通道,所以彩色图是做不了的。
原理大概就是这样,暂不细讲,后面再填坑,先开源一下代码。
本项目是基于 QT 开发的,构建工具用的 qmake。
首先要在项目的 .pro
文件加下面这句,中文才能正常编码。
QMAKE_CXXFLAGS += /source-charset:utf-8 /execution-charset:utf-8
然后就是 main.cpp
文件了。
#include <QApplication>
#include <QImage>
#include <QFileDialog>
#include <QInputDialog>
#include <iostream>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 使用文件对话框选择图片AQString fileA = QFileDialog::getOpenFileName(nullptr, "请选择前景图(白色背景下展示的图片)", "", "Images (*.png *.xpm *.jpg)");if (fileA.isEmpty()) {std::cerr << "No file selected for Image A." << std::endl;return 1;}QImage imageA(fileA);// 使用文件对话框选择图片BQString fileB = QFileDialog::getOpenFileName(nullptr, "请选择隐藏图(黑色背景下展示的图片)", "", "Images (*.png *.xpm *.jpg)");if (fileB.isEmpty()) {std::cerr << "No file selected for Image B." << std::endl;return 1;}QImage imageB(fileB);// 使用输入对话框获取最终图片的宽度和高度bool ok;int width = QInputDialog::getInt(nullptr, "Input Width", "输入效果图宽度(如 500)", 500, 1, 10000, 1, &ok);if (!ok) {std::cerr << "No width input." << std::endl;return 1;}int height = QInputDialog::getInt(nullptr, "Input Height", "输入效果图高度(如 500)", 500, 1, 10000, 1, &ok);if (!ok) {std::cerr << "No height input." << std::endl;return 1;}// 转为灰度图QImage grayA = imageA.convertToFormat(QImage::Format_Grayscale8);QImage grayB = imageB.convertToFormat(QImage::Format_Grayscale8);// 都强制修改为用户输入的宽度和高度QImage A = grayA.scaled(width, height);QImage B = grayB.scaled(width, height);QImage image(width, height, QImage::Format_ARGB32);for (int i = 0; i < width; i++) {for (int j = 0; j < height; j++) {int a = qGray(A.pixel(i, j));int b = qGray(B.pixel(i, j));// 把 a(白背景下的)都强制映射到 128~255,b(黑色背景下的)都强制映射到 0~127a = a * 0.5 + 128;b *= 0.5;int x = a - b; // 透明度int y = b / (1 - x / 255.0); // 灰度值,这个值就很有趣,会发现 y 范围一定是 0~255 的。image.setPixel(i, j, qRgba(y, y, y, 255 - x)); // tmd,原来这个Rgba的“a”是不透明度,值越大就越不透明[捂脸]}}// 使用文件对话框选择保存路径QString savePath = QFileDialog::getSaveFileName(nullptr, "保存效果图到", "", "PNG Files (*.png);;All Files (*)");if (savePath.isEmpty()) {std::cerr << "No file selected for saving the result." << std::endl;return 1;}// 保存图像到文件if (!image.save(savePath)) {std::cerr << "Failed to save the image." << std::endl;return 1;}return 0;
}
以上就是所有的代码,是不是有种大道至简的感觉呢?