技术标签: # MATLAB 笔记 matlab 路径还原 检测 图像分割 空心散点
问题描述:
有一张这样的图片,如何提取里面的红色圈圈坐标,并且连接这些坐标形成两个封闭的环路?
图像导入
oriPic=imread('test1.png');
subplot(2,2,1)
imshow(oriPic)
原理就是图中颜色种类比较少,只有红黑白,而红色和白色都是R通道数值较大,因此我们可以利用这一点进行图像分割
% 删除红色外的部分并构造二值图
grayPic=rgb2gray(oriPic);
grayPic(oriPic(:,:,1)<250)=255;
grayPic(grayPic<250)=0;
%subplot(2,2,2)
figure
imshow(grayPic)
对于白色来说是腐蚀,对于黑色来说是膨胀,这一步是为了让那些有缺口的小圆圈将缺口补起来
% 图像膨胀,使未连接边缘连接
SE=[0 1 0;1 1 1;0 1 0];
bwPic=imerode(grayPic,SE);
figure
imshow(bwPic)
就是把和边缘连接的不被黑色包围的区域变成黑色:
% 边缘清理:保留圆圈联通区域
bwPic=imclearborder(bwPic);
%subplot(2,2,3)
figure
imshow(bwPic)
现在每一个白点都是一个坐标区域,我们检测所有联通区域并计算各个区域的重心即可:
% 获取每一个联通区域
[LPic,labelNum]=bwlabel(bwPic);
% 计算每一个联通区域 坐标均值
pointSet=zeros(labelNum,2);
for i=1:labelNum
[X,Y]=find(LPic==i);
Xmean=mean(X);
Ymean=mean(Y);
pointSet(i,:)=[Xmean,Ymean];
end
% 画个图展示一下
%subplot(2,2,4)
figure
imshow(bwPic)
hold on
scatter(pointSet(:,2),pointSet(:,1),'r','LineWidth',1)
可以看出定位结果还是非常准确的:
就以一个点开始不断找最近的点呗,没啥好说的:
n=1;
while ~isempty(pointSet)
circleSetInd=1;
for j=1:length(pointSet)
disSet=sqrt(sum((pointSet-pointSet(circleSetInd(end),:)).^2,2));
[~,ind]=sort(disSet);
ind=ind(1:5);
[~,~,t_ind]=intersect(circleSetInd,ind);
ind(t_ind)=[];
if ~isempty(ind)
circleSetInd=[circleSetInd;ind(1)];
else
circleSet{
n}=pointSet(circleSetInd,:);
pointSet(circleSetInd,:)=[];
n=n+1;
break
end
end
end
figure
imshow(oriPic)
hold on
for i=1:n-1
plot(circleSet{
i}(:,2),circleSet{
i}(:,1),'LineWidth',2)
end
这效果就很美滋滋:
function redPnt
oriPic=imread('test1.png');
%subplot(2,2,1)
figure
imshow(oriPic)
% 删除红色外的部分并构造二值图
grayPic=rgb2gray(oriPic);
grayPic(oriPic(:,:,1)<250)=255;
grayPic(grayPic<250)=0;
%subplot(2,2,2)
figure
imshow(grayPic)
% 图像膨胀,使未连接边缘连接
SE=[0 1 0;1 1 1;0 1 0];
bwPic=imerode(grayPic,SE);
figure
imshow(bwPic)
% 边缘清理:保留圆圈联通区域
bwPic=imclearborder(bwPic);
%subplot(2,2,3)
figure
imshow(bwPic)
% 获取每一个联通区域
[LPic,labelNum]=bwlabel(bwPic);
% 计算每一个联通区域 坐标均值
pointSet=zeros(labelNum,2);
for i=1:labelNum
[X,Y]=find(LPic==i);
Xmean=mean(X);
Ymean=mean(Y);
pointSet(i,:)=[Xmean,Ymean];
end
%subplot(2,2,4)
figure
imshow(bwPic)
hold on
scatter(pointSet(:,2),pointSet(:,1),'r','LineWidth',1)
n=1;
while ~isempty(pointSet)
circleSetInd=1;
for j=1:length(pointSet)
disSet=sqrt(sum((pointSet-pointSet(circleSetInd(end),:)).^2,2));
[~,ind]=sort(disSet);
ind=ind(1:5);
[~,~,t_ind]=intersect(circleSetInd,ind);
ind(t_ind)=[];
if ~isempty(ind)
circleSetInd=[circleSetInd;ind(1)];
else
circleSet{
n}=pointSet(circleSetInd,:);
pointSet(circleSetInd,:)=[];
n=n+1;
break
end
end
end
figure
imshow(oriPic)
hold on
for i=1:n-1
plot(circleSet{
i}(:,2),circleSet{
i}(:,1),'LineWidth',2)
end
end
来波正方形试试:
可以看出效果还是很棒的,当然大家可以根据实际情况自行更改图像腐蚀模板形状,如果散点是其它颜色请自行更改第一步的图像分割条件。
后注:
若是因为点较为密集而导致圈形路径内部白色区域没被清除,可能会将内部区域也算作散点造成错误,解决方法是计算每个联通区域面积并剔除远远大于区域面积中位数的联通区域:
问题出现原因的图片描述:
如图所示种间那一大片区域也被算作散点
更改后代码如下:
function redPnt
oriPic=imread('test2.png');
figure
imshow(oriPic)
% 删除红色外的部分并构造二值图
grayPic=rgb2gray(oriPic);
grayPic(oriPic(:,:,1)<250)=255;
grayPic(grayPic<250)=0;
figure
imshow(grayPic)
% 图像膨胀,使未连接边缘连接
SE=[0 1 0;1 1 1;0 1 0];
bwPic=imerode(grayPic,SE);
figure
imshow(bwPic)
% 边缘清理:保留圆圈联通区域
bwPic=imclearborder(bwPic);
figure
imshow(bwPic)
% 获取每一个联通区域
[LPic,labelNum]=bwlabel(bwPic);
% 筛掉超大区域
pointSizeSet=zeros(1,labelNum);
for i=1:labelNum
pointSizeSet(i)=sum(sum(LPic==i));
end
[~,ind]=find(pointSizeSet>10*median(pointSizeSet));
% 计算每一个联通区域 坐标均值
pointSet=zeros(labelNum,2);
for i=1:labelNum
[X,Y]=find(LPic==i);
Xmean=mean(X);
Ymean=mean(Y);
pointSet(i,:)=[Xmean,Ymean];
end
pointSet(ind,:)=[];
figure
imshow(bwPic)
hold on
scatter(pointSet(:,2),pointSet(:,1),'r','LineWidth',1)
n=1;
while ~isempty(pointSet)
circleSetInd=1;
for j=1:length(pointSet)
disSet=sqrt(sum((pointSet-pointSet(circleSetInd(end),:)).^2,2));
[~,ind]=sort(disSet);
ind=ind(1:min(5,length(ind)));
[~,~,t_ind]=intersect(circleSetInd,ind);
ind(t_ind)=[];
if ~isempty(ind)
circleSetInd=[circleSetInd;ind(1)];
else
circleSet{
n}=pointSet(circleSetInd,:);
pointSet(circleSetInd,:)=[];
n=n+1;
break
end
end
end
figure
imshow(oriPic)
hold on
for i=1:n-1
plot(circleSet{
i}(:,2),circleSet{
i}(:,1),'LineWidth',2)
end
end
注:
2016版本及以前可能这句:
disSet=sqrt(sum((pointSet-pointSet(circleSetInd(end),:)).^2,2));
会出现数组大小不匹配问题,可以将其改为:
tempMat=repmat(pointSet(circleSetInd(end),:),[size(pointSet,1),1]);
disSet=sqrt(sum((pointSet-tempMat).^2,2));
main函数int main(int argc, char** argv){ ros::init(argc, argv, "lego_loam"); ROS_INFO("\033[1;32m---->\033[0m Feature Association Started."); FeatureAssociation FA;//调用构造函数进行初始化 ros::Rate rate(200); while (ros::ok()) { ros
数据不平衡问题在现实世界中非常普遍。对于真实数据,不同类别的数据量一般不会是理想的uniform分布,而往往会是不平衡的;如果按照不同类别数据出现的频率从高到低排序,就会发现数据分布出现一个“长尾巴”,也即我们所称的长尾效应。大型数据集经常表现出这样的长尾标签分布:为什么会存在不平衡的现象?其实很好理解,一个通用的解释就是特定类别的数据是很难收集的。拿Species分类来说(参考大型数据集iNaturalist[7]),特定种类(如猫,狗等)非常常见,但是有的种类(如高山兀鹫,随便举的例子...
递归形式的遍历都会有一个递归栈,因此对于非递归形式也可以使用一个栈来模拟递归栈来保存过程中的变量
为提交Bug页面设置bug必填字段by:授客 QQ:1033553122测试环境:禅道项目管理软件7.1.stable版本注:仅适合windows版步骤1、找到xampp\zentao\module\bug\view目录下的create.html.php步骤2、编辑该文件,设置必填项目。以设置所属项目为例子:找到填写框对对应的代码(根据代码里相关元素命名,一般不难识别出来,如下id值)找到输入框对...
不知道怎么描述,直接贴了代码了。有问题可以加Q群790537003讨论。先贴效果图: controller直接调用下面方法 就能直接下载pdf到本地了public static void invoicePdf(HttpServletResponse response, List&lt;Map&lt;String, Object&gt;&gt; data) { Document...
linux 最小化安装的问题,无法使用ssh连接其他电脑的解决方法:yum-y install openssh-clients
文件上传报错:cn.hutool.extra.ssh.JschRuntimeException: SftpException: Failure。原因:存储上传文件服务器的硬盘空间不足导致。解决办法:用工具看下自己的服务器空间是不是不足,清理下空间应该就可以了。解决过程:上午上传文件没发现问题,中午吃完饭就报上面的错误,很纳闷。我到服务器上查看文件是否上传成功,如图:...
按照坡面因子所描述的空间区域范围,可以将坡面因子划分为微观坡面因子与宏观坡面因子两种基本类型。常用的微观坡面因子主要有:坡度、坡向、坡长、坡度变率、坡向变率、平面曲率、剖面曲率等。常用的宏观坡面因子主要有:地形粗糙度、地形起伏度、高程变异系数、地表切割深度,以及宏观坡形因子(直线形斜坡、凸形斜坡、凹形斜坡、台阶形斜坡)等。按照提取坡面因子差分计算的阶数,...
tf.nn.softmax()与tf.nn.softmax_cross_entropy_with_logits
Pytorch是torch的Python版本,对TensorFlow造成很大的冲击,TensorFlow无疑是最流行的,但是Pytorch号称在诸多性能上要优于TensorFlow,比如在RNN的训练上,所以Pytorch也吸引了很多人的关注。之前有一篇关于TensorFlow实现的CNN可以用来做对比。下面我们就开始用Pytorch实现CNN。step 0 导入需要的包1 import t...
背景:生产上有台mysql服务器每天以定时任务方式用mysqldump命令进行数据库逻辑备份,定时任务执行时间为23:30,备份时长5分钟左右,生成的备份文件命名方式为‘mysql-$(date +%Y-%m-%d).sql’,大小3G左右,备份文件保留3份,即执行完mysqldump命令后对大前天备份文件进行删除操作。需求:对备份文件进行检查监控,若文件生产异常则触发告警。...