基于matlab实现掌纹掌静脉图片的ROI(感兴趣区域)提取

2023年7月31日 16:00 ry 556

最近任务比较重,要多线程实现400张掌纹掌静脉图片的裁剪,要求只保留中心部分,如图所示这是相机拍摄的掌纹图片我要提取掌纹中心部分区域,其他其余要剔除,这是目标图像,如图所示

注意哈,这个图像是上面图像经过旋转裁剪得来的哈。这就是我们所需要实现的效果,接下来我们用matlab代码实现,这是我们实验室祖传的代码,部分算法如下所示

function [newzg1y, newzg1x, d0, shuchusrc,angle]=ROI(InBw1,InImg)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[x,y]=size(InBw1);
s=[];
[a, LabMtx]=bwboundaries(InBw1);    %寻找连通域的函数    L是一个标记矩阵
for k=1:length(a)
    sz=size(a{k});
    s=[s sz(1)];
end   %取了a中的个数
[M, Ind]=max(s); %Ind为索引值
boundary1=a{Ind}; %获取了手掌的边界,X,Y  排序是从9点钟方向上的一点顺时针开始沿着边界走
PalmBoundaryImg=zeros(x, y);%开始描边

for z=1:size(boundary1, 1)
    PalmBoundaryImg(boundary1(z,1), boundary1(z,2))=1;
end
%figure(2),imshow(PalmBoundaryImg),title('边界图');%边界图
% % % % hold on;
% % % % plot(1012, 145,'r*');
% % % % hold off;

%%%%%%%%%% getting centroid of palm and displaying it 获得掌心的质心并显示它
cent=regionprops(LabMtx,'centroid');  %标注矩阵L中每一个标注区域的一系列属性。质心    返回值STATS是一个 长度为max(L(:))的结构数组,结构数组的相应域定义了每一个区域相应属性下的度量
centcor=[cent(Ind).Centroid];
%%%%%%%%%%找出质心画一条竖线与掌轮廓有两个交点选大的,对轮廓矩阵转移 %%%%%%%%%%%%
cenY=round(centcor(1));
cenX=round(centcor(2));
% % % %  hold on;
% % % %  plot(cenY, cenX,'ro');
% % % %  hold off;

[xInd]=find(boundary1(:,2)==cenY); %第二例取出判断  相当于Y的值等于944的 x1 x2
leftIndX=max(xInd); %leftIndY的数值代表boundary1中的排列数  相当于确定了手掌的位置
boundary2=circshift(boundary1,max(size(boundary1(:,1))-leftIndX+1));%矩阵的循环移动boundary2 将边界1逆时针旋转 让起始点逆时针变动到 原来手掌的位置
PalmBoundaryImg2=zeros(x, y);%开始描边
for z2=1:size(boundary2, 1)
    PalmBoundaryImg2(boundary2(z2,1), boundary2(z2,2))=1;
end
% figure(3),imshow(PalmBoundaryImg2); %起始点在6点钟手掌的位置,逆时针进行排序

% % % % hold on;
% % % % plot(516, 247,'r*');
% % % % hold off;

L=length(boundary2);
distance=sqrt( sum( (boundary2-repmat(boundary2(1,:),L,1) ).^2,2) );%应该是求到手掌位置的距离 边界上的点
%%%%%%%%%%%%%%%%%%%%% Finding finger extremeties 找到手指四肢%%%%%%%%%%%%%%%%%%%%%%%%%%%
W1=round(L/23);%23
W2=round(L/46);%46
tips=[];%代表指尖的标号
valleys=[];%代表指谷的标号
k=0;
tip=1;
valley=1;
%%%%%%%%%%%%%%% tips and valleys are found as the maxima and minima on the
%%%%%%%%%%%%%%% windoweddistance signal 在窗口距离信号上找到尖端和波谷作为最大值和最小值

%figure(3),plot(distance(:,1),'r*'),title('轮廓线各点距离手掌底部中心距离');%看出距离变化局部极小值代表手指谷点

