(来点有用的)MATLAB可视化手动抠图


by HPC_ZY

在做图像处理的时,常常需要对目标(感兴趣区域)进行分割,有时需要人工提取目标(抠图)。通过提供坐标范围进行提取,不够直观且难以一次成功。所以实现了一个简易的、可视化的、手动取点的抠图代码,分享给大家。
效果图如下:
手动选点生成选择范围
获取结果


第一步:手动选点

核心函数: [x, y, button] = ginput(N),用于获取鼠标所在坐标。其中,
x,y为鼠标坐标;
button为键位,返回值为1(左键),2(滚轮),3(右键);
N为记录点击的次数。

  • 准备工作
    显示图像,并初始化数组。
[M,N,D]=size(im);
figure
imshow(im)
k=0;
p=[];
  • 手动选点
    由于选取点数不确定,不能预设N值。所以通过数据按键来判断是否继续。
hold on
while 1
    [x,y,flag]=ginput(1);
    if flag==1
        k=k+1;
        p(k,1:2)=round([y,x]); % 交换,取整保存
        plot(x,y,'b.','MarkerSize',20) % 标记
   else
        break
    end
end
hold off

为了使当前选取范围更直观,可连接各选取点。修改后如下:

hold on
while 1
    [x,y,flag]=ginput(1);
    if flag==1
        k=k+1;
        p(k,1:2)=round([y,x]); % 交换,取整保存
        plot(x,y,'b.','MarkerSize',20) % 标记
        if k>1
           line([p(k-1,2),p(k,2)],[p(k-1,1),p(k,1)],'LineWidth',2) 
        end
    else
        line([p(1,2),p(k,2)],[p(1,1),p(k,1)],'LineWidth',2) 
        break
    end
end
hold off

注意:由于图像像素坐标索引与xy坐标系相反,所以要交换位置。


第二步:生成蒙板

主要方法:按序连接所有点形成封闭图形,并进行填充生成蒙板。

  • 编写脚本函数,实现连线功能
    核心原理:根据公式y-y0=k(x-x0),可计算线段表达式,从而通过取整确定线段覆盖的像素位置。详细计算过程不再赘述,实现如下:
% 其中 p0,p1为两个点的坐标,a为蒙板
function a=pixelcontect(a,p0,p1)

a(p0(1),p0(2))=1;
a(p1(1),p1(2))=1;
dis=p1-p0;
gap=((-1).^double(dis<0));
absdis=abs(dis);
more=max(absdis);
less=min(absdis);

if absdis(1)>=absdis(2)
    dir1=[gap(1),0];
    dir2=[0,gap(2)];
else
    dir2=[gap(1),0];
    dir1=[0,gap(2)];
end

lmp=less/more;
i=0;j=0;
while i<more
    p0=p0+dir1;
    a(p0(1),p0(2))=1;
    i=i+1;
 if i<more
        p1=p1-dir1;
        a(p1(1),p1(2))=1;
        i=i+1;
    end
 if j/i<lmp
        if j<less
            p0=p0+dir2;
            a(p0(1),p0(2))=1;
            j=j+1;
        end
        if j<less
           p1=p1-dir2;
            a(p1(1),p1(2))=1;
            j=j+1;
        end
    end
end

end % 函数结束
  • 循环调用,完成全点连接
    初始化蒙板,循环调用标记区域轮廓。
mask=zeros(M,N);
for i=1:k
    if i<k
        mask=pixelcontect(mask,p(i,:),p(i+1,:)); % 依次连接所有点
    else
        mask=pixelcontect(mask,p(i,:),p(1,:)); % 末尾与起点相连
    end
end
  • 填充模板
mask=imfill(mask,'hole');

第三步:提取目标

out=mask.*im; 

注意:此处默认图像为double类型,可根据自己实际类型调整上述代码,否则报错-矩阵类型不一致。

若处理彩色图像,可加入以下代码

if D>1 
   mask=cat(3,mask,mask,mask); 
end

最后

我们可以获得
1 p —— 标记点的坐标
2 mask —— 蒙板
3 out —— 目标图像

最后附上完整代码(简易版)

%% 主函数
function [out,mask,p]=manseg(im)
% 准备工作
[M,N,D]=size(im);
figure
imshow(im)
k=0;
p=[];

% 手动选点
hold on
while 1
    [x,y,flag]=ginput(1);
    if flag==1
        k=k+1;
        plot(x,y,'b.','MarkerSize',20)
        p(k,1:2)=round([y,x]);
        if k>1
           line([p(k-1,2),p(k,2)],[p(k-1,1),p(k,1)],'LineWidth',2) 
        end
    else
        line([p(1,2),p(k,2)],[p(1,1),p(k,1)],'LineWidth',2) 
        break
    end
end
hold off

% 生成蒙板
mask=zeros(M,N);
for i=1:k
    if i<k
        mask=pixelcontect(mask,p(i,:),p(i+1,:));
    else
        mask=pixelcontect(mask,p(i,:),p(1,:));
    end
end
mask=imfill(mask,'hole');

if D>1
   mask=cat(3,mask,mask,mask); 
end

% 提取目标
out=mask.*im;

end

%% 子函数
function a=pixelcontect(a,p0,p1)
% ---------详见上文
end

补充

由于不少网友在使用中遇到问题,现将测试代码上传
https://download.csdn.net/download/xsz591541060/11151459

猜你喜欢

转载自blog.csdn.net/xsz591541060/article/details/84345386