频域添加数字水印的方法,是指通过某种变换手段(傅里叶变换,离散余弦变换,小波变换等)将图像变换到频域(小波域),在频域对图像添加水印,再通过逆变换,将图像转换为空间域。相对于空域手段,频域手段隐匿性更强,抗攻击性更高。

代码使用OpenCvSharp / c#实现

添加水印:

// 读取图像并获取b通道
string filename = @"C:\Users\xiaomao\Desktop\123.png";
Mat origin = Cv2.ImRead(filename, ImreadModes.Color);
Mat[] arr = origin.Split();
Mat image = arr[0];// 将输入图像扩大到最佳尺寸
Mat padded = new Mat();
int m = Cv2.GetOptimalDFTSize(image.Rows);
int n = Cv2.GetOptimalDFTSize(image.Cols);
Cv2.CopyMakeBorder(image, padded, 0, m - image.Rows, 0, n - image.Cols, BorderTypes.Constant, Scalar.All(0));Mat temp = new Mat();
padded.ConvertTo(temp, MatType.CV_32F);
Mat[] planes = new Mat[] { temp, Mat.Zeros(padded.Size(), MatType.CV_32F) };
Mat complexImage = new Mat();
// 吧一个zeros通道和扩展通道合并在一起
Cv2.Merge(planes, complexImage);// 进行傅里叶变换
Cv2.Dft(complexImage, complexImage);Cv2.PutText(complexImage, "happy family", new OpenCvSharp.Point(50, 50), HersheyFonts.HersheyComplex, 1.5, Scalar.All(0), 6);// 将DFT实数和虚数部分变换成幅值
Cv2.Split(complexImage, out planes);// planes[0]为DFT变换结果的实部,planes[1]为虚部
Cv2.Magnitude(planes[0], planes[1], planes[0]);// 如此planes[0]存储的幅值大小Mat magImage = planes[0];// 将幅值转换到对数空间
magImage += Scalar.All(1);
Cv2.Log(magImage, magImage);// 如果图像的尺寸是奇数的话对图像进行裁剪并重新排列
magImage = new Mat(magImage, new Rect(0, 0, magImage.Cols & -2, magImage.Rows & -2));// 重新排列Fourier图像的象限,使得图像的中心在象限的原点
int cx = magImage.Cols / 2;
int cy = magImage.Rows / 2;Mat q0 = new Mat(magImage, new Rect(0, 0, cx, cy));  // 左上
Mat q1 = new Mat(magImage, new Rect(cx, 0, cx, cy));  // 右上
Mat q2 = new Mat(magImage, new Rect(0, cy, cx, cy));  // 左下
Mat q3 = new Mat(magImage, new Rect(cx, cy, cx, cy));     // 右下Mat tmp = new Mat();    //交换象限 (左上与右下交换)
q0.CopyTo(tmp);
q3.CopyTo(q0);
tmp.CopyTo(q3);//交换象限 (右上与左下)
q1.CopyTo(tmp);
q2.CopyTo(q1);
tmp.CopyTo(q2);// 将幅度矩阵转化为0~1之间的浮点型数据方便显示
Cv2.Normalize(magImage, magImage, 0, 1, NormTypes.MinMax);// 将32fc1的图片转为,8UC1, 0-1重新映射到0-255,为了显示
Mat temp1 = new Mat();
magImage.ConvertTo(temp1, MatType.CV_8UC1, 255);
Cv2.ImShow("spectrum magnitude", temp1);//傅里叶逆变换
Mat outMat = new Mat();
Cv2.Idft(complexImage, outMat, DftFlags.Scale | DftFlags.RealOutput);//合并回原图
outMat.ConvertTo(outMat, MatType.CV_8UC1);
arr[0] = new Mat(outMat, new Rect(0, 0, 894, 630));//.Resize(new OpenCvSharp.Size(894, 630));
Mat dst = new Mat(image.Size(), MatType.CV_8UC3);
Cv2.Merge(arr, dst);//输出并保存图片
Cv2.ImShow("outMat", dst);
Cv2.ImWrite(@"C:\Users\xiaomao\Desktop\20210927102553.jpg", dst);

左侧是原图,右侧是添加水印后的图,看不出来差别。

查看水印:

