辐角原理判断点和多边形的关系


\qquad 标题写的多边形,然而在现实情况中多边形只是该问题的一个子集;我们先讲点和连通域的关系,点和多边形的关系自然就包含在其中了。
\qquad 工作中碰到的这个问题的时候第一时间就想到了辐角原理:没有误差(除了边界点,问题直接就是连续的),实现简单(边界条件比其他算法少)。

一、辐角原理

二、适用条件

\qquad 能想到的复杂形状都能判别,多个连通域、连通域嵌套也可以判别。
\qquad 有时间再写,先把代码贴出来😍。

三、算法效果

实验图像:
在这里插入图片描述
实验结果:
在这里插入图片描述
在这里插入图片描述

四、matlab代码实现

\qquad 程序编写会比较简单,但是会用到图像边界的计算的程序;简单写写吧,这个代码对于单连通域是没有问题的,有兴趣的话可以稍微尝试修改,然后就可以得到对于多连域的程序了

%% 辐角原理的在 164 行
clear
close all
clc;
%% 算适用于连通区域为0的区域
%预处理阶段
a = imread('white10.bmp');
a(a<125) = 0;
a(a>=125) = 255;

%处理原图像使之符合要求
a = 255-a;
a = double(a);
b1 = zeros(size(a));
se1 =  [1 1 1;1 1 1;1 1 1];
for ii = 2:size(a,1)-1
    for jj = 2:size(a,2)-1
        val = sum(sum(a(ii - 1:ii+1,jj-1:jj+1).*se1));
        if val == 255 * 9
            b1(ii,jj) = 255;
        end
    end
end
a = b1;

subplot(221)
imshow(a);
title('原图');
a = double(a);
%% 计算边界
b = zeros(size(a));
se =  [1 1 1;1 1 1;1 1 1];
for ii = 2:size(a,1)-1
    for jj = 2:size(a,2)-1
        val = sum(sum(a(ii - 1:ii+1,jj-1:jj+1).*se));
        if val == 255 * 9
            b(ii,jj) = 255;
        end
    end
end
%erode
subplot(222)
imshow(b)
title('腐蚀');
c = a - b;%白色边界
subplot(223)
imshow(c)
title('边界');
subplot(224)
imshow(a)
title('边界连通域');
hold on;
% 顺时针记录连通域边界
x_pos = [];
y_pos = [];
pos_count = 1;
%% 连通域、边界长度
xId = [-1 0 1 1 1 0 -1 -1];
yId = [-1 -1 -1 0 1 1 1 0];
indexMap = zeros(size(c));
markMap  = zeros(size(c));
len = 0;%初始边缘长度
time = 0.0001;%绘制时间
%************搜索模板,搜索起点的值为9,顺时针搜索
%|1   2   3 |
%|8   9   4 |
%|7   6   5 |
%************
for i = 1:size(c,1)*size(c,2)
    i
    if c(i) ~= 0
        x= floor(i/size(c,1)) + 1;
        y= i-(x-1)*size(c,1);
        xStart = x
        yStart = y
        %         x = 68; %设置调试起点,自己设置的
        %         y = 144;
        indexMap(y,x) = 5;%索引起始点
        markMap(y,x)  = 2;%设置起始访问标记值
        plot(x,y,'r*');
        x_pos(pos_count) = x;
        y_pos(pos_count) = y;
        pos_count = pos_count + 1;
        tmp = 1;    %搜索位置起点:1~9
        tmp = tmp +2; %一般设置为1(按道理怎么设置都可以)
        flag = 0;%停止标志
        while 1     %进入该循环之后开始寻找连通域
            if flag
                break;
            end
            if tmp-3 == 0%数组循环,3是回退数量,保证搜索的位置全部包含
                start = tmp;
            else
                start = mod(tmp-3,9);
            end
            for j = start:start + 7 %在当前点位搜索的起始点
                if  j == 9
                    j = 8;
                else
                    jT = mod(j,9);
                end
                xTmp = x + xId(jT);
                yTmp = y + yId(jT);
                %                 c(yTmp,xTmp);%标记点
                %                 if indexMap(yTmp,xTmp) >= 9 %停止条件
                if yTmp == yStart && xTmp ==xStart  %停止条件
                    xEnd = x
                    yEnd = y
                    flag = 1;
                    break;
                end
                if c(yTmp,xTmp) >=125 && markMap(yTmp,xTmp) == 0 %未搜寻且为边界
                    if mod(jT,2) == 1 %在奇数位置进入下一个位置的寻找
                        for z = 1:7
                            if jT + z ==9
                                start2 = 8;
                            else
                                start2 = mod(jT + z,9);
                            end
                            if c(y + yId(start2),x + xId(start2)) == 0
                                break;
                            end
                        end
                    else
                        z = 1;
                    end
                    if jT + z - 1 == 9
                        start1 = 8;
                    else
                        start1 = mod(jT + z-1,9);
                    end
                    xTmp = x + xId(start1);
                    yTmp = y + yId(start1);
                    if xId(start1)*yId(start1)
                        len = len+2^(1/2);
                    else
                        len = len+1;
                    end
                    indexMap(y,x) = indexMap(y,x) + start1;%连通域索引
                    markMap(y,x)  = 1;%标记占用
                    plot(xTmp,yTmp,'r.');   %绘制连通域点
                    pause(time);
                    x = xTmp;
                    y = yTmp;
                    x_pos(pos_count) = x;
                    y_pos(pos_count) = y;
                    pos_count = pos_count + 1;
                    tmp = jT + z -1;
                    break;
                end
            end
        end
        break;
    end
