6.1 Python图像处理之图像编码技术和标准-DPCM编码

6.1 Python图像处理之图像编码技术和标准-DPCM编码

文章目录

  • 6.1 Python图像处理之图像编码技术和标准-DPCM编码
    • 1 算法原理
    • 2 代码
    • 3 效果

1 算法原理

预测编码利用的是信源相邻符号间的相关性。根据某一模型利用以往的样本值对新的样本值进行预测。然后将样本的实际值与预测值相减得到一个误差值,最后对这一误值进行编码。如果模型足够好且样本序列在时间上相关性比较强,则误差信号的幅度将远远小于原始信号,从而得到较大的数据压缩。

对于模拟信号,DPCM 编码采用预测编码的方式传输信号, 所谓预测编码就是根据过去的信号样值来预测下一个信号样值, 并仅把预测值与现实样值的差值加以量化, 编码后进行数字信号传输。

DPCM 是差分预测编码调制的缩写,是比较典型的预测编码系统。在 DPCM 系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在 DPCM 编码器中实际内嵌了一个解码器,如下图编码器中虚线框中所示。

对于图片等数字信号,可以省略了采样的步骤,直接进行量化和编码。可以认为是根据上一个的像素值来预测下一个像素值。

6.1 Python图像处理之图像编码技术和标准-DPCM编码_第1张图片

在代码中实现的是左侧的部分(因为没有进行传输,是边编码边解码),中文版如下图(缓冲器也可以叫预测器)

6.1 Python图像处理之图像编码技术和标准-DPCM编码_第2张图片

2 代码

运行代码说明

1.要改变代码中的图片地址(地址不能有中文)

更改第10行代码的图片地址:img = cv2.imread('img5.jpg')

2 代码依赖包:

matplotlib  3.4.2
numpy  1.20.3
opencv-python  4.1.2.30
# 如果没有安装依赖,可以按下面pip安装
pip install matplotlib numpy opencv-python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author:mgboy time:2021/6/30
import cv2
import numpy as np
import io

###############################################################################
# 读取图片,并转换为 y,v, u 分量。
img = cv2.imread('img5.jpg')
h, w = img.shape[:2]  # 高,宽

# 将 BGR 转换为 YCrCb(YCrCb 应用 YCrCb JPEG(或 YCC),“全范围”,
# 其中 Y 范围为 [0, 255],U、V 范围为 [0, 255](这是默认的 JPEG 格式颜色空间格式)。

yvu = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
y, v, u = cv2.split(yvu)

