基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现

一、引言

        该篇包括三部分,1)引言、2)图像变化技术简介和代码实现 、3)基于图像变换技术的数字水印技术及代码实现。

        数字水印是一种有效的数字产品版权保护和数据安全维护技术, 是信息隐藏领域的一个重要分支, 也是密码学的一种有益的补充技术。近年来它引起了人们的广泛关注。图像隐形水印是其中最主要的研究方向, 按照嵌入位置可分为空间域方法和变换域( DCT, DFT 和DWT 等) 方法。为了使水印信息有更好的鲁棒性(抵抗攻击的能力)众多学者采用变换域中的嵌入方法,前面我有两篇博客涉及到了有关DCT的数字水印方法和算法,接下来将分别介绍基于DCT、DFT、DWT三种基础图像变换技术的数字水印方法及代码实现。

二、DFT、DCT、DWT图像变换技术

         图像变换技术是为了能让图像用正交函数或正交矩阵表示而对原图像所作的变换,该变换是二维线性可逆的。一般称原始图像为空间域图像,称变换后的图像为转换域图像(也称为频率域),转换域图像可反变换为空间域图像。经过图像变换后,一方面能够更有效地反映图像自身的特征,另一方面也可使能量集中在少量数据上,更有利于图像的存储、传输及处理。从数学角度来说,图像变换是把图像中的像素表达成“另外一种形式”满足实际需求,大多数情况下需要对变换处理后的图.像进行逆变换,从而获取处理以后的图像。这种变换同样可以应用于其他有关物理或数学的各种问题中,并可以采用其他形式的变量。在数字水印领域中,常用的基础图像变换技术有傅里叶变换(DFT)、离散余弦变换(DCT)、小波变换(DWT)。

        2.1 图像傅里叶变换(DFT)

        傅里叶变换是以时间为自变量的“信号”与频域为自变量的“频普”函数之间的某种变换关系。从纯粹的数学意义上看,傅立叶变换是将一个图像函数转换为一系列周期函数来处理的;从物理效果看,傅立叶变换是将图像从空间域转换到频率域,其逆变换是将图像从频率域转换到空间域。实际上对图像进行二维傅立叶变换得到频谱图,就是图像梯度的分布图,傅立叶频谱图上看到的明暗不一的亮点,实际上图像上某--点与邻域点差异的强弱,即梯度的大小,也即该点的频率大小。如果频谱图中暗的点数更多,那么实际图像是比较柔和的:反之,如果频谱图中亮的点数多,那么实际图像一定是尖锐的,边界分明且边界两边像素差异较大。

        傅里叶变换包括一维连续傅里叶变换、二维连续傅里叶变换、一维离散傅里叶变换、二维离散傅里叶变换。在图像处理领域中常用二维离散傅里叶变换。其定义如下式(1):

                                                      F\left ( u,v \right )= \sum_{x=0}^{M-1}\sum_{y=0}^{N-1}f\left ( x,y \right )e^{-j2\pi \left ( \frac{ux}{M}+\frac{vy}{N} \right )}                                                 (1)

        其中u = 0, 1, ... , M-1;  v = 0, 1, ... , N-1 。 F(u, v)的二维离散傅里叶反变换定义为下式(2):
                                                       f\left ( x,y \right ) = \frac{1}{MN}\sum_{u=0}^{M-1}\sum_{v=0}^{N-1}F\left ( u,v \right )e^{i2\pi \left ( \frac{ux}{M}+\frac{vy}{N} \right )}                                          (2)                  

        图像的二维傅里叶结果通常是复数形式,故在进行图像处理的过程将结果进行平方处理,其具体的数学计算公式以及其他三种傅里叶变化的定义式可查阅《数字图像处理》——冈萨雷斯。

        定义式是抽象的表达了傅里叶的变换过程,但是落实图像是怎样的呢,接下来我们用MATLAB工具进行图像的傅里叶变换。其代码及结果如下:

close all;
clear all;
clc;
I = imread('pepper.bmp');
J = rgb2gray(I);
K_1 = fft2(J);
L_1 = abs(K_1/256);
K_2 = fftshift(K_1);
L_2 = abs(K_2/256);
figure;
subplot(2,2,1);
imshow(I); title('原始图像');
subplot(2,2,2);
imshow(J); title('灰度图像');
subplot(2,2,3);
imshow(uint8(L_1)); title('灰度图像傅里叶频谱');
subplot(2,2,4);
imshow(uint8(L_2)); title('平移后的频谱');

        其运行结果如下图:

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第1张图片 图1 图像傅里叶变换例

       

       2.2 离散余弦变换(DCT)

       离散余弦变换(DCT)是一组不同频率和幅值的余弦函数和来近似一副图像,实际上是傅里叶变换的实数部分。由于离散余弦变量对于一副图像,其大部分可视化信息都集中在少数的变换系数上。因此,离散余弦变量是数据压缩常用的一个变换编码方法,它能将高相关数据能量集中,使得它非常适用于图像压缩,例如国际压缩标准的JPEG格式中就采用了离散余弦变换。

       在傅立叶变换过程中,如果被展开的函数是实偶函数,那么其傅立叶变换中只包含余弦项,基于傅立叶变换的这一特点,人们提出了离散余弦变换。DCT变换先将图像函数变换成偶函数形式,再对其进行二维离散傅立叶变换,因此DCT变换可以看成是一种简化的傅立叶变换。离散余弦变换叶分为一维离散余弦变换和二维离散余弦变换,在图像处理中用到二维变化,所以介绍下其二维定义,其他定义可查阅《数字图像处理》——冈萨雷斯。其二维离散余弦变换定义如下式:

                              F\left ( u,v \right )=\alpha _{0}c\left ( u,v \right )\sum_{x=0}^{N-1}\sum_{y=0}^{N-1}f\left ( x,y \right )\cos \frac{\left ( 2x+1 \right )u\pi }{2N}cos\frac{\left ( 2y+1 \right )v\pi }{2N}                                    (3)

其中,u,v=0,1, ... ,N-1, \alpha _{0} = \frac{2}{N} c\left ( u,v \right )=   

         二维离散余弦反变换定义式:

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第2张图片                                               (4)

         用MATLAB工具进行图像的傅里叶变换。其代码及结果如下:

close all;
clear all;
clc;
I = imread ('boats.bmp');
J = dct2(I);
figure('Name','离散余弦变换');
subplot(1,2,1);
imshow(I); title('原始图像');
subplot(1,2,2);
imshow(log(abs(J))); title('离散余弦变换系数图像');

