图像处理自适应阈值分割算法(otsu)sobel边沿检测算法demo工程 包含matlab代码

直接打开Matlab新建脚本,咱们先整点硬核的。今天要搞的是图像阈值分割和边缘检测的联合作战方案——Otsu+sobel组合拳,先看效果:把一张灰度图自动分割出主体轮廓,再用边缘检测强化细节。别慌,代码都是能直接跑通的。

先上Otsu阈值分割的核心代码:

% Otsu自动阈值实现
function threshold = my_otsu(img)
hist = imhist(img); % 直方图统计
total = sum(hist);
max_var = 0;
for t=1:256
    w0 = sum(hist(1:t))/total;
    w1 = 1 - w0;
    mu0 = sum((0:t-1).*hist(1:t)')/(w0*total);
    mu1 = sum((t:255).*hist(t+1:end)')/(w1*total);
    class_var = w0*w1*(mu1 - mu0)^2;
    if class_var > max_var
        max_var = class_var;
        threshold = t-1; % Matlab索引从1开始
    end
end
end

这算法最骚的地方在于自动找类间方差最大的阈值。咱们遍历0-255每个灰度值,计算前后景的权重和均值,用概率统计玩转图像分割。注意那个(mu1 - mu0)^2才是关键,本质上是在找前景和背景差异最大的临界点。

图像处理自适应阈值分割算法(otsu)sobel边沿检测算法demo工程 包含matlab代码

接下来是Sobel边缘检测的暴力实现:

% Sobel算子手动实现
function edge_img = my_sobel(img)
kernel_x = [-1 0 1; -2 0 2; -1 0 1]; % 水平方向
kernel_y = [-1 -2 -1; 0 0 0; 1 2 1]; % 垂直方向

% 卷积操作
gx = imfilter(double(img), kernel_x, 'replicate');
gy = imfilter(double(img), kernel_y, 'replicate');
edge_strength = sqrt(gx.^2 + gy.^2); % 梯度幅值
edge_img = uint8(255 * edge_strength / max(edge_strength(:))); % 归一化
end

这里有个坑要注意:imfilter默认用相关运算而不是卷积,所以实际使用时要核对核的方向。咱们用'replicate'处理边界比补零更接近实际场景。梯度计算用平方和开根号比绝对值之和更准确,但计算量稍大。

把这两个算法组合起来用才是精髓:

% 主程序
img = imread('lena.jpg');
gray = rgb2gray(img); % 转灰度图

% Otsu分割
thresh = my_otsu(gray);
binary = gray > thresh; 

% Sobel检测
edge_img = my_sobel(binary.*255); 

% 显示结果
subplot(1,3,1); imshow(gray); title('原图');
subplot(1,3,2); imshow(binary); title('Otsu分割');
subplot(1,3,3); imshow(edge_img); title('边缘增强');

这里有个骚操作:二值图乘以255再进Sobel,避免二值图像素只有0和1导致梯度计算失效。实际运行会发现,先做阈值分割能有效减少噪声对边缘检测的干扰,比直接检测原图效果更干净。

遇到效果不理想时,可以在Sobel后面加个阈值过滤:

edge_binary = edge_img > 50; % 根据实际情况调整
imshow(edge_binary);

这时候边缘会变得更锐利,但可能丢失细节。建议用自适应阈值处理,不过那就是另一个故事了。整个工程跑下来,Matlab版本的Otsu比Python版快3倍左右,矩阵运算果然不是盖的。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