Matlab凭借GUI实现点云的中值滤波(附最简版)

news/2025/10/12 20:54:18/文章来源:https://www.cnblogs.com/slgkaifa/p/19137222

Matlab凭借GUI实现点云的中值滤波(附最简版)

        本次我们分享使用Matlab进行点云的中值滤波。中值滤波是一种非线性数字滤波技术,最早用于图像处理领域,后被成功应用于点云数据处理。在Matlab环境中,中值滤波通过选择每个点的邻域点集,对这些点的坐标值进行排序,然后用中值替代原始点的坐标,从而有效去除噪声点。

        与上一节的均值滤波相比,中值滤波在去除脉冲噪声的同时能够更好地保留点云的几何特征和边缘信息,特别适用于去除孤立的异常点(俗称"飞点")。

一、Matlab实现的主要流程

1. 数据准备与导入

% 读取点云数据
ptCloud = pcread('input_pointcloud.pcd');
% 或从矩阵创建点云
% xyzPoints = [x, y, z];
% ptCloud = pointCloud(xyzPoints);

2. 邻域搜索与构建
        Matlab提供了多种邻域搜索方法:
        - K近邻搜索:找到距离目标点最近的K个点
        - 半径搜索:找到指定半径范围内的所有点
        - 球体查询:定义球形邻域进行搜索

% K近邻搜索示例
k = 20; % 设置邻域大小
[indices, distances] = findNearestNeighbors(ptCloud, ptCloud.Location, k);

3. 中值滤波核心算法

function filteredCloud = medianFilterPointCloud(ptCloud, k)
    % 获取点的数量
    numPoints = ptCloud.Count;
    % 初始化输出点云
    filteredLocation = zeros(numPoints, 3);
    % 对每个点进行中值滤波
    for i = 1:numPoints
        % 找到当前点的k个最近邻
        [indices, ~] = findNearestNeighbors(ptCloud, ptCloud.Location(i,:), k);
        % 获取邻域点的坐标
        neighborPoints = ptCloud.Location(indices, :);
        % 对每个坐标维度分别计算中值
        filteredLocation(i, 1) = median(neighborPoints(:, 1));
        filteredLocation(i, 2) = median(neighborPoints(:, 2));
        filteredLocation(i, 3) = median(neighborPoints(:, 3));
    end
    % 创建滤波后的点云
    filteredCloud = pointCloud(filteredLocation);
end

4. 自适应中值滤波改进
为提高滤波效果,可采用自适应策略:

function filteredCloud = adaptiveMedianFilter(ptCloud, minK, maxK, threshold)
    numPoints = ptCloud.Count;
    filteredLocation = ptCloud.Location;
    for i = 1:numPoints
        currentK = minK;
        while currentK <= maxK
            % 获取当前邻域
            [indices, distances] = findNearestNeighbors(ptCloud, ptCloud.Location(i,:), currentK);
            % 计算邻域内点的坐标方差
            neighborPoints = ptCloud.Location(indices, :);
            variance = var(neighborPoints);
            % 如果方差小于阈值,应用滤波
            if max(variance) < threshold
                filteredLocation(i, :) = median(neighborPoints, 1);
                break;
            end
            currentK = currentK + 5; % 增加邻域大小
        end
    end
    filteredCloud = pointCloud(filteredLocation);
end

5. 性能优化策略
        - 并行计算:利用Matlab的并行计算工具箱
        - 空间索引:使用KD树或八叉树加速邻域搜索
        - GPU加速:对于大规模点云,考虑GPU并行处理

% 并行化处理示例
parfor i = 1:numPoints
    % 并行执行滤波操作
end

三、主要应用领域

1. 三维重建预处理
        在从多视角图像或激光扫描进行三维重建时,中值滤波能够有效去除由于传感器噪声、匹配错误等产生的异常点,提高重建模型的质量。

2. 自动驾驶与环境感知
        自动驾驶车辆获取的激光雷达点云数据常含有噪声,中值滤波可以:
        - 去除雨雪等天气造成的虚假点
        - 清理车辆运动产生的拖尾噪声
        - 提高障碍物检测的准确性

3. 工业检测与质量控制
        在工业产品表面检测中,中值滤波能够:
        - 去除扫描设备产生的系统噪声
        - 保留产品表面的真实几何特征
        - 为后续缺陷检测提供干净的输入数据

4. 建筑与文物保护
        对于建筑物或文物的三维扫描数据:
        - 去除由于反射、遮挡等造成的异常点
        - 保持建筑细节和文物特征
        - 为数字化保护提供高质量数据

5. 医疗影像处理
        在医学CT或MRI数据的三维重建中:
        - 去除图像重建过程中的伪影
        - 保持器官和组织的边界清晰度
        - 提高后续诊断和分析的准确性

四、优缺点分析

