数字图像处理:hough变换与区域分割

1,735 阅读7分钟

1.hough变换检测线

设计思路

使用Hough变换检测直线的目的是在图像中找到直线的位置和方向。首先,将原始图像转换为灰度图像,并进行边缘检测以提取直线的信息。然后,利用Hough变换在参数空间中累积直线的信息,通过寻找峰值点来确定直线的位置和方向。最后,在原始图像和Hough变换空间中绘制检测到的直线和峰值点。

实现方法

首先,使用imread函数读取原始图像,并将其转换为灰度图像。然后,利用边缘检测算法(这里使用的是Canny边缘检测)对灰度图像进行处理,得到二值化的边缘图像。接下来,利用Hough变换函数hough()计算二值化边缘图像中直线的参数空间。使用houghpeaks()函数找到参数空间中的峰值点。然后,利用houghlines()函数在原始图像上绘制检测到的直线。最后,将Hough变换空间进行可视化,标记出峰值点。

Matlab代码

% 1. 读取图像并进行预处理
originalImage = imread('daolu.jpg');
grayImage = rgb2gray(originalImage);
binaryImage = edge(grayImage, 'canny');

% 2. 使用Hough变换检测直线
[H, theta, rho] = hough(binaryImage);
peaks = houghpeaks(H, 2); % 设置峰值点数量

% 3. 在原始图像上绘制检测出的线
figure;
imshow(originalImage);
hold on;
lines = houghlines(binaryImage, theta, rho, peaks);
for k = 1:length(lines)
   xy = [lines(k).point1; lines(k).point2];
   plot(xy(:,1), xy(:,2), 'LineWidth', 2, 'Color', 'r');
end
hold off;

% 4. 在Hough变换空间中标记峰值点
figure;
imshow(imadjust(rescale(H)), 'XData', theta, 'YData', rho, 'InitialMagnification', 'fit');
xlabel('\theta (degrees)');
ylabel('\rho');
axis on;
axis normal;
hold on;
plot(theta(peaks(:,2)), rho(peaks(:,1)), 's', 'color', 'white');
hold off;

效果

image.png

2.hough变换检测圆

设计思路

利用Hough变换检测圆的目的是在图像中找到圆的位置和半径。首先,将原始图像转换为灰度图像,并进行边缘检测以提取圆的信息。然后,利用Hough变换在参数空间中累积圆的信息,通过寻找峰值点来确定圆的位置和半径。最后,在原始图像上绘制检测到的圆。

实现方法

首先,使用imread函数读取原始图像,并将其转换为灰度图像。然后,利用边缘检测算法(这里使用的是Canny边缘检测)对灰度图像进行处理,得到二值化的边缘图像。接下来,利用imfindcircles函数在二值化边缘图像中检测圆,设定圆的半径范围。然后,将检测到的圆在原始图像上进行可视化,使用viscircles函数绘制圆。

Matlab代码

% 1. 读取图像并进行预处理
originalImage = imread('qiu.jpg');
grayImage = rgb2gray(originalImage);
binaryImage = edge(grayImage, 'canny');

% 2. 使用Hough变换检测圆
[centers, radii, metric] = imfindcircles(binaryImage, [25 100]); % 设定半径范围

% 3. 在原始图像上绘制检测出的圆
figure;
imshow(originalImage);
hold on;
viscircles(centers, radii, 'EdgeColor', 'b');
hold off;

效果

image.png

3.区域分割(最优阈值分割)

设计思路

区域分割的目的是根据图像的灰度特性将其分为不同的区域或对象。采用最优阈值分割方法,通过计算图像的灰度直方图和累积分布函数,寻找使类间方差最大的阈值,将图像分割成两个区域,其中一个区域包含目标对象,另一个区域为背景。最后,使用找到的最优阈值对图像进行分割。

实现方法

首先,将原始图像转换为灰度图像,并计算其灰度直方图和累积分布函数。然后,通过遍历所有可能的阈值,计算每个阈值对应的类间方差,并找到使类间方差最大的阈值作为最优阈值。接下来,使用最优阈值将灰度图像分割成两个区域,其中大于阈值的像素点属于目标对象,小于阈值的像素点属于背景。最后,可视化原始图像、分割图像和直方图,并在直方图中标记出最优阈值对应的分界线。

Matlab代码

% 读取图像
image = imread('yingbi.jpg');

% 将图像转换为灰度图像
gray_image = rgb2gray(image);

% 计算灰度直方图
histogram = imhist(gray_image);

% 计算累积分布函数
cdf = cumsum(histogram) / numel(gray_image);

% 初始化变量
num_bins = 256;
optimal_threshold = 0;
max_variance = 0;

