基于 DWT 的盲数字水印实现(嵌入与提取)
一、原理盲数字水印Blind Watermarking指提取水印时无需原始载体图像仅依靠含水印图像和密钥即可完成。DWT离散小波变换 将图像分解为LL低频近似分量能量集中稳定性强适合嵌入水印LH/HL/HH高频细节分量边缘/纹理不适合嵌入易失真嵌入逻辑修改 LL 分量的系数如奇偶性、幅度偏移隐藏水印信息提取逻辑对含水印图像做相同 DWT 分解从 LL 分量反推水印信息。二、完整 C# 实现使用 AForge.NET2.1 环境配置!-- NuGet 依赖 --PackageReferenceIncludeAForge.ImagingVersion2.2.5/PackageReferenceIncludeAForge.MathVersion2.2.5/2.2 核心类DwtBlindWatermark.csusingAForge.Imaging;usingAForge.Imaging.Filters;usingAForge.Math;usingSystem;usingSystem.Drawing;usingSystem.Drawing.Imaging;namespaceDwtWatermark{publicclassDwtBlindWatermark{// 配置参数嵌入/提取必须一致privateconststringWaveletNamehaar;// 小波基haar 计算最快privateconstintDecompositionLevels1;// DWT 分解层数1层足够privateconstdoubleEmbedStrength0.05;// 嵌入强度0.01~0.1平衡不可见性privateconstintWatermarkSize32;// 水印尺寸32x32 二值图/// summary/// 嵌入水印盲水印仅修改 LL 分量/// /summarypublicBitmapEmbedWatermark(Bitmapcarrier,Bitmapwatermark,intsecretKey){// 1. 预处理转为灰度图vargrayCarrierGrayscale.CommonAlgorithms.BT709.Apply(carrier);vargrayWatermarkGrayscale.CommonAlgorithms.BT709.Apply(watermark);// 2. 载体 DWT 分解ComplexImagecomplexCarrierComplexImage.FromBitmap(grayCarrier);complexCarrier.ForwardDWT(WaveletName,DecompositionLevels);Complex[,]llcomplexCarrier.Image;// LL 分量复数数组取实部// 3. 水印二值化并转为序列bool[,]watermarkBitsBinarizeWatermark(grayWatermark);intbitIndex0;// 4. 嵌入水印修改 LL 系数的奇偶性RandomrndnewRandom(secretKey);intstridell.GetLength(1);for(inty0;yll.GetLength(0);y){for(intx0;xll.GetLength(1);x){if(bitIndexWatermarkSize*WatermarkSize)break;// 随机选择 LL 系数增强安全性intrxrnd.Next(ll.GetLength(0));intryrnd.Next(ll.GetLength(1));doublecoeffll[rx,ry].Re;// 嵌入规则水印位 1 → 系数调整为奇数0 → 偶数boolwatermarkBitwatermarkBits[bitIndex/WatermarkSize,bitIndex%WatermarkSize];doublemodifiedCoeffcoeff;if(watermarkBit)modifiedCoeffMath.Ceiling(coeff)%20?coeffEmbedStrength:coeff;elsemodifiedCoeffMath.Floor(coeff)%21?coeff-EmbedStrength:coeff;ll[rx,ry]newComplex(modifiedCoeff,ll[rx,ry].Im);bitIndex;}}// 5. 逆 DWT 重构含水印图像complexCarrier.BackwardDWT(WaveletName,DecompositionLevels);returncomplexCarrier.ToBitmap();}/// summary/// 提取水印无需原始载体/// /summarypublicBitmapExtractWatermark(BitmapwatermarkedCarrier,intsecretKey){// 1. 预处理vargrayCarrierGrayscale.CommonAlgorithms.BT709.Apply(watermarkedCarrier);// 2. 含水印图像 DWT 分解ComplexImagecomplexCarrierComplexImage.FromBitmap(grayCarrier);complexCarrier.ForwardDWT(WaveletName,DecompositionLevels);Complex[,]llcomplexCarrier.Image;// 3. 提取水印比特bool[,]extractedBitsnewbool[WatermarkSize,WatermarkSize];RandomrndnewRandom(secretKey);intbitIndex0;for(inty0;yll.GetLength(0);y){for(intx0;xll.GetLength(1);x){if(bitIndexWatermarkSize*WatermarkSize)break;intrxrnd.Next(ll.GetLength(0));intryrnd.Next(ll.GetLength(1));doublecoeffll[rx,ry].Re;// 提取规则系数为奇数 → 1偶数 → 0extractedBits[bitIndex/WatermarkSize,bitIndex%WatermarkSize]Math.Abs(coeff%2)0.5;bitIndex;}}// 4. 比特数组转水印图像returnBitsToBitmap(extractedBits);}#region辅助方法// 水印二值化阈值 128privatebool[,]BinarizeWatermark(Bitmapwatermark){bool[,]bitsnewbool[WatermarkSize,WatermarkSize];BitmapresizednewResizeNearestNeighbor(WatermarkSize,WatermarkSize).Apply(watermark);for(inty0;yWatermarkSize;y)for(intx0;xWatermarkSize;x)bits[y,x]resized.GetPixel(x,y).R128;returnbits;}// 比特数组转图像privateBitmapBitsToBitmap(bool[,]bits){BitmapbmpnewBitmap(WatermarkSize,WatermarkSize);for(inty0;yWatermarkSize;y)for(intx0;xWatermarkSize;x)bmp.SetPixel(x,y,bits[y,x]?Color.White:Color.Black);returnbmp;}#endregion}}2.3 主程序测试Program.csusingSystem;usingSystem.Drawing;usingSystem.Drawing.Imaging;namespaceDwtWatermark{classProgram{staticvoidMain(string[]args){Console.WriteLine( DWT 盲数字水印测试 \n);// 1. 读取图像替换为你的路径BitmapcarriernewBitmap(carrier.jpg);// 载体图像如风景照BitmapwatermarknewBitmap(logo.png);// 水印图像32x32 二值图intsecretKey123456;// 密钥嵌入/提取必须一致varwatermarkernewDwtBlindWatermark();// 2. 嵌入水印Console.WriteLine(嵌入水印...);Bitmapwatermarkedwatermarker.EmbedWatermark(carrier,watermark,secretKey);watermarked.Save(watermarked.jpg,ImageFormat.Jpeg);Console.WriteLine(含水印图像保存至watermarked.jpg\n);// 3. 提取水印Console.WriteLine(提取水印...);Bitmapextractedwatermarker.ExtractWatermark(watermarked,secretKey);extracted.Save(extracted_watermark.jpg,ImageFormat.Jpeg);Console.WriteLine(提取的水印保存至extracted_watermark.jpg\n);// 4. 评估PSNR峰值信噪比30dB 说明不可见性好doublepsnrCalculatePSNR(carrier,watermarked);Console.WriteLine($载体与含水印图像的 PSNR:{psnr:F2}dB);Console.WriteLine((PSNR 30dB 表示水印不可见));Console.WriteLine(\n测试完成按任意键退出...);Console.ReadKey();}// 计算 PSNR评估不可见性staticdoubleCalculatePSNR(Bitmaporiginal,Bitmapcompressed){doublemse0;for(inty0;yoriginal.Height;y){for(intx0;xoriginal.Width;x){Colorc1original.GetPixel(x,y);Colorc2compressed.GetPixel(x,y);mseMath.Pow(c1.R-c2.R,2)Math.Pow(c1.G-c2.G,2)Math.Pow(c1.B-c2.B,2);}}mse/(original.Width*original.Height*3);return10*Math.Log10(255*255/mse);}}}三、参数说明参数作用建议值WaveletName小波基haar计算快稳定性好DecompositionLevelsDWT 分解层数1层数过多易失真EmbedStrength嵌入强度0.01~0.1越大鲁棒性越强但易失真secretKey密钥整数嵌入/提取必须一致参考 盲水印嵌入提取www.youwenfan.com/contentcsu/63122.html四、鲁棒性测试对含水印图像进行以下攻击验证水印是否可提取JPEG 压缩质量 50%→ 水印应仍可识别高斯噪声均值 0方差 0.01→ 轻微影响裁剪裁剪 10% 边缘→ 依赖 LL 分量仍可能提取旋转±5°→ 需结合几何校正本示例未实现可扩展。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2608533.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!