数字图像处理 --- 图像的离散余弦变换(python实战)
图像的离散余弦变换(python实战)
这篇文章是我上两篇文章的延续,主要是觉得前面的文章太长了,所以把关于图像的DCT变换部分单独拎出来放到这里,这两篇文章分别是:
1,一维DCT
2,二维DCT
正文:
图像的离散余弦变换
正变换
定义图像DCT正变换与反变换的函数
def ImagePadding(x):
[M,N]=x.shape
# 定义零填充的大小
pad_height = (8 - M % 8) % 8
pad_width = (8 - N % 8) % 8
# 对图像进行零填充
padded_x = np.pad(x, ((0, pad_height), (0, pad_width)), mode='constant', constant_values=0)
return padded_x
def DCT2D_block(x):
#image padding
x_pad=ImagePadding(x)
print("padded image size=",x_pad.shape)
N=x_pad.shape[0]//8
#display padded image
plt.figure(figsize=(6, 6))
plt.imshow(x_pad,cmap='gray')
plt.title('Padded Image')
#build dct transform matrix
A=DCT1d_matrix(8)
AT=A.T
print("DCT Transform Matrix for N = 8:",A)
#分块
block8x8=np.zeros((8,8))
X=np.zeros((x_pad.shape))
for i in range(N):
for j in range(N):
for x in range(8):
for y in range(8):
block8x8[x,y]=x_pad[i*8+x,j*8+y]
X8x8=A@block8x8@AT
for p in range(8):
for q in range(8):
X[i*8+p,j*8+q]=X8x8[p,q]
return X
def DCT2D(x):
#image padding
x_pad=ImagePadding(x)
print("padded image size=",x_pad.shape)
#display padded image
plt.figure(figsize=(6, 6))
plt.imshow(x_pad,cmap='gray')
plt.title('Padded Image')
#build dct transform matrix
A=DCT1d_matrix(x_pad.shape[0])
AT=A.T
#DCT
X=A@x_pad@AT
return X
def IDCT2D(X):
#check
if not(X.shape[0]==X.shape[1]):
print("Err:this image is not squre")
return
#build dct transform matrix
A=DCT1d_matrix(X.shape[0])
AT=A.T
#IDCT
x=AT@X@A
return x
图像DCT正变换的例子,导入测试图像
from skimage import data
#load image
Img = data.astronaut()
print(Img.shape)
plt.figure(figsize=(3, 3))
plt.imshow(Img,cmap='gray')
plt.title('Astronaut')
分别用自己定义的函数和scipy库自带的函数对图像进行二维DCT运算,其中库函数用于验证我自己写的DCT函数的运行结果是否正确。
#调用自己定义的函数
Img_DCT=DCT2D(Img)
fig=plt.figure(figsize=(3,3))
plt.imshow(Img_DCT,cmap='gray')
#调用scipy库函数
dctlib=dct(dct(Img.T, norm='ortho').T, norm='ortho')
fig=plt.figure(figsize=(3,3))
plt.imshow(dctlib,cmap='gray',vmin=np.min(dctlib), vmax=np.max(dctlib))
print("my result:",Img_DCT)
print("result of lib:",dctlib)
运行结果如下:
整幅图像的DCT变换结果像是一张全黑的图,这是由于DCT系数只在左上角的很小一块区域的数值较大,而其他大部分区域都是很小的值,让人看起来就像是一幅全黑的图像。在后面的文章中,我打算只对整幅图像中的一小块内容做DCT变换,便于更好的演示。在演示之前,我们先看看图像DCT的反变换。
反变换
Img_idct=IDCT2D(Img_DCT)
fig=plt.figure()
plt.subplot(1,2,1)
plt.imshow(Img,cmap='gray')
plt.title('Org image')
plt.subplot(1,2,2)
plt.imshow(Img_idct,cmap='gray')
plt.title('Inv dct image')
运行结果如下:
一小块图像的DCT正变换与反变换
从图像中截取一小段图片,并对他进行二维DCT:
tiny = Img[20:28, 30:38] # a tiny 8 x 8 block, in the color=0 (Red) channel
fig=plt.figure()
plt.imshow(tiny)
plt.colorbar()
# And here are the numbers.
print("tiny:\n",tiny)
运行结果,这是原图中截取的一小段:
#2d dct of tiny
tiny_dct=DCT2D(tiny)
fig=plt.figure()
plt.imshow(tiny_dct)
plt.colorbar()
np.set_printoptions(linewidth=100) # output line width (default is 75)
round6 = np.vectorize(lambda m: '{:6.1f}'.format(m))
round6(tiny_dct)
这是与之对应的DCT结果,在二维DCT除了左上角(对应最低频率cos函数的系数,即,直流分量)以外,大量的DCT系数都很小,且越是接近左下角(对应频率最高的cos函数的系数)越是接近于0:
如果要压缩图像的话,可以把部分高频dct系数置0,以达到压缩的目的:
# First make a copy to work on.
tinyDCT_chopped = tiny_dct.copy()
N=tinyDCT_chopped.shape[0]
# Then zero the pieces below the x + y = 8 line.
for x in range(N):
for u in range(N):
if x + u > 8:
tinyDCT_chopped[x,u] = 0.0
fig=plt.figure()
plt.imshow(tinyDCT_chopped)
plt.colorbar()
round6(tinyDCT_chopped)
将压缩前后的小图进行对比,可以看到虽然我在上面对大量的高频DCT系数采取了置0操作,但反变换回去后的图像和原图相差无几:
#将压缩前后的小图像进行对比
tiny_zip=IDCT2D(tinyDCT_chopped)
fig=plt.figure()
plt.subplot(1,2,1)
plt.imshow(tiny,cmap='gray')
plt.title('Org image')
plt.subplot(1,2,2)
plt.imshow(tiny_zip,cmap='gray')
plt.title('compressed image')
运行结果:
(全文完)
作者 --- 松下J27
参考文献:
1,《数字图像处理技术详解与Visual C++实践》---左飞
3,dct
4,https://en.wikipedia.org/wiki/Discrete_cosine_transform
5,https://en.wikipedia.org/wiki/Cross-correlation
6,Amplitude, Period, Phase Shift and Frequency
版权声明:文中的部分图片,文字或者其他素材,可能来自很多不同的网站和说明,在此没法一一列出,如有侵权,请告知,立即删除。欢迎大家转载,但是,如果有人引用或者COPY我的文章,必须在你的文章中注明你所使用的图片或者文字来自于我的文章,否则,侵权必究。 ----松下J27
原文地址:https://blog.csdn.net/daduzimama/article/details/140857411
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!