在面向变换域的数字水印算法中dwt算法是一种,数字水印技术通过在数字化的多媒体数据中
由于之前在网上看到的关于LSB的方法大部分都是用MATLABPython写的,所以博主对思路进行了改编,得到了以下内容:
一、原则:1。首先准备一张彩色图片(2px*2px)
为了方便展示,我准备了一张(2px * 2px)的图片,用PS。图片中每个像素的RGB值为:
RGB [0,0] 10100200 [0,1] 20010010 [1,0] 20010100 [1,1] 10010200图像格式保存为bmp(无损压缩),保存jpg时会压缩图像内容。
2.需要注意的是,这里查看的代码不是cv:imshow(),而是cout。
int main(int argc,char * argv[]){ if(argc 2)return-1;cv:Mat img=imread(argv[1],cv:im read _ COLOR);cout img endl返回0;} $ ./a.out test.bmp
[200, 100, 10, 10, 100, 200;00,10,200,200,10,100]由此我们可以知道:
在
Mat
中,彩色图片的每个像素按照B、G、R
的图层顺序存储,存储的每个单元的值在0~255
之间。一行中的所有像素和每个像素的三层由逗号
隔开。就很容易知道上面的信息了~为了方便解释,我们将上面的矩阵作为两个。[11001000, 01100100, 00001010, 00001010, 01100100, 11001000;0100100,0001010,11001000,11001000,0001010,01100100]至此,我们可以愉快地解释LSB了。假设我们将每个单元中的最低有效位重置为零,然后根据要求填入我们想要的信息。
如果改变最后一位数字,最终值只有1,肉眼几乎感觉不到画面颜色有什么变化。就算修改是倒数第二个,最后值也就3了,感觉还行(效果图放最后测试)。如果倒数第二个数字被修改,则最终值为5,依此类推.
3.准备一张水印图片(黑白)
为了演示方便,我将水印图像和原始图像设置为相同的大小。下面的代码不用担心水印图像和原图大小不一致~
假设上图是我要加的水印,信息只有黑白,那么我们可以定义黑色为0;白色定义为1。然后把信息写进原图~
4.在原始图像中添加水印信息:【11001000,01100100,0001010,0001010,01100100,11001000;0100100,00001010,11001000,11001000,0001010,01100100]水印图:[000000001,00000001,0000001,00000000,000000,000000,000000,00000,000000,000000,000000,000000,0000000,0000000。原始图像的水印:[11001001,01100101,01100101,0001011,0001011,0001011,00001010,01100100100,00001010,11001000,11001001,0001011,01100101]原图:
添加水印的图片:
恢复后的水印:
图片上加了这样的水印信息,但肉眼几乎看不出什么区别。
需要注意的是,保存图片的最佳格式是
分号
格式。如果以其他格式(jpeg/png)保存,它们将被压缩和扭曲。扭曲的图像水印不会像以前那样清晰,这也是这种方法的一大缺点!
二、源码c:/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *。文件名:001_waterMarkLSB.cpp作者:彼得申邮件:peter704678976@126.com创建时间:2019年08月25日星期日00时00分09秒* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */#包含stdlib。 h #包含stdio。h #包含字符串#包含类型信息#包含opencv 2/core/utility。HPP #包括opencv 2/视频/跟踪。HPP #包括opencv 2/视频io。HPP #包括opencv 2/高图形用户界面。HPP #包含 opencv 2/imgproc/types _ c . h ;template typename _ Tp vector _ Tp convertMatToVector(const Mat Mat){ return(vector _ Tp)(Mat。shape(1,1));} template typename _ Tpcv:Mat convertVectorToMat(vector _ Tp v,int channels,int rows){ cv:Mat Mat=cv:Mat(v);cv:Mat dest=Mat。形状(通道,行)。clone();dest.convertTo(dest,CV _ 8U);返回目的地;} void showImageLSBWatermark(cv:Mat image,int num){ cv:Mat dst _ img;if(num 7 num 0)num=0;矢量v=convertMatToVectorint(image);向量u;int series=pow(2,num);int j=0,k=0;for(int I=0;I . v . size()/3;i) {j=0,k=0;v[3*i]/series % 2==0?j:k;v[3*i 1]/series % 2==0?j:k;v[3*i 2]/series % 2==0?j:k;u.push_back(j k?0 : 255);}dst_img=convertVectorToMat(u,1,image。行);cv:imshow(dst_img ,dst _ img);} template typename _ Tp vector _ Tp draw water mark animage(vector _ Tp v,vector_Tp w,int num){ if(num 7 num 0)return v;int series=pow(2,num);for(int I=0;I . v . size();i) {if (v[i]/series % 2!=0) v[i] -=级数;v[i]=pow(2,num)* w[I];} return v;} cv:Mat imageLSB(cv:Mat src _ img,cv:Mat mrk_img,int num) {if (src_img.size()!=mrk_img。size()){ cv:copyMakeBorder(mrk _ img,mrk _ img,0,src_img.rows - mrk_img.rows,0,src_img.cols - mrk_img.cols,cv:BORDER_WRAP,Scalar:all(0));} cv:Mat dst _ img;vector int src _ v=convertMatToVectorint(src _ img);vector int mrk _ v=convertMatToVectorint(mrk _ img);for(int I=0;I mrk _ v . size();i) {mrk_v[i]=mrk_v[i] 120?0 : 1 ;} src _ v=drawatermarkonimage(src _ v,mrk_v,num);dst _ img=convertVectorToMat(src _ v,1,src _ img。行);返回dst _ img}int main (int argc,char* argv[]) {if (argc 2) {cout 请选择enc/show endl;return-1;}if (strcmp(argv[1], enc)==0) { if (argc 5) { cout 请输入src_img水印秩(0 ~ 7) endl;return-1;} cv:Mat img_src=imread(argv[2],cv:im read _ COLOR);cv:Mat img_mrk=imread(argv[3],cv:im read _ gray);STD:vector cv:Mat imgs;cv:split(img_src,imgs);int num=atoi(argv[4]);//给三个图层分别添加,也可一选择其中一个加水印for(int I=0;i3;i) {imgs[i]=imageLSB(imgs[i],img_mrk,num);} cv:Mat img _ dst;cv:merge(imgs,img _ dst);cv:imshow(src ,img _ src);cv:imshow(dst ,img _ dst);cout 033[32m[提示]:写图像 033[0m endl;//无损压缩,其他格式保存会失真cv:imwrite(LSB.bmp ,img _ dst);} else if (strcmp(argv[1], show)==0) {if (argc 4) {cout 请输入src _ img rank(0 ~ 7) endl;return-1;}cv:Mat img_src=imread(argv[2],cv:im read _ COLOR);cv:imshow(src ,img _ src);int num=atoi(argv[3]);showImageLSBWatermark(img_src,num);} cv:waitKey(0);返回0;} 三、测试:水印图:
原图:
在最低位嵌入水印( 1):
在倒数第二位嵌入水印( 3):
在倒数第三位嵌入水印( 7):
在倒数第四位嵌入水印( 15):
在
bmp
时已经有肉眼明显可见的水印样子出来了,第三位
的时候更加明显,第四位
时需要仔细看才能看的到而第二位
基本看不到了而以上所有图片,把加水印的那一层提取出来,都能得到很清晰的水印:
目前图片格式为bmp,将图片通过附言(同后记);警官(警长)转换为使用联合图象专家组文件交换格式存储的编码图像文件扩展名格式后提取到的水印为:
(此处使用的是在倒数第二位加水印)
缩放图片后测试水印:
剪切后测试图片:
四。总结:优点:1。加入水印后,不会影响图片的整体美观,还保留了水印中的信息。
2.图片经过剪切、篡改、编辑后,仍然可以从保留的原始图片中提取出清晰的水印信息。
缺点:1。图像经过压缩和编辑后,水印信息会受到很大的干扰。
2.水印信息可以在后期被擦除,很容易被破坏。