// 读取添加过水印的图片
string filename = @"C:\Users\xiaomao\Desktop\20210927102553.jpg";
Mat origin = Cv2.ImRead(filename, ImreadModes.Color);
Mat image = origin.Split()[0];// Cv2.ImRead(filename, ImreadModes.Grayscale);
Mat imageCopy = image.Clone();// 将输入图像扩大到最佳尺寸
Mat padded = new Mat();
int m = Cv2.GetOptimalDFTSize(image.Rows);
int n = Cv2.GetOptimalDFTSize(image.Cols);
Cv2.CopyMakeBorder(image, padded, 0, m - image.Rows, 0, n - image.Cols, BorderTypes.Constant, Scalar.All(0));Mat temp = new Mat();
padded.ConvertTo(temp, MatType.CV_32F);
Mat[] planes = new Mat[] { temp, Mat.Zeros(padded.Size(), MatType.CV_32F) };
Mat complexImage = new Mat();
// 吧一个zeros通道和扩展通道合并在一起
Cv2.Merge(planes, complexImage);// 进行傅里叶变换
Cv2.Dft(complexImage, complexImage);// 将DFT实数和虚数部分变换成幅值
Cv2.Split(complexImage, out planes);// planes[0]为DFT变换结果的实部,planes[1]为虚部
Cv2.Magnitude(planes[0], planes[1], planes[0]);// 如此planes[0]存储的幅值大小Mat magImage = planes[0];// 将幅值转换到对数空间
magImage += Scalar.All(1);
Cv2.Log(magImage, magImage);// 如果图像的尺寸是奇数的话对图像进行裁剪并重新排列
magImage = new Mat(magImage, new Rect(0, 0, magImage.Cols & -2, magImage.Rows & -2));// 重新排列Fourier图像的象限,使得图像的中心在象限的原点
int cx = magImage.Cols / 2;
int cy = magImage.Rows / 2;Mat q0 = new Mat(magImage, new Rect(0, 0, cx, cy));  // 左上
Mat q1 = new Mat(magImage, new Rect(cx, 0, cx, cy));  // 右上
Mat q2 = new Mat(magImage, new Rect(0, cy, cx, cy));  // 左下
Mat q3 = new Mat(magImage, new Rect(cx, cy, cx, cy));     // 右下Mat tmp = new Mat();    //交换象限 (左上与右下交换)
q0.CopyTo(tmp);
q3.CopyTo(q0);
tmp.CopyTo(q3);//交换象限 (右上与左下)
q1.CopyTo(tmp);
q2.CopyTo(q1);
tmp.CopyTo(q2);// 将幅度矩阵转化为0~1之间的浮点型数据方便显示
Cv2.Normalize(magImage, magImage, 0, 1, NormTypes.MinMax);// 将32fc1的图片转为,8UC1, 0-1重新映射到0-255,为了显示
Mat temp1 = new Mat();
magImage.ConvertTo(temp1, MatType.CV_8UC1, 255);
Cv2.ImShow("spectrum magnitude", temp1);

添加水印的图