其运行结果如下图2:

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第3张图片 图2 离散余弦变换例

   

       2.3 小波变换(DWT)

      小波变化是对傅里叶变换和短时傅里叶变换的一个突破,其改变就在于,将无限长的三角函数基换成了有限长的会衰减的小波。小波变化的理论较多,更多内容可查阅《数字图像处理》——冈萨雷斯相关章节内容,以下从一个叫简单的角度来解释小波变换。

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第4张图片

       由上图也可以看出为什么叫小波,其波形较小。

       其一维连续小波的定义式为:

             WT_{f}=\left | a \right |^{-\frac{1}{2}}\int_{-\infty }^{\infty } f\left ( t \right )\varphi *\left ( \frac{t-b}{a}\right )dt                                                                                              (5)

       连续小波变换具有如下的重要性质: 线性、平移不变性、 冗余性

       在 MATLAB 小波变换工具箱中提供了多个母小波族函数如下表所示,不同的母小波具有不同的特点,其对图像的处理结果也不同。

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第5张图片 表1 小波变换母小波

        接下来以“haar”母小波为例,进行处理例,其代码如下:

close all;
clear all;
clc;
I = imread('lena.jpg');
I = rgb2gray(I);
I = im2double(I);
[ca1,ch1,cv1,cd1]=dwt2(I,'haar');
[ca2,ch2,cv2,cd2]=dwt2(ca1,'haar');
figure(1);
imshow(I);

figure('Name','载体小波分解')
% subplot(121)
% imshow([ca1,ch1;cv1,cd1])
% title('一级小波分解')
% subplot(122)
% imshow([ca2,ch2;cv2,cd2])
% title('二级小波分解')

%% 或者
subplot(121)
imagesc([wcodemat(ca1),wcodemat(ch1);wcodemat(cv1),wcodemat(cd1)])
title('一级小波分解')
subplot(122)
imagesc([wcodemat(ca2),wcodemat(ch2);wcodemat(cv2),wcodemat(cd2)])

其运行结果如下图:

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第6张图片 图3 小波分解例

三、 基于DCT、DFT、DWT图像变换的数字水印技术代码实现

         引言部分提到数字水印是密码学的一个重要分支之一。其实现主要分为三部分,水印标识的嵌入、图像攻击、水印提取。其过程可由下图5-7表示:

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第7张图片 图5 数字水印嵌入流程
基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第8张图片 图6 图像攻击

 

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第9张图片 图7 图像提取流程

     鉴于对文章篇幅的控制,本文对水印的嵌入和提取两部分进行实现,图像的攻击在后续进行更新总结。

     数字水印的嵌入与提取算法有多种多样,那怎样评价数字水印嵌入效果和提取效果的好坏呢?业界是这样评价的:针对嵌入效果,我们用峰值信噪比(PSNR)进行评价,数值越大嵌入效果越好。针对水印的提取效果,我们用归一化相关系数(NC)进行评价,数字越大效果越好。那么PSNR和NC的MATLAB代码怎样实现呢,见下代码

      PSNR函数MATLAB代码:

%nc(归一化相关系数)
function dNC = nc(ImageA,ImageB)

if (size(ImageA,1) ~= size(ImageB,1)) or (size(ImageA,2) ~= size(ImageB,2))
    error('ImageA <> ImageB');
    dNC = 0;
    return ;
end
ImageA=double(ImageA);
ImageB=double(ImageB);
M = size(ImageA,1);
N = size(ImageA,2);
d1=0 ;
d2=0;
d3=0;
for i = 1:M
    for j = 1:N
        d1=d1+ImageA(i,j)*ImageB(i,j) ;
        d2=d2+ImageA(i,j)*ImageA(i,j) ;
        d3=d3+ImageB(i,j)*ImageB(i,j) ;
    end
end
dNC=d1/(sqrt(d2)*sqrt(d3));
return

NC函数MATLAB 实现代码如下:

% PSNR (峰值信噪比)


function dPSNR = psnr(ImageA,ImageB)

if (size(ImageA,1) ~= size(ImageB,1)) or (size(ImageA,2) ~= size(ImageB,2))
    error('ImageA <> ImageB');
    dPSNR = 0;
    return ;
end
ImageA=double(ImageA);
ImageB=double(ImageB);
M = size(ImageA,1);
N = size(ImageA,2);
    
d = 0 ;
for i = 1:M
    for j = 1:N
        d = d + (ImageA(i,j) - ImageB(i,j)).^2 ;
    end
end

dPSNR = 10*log10((M*N*max(max(ImageA.^2)))/d) ;

return

      在后面的代码中将直接调用这两个函数,不再重复编写。      

      3.1 基于DCT变换的数字水印嵌入与提取流程的代码实现

      基于DCT数字水印代码叫简单,直接上代码,其具体需要注意的内容在代码注释中有具体讲解。

% The watermark image is embedded into the color image by DCT transformation 
% 将水印图像做DCT变换嵌入到彩色图像中 
clc;
clear all;
wtype = 'dct2';
iwtype = 'idct2';
originalImage=imread('lena256.bmp');
alpha=0.1;    % Embedded factor       嵌入因子 
dim_i=size(originalImage);
rm=dim_i(1);
cm=dim_i(2);
% Embedding formula         设嵌入公式v‘=v(1+aXk)中的a=0.1
% Display carrier image          显示原始图片
subplot(2,2,1);
imshow(originalImage);title('Original Image');

% Read and display watermark images         水印图片
watermark=imread('mark32.bmp');
watermark = rgb2gray(watermark);
subplot(2,2,2);
imshow(watermark);title('Watermark Image');

% DCT transform of watermark image      对水印图片做DCT变换
watermark_dct=blkproc(watermark,[8,8],wtype);
waterseria=watermark_dct(:);  % 列向量
% Extract green channel     提取绿色分量
image=imread('lena256.bmp');  % 重新读取一次原始图像,为了分离和复原颜色通道更方便。
image_g=image(:,:,2);
% DCT transformed for green channel   对绿色分量进行DCT变换
dct_image_g=blkproc(image_g,[8,8],wtype);   
dct_image1=dct_image_g;
k=1;
for i=1:rm/8
    for j=1:cm/8
        x=(i-1)*8;y=(j-1)*8;
        ave=(dct_image_g(x+3,y+5)+dct_image_g(x+5,y+5)+dct_image_g(x+4,y+4)+dct_image_g(x+4,y+6)+dct_image_g(x+2,y+7))/5;
        dct_image1(x+4,y+5)=ave+alpha*waterseria(k);
        k=k+1;
    end
