首页 > 编程知识 正文

图片加隐形水印防盗图(透明水印在线生成)

时间:2023-05-05 00:47:26 阅读:66293 作者:3415

作为xlang的一个项目示例,这篇博文主要讨论创建一个简单的隐形水印工具。

隐形水印是秘密嵌入在音频、视频、图像等介质中的信息,用户看不见,但可以通过特定算法检测到,即使用户发布媒体,该水印也不会消失。 由此,可以进行追踪。

本文主要通过fftw在图像的频域嵌入水印。

ftw是用于进行快速傅立叶变换的库。 这里大致说明使用傅立叶变换的频域变换。 时域和频域是信号的基本性质,图像也是信号。 从用户的观点来看是时域的图像,但使用FFTW可以得到频域的图像。 我们的水印是在图像信号的频域进行处理,关于时频域的细节需要自己去研究,但这里不太说明(不详细也没有影响)。 知道这个概略原理就可以了)。

开发原理:利用fftw库转换图像的数据,处理转换后的数据,并最终恢复图像。

需要支持文字图像或自定义模式,手动调整频域信号的能量,使其具有一定的攻击性。

然后,使用XStudio的新功能创建表单APP应用程序。

编辑ui接口文件。 (由于xlang使用qt作为基本接口库,因此编辑接口是否直接使用qtdesigner非常有用。

最终按照想要的方式编辑:

接下来,在SecretWatermark.xcs中定义一组控件与事件的关联。 省略详细步骤,必要时在文章末尾下载源代码自行确认。

然后在项目中引入fftw包,单击菜单【工具】-【包管理】,找到并选择xfftw,然后单击将其添加到项目中。 下图:

需要获取图像的像素数据。 这里使用QXImage类加载图像,并使用QXImage的getdata方法检索像素数据。 QXImage tmp=nilptr; 从try{//文件读取图像的tmp=newqximage(file,nilptr ); }catch(exceptione )//加载错误返回时间; //像素数据byte [] data=tmp.getdata (; //照片宽度int w=tmp.width (; //图高int h=tmp.height (; 然后,按字节对所有像素进行规范化,并处理将255.f转换为0到1的浮点数。 //像素数据是ARGB8888,所以如果1个像素有4字节,则length/4是像素总数int l=data.length/4; //读取数据并标准化的double []r=new double[l]; 双精度[ ] g=new双精度[ l ]; 双精度[ ] b=新双精度[ l ]; for(intI=0; i l; I ) r(I )=data((I*4)2)2]/255.f; g[I]=data[(I*4)1]/255.f; b[I]=data[(I*4)0]/255.f; }将所有数据规范化为单个双精度数组,并进行傅立叶变换: //傅立叶正变换Double[][]RF=fftw.FFT2(h、w、r、nilptr ); double[][]gf=fftw.fft2(h、w、g、nilptr ); double[][]BF=fftw.fft2(h,w,b,nilptr ); 同样,水印的图像也使用QXImage加载取得其像素数据,得到一个byte数组。 QXImage wmpic=nilptr; 从try{//文件加载水印图像WM pic=newq ximage (标记文件,nilptr ); }catch(exceptione )//加载错误QXMessageBox.Critical ),)无效的图像文件: ) markfile、QXMessageBox.Ok、QXMessageBox.Ok //像素数据byte [] wm=water.getdata (; //照片宽度int mw=water.width (; //图高int mh=water.height (; 然后,将水印字节数组中的像素数据直接与频域双精度数组混合。 //pf表示水印的能量系数for(intx=0; x mw; x ) for(inty=0; y mh; y ) intry=h-(ysh1 ); intrx=w-(xST1; int mi=y * mw x; intoi=(ysh ) w ) x st; int ni=(ry * w ) rx; RF[0][oi]=(WM[mi*4] ) pf; gf[0][oi]=(WM[mi*41] ) pf; BF[0][oi]=(WM[mi*42] ) pf; RF[0][Ni]=(WM[mi*4] ) pf; gf[0][Ni]=(WM[mi*41] ) pf; BF[0][Ni]=(WM[mi*42] ) pf; }最后使用傅立叶逆变换恢复图像。 //傅立叶逆变换double[][]rt=fftw.ifft2(h,w,rf[0],rf[1] ); double[][]gt=fftw.ifft2(h,w,gf[0],gf[1] ); double[][]Bt=fftw.ifft2(h,w,bf[0],bf[1] ); 双精度PV=255.f/l; byte数组byte []rgb=new byte [w * h * 4]; for(intI=0; i l; I ) (RGB(2) I*4)=math.max ) 0,math.min ) 255,(int ) rt(0) (I ) *PV ) ) ) ); RGB[1(I*4) ]=Math.max(0) 0,math.min ) 255,) int ) gt[0][i] * pv ); RGB[0(I*4) ]=Math.max(0) 0,math.min ) 255,) int ) bt[0][i] * pv ); RGB[3(I*4) ]=0xff; }runonui(newrunnable ) {void run ) override(/byte数组生成的QXImage恢复图像doneimg=newqximage ) RGB、w、h、qximage.format //}; ); 这是原始照片:

加载原图:

原图的频域是无意义的噪声,被认为是空白的。

这是水印图像:

请选择水印图像并查看效果:

调整和更新水印的位置和能量

可见,中间图像是最终生成的预览图像,在原始图像中几乎看不到。 然后保存点,并保存为bmp文件。

然后,重新运行程序并尝试加载上面保存的bmp文件。

可以清楚地看到频域的水印。 然后,将此bmp转换为其他格式(如png或jpg ),以尝试水印在遇到攻击时的效果。

在ps中打开bmp文件,并将其另存为png文件和jpg文件。

首先看png压缩。

让我们来看看jpg压缩:

虽然jpg的压缩变形比较严重,但是水印识别度仍然很高。

源代码下载地点是:点

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。