Opencv学习笔记 - 频域手段添加盲水印相关推荐

  1. OpenCV学习笔记(四十六)——FAST特征点检测features2D OpenCV学习笔记(四十七)——VideoWriter生成视频流highgui OpenCV学习笔记(四十八)——PCA算

    OpenCV学习笔记(四十六)--FAST特征点检测features2D 特征点检测和匹配是计算机视觉中一个很有用的技术.在物体检测,视觉跟踪,三维常年关键等领域都有很广泛的应用.这一次先介绍特征点检 ...

  2. OpenCV学习笔记(六)(七)(八)(九)(十)

    OpenCV学习笔记(六)--对XML和YAML文件实现I/O操作 1. XML.YAML文件的打开和关闭 XML\YAML文件在OpenCV中的数据结构为FileStorage,打开操作例如: [c ...

  3. python做直方图-python OpenCV学习笔记实现二维直方图

    本文介绍了python OpenCV学习笔记实现二维直方图,分享给大家,具体如下: 官方文档 – https://docs.opencv.org/3.4.0/dd/d0d/tutorial_py_2d ...

  4. OpenCV学习笔记(五十六)——InputArray和OutputArray的那些事core OpenCV学习笔记(五十七)——在同一窗口显示多幅图片 OpenCV学习笔记(五十八)——读《Mast

    OpenCV学习笔记(五十六)--InputArray和OutputArray的那些事core 看过OpenCV源代码的朋友,肯定都知道很多函数的接口都是InputArray或者OutputArray ...

  5. OpenCV学习笔记(五十一)——imge stitching图像拼接stitching OpenCV学习笔记(五十二)——号外:OpenCV 2.4.1 又出来了。。。。。 OpenCV学习笔记(五

    OpenCV学习笔记(五十一)--imge stitching图像拼接stitching stitching是OpenCV2.4.0一个新模块,功能是实现图像拼接,所有的相关函数都被封装在Stitch ...

  6. OpenCV学习笔记(四十一)——再看基础数据结构core OpenCV学习笔记(四十二)——Mat数据操作之普通青年、文艺青年、暴力青年 OpenCV学习笔记(四十三)——存取像素值操作汇总co

    OpenCV学习笔记(四十一)--再看基础数据结构core 记得我在OpenCV学习笔记(四)--新版本的数据结构core里面讲过新版本的数据结构了,可是我再看这部分的时候,我发现我当时实在是看得太马 ...

  7. OpenCV学习笔记(三十一)——让demo在他人电脑跑起来 OpenCV学习笔记(三十二)——制作静态库的demo,没有dll也能hold住 OpenCV学习笔记(三十三)——用haar特征训练自己

    OpenCV学习笔记(三十一)--让demo在他人电脑跑起来 这一节的内容感觉比较土鳖.这从来就是一个老生常谈的问题.学MFC的时候就知道这个事情了,那时候记得老师强调多次,如果写的demo想在人家那 ...

  8. OpenCV学习笔记(二十一)——绘图函数core OpenCV学习笔记(二十二)——粒子滤波跟踪方法 OpenCV学习笔记(二十三)——OpenCV的GUI之凤凰涅槃Qt OpenCV学习笔记(二十

    OpenCV学习笔记(二十一)--绘图函数core 在图像中,我们经常想要在图像中做一些标识记号,这就需要绘图函数.OpenCV虽然没有太优秀的GUI,但在绘图方面还是做得很完整的.这里就介绍一下相关 ...

  9. OpenCV学习笔记(一)(二)(三)(四)(五)

    OpenCV学习笔记(一) 决心开始研究OpenCV.闲言少叙,sourceforge网站最近的版本是2011年8月的OpenCV2.3.1,下载安装,我这里使用的开发环境是vs2008,网上搜了一下 ...

最新文章

  1. Linux磁盘配额应用
  2. (轉載) 大學就學貸款 可分12年還 (News)
  3. [渝粤教育] 中国地质大学 结构力学 复习题
  4. NYOJ 27 大数阶乘
  5. C#LeetCode刷题之#448-找到所有数组中消失的数字(Find All Numbers Disappeared in an Array)
  6. java final char_java基本数据类型总结 类型转换 final关键字的用法
  7. java实现tcp服务器(单线程、多线程)、客户端
  8. 生成xml报文方法并输出
  9. rust油桶用什么打_火龙果用什么膨大剂好?果子增大用什么肥料?什么时候打膨大素?...
  10. 《Python语言程序设计基础》:第2章:Python程序实例解析:程序练习题
  11. Winrar 5.60 beta 4 个性破解注册码(2018.5.22)
  12. python3GUI--做一款某雷影音播放器By:PyQt5
  13. 【vue+cesium】加载三维天地图
  14. 2022-2027年中国酒店及酒店管理市场竞争态势及行业投资前景预测报告
  15. 服务器系统启用来宾用户,系统日志中出现Internet来宾账户
  16. 人在职场:可以让你少奋斗10年的工作经验
  17. 洗地机排名前十的产品、洗地机品牌排行榜最新公布
  18. Mac Vmware
  19. 光纤布线系统的设计与检测(二)
  20. urllib、urllib2、urllib3 和 requests 模块有什么区别?

热门文章

  1. 修改QtCreater界面大小
  2. 从微信头像链接下载图片到服务器
  3. 剑指Offer(Python多种思路实现):树的子结构
  4. Error: Could not find tools necessary to compile a package/compilation failed for package
  5. Obiee+echarts实例之饼图(2)
  6. 易班优课YOOC考试解除禁止查卷
  7. 我的梦想,我的飞翔! 南航天合2013校园招聘火热启动
  8. ubuntu 常用命令及国内更新源
  9. 多传感器融合之雷达图像数据集自动生成 - 20220613
  10. FPGA信号处理--多相滤波器(二)