Opencv学习笔记 - 频域手段添加盲水印
频域添加数字水印的方法,是指通过某种变换手段(傅里叶变换,离散余弦变换,小波变换等)将图像变换到频域(小波域),在频域对图像添加水印,再通过逆变换,将图像转换为空间域。相对于空域手段,频域手段隐匿性更强,抗攻击性更高。
代码使用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学习笔记 - 频域手段添加盲水印相关推荐
- OpenCV学习笔记(四十六)——FAST特征点检测features2D OpenCV学习笔记(四十七)——VideoWriter生成视频流highgui OpenCV学习笔记(四十八)——PCA算
OpenCV学习笔记(四十六)--FAST特征点检测features2D 特征点检测和匹配是计算机视觉中一个很有用的技术.在物体检测,视觉跟踪,三维常年关键等领域都有很广泛的应用.这一次先介绍特征点检 ...
- OpenCV学习笔记(六)(七)(八)(九)(十)
OpenCV学习笔记(六)--对XML和YAML文件实现I/O操作 1. XML.YAML文件的打开和关闭 XML\YAML文件在OpenCV中的数据结构为FileStorage,打开操作例如: [c ...
- python做直方图-python OpenCV学习笔记实现二维直方图
本文介绍了python OpenCV学习笔记实现二维直方图,分享给大家,具体如下: 官方文档 – https://docs.opencv.org/3.4.0/dd/d0d/tutorial_py_2d ...
- OpenCV学习笔记(五十六)——InputArray和OutputArray的那些事core OpenCV学习笔记(五十七)——在同一窗口显示多幅图片 OpenCV学习笔记(五十八)——读《Mast
OpenCV学习笔记(五十六)--InputArray和OutputArray的那些事core 看过OpenCV源代码的朋友,肯定都知道很多函数的接口都是InputArray或者OutputArray ...
- OpenCV学习笔记(五十一)——imge stitching图像拼接stitching OpenCV学习笔记(五十二)——号外:OpenCV 2.4.1 又出来了。。。。。 OpenCV学习笔记(五
OpenCV学习笔记(五十一)--imge stitching图像拼接stitching stitching是OpenCV2.4.0一个新模块,功能是实现图像拼接,所有的相关函数都被封装在Stitch ...
- OpenCV学习笔记(四十一)——再看基础数据结构core OpenCV学习笔记(四十二)——Mat数据操作之普通青年、文艺青年、暴力青年 OpenCV学习笔记(四十三)——存取像素值操作汇总co
OpenCV学习笔记(四十一)--再看基础数据结构core 记得我在OpenCV学习笔记(四)--新版本的数据结构core里面讲过新版本的数据结构了,可是我再看这部分的时候,我发现我当时实在是看得太马 ...
- OpenCV学习笔记(三十一)——让demo在他人电脑跑起来 OpenCV学习笔记(三十二)——制作静态库的demo,没有dll也能hold住 OpenCV学习笔记(三十三)——用haar特征训练自己
OpenCV学习笔记(三十一)--让demo在他人电脑跑起来 这一节的内容感觉比较土鳖.这从来就是一个老生常谈的问题.学MFC的时候就知道这个事情了,那时候记得老师强调多次,如果写的demo想在人家那 ...
- OpenCV学习笔记(二十一)——绘图函数core OpenCV学习笔记(二十二)——粒子滤波跟踪方法 OpenCV学习笔记(二十三)——OpenCV的GUI之凤凰涅槃Qt OpenCV学习笔记(二十
OpenCV学习笔记(二十一)--绘图函数core 在图像中,我们经常想要在图像中做一些标识记号,这就需要绘图函数.OpenCV虽然没有太优秀的GUI,但在绘图方面还是做得很完整的.这里就介绍一下相关 ...
- OpenCV学习笔记(一)(二)(三)(四)(五)
OpenCV学习笔记(一) 决心开始研究OpenCV.闲言少叙,sourceforge网站最近的版本是2011年8月的OpenCV2.3.1,下载安装,我这里使用的开发环境是vs2008,网上搜了一下 ...
最新文章
- Linux磁盘配额应用
- (轉載) 大學就學貸款 可分12年還 (News)
- [渝粤教育] 中国地质大学 结构力学 复习题
- NYOJ 27 大数阶乘
- C#LeetCode刷题之#448-找到所有数组中消失的数字(Find All Numbers Disappeared in an Array)
- java final char_java基本数据类型总结 类型转换 final关键字的用法
- java实现tcp服务器(单线程、多线程)、客户端
- 生成xml报文方法并输出
- rust油桶用什么打_火龙果用什么膨大剂好?果子增大用什么肥料?什么时候打膨大素?...
- 《Python语言程序设计基础》:第2章:Python程序实例解析:程序练习题
- Winrar 5.60 beta 4 个性破解注册码(2018.5.22)
- python3GUI--做一款某雷影音播放器By:PyQt5
- 【vue+cesium】加载三维天地图
- 2022-2027年中国酒店及酒店管理市场竞争态势及行业投资前景预测报告
- 服务器系统启用来宾用户,系统日志中出现Internet来宾账户
- 人在职场:可以让你少奋斗10年的工作经验
- 洗地机排名前十的产品、洗地机品牌排行榜最新公布
- Mac Vmware
- 光纤布线系统的设计与检测(二)
- urllib、urllib2、urllib3 和 requests 模块有什么区别?
热门文章
- 修改QtCreater界面大小
- 从微信头像链接下载图片到服务器
- 剑指Offer(Python多种思路实现):树的子结构
- Error: Could not find tools necessary to compile a package/compilation failed for package
- Obiee+echarts实例之饼图(2)
- 易班优课YOOC考试解除禁止查卷
- 我的梦想,我的飞翔! 南航天合2013校园招聘火热启动
- ubuntu 常用命令及国内更新源
- 多传感器融合之雷达图像数据集自动生成 - 20220613
- FPGA信号处理--多相滤波器(二)