图像与视频处理作业
题目给定图像“foreman.qcif”,利用C语言进行以下编程操作
1.读取原始视频序列(2帧),其中第1帧为I帧,第2帧为P帧(本次作业第2帧可简单做与第1帧的整体图像帧差值);(20分)
2.进行8x8分块的DCT变换;(15分)
3.设定量化步长Qstep=22进行量化;(10分)
4.完成相应的反量化和反DCT变换;(25分)
5.将重组数据写入文件“re_foreman.qcif”(2帧);(20分)6.计算“foreman.qcif”和“re_foreman.qcif”的PSNR。(10分)
代码:
#图像与视频处理作业
# 给定图像“foreman.qcif”,利用C语言进行以下编程操作
# 1.读取原始视频序列(2帧),其中第1帧为I帧,第2帧为P帧(本次作业第2帧可简单做与第1帧的整体图像帧差值);(20分)
# 2.进行8x8分块的DCT变换;(15分)
# 3.设定量化步长Qstep=22进行量化;(10分)
# 4.完成相应的反量化和反DCT变换;(25分)
# 5.将重组数据写入文件“re_foreman.qcif”(2帧);(20分)6.计算“foreman.qcif”和“re_foreman.qcif”的PSNR。(10分)
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import math
PI = 33.14159265358979323
def getFrameInformation(filename,frameNum):
"""
:param frameNum: 读取哪一帧
:return: Yt,Ut,Vt: yuv视频三个数据段的数据
"""
# juv文件路径
filename = "foreman_qcif.yuv"
# 视频的尺寸
height = 144
width = 176
# 读取视频数据
fp = open(filename, 'rb')
# 获取U,V的高度和宽度
h_h = height // 2
h_w = width // 2
# 定义存储Y,U,V 的矩阵
Yt = np.zeros(shape=(height, width), dtype='double', order='C')
Ut = np.zeros(shape=(h_h, h_w), dtype='double', order='C')
Vt = np.zeros(shape=(h_h, h_w), dtype='double', order='C')
# for循环获取指定帧的数据
for i in range(frameNum):
Yt = np.zeros(shape=(height, width), dtype='double', order='C')
Ut = np.zeros(shape=(h_h, h_w), dtype='double', order='C')
Vt = np.zeros(shape=(h_h, h_w), dtype='double', order='C')
# 获取Y字段的数据
for m in range(height):
for n in range(width):
Yt[m, n] = ord(fp.read(1))
# 获取U字段的数据
for m in range(h_h):
for n in range(h_w):
Ut[m, n] = ord(fp.read(1))
# 获取V字段的数据
for m in range(h_h):
for n in range(h_w):
Vt[m, n] = ord(fp.read(1))
return Yt, Ut, Vt
def compare_predition(frameNum1, frameNum2):
"""
:param frameNum1: 选择帧数1
:param frameNum2: 选择帧数2
:return: Yt2-Yt1,Ut2-Ut1,Vt2-Vt1:两帧三个字段的差值
"""
# 获取第frameNum1帧的图片的数据
(Yt1, Ut1, Vt1) = getFrameInformation("foreman_qcif.yuv",1)
# 获取第frameNum2帧的图片的数据
(Yt2, Ut2, Vt2) = getFrameInformation("foreman_qcif.yuv",2)
# 返回三个字段的差值
return (Yt2 - Yt1, Ut2 - Ut1, Vt2 - Vt1)
def dct(Yt, Ut, Vt):
"""
:param Yt: 做DCT变换的Y字段
:param Ut: 做DCT变换的U字段
:param Vt: 做DCT变换的V字段
:return:
"""
# 定义
Yt_dct = np.zeros(shape=(144, 176), dtype='double', order='C')
Ut_dct = np.zeros(shape=(72, 88), dtype='double', order='C')
Vt_dct = np.zeros(shape=(72, 88), dtype='double', order='C')
# 计算变换矩阵A
a_array = np.zeros(shape=(8, 8), dtype='double', order='C')
for i in range(8):
for j in range(8):
if i == 0:
a_array[i][j] = 1 / 8 ** 2
else:
a_array[i][j] = 0.5 * math.cos(i * (j + 0.5) * PI / 8)
# 通过变换矩阵A 得到 其转置矩阵
at_array = np.zeros(shape=(8, 8), dtype='double', order='C')
for i in range(8):
for j in range(8):
at_array[i][j] = a_array[j][i]
# 计算Y的DCT变换
for i in range(18 * 22):
dct_8_8 = np.zeros(shape=(8, 8), dtype='double', order='C')
for n in range((i // 22) * 8, (i // 22) * 8 + 8):
for m in range((i % 22) * 8, (i % 22) * 8 + 8):
dct_8_8[n % 8][m % 8] = Yt[n][m]
dct_8_8 = cv2.dct(dct_8_8)
for n in range((i // 22) * 8, (i // 22) * 8 + 8):
for m in range((i % 22) * 8, (i % 22) * 8 + 8):
Yt_dct[n][m] = dct_8_8[n % 8][m % 8]
# 计算U的DCT变换
for i in range(9 * 11):
dct_8_8 = np.zeros(shape=(8, 8), dtype='double', order='C')
for n in range((i // 11) * 8, (i // 11) * 8 + 8):
for m in range((i % 11) * 8, (i % 11) * 8 + 8):
dct_8_8[n % 8][m % 8] = Ut[n][m]
dct_8_8 = cv2.dct(dct_8_8)
for n in range((i // 11) * 8, (i // 11) * 8 + 8):
for m in range((i % 11) * 8, (i % 11) * 8 + 8):
Ut_dct[n][m] = dct_8_8[n % 8][m % 8]
# 计算V的DCT变换
for i in range(9 * 11):
dct_8_8 = np.zeros(shape=(8, 8), dtype='double', order='C')
for n in range((i // 11) * 8, (i // 11) * 8 + 8):
for m in range((i % 11) * 8, (i % 11) * 8 + 8):
dct_8_8[n % 8][m % 8] = Vt[n][m]
dct_8_8 = cv2.dct(dct_8_8)
for n in range((i // 11) * 8, (i // 11) * 8 + 8):
for m in range((i % 11) * 8, (i % 11) * 8 + 8):
Vt_dct[n][m] = dct_8_8[n % 8][m % 8]
# 返回DCT变换的结果
return Yt_dct, Ut_dct, Vt_dct
def idct(Yt_dct, Ut_dct, Vt_dct):
Yt_dct = np.float32(Yt_dct) # 将数值精度调整为32位浮点型
Ut_dct = np.float32(Ut_dct) # 将数值精度调整为32位浮点型
Vt_dct = np.float32(Vt_dct) # 将数值精度调整为32位浮点型
Yt_idct = np.zeros(shape=(144, 176), dtype='double', order='C')
Ut_idct = np.zeros(shape=(72, 88), dtype='double', order='C')
Vt_idct = np.zeros(shape=(72, 88), dtype='double', order='C')
# 计算变换矩阵A
a_array = np.zeros(shape=(8, 8), dtype='double', order='C')
for i in range(8):
for j in range(8):
if i == 0:
a_array[i][j] = 1 / 8 ** 2
else:
a_array[i][j] = 0.5 * math.cos(i * (j + 0.5) * PI / 8)
# 通过变换矩阵A 得到 其转置矩阵
at_array = np.zeros(shape=(8, 8), dtype='double', order='C')
for i in range(8):
for j in range(8):
at_array[i][j] = a_array[j][i]
# 计算Y的DCT变换
for i in range(18 * 22):
idct_8_8 = np.zeros(shape=(8, 8), dtype='double', order='C')
for n in range((i // 22) * 8, (i // 22) * 8 + 8):
for m in range((i % 22) * 8, (i % 22) * 8 + 8):
idct_8_8[n % 8][m % 8] = Yt_dct[n][m]
idct_8_8 = cv2.idct(idct_8_8)
for n in range((i // 22) * 8, (i // 22) * 8 + 8):
for m in range((i % 22) * 8, (i % 22) * 8 + 8):
Yt_idct[n][m] = idct_8_8[n % 8][m % 8]
# 计算U的DCT变换
for i in range(9 * 11):
idct_8_8 = np.zeros(shape=(8, 8), dtype='double', order='C')
for n in range((i // 11) * 8, (i // 11) * 8 + 8):
for m in range((i % 11) * 8, (i % 11) * 8 + 8):
idct_8_8[n % 8][m % 8] = Ut_dct[n][m]
idct_8_8 = cv2.idct(idct_8_8)
for n in range((i // 11) * 8, (i // 11) * 8 + 8):
for m in range((i % 11) * 8, (i % 11) * 8 + 8):
Ut_idct[n][m] = idct_8_8[n % 8][m % 8]
# 计算V的DCT变换
for i in range(9 * 11):
idct_8_8 = np.zeros(shape=(8, 8), dtype='double', order='C')
for n in range((i // 11) * 8, (i // 11) * 8 + 8):
for m in range((i % 11) * 8, (i % 11) * 8 + 8):
idct_8_8[n % 8][m % 8] = Vt_dct[n][m]
idct_8_8 = cv2.idct(idct_8_8)
for n in range((i // 11) * 8, (i // 11) * 8 + 8):
for m in range((i % 11) * 8, (i % 11) * 8 + 8):
Vt_idct[n][m] = idct_8_8[n % 8][m % 8]
# 返回DCT变换的结果
return Yt_idct, Ut_idct, Vt_idct
def qstep(Yt, Ut, Vt):
Yt = np.uint8(Yt)
Ut = np.uint8(Ut)
Vt = np.uint8(Vt)
Yt_q = np.zeros(shape=(144, 176), dtype='uint8', order='C')
Ut_q = np.zeros(shape=(72, 88), dtype='uint8', order='C')
Vt_q = np.zeros(shape=(72, 88), dtype='uint8', order='C')
for i in range(144):
for j in range(176):
Yt_q[i][j] = Yt[i][j] // 22
for i in range(72):
for j in range(88):
Ut_q[i][j] = Ut[i][j] // 22
for i in range(72):
for j in range(88):
Vt_q[i][j] = Vt[i][j] // 22
return Yt_q, Ut_q, Vt_q
def iqstep(Yt_q, Ut_q, Vt_q):
Yt_q = np.uint8(Yt_q)
Ut_q = np.uint8(Ut_q)
Vt_q = np.uint8(Vt_q)
Yt_iq = np.zeros(shape=(144, 176), dtype='uint8', order='C')
Ut_iq = np.zeros(shape=(72, 88), dtype='uint8', order='C')
Vt_iq = np.zeros(shape=(72, 88), dtype='uint8', order='C')
for i in range(144):
for j in range(176):
Yt_iq[i][j] = Yt_q[i][j] * 22
for i in range(72):
for j in range(88):
Ut_iq[i][j] = Ut_q[i][j] * 22
for i in range(72):
for j in range(88):
Vt_iq[i][j] = Vt_q[i][j] * 22
return Yt_iq, Ut_iq, Vt_iq
def writeqcif(filename, Yt, Ut, Vt):
Yt = np.uint8(Yt)
Ut = np.uint8(Ut)
Vt = np.uint8(Vt)
ff = open(filename, "wb+")
for i in range(144):
for j in range(176):
ff.write(Yt[i][j])
for i in range(72):
for j in range(88):
ff.write(Ut[i][j])
for i in range(72):
for j in range(88):
ff.write(Vt[i][j])
return None
# 图像信噪比是用于评估图像超分结果的指标
def psnr(Yt1, Ut1, Vt1, Yt2, Ut2, Vt2):
ch_num = 0
#遍历图像
for i in range(144):
for j in range(176):
ch_num = ch_num + (math.fabs(Yt1[i][j]/255. - Yt2[i][j]/255.))**2
for i in range(72):
for j in range(88):
ch_num = ch_num + (math.fabs(Ut1[i][j]/255. - Ut2[i][j]/255.))**2
for i in range(72):
for j in range(88):
ch_num = ch_num + (math.fabs(Vt1[i][j]/255. - Vt2[i][j]/255.))**2
ch_num = ch_num/(144*3/2*176)
if ch_num < 1.0e-10:
return 100
PIXEL_MAX = 1
return 20 * math.log10(PIXEL_MAX / math.sqrt(ch_num))
if __name__ == '__main__':
# 从视频中获取第一帧和第二帧数据
(Yt1, Ut1, Vt1) = getFrameInformation("foreman_qcif.yuv",1)
(Yt2, Ut2, Vt2) = getFrameInformation("foreman_qcif.yuv",2)
# 图像化第一帧
writeqcif("foreman1.qcif", Yt1, Ut1, Vt1)
# 图像化第二帧
writeqcif("foreman2.qcif", Yt2, Ut2, Vt2)
#1.predition
(Yt_predition, Ut_predition, Vt_prediton) = compare_predition(1, 2)
print(Yt_predition,Ut_predition,Vt_prediton)
#2.进行DCT变换
(Yt_dct, Ut_dct, Vt_dct) = dct(Yt1, Ut1, Vt1)
#3.进行量化处理
(Yt_q, Ut_q, Vt_q) = qstep(Yt_dct, Ut_dct, Vt_dct)
#4.进行反量化
(Yt_iq, Ut_iq, Vt_iq) = iqstep(Yt_q, Ut_q, Vt_q)
Yt_iq = np.float32(Yt_iq) # 将数值精度调整为32位浮点型
Ut_iq = np.float32(Ut_iq) # 将数值精度调整为32位浮点型
Vt_iq = np.float32(Vt_iq) # 将数值精度调整为32位浮点型
#5.进行IDCT变换
Yt_idct, Ut_idct, Vt_idct = idct(Yt_iq, Ut_iq, Vt_iq)
# 将变换后的数据写入新的文件中
writeqcif("re_foreman1.qcif", Yt_idct, Ut_idct, Vt_idct)
# 对第二帧数据进行相同处理
# 进行DCT变换
(Yt_dct2, Ut_dct2, Vt_dct2) = dct(Yt2, Ut2, Vt2)
# 进行量化处理
(Yt_q2, Ut_q2, Vt_q2) = qstep(Yt_dct2, Ut_dct2, Vt_dct2)
# 进行反量化
(Yt_iq2, Ut_iq2, Vt_iq2) = iqstep(Yt_q2, Ut_q2, Vt_q2)
# 进行IDCT变换
Yt_idct2, Ut_idct2, Vt_idct2 = idct(Yt_iq2, Ut_iq2, Vt_iq2)
# 将变换后的数据写入新的文件中
writeqcif("re_foreman2.qcif", Yt_idct2, Ut_idct2, Vt_idct2)
#输出
print("第一帧原始图像与进行变换后图像的qsnr值为:")
print(psnr(Yt1, Ut1, Vt1,Yt_idct, Ut_idct, Vt_idct))
print("第二帧原始图像与进行变换后图像的qsnr值为:")
print(psnr(Yt2, Ut2, Vt2, Yt_idct2, Ut_idct2, Vt_idct2))
结果展示:
1.读取原始视频序列(2帧),其中第1帧为I帧,第2帧为P帧(本次作业第2帧可简单做与第1帧的整体图像帧差值);(20分)
第一帧图像及3通道信息:
图像:
y通道:
u通道
v通道
第一帧与第二帧的差值
Y_predition
U_predition
V_predition
2.进行8x8分块的DCT变换;(15分)
Y_DCT
U_DCT
V_DCT
3.设定量化步长Qstep=22进行量化;(10分) ------合并写
4.完成相应的反量化和反DCT变换;(25分) -------合并写
Y_IDCT
U_IDCT
V_IDCT
5.将重组数据写入文件“re_foreman.qcif”(2帧);(20分)6.计算“foreman.qcif”和“re_foreman.qcif”的PSNR。(10分)
只进行dct和idct重组出的两幅qcif图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FCXhtHPw-1621643312433)(…/AppData/Roaming/Typora/typora-user-images/image-20210520091843543.png)]
进行进行8x8分块的DCT变换,设定量化步长Qstep=22进行量化;完成相应的反量化和反DCT变换重组出的两幅qcif图
计算出的PSNR
第一帧原始图像与进行变换后图像的qsnr值为:
2.541566509325704
第二帧原始图像与进行变换后图像的qsnr值为:
2.545820360785359
NR。(10分)
只进行dct和idct重组出的两幅qcif图
[外链图片转存中…(img-FCXhtHPw-1621643312433)]
[外链图片转存中…(img-ORdVM5zL-1621643312435)]
进行进行8x8分块的DCT变换,设定量化步长Qstep=22进行量化;完成相应的反量化和反DCT变换重组出的两幅qcif图
[外链图片转存中…(img-X4PBYYkv-1621643312443)]
[外链图片转存中…(img-htygHpsA-1621643312446)]