end
image2=blkproc(dct_image1,[8,8],iwtype);  % 反DCT变换
%将嵌入水印的绿色分量加到原图中
image(:,:,2)=image2;
% 计算PSNR
PSNR=psnr(image_g,image2);
image = uint8(image);
%加水印之后的图片
subplot(2,2,3);
imshow(image)
name='嵌入水印图像';
title(strcat(num2str(name),'   k=',num2str(alpha),'   PSNR=',num2str(PSNR)));
imwrite(image,'withmark.bmp','bmp');

%% 水印提取
%提取绿色分量
outpicture = imread('withmark.bmp');
out_image=outpicture(:,:,2);  %提取绿色分量
%水印提取过程
outdct_image=blkproc(out_image,[8,8],wtype);  %dct变换 
%提取频谱
k=1;
for i=1:rm/8
    for j=1:cm/8
        x=(i-1)*8;y=(j-1)*8;
        ave=(outdct_image(x+3,y+5)+outdct_image(x+5,y+5)+outdct_image(x+4,y+4)+outdct_image(x+4,y+6)+outdct_image(x+2,y+7))/5;
        outwaterseria(k)=(outdct_image(x+4,y+5)-ave)/alpha;
        k=k+1;
    end
end

k=1;
for i=1:rm/8
    for j=1:cm/8
        outwatermark_dct(j,i)=outwaterseria(k);
        k=k+1;
    end 
end
outwatermark=blkproc(outwatermark_dct,[8,8],iwtype);
outwatermark = uint8(outwatermark);
%% 计算NC(归一化相关系数)%%
NC=nc(outwatermark,watermark)
subplot(2,2,4);
imshow(outwatermark);
name = 'Extract image';
title(strcat(num2str(name),   '  NC=',num2str(NC)));

其运行结果如下图:
 

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第10张图片 图8 基于DCT数字水印嵌入提取效果

   

      3.2 基于DFT变换的数字水印嵌入与提取流程的代码实现       

      该代码中用到了图像置乱,考虑到置乱周期问题 ,所设计的代码要求有两:1)水印图像的尺寸为40*40dpi;2)原始载体图像的 (长*宽)/ (分块的平方)要大于等于40*40. 以下为代码。由于代码较长,遵循代码模块化设计原则,将代码分为嵌入embed 和 提取recover两部分,其具体需要注意的内容在代码注释中有具体讲解,如下:

    embed 嵌入:

%基于傅立叶域的数字水印
%注意:水印必须为40*40的二值图像 
%因为40阶的二维arnold置乱周期为30,所以嵌入时置乱8次,提取时置乱22.可以根据自己的需要更改.
%嵌入源码
clc
clear all;

% 保存开始时间
start_time=cputime;
iTimes=8;      %置乱次数
k=1.5;                            % 设置嵌入强度系数
blocksize=8;                    % 块的大小
filter_m=[  1,1,1,1,1,1,1,1;    % 滤波矩阵
            1,1,1,1,1,1,1,1;
            1,1,0,0,0,0,1,1;
            1,1,0,0,0,0,1,1;
            0,0,0,0,0,0,0,0;
            0,0,0,0,0,0,0,0;
            0,0,0,0,0,0,0,0;
            0,0,0,0,0,0,0,0;];
        
% 读入载体图像
original_image=imread('lena.jpg');
file_name_g=original_image(:,:,2);%提取绿色分量
cover_object=double(file_name_g)/255;
% 载体图像矩阵的行数与列数
Mc=size(cover_object,1);	        
Nc=size(cover_object,2);	       

% 最大嵌入信息量
max_message=Mc*Nc/(blocksize^2);

% 读入水印图像
mark=imread('mark40.bmp');
mark=rgb2gray(mark);
mark=im2bw(mark);
message=double(mark);
%水印图像矩阵的行数与列数
Mm=size(message,1);	                
Nm=size(message,2);	                

% 检查水印信息是否过大
if  Mm*Nm>max_message   % 载体图像的行*列要大于102400 
   error('水印信息过大')
end

%对水印图像进行Arnold置乱
if Mm~=Nm
    error('水印矩阵必须为方阵');
end
if Mm~=40
    error('必须为40*40大小,或者修改置乱次数');
end
tempImg=message;
for n=1:iTimes % 次数
    for u=1:Mm
        for v=1:Nm
          temp=tempImg(u,v);
          ax=mod(u+v,Mm)+1;
          ay=mod(u+2*v,Nm)+1;
          outImg(ax,ay)=temp;
        end
    end
  tempImg=outImg;
end
message_vector=reshape(outImg,1,Mm*Nm);

% 将cover_object(原图绿色通道矩阵)写入watermarked_image
withmark_image=cover_object;

%置随机数发生器的状态为1100
key=1100;
rand('state',key);

% 产生伪随机序列
pn_sequence_zero=round(2*(rand(1,sum(sum(filter_m)))-0.5));
pn_sequence_one=round(2*(rand(1,sum(sum(filter_m)))-0.5)); 
% 将图像分块
x=1;
y=1;
h=waitbar(0,'嵌入水印,请等待');
for (kk = 1:length(message_vector))
    % 做傅立叶变换
    fft_block=fft2(cover_object(y:y+blocksize-1,x:x+blocksize-1));
    %计算幅值
    abs_block=fftshift(abs(fft_block));
    %计算相位
    angle_block=angle(fft_block);
    % 当message_vector=0且filter_m=1时用伪随机序列pn_sequence_zero叠加abs_block
    % 当message_vector=1且filter_m=1时用伪随机序列pn_sequence_one叠加abs_block
    ll=1;
    if (message_vector(kk)==0)
        for ii=1:blocksize
            for jj=1:blocksize
                if (filter_m(ii,jj)==1)
                    abs_block_o=abs_block(ii,jj);
                    abs_block(ii,jj)=abs_block(ii,jj)*(1+k*pn_sequence_zero(ll));
  abs_block(blocksize-ii+1,blocksize-jj+1)=abs_block(blocksize-ii+1,blocksize-jj+1)+abs_block(ii,jj)-abs_block_o;
                    ll=ll+1;
                end
            end
        end
    else                                     
        for ii=1:blocksize                    
            for jj=1:blocksize
                if (filter_m(ii,jj)==1)
                    abs_block_o=abs_block(ii,jj);
                    abs_block(ii,jj)=abs_block(ii,jj)*(1+k*pn_sequence_one(ll));
  abs_block(blocksize-ii+1,blocksize-jj+1)=abs_block(blocksize-ii+1,blocksize-jj+1)+abs_block(ii,jj)-abs_block_o;
                    ll=ll+1;
                end
            end
        end
    end
    
    % 进行傅立叶逆变换
    abs_block=fftshift(abs_block);
    withmark_image(y:y+blocksize-1,x:x+blocksize-1)=abs(ifft2(abs_block.*exp(i*angle_block)));    
    
    % 移动到下一块
    if (x+blocksize) >= Nc
        x=1;
        y=y+blocksize;
    else
        x=x+blocksize;
    end
    waitbar(kk/length(message_vector),h);
