2018版MatLAB从背景单一、物体相对简单且相互分离的图片中求其照片中物体的最小外接圆圆心、半径,并画出最小外接圆
摘要: 该篇提供一个用于从背景单一、物体相对简单且相互分离的图片中(如下面两张图)获得图片中的物体最小外接圆的圆心与半径的matlab函数:
[PIC,center,radius]=m_minCircumferentialCircle(pic,background)
进而在其原图上通过所得圆心位置、圆半径对每个分离的物体利用画线函数画出最小外接圆。
注:具体实现方法见函数以及注释!
然后,这个函数是作者目前做图像作业时临时想到的求最小外接圆的办法,所以写了这样一个函数。所以函数考虑的不一定很全面,如果各位大佬有更好的可行办法,希望能交流交流…
1、函数测试效果
1)、测试代码:
// An highlighted block
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 函数测试代码: 图像处理
% 从图片相对简单、单一照片中获取其中物体最小外接圆,返回圆心、半径
% 1、调用自建函数:[PIC,center,radius] = m_minCircumferentialCircle(pic,background)
% 采用遍历查询确定最小外接圆半径。
% pic —— 原图(彩图/灰度图/二值图)
% background —— 原图背景色,0则为黑、1为白;
% 默认背景为白色,pic的二值图中物体为黑区
% minCnum —— 外接圆个数
% center —— 圆中心位置,数据格式为: [height1,width1]
% [height2,width2]
% radius —— 圆半径,数据格式为:[radius1]
% [radius2]
%
% 注:该函数没有边界检测,所画的圆可能超出原图大小。
% https://blog.csdn.net/BinHeon
% 2019/5/24
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
close all;
clear;
clc;
%%%% %%%% 读入图像,并显示
pic=imread('test2.jpg');
figure;
imshow(pic); title('原图(彩图以及灰度图二值图都可以)');
%%%% %%%% %%%% !!!调用函数计算最小外接圆圆心与半径,且默认图片背景为白;因为我测试图片背景为白色!
[minCnum,center,radius] = m_minCircumferentialCircle(pic);
%%%% %%%% %%%% 显示 pic,并在其上画出所有求得的最小外接圆
imshow(pic);
for i = 1:minCnum % 利用画线函数,画最小外接圆
%%%% 使用画线函数在pic图上 画圆
theta = 0:2*pi/3600:2*pi;
Circle1 = center(i,2) + radius(i)*cos(theta);
Circle2 = center(i,1) + radius(i)*sin(theta);% 构建圆
hold on;
plot(Circle1,Circle2,'m','Linewidth',1);% 画线
title('最小外接圆');
end
2)、处理效果:
2、函数代码部分
// An highlighted block
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 图像处理
% 从图片相对简单、单一照片中获取其中物体最小外接圆,返回圆心、半径
% 1、调用函数:[PIC,center,radius] = m_minCircumferentialCircle(pic,background)
% 采用遍历查询确定最小外接圆半径。
% pic —— 原图(彩图/灰度图/二值图)
% background —— 原图背景色,0则为黑、1为白;
% 默认背景为白色,pic的二值图中黑区表示的物体
% minCnum —— 外接圆个数
% center —— 圆中心位置,数据格式为: [height1,width1]
% [height2,width2]
% radius —— 圆半径,数据格式为:[radius1]
% [radius2]
% 注:该函数没有边界检测,所画的圆可能超出原图大小。
% 该函数的思想是:1)、对输入图片进行二值化;
% 2)、利用bwlabel()函数判断其二值图中的连通区域(这里前提是以每一个连通区域作为一个物体);
3)、对每个连通区域求其质心,以质心作为其最小外接圆的圆心;
4)、遍历各个像素点,分别计算每个物体的像素点是否在其物体当前的半径内;如果不在则用当前像素点与圆心的距离作为新的半径;从而类似迭代更新得到最小外接圆半径。
笔者采用的是2018a版的MatLAB,其中例如二值化函数可能与之前版本不一致
% https://blog.csdn.net/BinHeon
% 2019/5/24
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [minCnum,center,radius] = m_minCircumferentialCircle(pic,background)
%%%% %%%% %%%% %%%% 输入参数处理
if nargin < 2 % 如果只输入pic图片,默认背景为白
background = 1;
end
%%%% %%%% %%%% %%%% 处理图片
if (ndims(pic) == 3) % 获取输入图片维度,如果是三维图像需要获得其二值图
bw1 = rgb2gray(pic);
spic = imbinarize(bw1); % 2值化,之后的便是对二值图进行开闭运算
else
spic = imbinarize(pic); % 如果输入图片为灰度图,则直接二值化
end
figure;
imshow(spic);
%%%% %%%% %%%% %%% 获取二值图像中的连通区域
%%%% 注意:此bwlabel函数标注的是二值图中值为“1”的点,因而需要确定其二值图背景与物体
%%%% 如果背景为白色,则需要对二值图像取反操作。
if background
[L,num]=bwlabel(~spic,8); % 标注二值图中已连接的黑色(0),即背景为白,物体为黑
else
[L,num]=bwlabel(spic,8); % 标注二值图中已连接的白色(1),即背景为黑,物体为白
end
%%%% %%%% %%%% %%% 获取最小外接圆个数
minCnum = num;
%%%% %%%% %%%% %%%% 利用二值图获取物体质心位置
[height,width]=size(spic); % 获取图片大小
%%%% %%%% 初始化圆心
center=zeros(minCnum,2); % 用于记录质心位置的坐标
%%%% %%%% 计算每个物体中心
for cn = 1:minCnum
% 初始化参数
sum_x=0;sum_y=0;area=0;
for i=1:height
for j=1:width
if L(i,j) == cn
sum_x=sum_x+i;
sum_y=sum_y+j;
area=area+1;
end
end
end
%%质心坐标
center(cn,1) = fix(sum_x/area);
center(cn,2) = fix(sum_y/area);
end
%%%% %%%% %%%% %%%% 遍历每一个像素点求每个物体的半径
for rc = 1:minCnum
radius = zeros(minCnum,1);% 初始化一个minCnum*1的矩阵,用于存每个半径值
radius(:,1) = 2; % 每个最小外接圆,初始半径2个像素点
for i = 1:height % 遍历图片,查找物体像素点(二值化之后,物体像素点“0”)
for j = 1:width
if L(i,j) == rc % 物体像素点
elem = [i j]; % 该像素位置
distance = norm( elem - center(rc,:) ); % 该像素与质心距离(范数)
if distance > radius(rc,1)
radius(rc,1) = round(distance);
end
end
end
end
end