# 下采样 U 和 V(应用 420 格式)。
u = cv2.resize(u, (u.shape[1] // 2, u.shape[0] // 2))  # 要注意 w或h 为单数的情况
v = cv2.resize(v, (v.shape[1] // 2, v.shape[0] // 2))
print('1-'*50)
print('y分量形状',y.shape)
print('u分量形状',u.shape)
print('v分量形状',v.shape)
############################################################################
# 打开内存中的字节流(而不是使用 文件)
# 将 Y、U 和 V 写入“流”。之后就可以以字节的形式读取,
# 这个是为了模拟读取YUV文件的情况,直接由上面的yuv分量转换形状为一维数据应该也可以
# 这样做的原因是我在网上找的DPCM的C语言版本都是直接读取 .yuv文件的,我为了遵循他们,就这么处理了(其实是懒。。)

f = io.BytesIO()

# Write Y, U and V to the "streams".
f.write(y.tobytes())
f.write(u.tobytes())
f.write(v.tobytes())
f.seek(0)

img_np = np.frombuffer(f.read(), np.uint8)  # 原图的yuv420,一定要420,要不然要修改数组截取大小

img_yuv_len = img_np.size
img_y_len = h * w

y = img_np[:img_y_len]
u = img_np[img_y_len:(img_yuv_len - img_y_len) // 2 + img_y_len]  # 要注意 w或h 为单数的情况
v = img_np[(img_yuv_len - img_y_len) // 2 + img_y_len:]
# print(img_np.size)  # 16328
############################################################################
# DPCM量化编码,采用边编码,边解码的形式,核心是下面for循环部分
img_re = np.zeros(img_y_len, np.uint16)  # 用来存储重建图像,因为中间计算可能超过255,先用16,后面转回8
yprebuff = np.zeros(img_y_len, np.uint16)  # 预测
# print(prebuff.size) # 8164
# print(prebuff.shape) # (8164,)

radio=512/(1<<8)  # //量化因子  8是左向预测8bit量化,如果要进行4或2等的自行更改
for i in range(h):
    for j in range(w):
        # 左向预测8bit量化
        if j == 0:
            # 每行第一个像素要进行特殊处理,或保留,或进行一定预测,本设计中是做一定变换预测
            ypre = y[j + i * w]-128  # 计算预测误差
            yprebuff[j + i * w] = (ypre+255)/radio  # 量化预测误差
            img_re[j + i * w] = (yprebuff[j + i * w]-255/radio)*radio+128  # 重建像素,j解码
            if img_re[j + i * w]>255:
                img_re[j + i * w] = 255# 防止重建像素超过255
            yprebuff[j + i * w] = yprebuff[j + i * w]*radio/2

        else:
            ypre = y[j + i * w] - img_re[j + i * w - 1]  # 计算预测误差
            yprebuff[j + i * w] = (ypre+255) /radio  # 量化  # 量化器
            img_re[j + i * w] = (yprebuff[j + i * w]-255/radio)*radio+img_re[j + i * w - 1]  # 反量化
            yprebuff[j + i * w] = yprebuff[j + i * w] * radio / 2  # 预测器
            if img_re[j + i * w]>255:
                img_re[j + i * w] = 255# 防止重建电平超过255
img_re = img_re.astype(np.uint8) # 用来存储重建图像,后面转回uint8
yprebuff = yprebuff.astype(np.uint8)  # 预测误差

##########################################################################################
# 重建图片
y = y.reshape((h,w))  # 转换向量形状回原来的y分量

yprebuff = yprebuff.reshape((h,w))  # 预测的y分量

img_re = img_re.reshape((h,w))  # 重建的y分量

u = u.reshape((h//2,w//2))  # 恢复采样后的u分量
v = v.reshape((h//2,w//2))
ru = cv2.resize(u,(w,h))  # 恢复采样前的u分量,用这个u分量来重建图片文件
rv = cv2.resize(v,(w,h))

yvu = cv2.merge((y, rv, ru))
bgr = cv2.cvtColor(yvu, cv2.COLOR_YCrCb2BGR)  # 将原来的y,u,v分量转换回图片

yvu_pre = cv2.merge((yprebuff, rv, ru))
bgr_pre = cv2.cvtColor(yvu_pre, cv2.COLOR_YCrCb2BGR)  # 将y的预测误差转换为图片

yvu_re = cv2.merge((img_re, rv, ru))
bgr_re = cv2.cvtColor(yvu_re, cv2.COLOR_YCrCb2BGR)  # 将解码后的的y,u,v分量转换回原图

###############################################################################
# 显示结果
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

plt.subplot(241), plt.imshow(cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)),
plt.title('原图'), plt.axis('off')
plt.subplot(242), plt.imshow(cv2.cvtColor(bgr_pre, cv2.COLOR_BGR2RGB), cmap='gray'),
plt.title('预测误差'), plt.axis('off')
plt.subplot(243), plt.imshow(cv2.cvtColor(bgr_re, cv2.COLOR_BGR2RGB), cmap='gray'),
plt.title('重建'), plt.axis('off')

plt.subplot(244), plt.imshow(cv2.cvtColor(y, cv2.COLOR_BGR2RGB)),
plt.title('y分量'), plt.axis('off')
plt.subplot(245), plt.imshow(cv2.cvtColor(ru, cv2.COLOR_BGR2RGB), cmap='gray'),
plt.title('u分量'), plt.axis('off')
plt.subplot(246), plt.imshow(cv2.cvtColor(rv, cv2.COLOR_BGR2RGB), cmap='gray'),
plt.title('v分量'), plt.axis('off')
plt.show()

3 效果

6.1 Python图像处理之图像编码技术和标准-DPCM编码_第3张图片

你可能感兴趣的:(python图像处理,python,计算机视觉,opencv)