end
close(h);

% 转换为uint8,并写入
watermarked_image_g=(withmark_image*255);
original_image(:,:,2)=watermarked_image_g;
imwrite(original_image,'withwatermarked_image.bmp','bmp');
%计算运行时间
elapsed_time=cputime-start_time

%计算psnr
PSNR=psnr(cover_object,withmark_image);

% 显示水印,嵌入水印图像与原始图像
figure(1)
subplot(2,2,2)
imshow(message);
title('原始水印');
subplot(2,2,3);
imshow(tempImg);
title('置乱水印');
subplot(2,2,4)
imshow(original_image);
name='嵌入水印图像';
title(strcat(num2str(name),'   k=',num2str(k),'   PSNR=',num2str(PSNR)));
subplot(2,2,1)
imshow(original_image)
title('原始图像');

其运行结果如下入:

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第11张图片 图9 基于DFT数字水印嵌入效果

    recover 提取代码:

%提取
clc
clear all;

% 保存开始时间
start_time=cputime;
iTimes=22;              %置乱次数
blocksize=8;            % 设置块的大小
filter_m=[  1,1,1,1,1,1,1,1;    % 滤波矩阵
            1,1,1,1,1,1,1,1;
            1,1,0,0,0,0,1,1;
            1,1,0,0,0,0,1,1;
            0,0,0,0,0,0,0,0;
            0,0,0,0,0,0,0,0;
            0,0,0,0,0,0,0,0;
            0,0,0,0,0,0,0,0;];
% 读入嵌入水印图像
withmark_1=imread('withwatermarked_image.bmp');
withmark=withmark_1(:,:,2);
imshow(withmark_1)
watermarked_image=double(withmark)/255;

% 嵌入水印图像矩阵的行数与列数
Mw=size(watermarked_image,1);	
Nw=size(watermarked_image,2);	        

% 最大可嵌入信息量
max_message=Mw*Nw/(blocksize^2);

% 读入原始水印
mark=imread('mark40.bmp');
mark=rgb2gray(mark);
orig_watermark=double(mark);

% 原始水印矩阵的行数与列数
Mo=size(orig_watermark,1);	
No=size(orig_watermark,2);	

%置随机数发生器的状态为1100
key=1100;
rand('state',key);

% 产生伪随机序列
pn_sequence_zero=round(2*(rand(1,sum(sum(filter_m)))-0.5));
pn_sequence_one=round(2*(rand(1,sum(sum(filter_m)))-0.5));              
% 将图像分块
x=1;
y=1;
h=waitbar(0,'提取水印,请等待');
for (kk = 1:max_message)

    % 傅立叶变换
    fft_block_w=fft2(watermarked_image(y:y+blocksize-1,x:x+blocksize-1));
    abs_block_w=abs(fftshift(fft_block_w));
    ll=1;
    for ii=1:blocksize
        for jj=1:blocksize
            if (filter_m(ii,jj)==1)
                sequence(ll)=abs_block_w(ii,jj); 
                ll=ll+1;
            end
        end
    end
   
    % 计算sequence与pn_sequence_zero和pn_sequence_one的相关系数
   correlation_zero(kk)=corr2(pn_sequence_zero,sequence);
   correlation_one(kk)=corr2(pn_sequence_one,sequence);               
    
    % 移动到下一块
    if (x+blocksize) >= Nw
        x=1;
        y=y+blocksize;
    else
        x=x+blocksize;
    end
    waitbar(kk/max_message,h);
end
close(h);

% 如果correlation_zero>correlation_one,那么message_vector=0,反之为1.
for (kk=1:Mo*No)
    if correlation_zero(kk)>correlation_one(kk)
        message_vector(kk)=0;
    else
        message_vector(kk)=1;
    end
end

% Arnold置乱
tempImg=reshape(message_vector(1:Mo*No),Mo,No);
message_arnold=tempImg;
for n=1:iTimes % 次数
    for u=1:Mo
        for v=1:No
          temp=tempImg(u,v);
          ax=mod(u+v,Mo)+1;
          ay=mod(u+2*v,No)+1;
          outImg(ax,ay)=temp;
        end
    end
  tempImg=outImg;
end
message=outImg;
message=uint8(message);
imwrite(outImg,'marked.jpg','jpg')

% 计算运行时间
elapsed_time=cputime-start_time,
%计算NC(归一化相关系数)
NC=nc(message,orig_watermark)

% 显示提取水印与原始水印
figure(3)
subplot(1,2,1);
imshow(message,[]);
name='提取水印';
title(strcat(num2str(name),'NC=',num2str(NC)));
subplot(1,2,2)
imshow(orig_watermark,[])
title('原始水印');

     其运行效果如图:

基于离散余弦变换(DCT)傅里叶变换(DFT)小波变换(DWT)的彩色图像数字水印的嵌入、提取简介及MATLAB实现_第12张图片 图10 基于DFT数字水印提取效果

   

     3.2 基于DWT变换的数字水印嵌入与提取流程的代码实现

      该部分代码实现中用到了随机数种子,上面的基于DFT数字水印方法也用到了随机数。所以在使用grng(seed)需要注意之前是否有使用过随机数,具体注意事项在代码注释有解释。该部分代码分为三部分,主函数、嵌入函数、提取函数。其代码如下:

