MATLAB中物体夹角的检测

前言

实验中经常需要测量一个物体的角度变化,如果开发一个图像处理的方法可以大大节省我们的时间,这次我们使用霍夫变换等进行物体夹角的预测。

任务

图像如下图所示
在这里插入图片描述
我们需要检测的夹角示意图为:
在这里插入图片描述
因此整个任务可以分解成两个子任务:

  1. 检测红边的直线
  2. 检测绿边的直线
    之后通过两条直线的k就可以算出夹角,由于实验中红边的位置几乎固定,根据绿边k的符号就可以判断夹角是锐角还是钝角。

检测红边

很明显,红边所在的位置即为交界处,可以使用边缘检测算子,但是实际的环境很难排除噪声,因此我们这里使用基于颜色的聚类方式首先将各个部分分割出来,代码为:

 img = imread('test.jpg');
 %% kmeans 
 %通过聚类及边界提取首先获取垂直线的坐标
 numOfClass = 5;
 mask = kmeansS(double(img),numOfClass);

代码中KmeanS会放在下面,这里对MATLAB内置的kmeans函数进行了一个简单的封装,得到的结果为:
在这里插入图片描述
这条边界现在看起来十分清晰,但是由于这种基于颜色的聚类并未考虑到空间信息,其他的图像中会存在一个大区域的一种标签内含一个小区域的现象,因此我们可以直接使用填充空洞对结果进行一个小小的改进:

 %填充空洞
 for kkk= 1:numOfClass
      maskt = mask==kkk;
      maskt = imfill(maskt,'holes');
      mask(maskt) = kkk;
  end

改进之后可以直接使用log算子提取边界,这里不要使用canny算子,因为它会使直线变得弯曲:

 mask_edge =  imfilter(mask,fspecial( 'log'));
 mask_edge = mask_edge>0;

下面,我们可以直接把左下角的部分直接摘出来使用霍夫变换检测直线:

mask_edge_ld = false(size(mask_edge));
[M,N] = size(mask_edge);
%提取左下角的部分拟合直线
mask_edge_ld(end-floor(M/3):end,end-floor(N/3):end) =  mask_edge(end-floor(M/3):end,end-floor(N/3):end);

[H,T,R] = hough(mask_edge_ld,'RhoResolution',0.5,'Theta',-90:0.5:89);
P  = houghpeaks(H,5,'threshold',ceil(0.3*max(H(:))));
lines = houghlines(mask_edge_ld,T,R,P,'FillGap',5,'MinLength',15);
max_len = 0;

for k = 1:length(lines)
   xy = [lines(k).point1; lines(k).point2];
   % Determine the endpoints of the longest line segment
   len = norm(lines(k).point1 - lines(k).point2);
   if ( len > max_len)
      max_len = len;
      xy_long = xy;
   end
end

上面这一节代码中我们把最长的直线选择了出来,绘制出来的直线示意图为:
在这里插入图片描述
虽然只有那么一小截,但这个也足够了,接着我们就开始处理弯曲的物体了,右下部分不需要了,我们裁出来即可:

 %直接选取最长的直线作为参考,此节处理完毕,下面开展另外一条边
if xy_long(1,1) == xy_long(2,1)%垂直线
    xy_points = zeros(min([xy_long(1,2),xy_long(2,2)]),2);
    xy_points(1:end,2) = min([xy_long(1,2),xy_long(2,2)]):-1:1;
    xy_points(1:end,1) = xy_long(1,1);
else%非垂直线
    %在这里有个技巧,需要将x,y的坐标轴转换一下
    funct = polyfit([xy_long(1,2),xy_long(2,2)],[xy_long(1,1),xy_long(2,1)],1);
    xy_points = zeros(min([xy_long(1,2),xy_long(2,2)]),2);
    xy_points(1:end,2) = min([xy_long(1,2),xy_long(2,2)]):-1:1;
    xy_points(1:end,1) = polyval(funct, xy_points(1:end,2));
end
%从直线的顶点开始一直往上搜寻,根据边缘数量判断中心点
xy_points = floor(xy_points);
if xy_long(1,2)<xy_long(2,2)
    newM = xy_long(1,2);
    newN = xy_long(1,1);
else
    newM = xy_long(2,2);
    newN = xy_long(2,1);
end
new_img= img(1:newM,1:newN,:);

这一节包括两部分,第一部分是计算红边在图像中的所有位置,代码中自变量设置成了纵坐标,因变量设置成了横纵标,相当于进行了一下变换。截取后的图像为:
在这里插入图片描述
显然干净了很多,也没有其余部分影响,下面我们使用图像中的色调对图像进行二值化把这个弯曲的物体先分割出来:

hsv = rgb2hsv(new_img);
second_mask =  imbinarize(hsv(:,:,1));
second_mask_edge = imfilter(second_mask,fspecial('sobel'));
CC = bwconncomp(second_mask_edge);
stats = regionprops(CC,'MajorAxisLength');
mls = cat(1,stats.MajorAxisLength);
for k = 1:CC.NumObjects
    if mls(k) <8
        second_mask_edge(CC.PixelIdxList{k}) = 0;
    end
end

分割出来之后使用sobel算子提取边界,之后根据二值化组分中的主轴长度排除存在的噪声点,之后从图像的右侧到左侧选取8个点拟合直线:

 %选取8个点
 pointst=  zeros(8,2);
 count = 1;
 for k = size(second_mask,2):-1:1
      if sum(second_mask_edge(:,k)) <10 && sum(second_mask_edge(:,k)) >1
          ind = find(second_mask_edge(:,k));
          pointst(count,1) = k;
          pointst(count,2) = ind(1);
          count = count +1;
          if count>8
              break;
          end
      end
  end

直线拟合之后使用https://zhidao.baidu.com/question/1731029675143733347.html的公式即可计算夹角:

 funct2 = polyfit(pointst(:,2),pointst(:,1),1);
 if numel(unique(xy_points(:,1))) == 1
     angle =atan(abs(funct2(1)))*180/pi;
 else
     angle =atan(abs((funct(1)-funct2(1))./(1+funct(1).*funct2(1))))*180/pi;
 end
 if funct2(1)>0
     angle  = 180- angle;
 end

在这里插入图片描述
刚开始计算出来的夹角为锐角,根据实际情况即可重新调整。

有疑问欢迎评论交流~

  • 11
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值