【数字图像处理】求包含白色点得最小凸多边形

题目:一幅图像,背景为黑色,其中包含一些白色孤点,求包含白色点的最小的凸多边形。

比如图像:


思路:首先找到最下方的白色点。然后遍历每个白色点,求出当前点V1与每个白色点连成的方向向量。找出与单位向量向量(0,1)(当前向量)内积最小的那个方向向量。组成那个向量的白点即和V1相邻的下一个点V2。接着,更新当前向量为V1和V2连成的单位向量。再遍历每个白点,求出当前点V2和每个白色点连成的方向向量。找出与当前向量内积最小的那个单位向量。组成那个向量的白点即和V2相邻的下一个点V3。接着找出和V3相邻的下一个点。直到下一个点变为V1.即所有的边缘点都已找到。

参考代码:

%寻找包围白色点的最小的凸多边形
%生成一幅包含多个白色像素点的图片
height = 256;%图像高度
width = 256;%图像宽度
I = zeros(height,width);
%在图像中生成N个白色点
I(10,20) = 255;
I(30,50) = 255;
I(150,90) = 255;
I(240,100) = 255;
I(45,220) = 255;
I(90,90) = 255;
I(230,10) = 255;
I(220,240) = 255;
% I = imread('pp.jpg');
figure,imshow(I)
% [height,width] = size(I);
%寻找最下方的白色点
%注意此处跳出二重循环!!!
for i = height:-1:1
    flag = 0;%标记是是否找到
    for j = width:-1:1
        if i >= 1 && j >= 1 && I(i,j) == 255
            lowest_i = i;
            lowest_j = j;%记录最下方的点得坐标
            flag = 1;%已找到
            break;
        end
    end
    if flag == 1%已找到,跳出循环
        break;
    end
end

MAXNUM = 9999999;
count = 0;%记录图像中白色点的数目
loca = zeros(MAXNUM,2);%记录各白色点的坐标
for i = 1:height
    for j = 1:width
        if I(i,j) == 255
            count = count + 1;%白色点数目增加一
            loca(count,1) = i;
            loca(count,2) = j;
        end
    end
end

%按序寻找位于凸多边形上的白色点
NumVetex = 0;%记录边缘点的个数
LocVetex = zeros(count,2);%按序记录各边缘点的坐标
%加入最下方的点
NumVetex = NumVetex + 1;
LocVetex(NumVetex,1) = lowest_i;
LocVetex(NumVetex,2) = lowest_j;
current_i = lowest_i;%当前点得坐标
current_j = lowest_j;
next_i = -1;%与当前点相邻的下一个位于凸多边形上面的白色点的坐标
next_j = -1;
while next_i ~= lowest_i && next_j ~= lowest_j%终止条件:回到最下方的点
    if current_i == lowest_i && current_j == lowest_j%第一个点
        current_prod_i = 0;%当前单位向量
        current_prod_j = 1;
    end
    MaxProd = -999999;%最大内积
    %寻找下一个点:内积最大
    for i = 1:count
        if current_i ~= loca(i,1) && current_j ~= loca(i,2)%跳过当前点
            %求其他点和当前点组成的向量
            prod_x = loca(i,1) - current_i;
            prod_y = loca(i,2) - current_j;
            %单位化
            prod_length = sqrt(prod_x * prod_x + prod_y * prod_y);
            prod_x = prod_x / prod_length;
            prod_y = prod_y / prod_length;
            TempProd = prod_x * current_prod_i + prod_y * current_prod_j;
            if MaxProd < TempProd%找到更大的内积
                MaxProd = TempProd;
                next_i = loca(i,1);%记录内积更大的点,即下一个边缘点
                next_j = loca(i,2);
            end
        end
    end
    %把下一个点加入边缘点坐标数组
    NumVetex = NumVetex + 1;
    LocVetex(NumVetex,1) = next_i;
    LocVetex(NumVetex,2) = next_j;
    %修改变量
    %当前单位向量变化
    prod_length = sqrt((next_i - current_i) * (next_i - current_i) + (next_j - current_j) * (next_j - current_j));
    current_prod_i = (next_i - current_i) / prod_length;
    current_prod_j = (next_j - current_j) / prod_length;
    %当前点后移
    current_i = next_i;
    current_j = next_j;
end

%绘制多边形的边
for i = 2:NumVetex
    grad = (LocVetex(i,2) - LocVetex(i - 1,2)) / (LocVetex(i,1) - LocVetex(i - 1,1));%直线斜率
    if LocVetex(i - 1,1) < LocVetex(i,1)
        for index_i = LocVetex(i - 1,1):LocVetex(i,1)
            index_j = LocVetex(i - 1,2) + grad * (index_i - LocVetex(i - 1,1));
            index_j = uint8(index_j);
            I(index_i,index_j) = 255;
        end
    else
        for index_i = LocVetex(i - 1,1):-1:LocVetex(i,1)
            index_j = LocVetex(i - 1,2) + grad * (index_i - LocVetex(i - 1,1));
            index_j = uint8(index_j);
            I(index_i,index_j) = 255;
        end
    end
end
figure,imshow(I)


运行结果:


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没有昵称阿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值