while k<L-W1
    k=k+1;
    window1=distance(k:k+(W1-1));
    [Min,MinIndex1]=min(window1);
    [Max,MaxIndex1]=max(window1);
    if MaxIndex1~=1 & MaxIndex1~=W1
        if MaxIndex1+k-1+W2<=L & MaxIndex1+k-1-W2>=1
            window2=distance(MaxIndex1+k-1-W2:MaxIndex1+k-1+W2);
        elseif MaxIndex1+k-1-W2<1
            window2=distance(1:MaxIndex1+k-1+W2);
        else
            window2=distance(MaxIndex1+k-1-W2:L);
        end
        [Max,MaxIndex2]=max(window2);
        if MaxIndex2==W2+1
            tip=MaxIndex1+k-1;
            tips=[tips;tip];%tip列向合并给tips
        end
    end
    %%%%%%%%{1,88}为一段,找凹点,最小值点不在两端,记下最小值的索引号
    if MinIndex1~=1 & MinIndex1~=W1%最小值点不在两端
        if MinIndex1+k-1+W2<=L & MinIndex1+k-1-W2>=1%判断是否超出边界
            window2=distance(MinIndex1+k-1-W2:MinIndex1+k-1+W2);%再重新从MinIndex1+k-1-W2(以最小值的索引点两边平分44为区间)
        elseif MinIndex1+k-1-W2<1
            window2=distance(1:MinIndex1+k-1+W2);
        else
            window2=distance(MinIndex1+k-1-W2:L);
        end
        [Min,MinIndex2]=min(window2);%把以最低点为中心重新分好的区间最小值给Min,索引号给MinIndex2一般为45
        if MinIndex2==W2+1%45=44+1
            valley=MinIndex1+k-1;
            valleys=[valleys;valley];%valley列向合并给valleys
        end
    end
    k=max([tip valley k]);
end

    tips=[distance(tips) tips];%把索引号的距离与tips行向合并 先距离后索引号  距离是到手掌6点钟原点的直线距离
    tips=flipud(sortrows(tips,1));%flipud(X)实现了矩阵的翻转 从大到小
 if length(tips) < 3
    shuchu=0;
    newzg1y=0;
    newzg1x=0;
    d0=0;
    shuchusrc=0;
 else
    shuchu=1;
    tips=sort(tips(1:4,2));%根据距离找到四根手指,去掉拇指 根据距离去掉最小的拇指
    temp=zeros(4,1);
    valleys=flipud(sortrows(valleys,1));
    for v=1:3%把valleys中数值从小到大插入到tips中
        kk=find(valleys>tips(v) & valleys<tips(v+1));
        if length(kk)<1
            shuchu=0;
            angle=0;
            break;
        else
            temp(v)=valleys(kk(1));
        end
    end
   if shuchu==0
        
        newzg1y=0;
        newzg1x=0;
        d0=0;
        shuchusrc=0;
   else
        valleys=temp;
        %imtool(PalmBoundaryImg)
        %hold(imgca,'on')
        zg=boundary2(valleys(1:3),:);%代表手指谷的位置 分别为从左到右 XY
        zj=boundary2(tips(1:4),:);%代表手指尖的位置 分别为从左到右
        %
        %---------------------------------------------------------------------------------------------------
        
     %   figure(4),imshow(PalmBoundaryImg2),title('*代表指谷点、o代表指尖点'); %起始点在6点钟手掌的位置,逆时针进行排序
%          figure(6),imshow(InImg),title('*代表指谷点、o代表指尖点'); %起始点在6点钟手掌的位置,逆时针进行排序
         hold on; plot( zg(:,2),zg(:,1),'r*');
         hold off;
