广告位联系
返回顶部
分享到

基于Matlab的空心散点检测介绍

C语言 来源:互联网 作者:秩名 发布时间:2022-02-28 14:26:24 人浏览
摘要

问题描述 有一张这样的图片,如何提取里面的红色圈圈坐标,并且连接这些坐标形成两个封闭的环路? 过程展示 图像导入 1 2 3 4 oriPic=imread(test1.png); subplot(2,2,1) imshow(oriPic) 依据RGB值图

问题描述

有一张这样的图片,如何提取里面的红色圈圈坐标,并且连接这些坐标形成两个封闭的环路?

过程展示

图像导入

1

2

3

4

oriPic=imread('test1.png');

 

subplot(2,2,1)

imshow(oriPic)

依据RGB值图像二值化

原理就是图中颜色种类比较少,只有红黑白,而红色和白色都是R通道数值较大,因此我们可以利用这一点进行图像分割

1

2

3

4

5

6

7

8

% 删除红色外的部分并构造二值图

grayPic=rgb2gray(oriPic);

grayPic(oriPic(:,:,1)<250)=255;

grayPic(grayPic<250)=0;

 

%subplot(2,2,2)

figure

imshow(grayPic)

图像腐蚀

对于白色来说是腐蚀,对于黑色来说是膨胀,这一步是为了让那些有缺口的小圆圈将缺口补起来

1

2

3

4

5

6

% 图像膨胀,使未连接边缘连接

SE=[0 1 0;1 1 1;0 1 0];

bwPic=imerode(grayPic,SE);

 

figure

imshow(bwPic)

图像边缘清理

就是把和边缘连接的不被黑色包围的区域变成黑色:

1

2

3

4

5

% 边缘清理:保留圆圈联通区域

bwPic=imclearborder(bwPic);

%subplot(2,2,3)

figure

imshow(bwPic)

联通区域查找与坐标均值计算

现在每一个白点都是一个坐标区域,我们检测所有联通区域并计算各个区域的重心即可:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

% 获取每一个联通区域

[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)

可以看出定位结果还是非常准确的:

圈查找

就以一个点开始不断找最近的点呗,没啥好说的:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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

这效果就很美滋滋:

完整代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

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

其它形状空心散点检测

来波正方形试试:

可以看出效果还是很棒的,当然大家可以根据实际情况自行更改图像腐蚀模板形状,如果散点是其它颜色请自行更改第一步的图像分割条件。

后注:

若是因为点较为密集而导致圈形路径内部白色区域没被清除,可能会将内部区域也算作散点造成错误,解决方法是计算每个联通区域面积并剔除远远大于区域面积中位数的联通区域:

问题出现原因的图片描述:

如图所示种间那一大片区域也被算作散点

更改后代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

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版本及以前可能这句:

1

disSet=sqrt(sum((pointSet-pointSet(circleSetInd(end),:)).^2,2));

会出现数组大小不匹配问题,可以将其改为:

1

2

tempMat=repmat(pointSet(circleSetInd(end),:),[size(pointSet,1),1]);

disSet=sqrt(sum((pointSet-tempMat).^2,2));


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/slandarer/article/details/120025954
相关文章
  • C++中类的六大默认成员函数的介绍

    C++中类的六大默认成员函数的介绍
    一、类的默认成员函数 二、构造函数Date(形参列表) 构造函数主要完成初始化对象,相当于C语言阶段写的Init函数。 默认构造函数:无参的构
  • C/C++实现遍历文件夹最全方法总结介绍

    C/C++实现遍历文件夹最全方法总结介绍
    一、filesystem(推荐) 在c++17中,引入了文件系统,使用起来非常方便 在VS中,可以直接在项目属性中调整: 只要是C++17即以上都可 然后头文件
  • C语言实现手写Map(数组+链表+红黑树)的代码

    C语言实现手写Map(数组+链表+红黑树)的代码
    要求 需要准备数组集合(List) 数据结构 需要准备单向链表(Linked) 数据结构 需要准备红黑树(Rbtree)数据结构 需要准备红黑树和链表适配策略
  • MySQL系列教程之使用C语言来连接数据库

    MySQL系列教程之使用C语言来连接数据库
    写在前面 知道了 Java中使用 JDBC编程 来连接数据库了,但是使用 C语言 来连接数据库却总是连接不上去~ 立即安排一波使用 C语言连接 MySQL数
  • 基于C语言实现简单学生成绩管理系统

    基于C语言实现简单学生成绩管理系统
    一、系统主要功能 1、密码登录 2、输入数据 3、查询成绩 4、修改成绩 5、输出所有学生成绩 6、退出系统 二、代码实现 1 2 3 4 5 6 7 8 9 10 11
  • C语言实现共享单车管理系统

    C语言实现共享单车管理系统
    1.功能模块图; 2.各个模块详细的功能描述。 1.登陆:登陆分为用户登陆,管理员登陆以及维修员登录,登陆后不同的用户所执行的操作
  • C++继承与菱形继承的介绍

    C++继承与菱形继承的介绍
    继承的概念和定义 继承机制是面向对象程序设计的一种实现代码复用的重要手段,它允许程序员在保持原有类特性的基础上进行拓展,增加
  • C/C++指针介绍与使用介绍

    C/C++指针介绍与使用介绍
    什么是指针 C/C++语言拥有在程序运行时获得变量的地址和操作地址的能力,这种用来操作地址的特殊类型变量被称作指针。 翻译翻译什么
  • C++进程的创建和进程ID标识介绍
    进程的ID 进程的ID,可称为PID。它是进程的唯一标识,类似于我们的身份证号是唯一标识,因为名字可能会和其他人相同,生日可能会与其他
  • C++分析如何用虚析构与纯虚析构处理内存泄漏

    C++分析如何用虚析构与纯虚析构处理内存泄漏
    一、问题引入 使用多态时,如果有一些子类的成员开辟在堆区,那么在父类执行完毕释放后,没有办法去释放子类的内存,这样会导致内存
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计