- 在线时间
- 479 小时
- 最后登录
- 2026-5-9
- 注册时间
- 2023-7-11
- 听众数
- 4
- 收听数
- 0
- 能力
- 0 分
- 体力
- 7813 点
- 威望
- 0 点
- 阅读权限
- 255
- 积分
- 2931
- 相册
- 0
- 日志
- 0
- 记录
- 0
- 帖子
- 1173
- 主题
- 1188
- 精华
- 0
- 分享
- 0
- 好友
- 1
该用户从未签到
 |
离散余弦变换(Discrete Cosine Transform,DCT)是一种在信号处理和数据压缩领域广泛应用的数学变换方法。其核心思想是将一系列数据点通过一组余弦函数的加权和转换,从而将信号或图像从时域/空域表示转换为频域表示。DCT在信息编码和压缩中扮演着重要的角色,尤其在图像和音频领域,它通过能量集中的方式,更高效地表示信号的频率分量。. j# n2 \, I6 s/ _% ^! U! u
DCT的原理包括以下几个关键点:
' D' [. V+ u# o3 Z; U; }/ K$ S( P4 Z
1.变换域: DCT将输入的序列或图像分解为一组频率成分,每个分量对应不同频率,类似于傅里叶变换,但DCT的基函数是实数。2 O- P% m) b1 S. @
2.余弦函数: DCT使用一组余弦函数作为基函数,这些函数在不同频率上振荡,与傅里叶变换相似但更适合实际应用。, x3 ^2 U8 K1 x0 ?6 x. T
3.变换步骤: 对于一维序列,DCT将N个数据点转换为N个频率分量。对于二维图像,DCT将图像分块并对每个块应用变换,得到每个块的频率分量。/ N' G) _8 ?' z# }+ Q% J" Y; X
4.能量集中: 与傅里叶变换不同,DCT倾向于将信号或图像的能量集中在少数低频分量上,这在图像压缩中尤为有用。% h' ?1 q9 X& E% U" a. ^! s/ o
5.类型: 存在不同类型的DCT变换,其中类型II是最常用的,特别是在图像压缩中得到广泛应用。% y& ]" h1 o, S3 r
q) m- @* D0 w. [. S
DCT的应用广泛,其中包括:
+ l3 M! Z8 L: g+ {
6 Q) A. t% c; c& G v. i0 V: V/ t6.图像压缩: JPEG图像压缩利用DCT将图像转换为频域表示,通过去除或量化高频分量,实现了高效的图像压缩。
7 m% b4 n( Q' F% T8 p4 Q7.音频处理: MP3等音频压缩格式使用DCT将音频信号转换为频域表示,以减小文件大小同时保留主要信息。
2 D9 K7 P9 P' n4 x' j5 W) E8.信号处理: 在通信领域,DCT用于数据传输和信号处理,有助于分析信号的频率成分。) J" W9 Q4 T' ]9 B, ~: Y
+ V# \; x( C6 C ?) m
总体而言,DCT是一种强大的数学工具,能够以更适合分析和处理的方式表示信号或图像,为多个领域提供了有力的支持。现在,我们将通过DCT的原理和应用,探讨如何将水印嵌入图像的具体过程。
8 O9 v `& X# L3 h8 ]' I0 e- K, {1 W
现在我们使用DCT将水印提案加到图片中
8 Z+ T& N7 g* @# y- {, L& `* D" J这段代码执行了图像水印嵌入的过程,以下是逐行代码的解释:- clear;clc3 N7 t4 b& S4 X; a& A- W
, D q% ?, z. ^2 x$ ^) v4 v- size=512;
- W+ R8 z; O6 K - block=8;
; O, X3 p: b j2 m - blockno=size/block;& V, D\" W+ E: D4 x\" z
- LENGTH=size*size/64;
\" F; d* g, _- m8 G& b - Alpha1=0.02; Alpha2=0.02;
\" v7 ?( [, X; d! j3 b) Y# G0 P - T1=100;! Y% u2 e! M$ i9 J$ _
- I=zeros(size,size);
. H# ]* w, ~( V\" q - D=zeros(size,size);( `4 m% {# Y2 \ @
- BW=zeros(size,size);
& d1 N; Q' ~4 N2 ^& N2 Q/ _ - block_dct1=zeros(block,block);% N6 _\" j5 ?2 s* I
: o. C# g9 O+ b- M- i=imread('watermark64by64.png');
' r. O2 q5 l4 b- P/ ]/ n) c - mark=reshape(i,1,LENGTH);& O4 v; C0 U4 Z8 I
- figure;imshow(i);title('水印');
\" o0 E6 i, ]- b9 z# s- ~( r - %subplot(3,2,1);plot(mark);title('水印');
5 @2 h\" w1 t: E& l- _ - %显示原图
O; g( \) F( h* o5 f! [% }# l: y - figure;I=imread('lena512512.jpg');- H$ Y: Z$ n/ h5 R
- . \, V8 k7 e2 A% P' x, ?) }
- I0=I;
# k3 {7 n; w1 v6 n\" i0 T - imshow(I);title('原始图像');* _7 b! g- I+ V e# v; x: @, a' J
' X& V3 O. u/ X, r9 R5 ^- % BW=edge(I,'canny');figure;;imshow(BW);
$ w* V7 z9 u3 Z, M- ` - % title('edge of origine image');5 w2 r3 @6 |3 V* K: ?
- %嵌入水印/ V2 l0 a5 a5 k q* P
- k=1;
, l4 |2 f/ g' }5 A0 b% {+ \ - for m=1:blockno2 S+ U4 |* V% ^ X/ Q' d2 ?% S
- for n=1:blockno
0 k! k4 q\" L& X8 e\" O7 R( @5 l5 v - x=(m-1)block+1; y=(n-1)block+1;
\" ~! A0 o8 V+ Q1 ^' l1 P8 K - block_dct1=I(x:x+block-1,y:y+block-1);
: Z! A) F8 d+ B0 {( j2 l1 I - block_dct1=dct2(block_dct1);9 C5 h1 ^3 Y) R
- BW_8_8=BW(x:x+block-1,y:y+block-1);/ D. ~/ G# M' ?( }0 u
- if m<=1|n<=1
: l$ C$ p' S# C+ _) E - T=0;
% H$ Q7 j. E- P1 s - else4 b! h' g; K, X) `
- T=sum(BW_8_8); T=sum(T);
& \& K- J5 f- G6 A - end. B5 \4 |9 v* c: q4 ^
- if T>T1
2 O5 a* ]. w N: t' N( { - Alpha=Alpha2;: w5 C8 `7 f' ?9 I7 t& B$ }$ P
- else
# a& N$ j1 ?8 a$ o4 v) s/ \ - Alpha=Alpha1;
, H' w2 J' b) ?, i1 O7 x# y9 X - end6 X* u# G( H6 S9 \+ y* [
- block_dct1(1,1)=block_dct1(1,1)(1+Alphamark(k));4 f1 L* z7 M. C
- block_dct1=idct2(block_dct1);
# A+ `' c8 X& C6 @6 e0 S% k2 | - D(x:x+block-1,y:y+block-1)=block_dct1;' L\" |8 S8 b+ ~2 I( c
- k=k+1;: I. q0 T1 S+ m
- end% Z8 G& f! R! Y2 R& l
- end
\" }2 j1 _0 ?! {. V1 Q' I - / ~& j7 l4 g\" f( M5 a t; W* O+ v) w2 w
- figure;imshow(D,[]);title('嵌入水印后的图像');
复制代码 1.clear; clc;: 这两个命令清空了 MATLAB 的工作区和命令窗口,以确保在开始之前没有残留的变量或输出。
6 m5 N2 {8 ^" L/ d0 }6 l" ^2.size = 512; block = 8; blockno = size / block; LENGTH = size * size / 64; Alpha1 = 0.02; Alpha2 = 0.02; T1 = 100;: 这些是设置图像处理所需的变量和参数。size 定义了图像的尺寸,block 是用于分块的大小,blockno 是图像分块后的数量,LENGTH 是图像长度,Alpha1 和 Alpha2 是用于水印嵌入的参数,T1 是一个阈值。
" C: O8 H1 {3 E1 o3 ]3.I = zeros(size, size); D = zeros(size, size); BW = zeros(size, size); block_dct1 = zeros(block, block);: 这些命令初始化了一些矩阵和数组,用于存储图像、水印、DCT 变换后的块等。
! d9 E+ ^+ e5 R5 C4.i = imread('watermark64by64.png'); mark = reshape(i, 1, LENGTH);: 从文件 'watermark64by64.png' 中读取水印图像,然后将其重新形状化为一个向量 mark。
8 o: I8 l7 p# }9 C1 `6 O5.figure; imshow(i); title('水印');: 这段代码显示了读取的水印图像。
+ |0 R7 w+ e$ I) n7 p2 W+ o0 q6.figure; I = imread('lena512512.jpg'); I0 = I; imshow(I); title('原始图像');: 从文件 'lena512512.jpg' 中读取原始图像,并显示它。( b+ R" l: {, L" m% |& @
7.接下来的部分是对原始图像进行边缘检测,但是注释掉了:BW = edge(I, 'canny'); figure; imshow(BW); title('edge of origine image');。因为这部分代码被注释掉了,所以不会实际执行。: Q$ r' P% Q# e% C1 w
8.for m = 1:blockno for n = 1:blockno ... end end: 这是一个嵌套循环,用于对图像进行分块处理和水印嵌入。7 |8 t) n; d7 P" ?2 ~$ T* m
9.在嵌入水印的循环中,它首先将图像按照设定的块大小进行处理,对每个块应用 DCT 变换,然后根据水印像素的值和设定的阈值 T1 进行水印嵌入的处理。# S! X5 H5 W8 D8 C
10.最后,它显示了嵌入水印后的图像:figure; imshow(D, []); title('嵌入水印后的图像');。- %提取水印& O, [1 ?3 ]6 t
- k=1;, l, q `: \) Z1 ]2 A
- mark1=[];\" _: ]\" q# B/ {7 c( {& ?) z
- for m=1:blockno( }' {4 ~& f! {
- for n=1:blockno
( i3 }; k- B- z7 n - x=(m-1)*block+1; y=(n-1)*block+1;, l) X( h. c/ ]# x4 N9 p$ S! A
- block_dct1=D(x:x+block-1,y:y+block-1);
5 |) T, o: ?7 Q - block_dct0=I0(x:x+block-1,y:y+block-1);5 i\" [. z3 a+ E Q
- block_dct1=dct2(block_dct1);8 \+ V6 g0 u, i$ c
- block_dct0=dct2(block_dct0);
$ n8 @6 K- X/ `\" }* l - BW_8_8=BW(x:x+block-1,y:y+block-1);% o$ E+ t# X- j
- if m<=1|n<=1% X3 t0 l3 T( N
- T=0;
G9 B, Y% D; x/ ~% x - else
7 S+ p' \0 F\" r3 U h& y$ H1 d - T=sum(BW_8_8); T=sum(T);
/ G# {1 O' a B) ^4 F - end; g8 H# w, [, ]% G8 d. _
- if T>T1
0 [( L1 [6 a! H - Alpha=Alpha2;
7 e4 [3 ]4 q/ C - else, f2 E8 V\" {9 Z& Q4 j
- Alpha=Alpha1;
$ Y# I0 e8 N0 W2 c& b& @1 l4 K; h - end0 u- s. W- y* L\" p# c2 _2 a9 ~
- 3 \) F' B* x( z$ [3 t) K\" M
- mark1(k)=(block_dct1(1,1)/block_dct0(1,1)-1)/Alpha;
' n/ H4 r* ]9 d6 R8 k/ l7 \ - k=k+1;$ i4 ]# W9 F/ H& m! r8 h\" k
- end
0 |5 i5 q& k K) ?* p - end
\" ^ q8 _& q+ U7 W - mark1=reshape(mark1,64,64);% p9 y. W- D2 ^
- figure# {8 m0 O d8 \1 [- P8 M3 A
- imshow(mark1)
( U' U\" h\" ^8 j/ j& o - title('提取的水印')
复制代码 这部分代码是关于从嵌有水印的图像中提取水印信息的过程。让我为你解释一下:
' d4 e; W& F# z$ E
/ d8 e8 G- q: |0 z2 O1 d- G6 s1.k=1; mark1=[];: 这两个语句初始化了一个索引变量 k 和一个空数组 mark1,用于存储提取的水印信息。. R$ W d7 c5 J
2.for m=1:blockno for n=1:blockno ... end end: 这是一个嵌套循环,用于遍历图像的分块。
2 }( g: _* n4 X' w4 C3.在循环内部,它首先确定当前块的位置 x 和 y,然后分别从嵌有水印的图像 D 和原始图像 I0 中提取对应的块。" ~! K+ c/ L8 z) x. {. h
4.对提取的块应用 DCT 变换:block_dct1 = dct2(block_dct1); block_dct0 = dct2(block_dct0);。这里对嵌有水印的块和原始图像的块都进行了 DCT 变换。
( k1 H: {2 H" C! `5 K5 a5.计算了当前块的边缘信息 BW_8_8。6 q( u, U7 J7 }6 |6 H9 _4 t* G7 T
6.根据设定的阈值 T1,确定 Alpha 值。这与嵌入水印的过程中相似。5 R0 Y& n7 }! J t. G8 w
7.接下来的代码是用于从嵌有水印图像和原始图像中提取水印信息的关键步骤:3 i& @9 h3 K# k3 |, i* X/ J
$ O" Y/ o% ]9 c! v$ H% N. z/ O
mark1(k) = (block_dct1(1,1) / block_dct0(1,1) - 1) / Alpha; t6 z( I2 t ~! \ k7 ]
3 R: J! i, }) D: U6 M$ E6 E
这个式子计算了水印信息,并将其存储到 mark1 数组中。
. m" a( j/ r( I/ T( g d1 a6 t6 c. s! a3 B; S2 A& B
8.循环结束后,mark1 存储了提取出的水印信息。接下来,代码对 mark1 进行重新形状化为 64x64 的矩阵,并显示提取的水印图像。 g( l- {) Z5 O1 l
. a. |- Z- `: k4 R5 w最后的 imshow(mark1) 代码会显示提取出的水印图像。请确保之前的嵌入过程已经执行,并且使用相同的图像来提取水印,以获取正确的结果。8 i5 J1 o5 i; U6 @, ?& z# t
1 v4 O; C( F2 o4 i0 U0 A+ I! Q- n, @0 ?9 n
5 s5 b8 c! r& K: U |
zan
|