Loading

霍夫曼编码 & 基于区域增长的图像分割算法

图像处理与机器视觉第三次作业

task1、霍夫曼编码。

对给定图像lena.bmp进行霍夫曼编码,在word中贴出代码,以及编码的码字结果、编码的平均长度、压缩比值。

1.1 实验结果

1.2 实现步骤如下

  1. 读取图像并将其转换为灰度图像;
  2. 计算图像总像素数N和每个灰度级的频率freq;
  3. 计算每个灰度级的概率prob;
  4. 使用matlab自带的函数huffmandict生成霍夫曼编码字典dict;
  5. 对图像进行霍夫曼编码,得到编码后的码字code;
  6. 计算编码后的码字长度len;
  7. 计算编码后的平均长度avg_len;
  8. 计算压缩比值ratio,其中8表示原图每个像素使用8位二进制表示;
  9. 显示结果。

1.3 代码

% 读取图像
img = imread('lena.bmp');
% 转换为灰度图像
img = im2gray(img);
% 获取图像的大小
[m,n] = size(img);
% 计算图像的总像素数
N = m*n;
% 计算图像的每个灰度级的频率
freq = zeros(1,256);
for i = 1:m
    for j = 1:n
        freq(img(i,j)+1) = freq(img(i,j)+1) + 1;
    end
end
% 计算图像的每个灰度级的概率
prob = freq / N;
% 使用matlab自带的函数生成霍夫曼编码字典
dict = huffmandict(0:255,prob);
% 对图像进行霍夫曼编码
code = huffmanenco(img(:),dict);
% 计算编码后的码字长度
len = length(code);
% 计算编码后的平均长度
avg_len = len / N;
% 计算压缩比值
ratio = 8 / avg_len;
% 显示结果
disp('编码后的码字长度为:');
disp(len);
disp('编码后的平均长度为:');
disp(avg_len);
disp('压缩比值为:');
disp(ratio);

task2、基于区域增长的图像分割算法

2.1 实验结果

中间结果图 结果图
img img

2.2 实现步骤

  1. 读取图像并转化为灰度图像。
I = imread('regiongrowing.bmp');
I = im2gray(I);
  1. 在图像上选择两个种子点,作为两个区域的起始点。
figure; imshow(I, []);
[x1, y1] = ginput(1);
hold on; plot(x1, y1, 'r+', 'MarkerSize', 20, 'LineWidth', 3);
[x2, y2] = ginput(1);
plot(x2, y2, 'g+', 'MarkerSize', 20, 'LineWidth', 3);
  1. 对两个种子点进行区域增长,将同一区域内的像素标记为1,不属于该区域的像素标记为0。
reg_maxdist = 10;
J1 = regiongrowing(I, round(y1), round(x1), reg_maxdist);
J2 = regiongrowing(I, round(y2), round(x2), reg_maxdist);
  1. 将两个区域的标记结果保存为图像文件,便于进行结果分析。
imwrite(J1, 'regiongrowing1.bmp');
imwrite(J2, 'regiongrowing2.bmp');
  1. 绘制两个区域的标记结果。
figure;
subplot(121); imshow(J1, []); title('Seed1');
subplot(122); imshow(J2, []); title('Seed2');
  1. 实现区域增长算法的具体细节。该算法基于队列,将种子点从队尾放入队列,按照广度优先的顺序,从队首取出元素。遍历图像中与当前像素距离小于阈值且未被访问过的像素,标定为同一区域内的像素,将其加入队列。
function J = regiongrowing(I, seed_row, seed_col, thresh)
  • 此处定义了一个名为 regiongrowing() 的函数,它接收四个参数:输入图像 I、种子点的行坐标 seed_row、种子点的列坐标 seed_col,以及区域增长的最大距离 thresh。
J = zeros(size(I));
visited = zeros(size(I));
queue = zeros(10000, 2);
queue_len = 0;
  • 这四行代码初始化了输出图像 J、访问标志矩阵 visited、队列 queue,以及队列长度 queue_len。其中,J 和 visited 的大小与输入图像 I 相同,而 queue 的大小为 10000×2,表示队列最多可以存储 10000 个二维坐标。queue_len 初始值为 0,表示队列为空。
queue_len = queue_len + 1;
queue(queue_len, :) = [seed_row, seed_col];
visited(seed_row, seed_col) = 1;
  • 首先将队列长度加一,并将种子点 (seed_row, seed_col) 加入队列。由于种子点已经被访问过,所以在访问标志矩阵 visited 中将其标记为 1。
while queue_len > 0
    current_pixel = queue(queue_len, :);
    queue_len = queue_len - 1;
    row = current_pixel(1);
    col = current_pixel(2);
  • 接下来进入 while 循环。只要队列不为空,就一直执行循环。每次循环从队尾取出一个元素,并将队列长度减一。这里的队列是先进先出(FIFO)的,因此每次取出的元素是距离种子点最远的像素。

  • 然后将取出的像素的行坐标和列坐标分别保存到 row 和 col 变量中。

    if (row > 1 && visited(row-1, col) == 0 && abs(I(row, col) - I(row-1, col)) <= thresh)
        queue_len = queue_len + 1;
        queue(queue_len, :) = [row-1, col];
        visited(row-1, col) = 1;
        J(row-1, col) = 1;
    end
    if (col > 1 && visited(row, col-1) == 0 && abs(I(row, col) - I(row, col-1)) <= thresh)
        queue_len = queue_len + 1;
        queue(queue_len, :) = [row, col-1];
        visited(row, col-1) = 1;
        J(row, col-1) = 1;
    end
    if (row < size(I,1) && visited(row+1, col) == 0 && abs(I(row, col) - I(row+1, col)) <= thresh)
        queue_len = queue_len + 1;
        queue(queue_len, :) = [row+1, col];
        visited(row+1, col) = 1;
        J(row+1, col) = 1;
    end
    if (col < size(I,2) && visited(row, col+1) == 0 && abs(I(row, col) - I(row, col+1)) <= thresh)
        queue_len = queue_len + 1;
        queue(queue_len, :) = [row, col+1];
        visited(row, col+1) = 1;
        J(row, col+1) = 1;
    end
  • 接下来对当前像素的四个相邻像素进行遍历。只有满足以下三个条件的像素才标记为同一区域内的像素:

    • 距离种子点的距离小于等于阈值 thresh;
    • 该像素未被访问过;
    • 当前像素与相邻像素的灰度值差不超过阈值 thresh。
  • 如果这些条件都满足,就将相邻像素的坐标加入队列,并在访问标志矩阵 visited 中标记为访问过;同时,在输出图像 J 中将其对应位置的像素标记为 1。

end
  • 最后结束 while 循环。
end
  • 最后结束函数的定义。
posted @ 2023-04-16 22:16  happyzew  阅读(213)  评论(0)    收藏  举报