end

figure
plot(x_pos,-y_pos)
% %% 圆形度
% len  = len + sqrt((x-xStart)^2 + (y-yStart)^2);
% s = len^2/4/pi;
% Ratio = area / s
% str = num2str(Ratio);
% handleT = title(['圆形度:',str]);
% handle = get(handleT,'Position');

%% 辐角原理判断点与连通域的关系(包含、不包含、在边界)
margin = 0.1;   %角度差值的裕度
margin2 = 0.0000002;   %判断点是否包含的裕度(除去边界,误差理论上只有计算机的舍入误差),margin2可以比较小,
x_pos = [x_pos,x_pos(1)]; %连通域闭环
y_pos = [y_pos,y_pos(1)];
result = 255 * ones(size(a));
if size(x_pos,2) > 2
    for j = 1:size(a,1)
        for i = 1:size(a,2)
%             i = x_pos(end - 1) % 调试使用
%             j = y_pos(end - 1)
            dx = x_pos(1) - i;
            dy = y_pos(1) - j;
            theta = atan2(dy,dx); % 初始角度
            accumulator = 0; %角度变化累加
            % 该循环计算每个像素点的累加角度积分
            for k = 2:size(x_pos,2) 
                theta_tmp = theta; %记录上一个角度
                dx = x_pos(k) - i;
                dy = y_pos(k) - j;
                flag = 0;
                if dx == 0 && dy == 0
                    flag = 1;
                    break;
                end
                %计算theta
                theta = atan2(dy,dx);
                d_theta = theta - theta_tmp;
                if abs(d_theta)> pi / 2 + margin % 注意连通域上两个连续点之间的角度差值不会大于90°即pi/2(理论值),除去点在边界的情况最大差值为 pi
                    if d_theta > 0
                        d_theta = d_theta - 2 * pi;
                    else
                        d_theta = d_theta + 2 * pi;
                    end
                end
%                 d_theta
                accumulator = accumulator + d_theta;
            end
            %判断包含关系
            if flag == 0
                if abs(accumulator) < margin2 % 判断为不包含
                    result(j,i) = 128;
                else
                    while abs(accumulator)>pi * 2 - margin2
                        if accumulator > 0
                            accumulator = accumulator - pi * 2;
                        else
                            accumulator = accumulator + pi * 2;
                        end
                    end
                    if abs(accumulator) < margin2 % 判断为包含
                        result(j,i) = 0;
                    else
                        disp('程序编写很大概率出错,并没有达到margin2精度要求!');
                    end
                end
            end
        end
    end
else
    disp('Short of Points!');
end
figure
imshow(uint8(result));title('灰度128判断在连通域外,0判断在边界,255判断在内部','fontsize',16);











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值