作为xlang的项目示例之一, 这篇博文主要讲制作一个简单的隐形水印工具。
隐形水印就是把一些信息秘密地嵌入到音频、视频、图片等载体中,用户角度上看不到,但可以使用特定算法检测出来,用户传播媒体,该水印也不会消失,这样可以实现追踪。
本文主要讲通过fftw在图片频域嵌入水印。
FFTW是用做快速傅里叶变换的库,关于使用傅里叶变换进行时频域转换这里做大概介绍,时域和频域是信号的基本性质,图像也是一种信号,用户角度观察到的是时域图像,而使用fftw则可得到频域图像,我们的水印就是在图像信号的频域进行处理,想了解时频域相关详细资料自行查询, 这里不多做解释(不了解详细也不影响,知道这个大概原理即可)。
开发原理: 使用fftw库对图像的数据进行变换,然后对变换后的数据进行处理,最后还原图像。
需要支持文字图像或者自定义的图案,并且需要手动调节频域信号的能量,使之具有一定的抗攻击性。
接下来使用XStudio新建功能创建一个form应用.
并编辑ui界面文件(xlang使用了qt作为基本界面库, 所以编辑界面是直接使用qtdesigner的,还是比较方便的)。
编辑成最终想要的样子:
然后在SecretWatermark.xcs中定义一系列控件和事件关联,详细过程略去,需要的在文章末尾下载源代码自行查看。
紧接着我们给项目引入fftw包,点击菜单【工具】-》【包管理】,找到并选中 xfftw 然后点击添加到项目,如下图:
我们需要得到图像的像素数据,在这里使用QXImage 类加载图片, 然后使用QXImage的getdata方法即可获得像素数据:
QXImage tmp = nilptr;
try{
// 从文件加载图片
tmp = new QXImage(file, nilptr);
}catch(Exception e){
// 加载出错了
return tmp;
}
//获取像素数据
byte [] data = tmp.getdata();
//图片宽
int w = tmp.width();
//图片高
int h = tmp.height();
然后对所有像素按字节进行归一化, 处理255.f 转为 0~1的浮点数。
// 像素数据是ARGB8888的 所以一个像素有四个字节,则 length / 4是像素总数
int l = data.length / 4;
//读取数据并归一化
double []r = new double[l];
double []g = new double[l];
double []b = new double[l];
for (int i = 0; i < l; i ++){
r[i] = data[(i * 4) + 2] /