% 寻找最优阈值
for t = 1:num_bins
    % 计算类间方差
    class1_prob = cdf(t);
    class2_prob = 1 - class1_prob;
    class1_mean = sum((0:t-1)'.*histogram(1:t)) / sum(histogram(1:t));
    class2_mean = sum((t:num_bins-1)'.*histogram(t+1:end)) / sum(histogram(t+1:end));
    between_class_variance = class1_prob * class2_prob * (class1_mean - class2_mean)^2;
    
    % 更新最大方差和最优阈值
    if between_class_variance > max_variance
        max_variance = between_class_variance;
        optimal_threshold = t - 1;
    end
end

% 使用最优阈值进行分割
segmented_image = gray_image > optimal_threshold;

% 显示原始图像、分割图像和直方图
figure;
subplot(2, 2, 1);
imshow(gray_image);
title('Original Image');

subplot(2, 2, 2);
imshow(segmented_image);
title('Segmented Image');

subplot(2, 2, 3);
bar(histogram);
title('Histogram');

% 在直方图空间展示分界线
hold on;
line([optimal_threshold, optimal_threshold], [0, max(histogram)], 'Color', 'r', 'LineWidth', 2);
hold off;

效果

image.png

4.区域分割(分块)

设计思路

采用分块的方法进行区域分割,目的是将图像分成多个均匀的子块,然后对每个子块独立进行阈值分割。首先,将图像划分成固定大小的块,并计算每个块的灰度直方图和累积分布函数。然后,在每个块中寻找使类间方差最大的阈值,作为该块的最优阈值。最后,根据每个块的最优阈值将相应的像素分割成目标对象和背景,从而完成整个图像的区域分割。

实现方法

首先,将原始图像转换为灰度图像,并定义分块大小。然后,将图像分成块,并在每个块中计算灰度直方图和累积分布函数。接下来,在每个块中寻找使类间方差最大的阈值,并存储在阈值矩阵中。最后,根据每个块的最优阈值对图像进行分割,并将分割结果拼接成整个图像的分割图像。可视化原始图像、分割图像和直方图,并在直方图中展示每个块的阈值分界线。

Matlab代码

% 读取图像
image = imread('yingbi.jpg');

% 将图像转换为灰度图像
gray_image = rgb2gray(image);

% 定义分块大小
block_size = 64;

% 获取图像大小
[rows, cols] = size(gray_image);

% 初始化变量
num_rows = floor(rows / block_size);
num_cols = floor(cols / block_size);
thresholds = zeros(num_rows, num_cols);

% 对每个分块进行分割
for i = 1:block_size:rows
    for j = 1:block_size:cols
        % 获取当前分块
        block = gray_image(i:min(i+block_size-1, rows), j:min(j+block_size-1, cols));
        
        % 计算当前分块的灰度直方图
        histogram = imhist(block);
        
        % 计算累积分布函数
        cdf = cumsum(histogram) / numel(block);
        
        % 寻找最优阈值
        optimal_threshold = 0;
        max_variance = 0;
        for t = 1:num_bins
            % 计算类间方差
            class1_prob = cdf(t);
            class2_prob = 1 - class1_prob;
            class1_mean = sum((0:t-1)'.*histogram(1:t)) / sum(histogram(1:t));
            class2_mean = sum((t:num_bins-1)'.*histogram(t+1:end)) / sum(histogram(t+1:end));
            between_class_variance = class1_prob * class2_prob * (class1_mean - class2_mean)^2;
            
            % 更新最大方差和最优阈值
            if between_class_variance > max_variance
                max_variance = between_class_variance;
                optimal_threshold = t - 1;
            end
        end
        
        % 存储最优阈值
        thresholds((i-1)/block_size+1, (j-1)/block_size+1) = optimal_threshold;
    end
end

% 生成分割图像
segmented_image = zeros(rows, cols);
for i = 1:block_size:rows
    for j = 1:block_size:cols
        threshold = thresholds((i-1)/block_size+1, (j-1)/block_size+1);
        segmented_image(i:min(i+block_size-1, rows), j:min(j+block_size-1, cols)) = gray_image(i:min(i+block_size-1, rows), j:min(j+block_size-1, cols)) > threshold;
    end
end

% 显示原始图像、分割图像和直方图
figure;
subplot(2, 2, 1);
imshow(gray_image);
title('Original Image');

subplot(2, 2, 2);
imshow(segmented_image);
title('Segmented Image');

subplot(2, 2, 3);
bar(imhist(gray_image));
title('Histogram');

% 在直方图空间展示分界线
hold on;
for i = 1:block_size:rows
    for j = 1:block_size:cols
        threshold = thresholds((i-1)/block_size+1, (j-1)/block_size+1);
        line([threshold, threshold], [0, max(imhist(gray_image))], 'Color', 'r', 'LineWidth', 0.5);
    end
end
hold off;

效果

image.png