MATLAB图像精简术,利用bitget实现高效位深度压缩

在数字图像处理领域,图像压缩是一个永恒的话题,我们常常需要在保证图像质量的前提下,尽可能地减小文件大小,以节省存储空间、加快网络传输速度,除了常见的JPEG、PNG等有损或无损压缩格式外,从图像数据本身的位深度入手进行压缩,是一种简单而高效的精简方法,本文将详细介绍如何利用MATLAB中的bitget函数,通过降低图像位深度来实现图像压缩,并探讨其原理、实现步骤与效果。

什么是位深度与图像压缩?

在开始之前,我们首先要理解两个核心概念:

  1. 位深度:位深度指的是存储一个像素点颜色所使用的二进制位数,位数越多,能表示的颜色范围就越广,图像色彩层次就越丰富,常见的位深度有:

    • 8位:这是最标准的形式,通常指灰度图像(256个灰度级,0-255)或彩色图像的每个通道(RGB各有256个级别)。
    • 16位:每个通道有65536个级别,能记录更丰富的色彩和亮度细节,常用于专业摄影和后期制作。
    • 24位:通常指真彩色图像,由8位的红、绿、蓝三个通道叠加而成,总共约1670万种颜色。
  2. 图像压缩:图像压缩的目的是减少表示图像所需的数据量,它分为两类:

    • 无损压缩:压缩后可以完全还原原始图像,没有任何信息损失,例如PNG格式。
    • 有损压缩:压缩过程中会丢弃一部分人眼不敏感的数据,以换取更高的压缩率,例如JPEG格式。

我们今天要讨论的位深度压缩,本质上是一种有损压缩,通过减少表示像素的位数,我们直接丢弃了最低位的颜色信息,从而减小了图像的数据量。

核心工具:bitget函数

MATLAB的bitget函数是实现位深度压缩的关键,它的作用是从一个整数中提取指定位的值。

语法: c = bitget(A, bit)

参数说明:

  • A:输入的整数数组(在我们的场景中,就是图像矩阵)。
  • bit:要提取的位的位置,从1(最低位)到最高位。

返回值:

  • c:一个与A大小相同的数组,其元素是A中对应元素指定位的值(0或1)。

简单示例: 假设我们有一个像素值 A = 200(二进制为 11001000)。

  • bitget(200, 1) 提取最低位,得到 0
  • bitget(200, 8) 提取最高位,得到 1

bitget函数就像一个精密的“数字镊子”,能精准地操作图像数据中的每一位,这正是我们进行位深度压缩的基础。

使用bitget进行图片压缩的步骤

下面我们通过一个具体的例子,将一幅标准的24位彩色图(每个通道8位)压缩到4位,来演示整个流程。

第一步:读取原始图像

我们使用imread函数读取一张图片,为了清晰展示效果,我们选择一张色彩丰富的图片。

% 读取原始图像
original_img = imread('peppers.png'); 
% 假设原始图像是 uint8 类型,每个通道8位
% 显示原始图像
figure;
subplot(1, 2, 1);
imshow(original_img);'原始图像 (8-bit per channel)');

第二步:确定目标位深度并进行数据截断

假设我们的目标是将每个颜色通道从8位压缩到4位,这意味着我们只需要保留原始8位数据中的高4位,而丢弃低4位。

如何实现?我们可以利用bitget提取高4位(即第5位到第8位),然后将它们重新组合成一个4位的整数。

% 目标位深度
target_bits = 4;
% 提取高4位 (第5, 6, 7, 8位)
% 注意:bit的位置从1开始计数
high_4_bit = bitget(original_img, 8:-1:8-target_bits 1);
% 将逻辑数组 (true/false) 转换为 double (0/1)
high_4_bit = double(high_4_bit);
% 将4位数据重新组合成一个整数
% [b8, b7, b6, b5] -> b8*8   b7*4   b6*2   b5*1
compressed_img = uint8(high_4_bit(:,:,1) * 2^3   high_4_bit(:,:,2) * 2^2   high_4_bit(:,:,3) * 2^1   high_4_bit(:,:,4) * 2^0);

代码解释:

  1. bitget(original_img, 8:-1:8-target_bits 1):一次性提取了每个像素值的高4位。8:-1:5 表示从第8位提取到第5位。
  2. double(high_4_bit)bitget返回的是逻辑类型(logical),我们需要将其转换为double类型以便进行后续的数学运算。
  3. compressed_img = ...:这一步是核心,我们将提取出的4个位(现在它们是0或1的矩阵)通过加权求和的方式,重新组合成一个0到15之间的整数,如果高4位是1101,计算结果就是 1*8 1*4 0*2 1*1 = 13

第三步:显示并比较结果

我们将原始图像和压缩后的图像放在一起进行对比。

% 显示压缩后的图像
subplot(1, 2, 2);
imshow(compressed_img);['压缩图像 (', num2str(target_bits), '-bit per channel)']);
% 计算压缩率
original_size = numel(original_img); % 像素总数
compressed_size = numel(compressed_img);
compression_ratio = (1 - compressed_size / original_size) * 100;
fprintf('原始图像大小: %d 像素\n', original_size);
fprintf('压缩后图像大小: %d 像素\n', compressed_size);
fprintf('数据量减少了: %.2f%%\n', compression_ratio);

效果分析: 运行上述代码,你会发现压缩后的图像出现了明显的色带轮廓效应,这是因为从256个级别锐减到16个级别,色彩过渡不再平滑,图像的主体结构和内容依然可辨,控制台会输出压缩率,对于从8位到4位的压缩,数据量正好减少了一半(50%)。

更通用的压缩函数

为了方便重复使用,我们可以将上述逻辑封装成一个函数。

function compressed_img = compress_image_by_bits(original_img, target_bits)
% COMPRESS_IMAGE_BYBITS 通过降低位深度来压缩图像
%   compressed_img = compress_image_bybits(original_img, target_bits)
%   将原始图像的每个通道压缩到 target_bits 位。
    % 检查输入有效性
    if ~ismember(class(original_img), {'uint8', 'uint16'})
        error('输入图像必须是 uint8 或 uint16 类型。');
    end
    if target_bits <= 0 || target_bits >= 16
        error('目标位深度应在1到15之间。');
    end
    % 获取原始位深度
    original_bits = intmax(class(original_img)); % 对于uint8是255, uint16是65535
    % 提取目标的高位
    bits_to_get = original_bits:-1:original_bits-target_bits 1;
    high_bits = bitget(original_img, bits_to_get);
    % 转换并重组
    high_bits = double(high_bits);
    weights = 2.^(target_bits-1:-1:0);
    % 对每个通道进行计算
    if size(high_bits, 3) == 1 % 灰度图
        compressed_img = uint8(sum(high_bits .* weights, 3));
    else % 彩色图
        compressed_img = uint8(sum(high_bits .* weights, 4));
    end
end

使用这个函数非常简单:

% 使用通用函数进行压缩
compressed_img_5bit = compress_image_by_bits(original_img, 5);
figure;
imshow(compressed_img_5bit);['压缩图像 (5-bit per channel)']);

总结与展望

利用bitget函数进行位深度压缩,是MATLAB中一种非常直观且强大的图像处理技巧,它的优点在于:

  • 实现简单:核心逻辑清晰,代码量少。
  • 原理明确:直接操作图像数据的最小单位——位

相关文章