1. 优点:
        - 保持边缘:相比线性滤波,中值滤波能更好地保持点云的几何特征
        - 去除脉冲噪声:对孤立的异常点特别有效
        - 计算简单:算法实现相对简单,易于优化
        - 适应性强:可以根据点云特性调整参数

2. 缺点:
        - 计算量大:对每个点都需要进行邻域搜索和排序
        - 参数敏感:邻域大小选择不当可能导致过度平滑或滤波不足
        - 对高密度噪声效果有限:当噪声点密度较高时,效果会下降
        - 可能改变点密度:滤波后点云的分布特性可能发生变化

五、最佳实践建议

        1. 参数调优:根据点云密度和噪声特性选择合适的邻域大小
        2. 预处理配合:可与其他滤波方法(如统计滤波、半径滤波)结合使用
        3. 分块处理:对于大规模点云,采用分块处理提高效率
        4. 质量评估:使用点云质量评估指标验证滤波效果
        5. 保持备份:滤波前保存原始数据,便于对比和回退

        通过合理应用Matlab中的中值滤波技术,可以显著提升点云数据质量,为后续的三维建模、分析和应用奠定良好基础。

本次使用的数据是——————窗帘!

一、点云中值滤波的程序

1、最简版

%% 0. 清空环境
clear; clc; close all;
%% 1. 读入点云
[file, path] = uigetfile({'*.ply;*.pcd;*.xyz', '点云文件 (*.ply,*.pcd,*.xyz)'}, ...'请选择点云');
if file == 0; return; end
fname = fullfile(path, file);
ptCloud = pcread(fname);
N = ptCloud.Count;
fprintf('原始点云有 %d 个点\n', N);
%% 2. 中值滤波(半径 50 mm)
radius = 50;
cloudMedian = pcdMedianFilter(ptCloud, radius);
fprintf('中值滤波(半径=%d mm)后 %d 个点\n', radius, cloudMedian.Count);
%% 3. 可视化
figure('Name', '原始点云', 'NumberTitle', 'off');
pcshow(ptCloud); axis on; view(3);
figure('Name', '中值滤波', 'NumberTitle', 'off');
pcshow(cloudMedian); axis on; view(3);
function out = pcdMedianFilter(pc, radiusMm)
% 中值滤波(模仿 block-wise 风格)
% pc        : pointCloud 对象
% radiusMm  : 邻域半径,单位 mm
xyz = pc.Location;
radius = radiusMm;
n = size(xyz, 1);
newXYZ = zeros(n, 3, 'single');
kd = createns(xyz, 'NSMethod', 'kdtree');
block = 5000;                   % 按内存可调
for i = 1:block:nir = min(i + block - 1, n);idxCell = rangesearch(kd, xyz(i:ir, :), radius);for j = i:iridx = idxCell{j-i+1};newXYZ(j, :) = median(xyz(idx, :), 1);   % 中值坐标end
end
% 重建 pointCloud,保留颜色等信息
out = pointCloud(newXYZ, 'Color', pc.Color, ...'Normal', pc.Normal);
end

2、GUI版本