clc;
clear;
close  all
%% 主函数
I = imread('xuxian.jpg');    %读取载体图像
I = rgb2gray(I);         %转换为灰度图
W = imread('logo.tif');    %读取水印图像
W=W(12:91,17:96);    %剪裁为长宽相等
figure('Name','载体图像')
imshow(I);
title('载体图像')
figure('Name','水印图像')
imshow(W);
title('水印图像')
ntimes=23;    %密钥1, Arnold置乱次数
rngseed=59433;     %密钥2,随机数种子
flag=1;      %是否显示中间图像
[Iw,psnr]=setdwtwatermark(I,W,ntimes,rngseed,flag);    %水印嵌入
[Wg,nc]=getdwtwatermark(Iw,W,ntimes,rngseed,flag);      %水印提取

%% 嵌入函数
function [Iw,psnr]=setdwtwatermark(I,W,ntimes,rngseed,flag)    %小波水印嵌入
type=class(I);  %数据类型
I=double(I);    %强制类型转换为double
W=logical(W);    %强制类型转换为logical
[mI,nI]=size(I);
[mW,nW]=size(W);
if mW~=nW      %由于Arnold置乱只能ui方正图像进行处理
    error('SETDWTWATERMARK:ARNOLD','ARNOLD置乱要求水印图像长宽必须相等!')
end

%对载体图像进行小波分解
%一级Harr小波分解
%低频,水平,垂直,对角线
[ca1,ch1,cv1,cd1]=dwt2(I,'haar');
%二级小波分解
[ca2,ch2,cv2,cd2]=dwt2(ca1,'haar');

if flag
    figure('Name','载体小波分解')
    subplot(121)
    imagesc([wcodemat(ca1),wcodemat(ch1);wcodemat(cv1),wcodemat(cd1)])
    title('一级小波分解')
    subplot(122)
    imagesc([wcodemat(ca2),wcodemat(ch2);wcodemat(cv2),wcodemat(cd2)])
    title('二级小波分解')
end
%对水印图像进行预处理
%初始化置乱数组
Wa=W;
%对水印进行Arnold变换
H=[1,1;1,2]^ntimes;     
for i=1:nW
    for j=1:nW
        idx=mod(H*[i-1;j-1],nW)+1;
        Wa(idx(1),idx(2))=W(i,j);
    end
end

if flag
    figure('Name','水印置乱效果')
    subplot(121)
    imshow(W)
    title('原始水印')
    subplot(122)
    imshow(Wa)
    title(['置乱水印,变换次数=',num2str(ntimes)]);