%          hold on;
%          plot( zj(:,2),zj(:,1),'ro');
%          hold off;
        
        zg1X=boundary2(valleys(1),2);
        zg1Y=boundary2(valleys(1),1);
        zg2X=boundary2(valleys(2),2);
        zg2Y=boundary2(valleys(2),1);
        zg3X=boundary2(valleys(3),2);
        zg3Y=boundary2(valleys(3),1);
        % hold(imgca,'on')  %@@@@@@@@@@@@@@@@@@@@@@@@@@
        % plot(imgca,[zg1X zg3X],[zg1Y zg3Y]);
        % hold(imgca,'off');%@@@@@@@@@@@@@@@@@@@@@@@
        zhijiaoX=zg3X;
        zhijiaoY=zg1Y;% 代表三角形的直角顶点
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        angle=atan((zg3Y-zhijiaoY)/(zhijiaoX-zg1X))*(180/pi);     %两谷点角度
        TT=angle;
        %@@@@@@@@@@@@@@@@@@@@
        % hold(imgca,'on')
        % t=180;
        % nxx1=(xx1*cosd(t))-(yy1*sind(t))-320*cosd(t)+240*sind(t)+320;
        % nyy1=(xx1*sind(t))+(yy1*cosd(t))-320*sind(t)-240*cosd(t)+240;
        % plot(imgca,nxx1,nyy1,'w+');
        % hold(imgca,'off');
        %@@@@@@@@@@@@@@@@@
        RotdImg=imrotate(InImg,angle,'nearest','crop');    %旋转,crop输出图像和原来一样大小
        figure(5),imshow(RotdImg),title('旋转后的掌纹图像'); 
        
        
        t=-TT;%旋转角度
        zg1tomidlength=sqrt((0.5*y-zg(1,2))^2+(0.5*x-zg(1,1))^2);%求左边第一个手指谷点到 图形旋转中心的距离 旋转中心为图像中心
        zg1tomidangle=atan( (0.5*x -(zg(1,1))) / (0.5*y-zg(1,2)) )*(180/pi); %求左边第一个手指谷点到 中心点的一个角度 也可以理解为初始点的角度
        newzg1tomidangle=zg1tomidangle + t;%角度相加 因为要旋转
        newzg1y=0.5*y - zg1tomidlength * cosd(newzg1tomidangle);
        newzg1x=0.5*x - zg1tomidlength * sind(newzg1tomidangle);%计算旋转后的左边第一个手指谷的点的新坐标
        newzg1y=round(newzg1y);
        newzg1x=round(newzg1x);
        
        
        d0=sqrt((zg1X-zg3X)^2+(zg1Y-zg3Y)^2);%求两点距离  求一条斜线的长度 左边第一个手指谷点到第三个谷点的直线距离 横向ROI长度
        hold on;
        plot( newzg1y,newzg1x,'ro');
        hold off;
        hold on;
        plot( newzg1y+d0,newzg1x,'ro');
        hold off;
        im1=RotdImg;
        palm1=imcrop(im1,[newzg1y newzg1x 640 480]);%剪切函数以nxx1 (nyy1+10)为图像左上角d0为宽度d1为高度[xmin ymin width height]  d0是找的两个手指谷的间隙
        k=im1;
        shuchusrc=palm1;%ROI原始
        [m,n]=size(k);
        %%%%%%%%%%%%%%%%%%%%%%%%%%灰度归一化
        p=max(max(k(:,:)))-min(min(k(:,:)));
        y=double(256/double(p));
        k(:,:)=double((double(y)*double((k(:,:)-min(min(k(:,:)))))));
        % shuchu=k;%归一化后的ROI
    end
 end
%imtool(k);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

由于我c++上要实现多线程裁剪,直接打包成dll即可,十分方便!!!!,需要源码的可以联系我qq:1449917271 ,微信:liuyoudyping。

如果上述代码帮助您很多,可以打赏下以减少服务器的开支吗,万分感谢!

欢迎发表评论~

点击此处登录后即可评论


评论列表
暂时还没有任何评论哦...

赣ICP备2021001574号-1

赣公网安备 36092402000079号