function medianFilterGUI
% 中值滤波 GUI —— 2020a 兼容
% 1. 浏览选点云  2. 邻域半径/mm 滑块  3. 实时中值滤波  4. 保存结果
fig = figure('Name','中值滤波工具','NumberTitle','off',...'MenuBar','none','ToolBar','none','Position',[100 100 1280 720]);
%% ---------- 左侧图像区(78 %) ----------
imgWidth = 0.78;
panelW   = imgWidth/2 - 0.01;
pnlOrig = uipanel('Parent',fig,'Units','normalized',...'FontSize',16,'Position',[0.02 0.02 panelW 0.96],'Title','原始点云');
pnlFilt = uipanel('Parent',fig,'Units','normalized',...'FontSize',16,'Position',[0.02+panelW+0.01 0.02 panelW 0.96],'Title','中值滤波');
axOrig = axes('Parent',pnlOrig,'Units','normalized','Position',[0.05 0.05 0.90 0.90]);
axFilt = axes('Parent',pnlFilt,'Units','normalized','Position',[0.05 0.05 0.90 0.90]);
%% ---------- 右侧控制区(22 %) ----------
pnlCtrl = uipanel('Parent',fig,'Units','normalized',...'FontSize',16,'Position',[0.78 0 0.22 1],'Title','控制');
txtH  = 0.04;
btnH  = 0.06;
gap   = 0.02;
yTop  = 0.94;
% 1. 浏览
uicontrol('Parent',pnlCtrl,'Style','pushbutton','String','浏览…',...'FontSize',16,'Units','normalized','Position',[0.05 yTop-btnH 0.90 btnH],...'Callback',@loadCloud);
yTop = yTop - btnH - gap;
lblInfo = uicontrol('Parent',pnlCtrl,'Style','text','String','未加载点云',...'FontSize',10,'Units','normalized','Position',[0.05 yTop-txtH 0.90 txtH],...'HorizontalAlignment','left');
yTop = yTop - txtH - gap;
% 2. radius/mm
uicontrol('Parent',pnlCtrl,'Style','text','String','邻域半径 / mm',...'FontSize',12,'FontWeight','bold','Units','normalized','Position',[0.05 yTop-txtH 0.90 txtH],...'HorizontalAlignment','left');
yTop = yTop - txtH - gap;
sliderR = uicontrol('Parent',pnlCtrl,'Style','slider','Min',1,'Max',100,'Value',50,...'FontSize',16,'Units','normalized','Position',[0.05 yTop-btnH 0.65 btnH],...'Callback',@refreshFilter);
txtR    = uicontrol('Parent',pnlCtrl,'Style','edit','String','50',...'FontSize',16,'Units','normalized','Position',[0.75 yTop-btnH 0.20 btnH],...'Callback',@editRCB);
yTop = yTop - btnH - gap;
% 3. 保存
uicontrol('Parent',pnlCtrl,'Style','pushbutton','String','保存滤波结果',...'FontSize',16,'Units','normalized','Position',[0.05 yTop-btnH 0.90 btnH],...'Callback',@(s,e)saveCloud(ptCloudFilt));
%% ---------- 数据 ----------
ptCloudOrig = pointCloud.empty;
ptCloudFilt = pointCloud.empty;%% ---------- 回调 ----------function loadCloud(~,~)[file,path] = uigetfile({'*.pcd;*.ply;*.xyz','点云文件'},'选择点云');if isequal(file,0), return; endtryptCloudOrig = pcread(fullfile(path,file));catch MEerrordlg(ME.message,'读取失败'); return;endshowPointCloud(axOrig,ptCloudOrig);N = ptCloudOrig.Count;set(lblInfo,'String',sprintf('已加载:%s  (%d 点)',file,N));refreshFilter();endfunction refreshFilter(~,~)if isempty(ptCloudOrig), return; endr = get(sliderR,'Value');ptCloudFilt = pcdMedianFilter(ptCloudOrig,r);showPointCloud(axFilt,ptCloudFilt);set(txtR,'String',num2str(r));endfunction editRCB(src,~)v = str2double(get(src,'String'));if isnan(v), v = 50; endv = max(1,min(100,v));set(sliderR,'Value',v);refreshFilter();endfunction saveCloud(cloud)if isempty(cloud)errordlg('请先完成中值滤波','提示'); return;end[file,path] = uiputfile({'*.pcd','PCD';'*.ply','PLY';'*.xyz','XYZ'},'保存滤波点云');if isequal(file,0), return; endtrypcwrite(cloud,fullfile(path,file),'Precision','double');msgbox('保存成功!','提示');catch MEerrordlg(ME.message,'保存失败');endendfunction showPointCloud(ax,pc)cla(ax); set(ax,'Color','w');pcshow(pointCloud(nan(0,3)),'Parent',ax);  % 2020a 暖启动pcshow(pc,'Parent',ax,'MarkerSize',35);axis(ax,'tight'); grid(ax,'on'); view(ax,3);end%% ---------- 中值滤波核心 ----------function out = pcdMedianFilter(pc,radiusMm)xyz  = pc.Location;n    = size(xyz,1);radius = radiusMm;kd = createns(xyz,'NSMethod','kdtree');block = 10000;                   % 批查询xyzMed = zeros(n,3,'like',xyz);for i = 1:block:nir = min(i+block-1,n);idxCell = rangesearch(kd, xyz(i:ir,:), radius);for k = i:iridx = idxCell{k-i+1};if numel(idx)>0xyzMed(k,:) = median(xyz(idx,:),1);  % 逐维中值elsexyzMed(k,:) = xyz(k,:);              % 无邻域保持原值endendendout = pointCloud(xyzMed, ...'Color', pc.Color, ...'Normal', pc.Normal);end
end

二、点云中值滤波的结果

        可以看到,随着滑块的变化,窗帘被动态滤波了。感兴趣的童鞋可以试着调一调别的点云呀,绝知此事要躬行!

就酱,下次见^-^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/935683.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CF数据结构题做题记录-1