end
%小波数字水印的嵌入
%初始化嵌入水印的ca2系数
ca2w=ca2;
%从ca2中随机选择mW*nW个系数
rng(rngseed);   % 确保您在执行此程序之前没有生成过其他随机数,如果有可使用 rng('default')或者重新启动 MATLAB
idx=randperm(numel(ca2),numel(Wa));
% 将水印信息嵌入到ca2中
for i=1:numel(Wa)
    %二级小波系数
    c=ca2(idx(i));
    z=mod(c,nW);
    %添加水印信息
    if Wa(i)   %水印对应二进制位1
        if z
                    
                    
  • 华为OD机试 - 特殊的加密算法 - 深度优先搜索DFS(Java 2024 D卷 200分) 哪 吒 华为od深度优先java
    华为OD机试2024D卷题库疯狂收录中,刷题点这里专栏导读本专栏收录于《华为OD机试(JAVA)真题(D卷+C卷+A卷+B卷)》。刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。一、题目描述有一种特殊的加密算法,明文为一段数字串,经过密码本查找转换,生成另一段密文数字串。规则如下明文为一段数字串由0-9
  • E卷-特殊的加密算法-(200分) 春秋招笔试突围 华为OD刷题笔记E卷华为OD刷题笔记E+D卷深度优先算法
    专栏订阅特殊的加密算法问题描述有一种特殊的加密算法,明文为一段数字串,经过密码本查找转换,生成另一段密文数字串。规则如下:明文为一段由0-9组成的数字串。密码本为由数字0-9组成的二维数组。需要按明文串的数字顺序在密码本里找到同样的数字串,密码本里的数字串是由相邻的单元格数字组成,上下和左右是相邻的,注意:对角线不相邻,同一个单元格的数字不能重复使用。每一位明文对应密文即为密码本中找到的单元格所在
  • 阿里云MWC 2019发布7款重磅产品,助力全球企业迈向智能化 数据库技术分享者 大数据数据库人工智能
    当地时间2月25日,在巴塞罗那举行的MWC2019上,阿里云面向全球发布了7款重磅产品,涵盖无服务器计算、高性能存储、全球网络、企业级数据库、大数据计算等主要云产品,可满足电子商务、物流、金融科技以及制造等各行业企业的数字化转型需求,助力全球企业迈向智能化。在大会期间,阿里云还携手德勤、RedHat以及VMware等合作伙伴展示了从基础设施到企业级应用的智能化解决方案。阿里云在MWC2019上展示
  • SAP_ABAP_MM_物料视图维护监控报表(自定义开发) Terry谈企业数字化 Abap编程SAPABAP
    SAPABAP顾问(开发工程师)能力模型_Terry谈企业数字化的博客-CSDN博客文章浏览阅读458次。目标:基于对SAPabap顾问能力模型的梳理,给一年左右经验的abaper快速成长为三年经验提供超级燃料!https://blog.csdn.net/java_zhong1990/article/details/1324699771应用场景,查询物料主数据维护情况,为物料维护及时性提供参考。2
  • “告别服务器:5步在AWS S3部署静态网站,费用低至每月4刀? AWS官方合作商 aws云计算云存储静态网站java
    在数字化转型的浪潮中,静态网站凭借其速度快、安全性高、维护成本低的优势,成为企业官网、博客、产品展示页的首选。然而,传统的服务器托管方案不仅需要高昂的运维成本,还可能面临流量突增导致的宕机风险。AWSS3(SimpleStorageService)作为全球领先的云存储服务,提供了一种革命性的静态网站托管方案,将成本、性能和易用性完美结合。本文带你深入解析AWSS3托管的优势与成本,助你轻松上云一、
  • 5G应用创新发展策略研究 米朵儿技术屋 计算机科学及电子科技技术专栏5G
    【摘要】我国高度重视5G产业发展,积极推进5G赋能垂直行业数字化转型,5G应用发展环境不断完善,5G应用进入加速导入期。主要分析了5G应用发展环境、国内外现状以及产业融合应用发展存在的问题,并给予产业应用创新发展相关建议,推动网络快速部署,加速行业数字化转型升级,实现数字经济社会新变革。【关键词】5G;融合应用;智简网络15G应用发展环境目前全球5G商用发展已初具规模,为5G应用的规模落地和创新发
  • Java学习教程,从入门到精通,Java 正则表达式知识点及案例代码(120) 知识分享小能手 编程语言如门Java大数据java学习正则表达式jdbc开发语言数据库java后端开发
    Java正则表达式知识点及案例代码一、正则表达式简介正则表达式(RegularExpression,简称regex)是一种用于描述字符串模式的强大工具。它可以用来进行字符串的匹配、查找、替换等操作。Java提供了java.util.regex包来支持正则表达式。二、Java正则表达式语法1.基本语法元字符描述.匹配除换行符以外的任意字符\d匹配数字,等价于[0-9]\D匹配非数字,等价于[^0-9
  • 编程语言背后的“江湖”:揭秘科技巨头们的技术DNA 虫洞没有虫 科技资讯\好文分享科技pythonjavaphpc++javascriptruby
    引言在数字世界的江湖中,每一家互联网公司都像一位身怀绝技的“武林高手”,而他们手中的“兵器”正是编程语言。从Google的搜索引擎到微信的十亿级消息推送,从Meta的社交帝国到微软的云端生态,这些科技巨头的技术基因深深烙印在其选择的编程语言中。为什么不同公司对编程语言的偏好差异如此之大?答案藏在他们各自的业务需求、技术哲学与历史积淀中。本文将带你一探究竟。一、Google:效率与创新的双重奏作为技
  • 从一张图片到显卡“冒烟”:解密图像处理那些事儿 CCSBRIDGE StableDiffusionComfyUI图像处理人工智能
    前言当我们看一张图片时,它可能是风景如画的日落,也可能是逗趣的猫咪。但对于计算机来说,图片是一堆数字。今天,我们来聊聊图片是如何被计算机“看见”的,以及为什么显卡会因为图片“冒烟”。像素点:图片的最小单位图片是由无数个小方格组成的,这些小方格就叫像素点。每个像素点都有自己的颜色,而这个颜色是由三种基础颜色R(红)、G(绿)、B(蓝)混合而成。一个像素点怎么存储?假设一个像素点是红色的,计算机会用这
  • 智能客服平台的架构设计:实现高效、安全、可靠的服务运行 AI天才研究院 DeepSeekR1&大数据AI人工智能大模型AI大模型企业级应用开发实战LLM大模型落地实战指南自然语言处理人工智能语言模型编程实践开发语言架构设计
    这篇文章将深入探讨智能客服平台的架构设计,以及如何实现高效、安全、可靠的服务运行。我会遵循您提供的要求和结构模板来撰写这篇文章。让我们开始吧。智能客服平台的架构设计,实现高效、安全、可靠的服务运行关键词:智能客服、架构设计、高效性、安全性、可靠性、微服务、自然语言处理、机器学习1.背景介绍在当今数字化时代,客户服务已成为企业与客户之间沟通的关键纽带。随着人工智能技术的快速发展,智能客服平台应运而生
  • 量化噪声介绍 正是读书时 知识点概率论线性代数
    量化噪声是在将模拟信号转换为数字信号的量化过程中产生的噪声。以下为你详细介绍:1.量化的基本概念在模拟信号数字化过程中,采样是对模拟信号在时间上进行离散化,而量化则是对采样值在幅度上进行离散化。由于模拟信号的取值是连续的,而数字信号的取值是离散的有限个值,所以在量化时,需要将模拟信号的采样值映射到最接近的离散量化电平上,这种映射过程不可避免地会产生误差,这种误差就表现为量化噪声。2.量化噪声的定义
  • 3G通信的一些概念 大水 网络知识学习电话网络数据库存储电信
    3GPSTN(PublicSwitchedTelephoneNetwork)定义公共交换电话网络,一种常用旧式电话系统。PSTN是一种以模拟技术为基础的电路交换网络。ISDN综合业务数字网(IntegratedServicesDigitalNetwork,ISDN)是一个数字电话网络国际标准,是一种典型的电路交换网络系统。ISDN是最早为人们接受的宽带上网方式,除了具备128Kbps的传输速率外,
  • MAX9295配置说明:高效视频传输与图像处理的利器 段惟果Edwin
    MAX9295配置说明:高效视频传输与图像处理的利器【下载地址】MAX9295配置说明MAX9295配置说明项目地址:https://gitcode.com/Open-source-documentation-tutorial/5d74a项目介绍在现代视频传输和图像处理领域,高效、稳定的信号转换是关键。MAX9295芯片作为一款专为MIPI转GMSL2设计的芯片,凭借其卓越的性能和灵活的配置,成为
  • 2025-02-13 学习记录--C/C++-PTA 7-14 求整数段和 小呀小萝卜儿 学习-C/C++学习c语言
    一、题目描述⭐️给定两个整数A和B,输出从A到B的所有整数以及这些数的和。输入格式:给定两个整数A和B,输出从A到B的所有整数以及这些数的和。输出格式:首先顺序输出从A到B的所有整数,每5个数字占一行,每个数字占5个字符宽度,向右对齐。最后在一行中按Sum=X的格式输出全部数字的和X。输入样例:-38输出样例:二、代码(C语言)⭐️#includeintmain(){intA,B,//2个整数A和
  • 【人工智能在制造业的具体应用案例-质量控制】 局外人_Jia 深度学习大数据人工智能c#
    首先,我需要明确质量控制的关键点。质量控制通常涉及产品检测、缺陷识别、数据分析等。可能用到的技术包括图像处理、机器学习模型、实时监控和数据收集等。我们已经了解预测性维护的步骤,所以需要类比但调整到质量控制上。比如数据采集可能不再是传感器数据,而是图像或视觉数据。需要思考如何用C#处理图像,是否有合适的库,比如OpenCV的.NET版本EmguCV。接下来,数据处理部分可能需要特征提取,比如从图像中
  • 探索时间的脉络:Vue.js下的Timeline组件——Timeline Vuejs 房耿园Hartley
    探索时间的脉络:Vue.js下的Timeline组件——TimelineVuejs项目地址:https://gitcode.com/gh_mirrors/ti/timeline-vuejs在数字时代,将信息以时间轴的形式展示变得日益重要,它帮助我们清晰地追踪事件的发展和变迁。今天,我们要推荐一个精巧且功能强大的Vue.js组件——TimelineVuejs。这款开源项目专为Vue爱好者设计,旨在优
  • 你的网络屏障在哪里?端口安全技术详解 Yori_22 安全网络php
    在数字化时代,网络已成为信息传输和交互的重要通道。然而,随着网络应用的广泛普及,网络安全问题也日益凸显。其中,端口安全作为网络防御的重要一环,其重要性不容忽视。本文将深入探讨端口安全技术,帮助你了解如何构建坚不可摧的网络屏障。一、端口安全概述端口是网络通信的入口和出口,它负责数据传输的转发和控制。在计算机网络中,每个应用程序或服务都会绑定到一个或多个端口上,以便进行网络通信。然而,端口的开放也带来
  • 万字长文破解 AI 图片生成算法-Stable diffusion (第一篇) 悟空 AI 人工智能深度学习
    想象一下:你闭上眼睛,脑海中构思一个场景,用简短的语言描述出来,然后“啪”的一声,一张栩栩如生的图片就出现在你眼前。这不再是科幻小说里才有的情节,而是StableDiffusion——一种前沿的AI图片生成算法——所带来的现实。在本系列的万字长文中,我们将深入探索StableDiffusion的神秘面纱,揭秘它是如何将文字描述转化为令人惊叹的视觉艺术。无论你是AI技术的爱好者、数字艺术的探索者,还
  • Hadoop(一) 朱辉辉33 hadooplinux
    今天在诺基亚第一天开始培训大数据,因为之前没接触过Linux,所以这次一起学了,任务量还是蛮大的。 首先下载安装了Xshell软件,然后公司给了账号密码连接上了河南郑州那边的服务器,接下来开始按照给的资料学习,全英文的,头也不讲解,说锻炼我们的学习能力,然后就开始跌跌撞撞的自学。这里写部分已经运行成功的代码吧.    在hdfs下,运行hadoop fs -mkdir /u
  • maven An error occurred while filtering resources blackproof maven报错
    转:http://stackoverflow.com/questions/18145774/eclipse-an-error-occurred-while-filtering-resources   maven报错: maven An error occurred while filtering resources   Maven -> Update Proje
  • jdk常用故障排查命令 daysinsun jvm
    linux下常见定位命令: 1、jps      输出Java进程       -q       只输出进程ID的名称,省略主类的名称;       -m      输出进程启动时传递给main函数的参数;     &nb
  • java 位移运算与乘法运算 周凡杨 java位移运算乘法
      对于 JAVA 编程中,适当的采用位移运算,会减少代码的运行时间,提高项目的运行效率。这个可以从一道面试题说起:     问题: 用最有效率的方法算出2 乘以8 等於几?” 答案:2 << 3 由此就引发了我的思考,为什么位移运算会比乘法运算更快呢?其实简单的想想,计算机的内存是用由 0 和 1 组成的二
  • java中的枚举(enmu) g21121 java
    从jdk1.5开始,java增加了enum(枚举)这个类型,但是大家在平时运用中还是比较少用到枚举的,而且很多人和我一样对枚举一知半解,下面就跟大家一起学习下enmu枚举。先看一个最简单的枚举类型,一个返回类型的枚举: public enum ResultType { /** * 成功 */ SUCCESS, /** * 失败 */ FAIL,
  • MQ初级学习 510888780 activemq
    1.下载ActiveMQ 去官方网站下载:http://activemq.apache.org/ 2.运行ActiveMQ 解压缩apache-activemq-5.9.0-bin.zip到C盘,然后双击apache-activemq-5.9.0-\bin\activemq-admin.bat运行ActiveMQ程序。 启动ActiveMQ以后,登陆:http://localhos
  • Spring_Transactional_Propagation 布衣凌宇 springtransactional
    //事务传播属性 @Transactional(propagation=Propagation.REQUIRED)//如果有事务,那么加入事务,没有的话新创建一个 @Transactional(propagation=Propagation.NOT_SUPPORTED)//这个方法不开启事务 @Transactional(propagation=Propagation.REQUIREDS_N
  • 我的spring学习笔记12-idref与ref的区别 aijuans spring
    idref用来将容器内其他bean的id传给<constructor-arg>/<property>元素,同时提供错误验证功能。例如: <bean id ="theTargetBean" class="..." /> <bean id ="theClientBean" class=&quo
  • Jqplot之折线图 antlove jsjqueryWebtimeseriesjqplot
    timeseriesChart.html <script type="text/javascript" src="jslib/jquery.min.js"></script> <script type="text/javascript" src="jslib/excanvas.min.js&
  • JDBC中事务处理应用 百合不是茶 javaJDBC编程事务控制语句
      解释事务的概念; 事务控制是sql语句中的核心之一;事务控制的作用就是保证数据的正常执行与异常之后可以恢复   事务常用命令:             Commit提交         
  • [转]ConcurrentHashMap Collections.synchronizedMap和Hashtable讨论 bijian1013 java多线程线程安全HashMap
    在Java类库中出现的第一个关联的集合类是Hashtable,它是JDK1.0的一部分。 Hashtable提供了一种易于使用的、线程安全的、关联的map功能,这当然也是方便的。然而,线程安全性是凭代价换来的――Hashtable的所有方法都是同步的。此时,无竞争的同步会导致可观的性能代价。Hashtable的后继者HashMap是作为JDK1.2中的集合框架的一部分出现的,它通过提供一个不同步的
  • ng-if与ng-show、ng-hide指令的区别和注意事项 bijian1013 JavaScriptAngularJS
            angularJS中的ng-show、ng-hide、ng-if指令都可以用来控制dom元素的显示或隐藏。ng-show和ng-hide根据所给表达式的值来显示或隐藏HTML元素。当赋值给ng-show指令的值为false时元素会被隐藏,值为true时元素会显示。ng-hide功能类似,使用方式相反。元素的显示或
  • 【持久化框架MyBatis3七】MyBatis3定义typeHandler bit1129 TypeHandler
    什么是typeHandler? typeHandler用于将某个类型的数据映射到表的某一列上,以完成MyBatis列跟某个属性的映射   内置typeHandler MyBatis内置了很多typeHandler,这写typeHandler通过org.apache.ibatis.type.TypeHandlerRegistry进行注册,比如对于日期型数据的typeHandler,
  • 上传下载文件rz,sz命令 bitcarter linux命令rz
    刚开始使用rz上传和sz下载命令: 因为我们是通过secureCRT终端工具进行使用的所以会有上传下载这样的需求: 我遇到的问题: sz下载A文件10M左右,没有问题 但是将这个文件A再传到另一天服务器上时就出现传不上去,甚至出现乱码,死掉现象,具体问题 解决方法: 上传命令改为;rz -ybe 下载命令改为:sz -be filename 如果还是有问题: 那就是文
  • 通过ngx-lua来统计nginx上的虚拟主机性能数据 ronin47 ngx-lua 统计 解禁ip
    介绍 以前我们为nginx做统计,都是通过对日志的分析来完成.比较麻烦,现在基于ngx_lua插件,开发了实时统计站点状态的脚本,解放生产力.项目主页: https://github.com/skyeydemon/ngx-lua-stats 功能 支持分不同虚拟主机统计, 同一个虚拟主机下可以分不同的location统计. 可以统计与query-times request-time
  • java-68-把数组排成最小的数。一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的。例如输入数组{32, 321},则输出32132 bylijinnan java
    import java.util.Arrays; import java.util.Comparator; public class MinNumFromIntArray { /** * Q68输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。 * 例如输入数组{32, 321},则输出这两个能排成的最小数字32132。请给出解决问题
  • Oracle基本操作 ccii Oracle SQL总结Oracle SQL语法Oracle基本操作Oracle SQL
    一、表操作 1. 常用数据类型 NUMBER(p,s):可变长度的数字。p表示整数加小数的最大位数,s为最大小数位数。支持最大精度为38位 NVARCHAR2(size):变长字符串,最大长度为4000字节(以字符数为单位) VARCHAR2(size):变长字符串,最大长度为4000字节(以字节数为单位) CHAR(size):定长字符串,最大长度为2000字节,最小为1字节,默认
  • [强人工智能]实现强人工智能的路线图 comsci 人工智能
        1:创建一个用于记录拓扑网络连接的矩阵数据表      2:自动构造或者人工复制一个包含10万个连接(1000*1000)的流程图      3:将这个流程图导入到矩阵数据表中      4:在矩阵的每个有意义的节点中嵌入一段简单的
  • 给Tomcat,Apache配置gzip压缩(HTTP压缩)功能 cwqcwqmax9 apache
    背景: HTTP 压缩可以大大提高浏览网站的速度,它的原理是,在客户端请求网页后,从服务器端将网页文件压缩,再下载到客户端,由客户端的浏览器负责解压缩并浏览。相对于普通的浏览过程HTML ,CSS,Javascript , Text ,它可以节省40%左右的流量。更为重要的是,它可以对动态生成的,包括CGI、PHP , JSP , ASP , Servlet,SHTML等输出的网页也能进行压缩,
  • SpringMVC and Struts2 dashuaifu struts2springMVC
    SpringMVC VS Struts2 1: spring3开发效率高于struts 2: spring3 mvc可以认为已经100%零配置 3: struts2是类级别的拦截, 一个类对应一个request上下文, springmvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应 所以说从架构本身上 spring3 mvc就容易实现r
  • windows常用命令行命令 dcj3sjt126com windowscmdcommand
    在windows系统中,点击开始-运行,可以直接输入命令行,快速打开一些原本需要多次点击图标才能打开的界面,如常用的输入cmd打开dos命令行,输入taskmgr打开任务管理器。此处列出了网上搜集到的一些常用命令。winver 检查windows版本 wmimgmt.msc 打开windows管理体系结构(wmi) wupdmgr windows更新程序 wscrip
  • 再看知名应用背后的第三方开源项目 dcj3sjt126com ios
    知名应用程序的设计和技术一直都是开发者需要学习的,同样这些应用所使用的开源框架也是不可忽视的一部分。此前《 iOS第三方开源库的吐槽和备忘》中作者ibireme列举了国内多款知名应用所使用的开源框架,并对其中一些框架进行了分析,同样国外开发者 @iOSCowboy也在博客中给我们列出了国外多款知名应用使用的开源框架。另外txx's blog中详细介绍了 Facebook Paper使用的第三
  • Objective-c单例模式的正确写法 jsntghf 单例iosiPhone
    一般情况下,可能我们写的单例模式是这样的: #import <Foundation/Foundation.h> @interface Downloader : NSObject + (instancetype)sharedDownloader; @end #import "Downloader.h" @implementation
  • jquery easyui datagrid 加载成功,选中某一行 hae jqueryeasyuidatagrid数据加载
    1.首先你需要设置datagrid的onLoadSuccess $( '#dg' ).datagrid({onLoadSuccess :  function (data){      $( '#dg' ).datagrid( 'selectRow' ,3); }});   2.onL
  • jQuery用户数字打分评价效果 ini JavaScripthtmljqueryWebcss
    效果体验:http://hovertree.com/texiao/jquery/5.htmHTML文件代码: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>jQuery用户数字打分评分代码 - HoverTree</
  • mybatis的paramType kerryg DAOsql
    MyBatis传多个参数: 1、采用#{0},#{1}获得参数:    Dao层函数方法:     public User selectUser(String name,String area); 对应的Mapper.xml    <select id="selectUser" result
  • centos 7安装mysql5.5 MrLee23 centos
    首先centos7 已经不支持mysql,因为收费了你懂得,所以内部集成了mariadb,而安装mysql的话会和mariadb的文件冲突,所以需要先卸载掉mariadb,以下为卸载mariadb,安装mysql的步骤。   #列出所有被安装的rpm package rpm -qa | grep mariadb   #卸载 rpm -e mariadb-libs-5.
  • 利用thrift来实现消息群发 qifeifei thrift
               Thrift项目一般用来做内部项目接偶用的,还有能跨不同语言的功能,非常方便,一般前端系统和后台server线上都是3个节点,然后前端通过获取client来访问后台server,那么如果是多太server,就是有一个负载均衡的方法,然后最后访问其中一个节点。那么换个思路,能不能发送给所有节点的server呢,如果能就
  • 实现一个sizeof获取Java对象大小 teasp javaHotSpot内存对象大小sizeof
       由于Java的设计者不想让程序员管理和了解内存的使用,我们想要知道一个对象在内存中的大小变得比较困难了。本文提供了可以获取对象的大小的方法,但是由于各个虚拟机在内存使用上可能存在不同,因此该方法不能在各虚拟机上都适用,而是仅在hotspot 32位虚拟机上,或者其它内存管理方式与hotspot 32位虚拟机相同的虚拟机上 适用。     
  • SVN错误及处理 xiangqian0505 SVN提交文件时服务器强行关闭
    在SVN服务控制台打开资源库“SVN无法读取current” ---摘自网络 写道 SVN无法读取current修复方法 Can't read file : End of file found 文件:repository/db/txn_current、repository/db/current   其中current记录当前最新版本号,txn_current记录版本库中版本