CF3000的数据结构题做题记录-1 CF464E. The Classic Problem 肯定还是跑最短路,假设比较的复杂度是 \(O(\alpha)\),相加的复杂度是 \(O(\beta)\),那么我们直接使用 dijkstra 的复杂度是 \(O(\alpha(n+m)\log n+\bet…

完整教程:安宝特产品丨FME Realize:重构数据与现实的边界,让空间计算赋能现场决策

完整教程:安宝特产品丨FME Realize:重构数据与现实的边界,让空间计算赋能现场决策pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; f…

尝试对音频功率放大器芯片的噪声基底特性进行测量与计算:以纳芯威NS4268为例

前言 最近我有一个项目需要用到带音量控制功能的耳机音频功率放大器芯片。在群友的推荐下,我选择了NS4268,但测试后发现它的噪声性能较差。于是,我制作了测试PCB,对其噪声特性进行简单测量。 测试PCB 测试使用的PC…

常见问题解决 --- wireshark安装失败

常见问题解决 --- wireshark安装失败Wireshark 4.2 是官方支持 Windows 10 的最后一个发布分支。 Wireshark 4.0 是官方支持 Windows 8.1 和 Windows Server 2012 的最后一个发布分支。 Wireshark 3.6 是官方支持 32 位…

Node.js 性能优化:实用技巧与实战指南 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

3.1 策略梯度方法(Policy Gradient Methods)

策略梯度方法(Policy Gradient Methods)背景 在基于值函数的方法(如 DQN)中,直接逼近 Q 值存在多种问题:Q 值无界:可能取任意实数(正或负),输出层必须是线性的; Q 值方差大:不同 \((s,a)\) 对的 Q 值差异巨…

perl语言中的三目运算符和do代码块

我有这么一个需求,根据学生考试成绩进行ABC划分,比如80分以上为A,60-80分为B,60分一下为C 我们能够相当的最简单的方式就是通过if判断并赋值的方式实现,如下代码: $ perl -E my $a; my $b=67; if($b > 80){$…

ll

llimport numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split, KFold, cross_val_score from sklearn.linear_model imp…

CCPC2023女生专场 游记(VP)

整体进步明显,女生赛再砍一金,我们走在正确的道路上。省流 整体进步明显,女生赛再砍一金,我们走在正确的道路上。 在解决掉 \(vivid\_stareium\) 这个问题之后,\(ZWU\) 进入了 \(jianfeijian\) 和 \(yrjzs\) 的时…

tp3.2不再生成Runtime/Logs日志

<?php// +----------------------------------------------------------------------// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]// +----------------------------------------------------------------------…

2.5 分布式学习(Distributed Learning)

分布式学习(Distributed Learning)分布式 DQN(GORILA) 深度强化学习的主要瓶颈是学习速度慢,主要由以下两点决定:样本复杂度(sample complexity):获得令人满意的策略所需的状态转移数量; 在线交互限制(onli…

心得:刷算法的痛点-只根据题目的case思考,不考虑边界情况,写出一坨shit

977. 有序数组的平方 不停地根据错误用例给代码打补丁,最后还是会有新的错误用例,永远补不好。 下面展示一下耗时1小时产出的💩 class Solution {public int[] sortedSquares(int[] nums) {// 统计nums数组中非正数…

11-Redis 集合类型深度指南:从去重特性到集合运算场景落地 - 详解

11-Redis 集合类型深度指南:从去重特性到集合运算场景落地 - 详解2025-10-12 20:28 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !i…

OI 数论 1

部分摘自OiWikigcd 与 ex_gcd 的 C++ 实现 1. 最大公约数(GCD) 1.1 定义 最大公约数(Greatest Common Divisor)指两个或多个整数共有约数中最大的一个,记为 gcd(a, b)。对于非负整数 a 和 b,gcd(a, b) 是能同时整…

2.4 DQN 变体(Rainbow)

DQN 变体(Rainbow)双重 DQN(Double DQN) 在原始 DQN 中,经验回放与目标网络的引入使得 CNN 能够在强化学习中成功训练,但也带来了两个缺点:学习速度显著降低,样本复杂度增高; 稳定性较差,不同运行结果可能不…

Linux存储媒介devmount

Linux 存储媒介dev mount 挂载和卸载存储设备 管理存储设备的第一步是把设备连接到文件系统树中。这个叫做”挂载” 有一个叫做/etc/fstab 的文件可以列出系统启动时要挂载的设备。大多数文件系统是虚拟的,还有实际存…

单片机--概述 - 指南

单片机--概述 - 指南2025-10-12 20:18 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-f…

Emacs折腾日记(三十二)——org mode的基本美化

在上一篇,已经介绍了org mode的基础知识,它与markdown非常相似,并且也十分容易上手,但是它的可扩展性比markdown要强很多。如果将来打算重度使用org mode,那么此时可以对它进行一些基本的配置和美化 基本配置 org…

pp

ppimport numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split, KFold, cross_val_score from sklearn.linear_model imp…

2025 工业风机十大品牌全景解析报告:覆盖离心风机,防爆风机,矿用风机的最新推荐

本报告基于 2025 年行业权威数据,结合中国玻璃钢协会、美国国际空气运动及控制协会(AMCA)等机构的测评结果,从技术创新、性能表现、市场布局三大维度,对工业风机十大品牌进行全景解析,为企业选购适配冶金、石化、…