手势识别MATLAB代码

手势识别是智能设备常用的需求, 下面我们用MATLAB来识别手部的形态:

主程序main.m


clc;clear all;close all;%清除命令行和窗口
im=imread('DSC05815.JPG');

[skin,bwycbcr,w,h] = hand_segmentation(im);
im1=bwycbcr;
%  se = strel('ball',[1 1 1;1 1 1;1 1 1]);
 im1 = imdilate(im1,[1 1 1;1 1 1;1 1 1]);
 figure;
 imshow(im1);
 title('Dilated');
I_closed = imageclose(im1);


bw2=imadjust(I_closed,[0,1]);
%去除少像素连通区域
bw3=bwareaopen(bw2,round(w*h/10));
figure;
imshow(bw3); 
title('去除少数像素');
se=strel('disk',5);
I_closed2=imclose(bw3,se);


I=I_closed2;
BW1=edge(I,'sobel'); %用SOBEL算子进行边缘检测
BW2=edge(I,'roberts');%用Roberts算子进行边缘检测
BW3=edge(I,'prewitt'); %用prewitt算子进行边缘检测
BW4=edge(I,'log'); %用log算子进行边缘检测
BW5=edge(I,'canny'); %用canny算子进行边缘检测
h=fspecial('gaussian',5);
BW6=edge(I,'canny');
figure;
subplot(2,3,1), imshow(BW1);
title('sobel edge check');
subplot(2,3,2), imshow(BW2);
title('sobel edge check');
subplot(2,3,3), imshow(BW3);
title('prewitt edge check');
subplot(2,3,4), imshow(BW4);
title('log edge check');
subplot(2,3,5), imshow(BW5);
title('canny edge check');
subplot(2,3,6), imshow(BW6);
title('gasussian&canny edge check');%此为用高斯滤波后Canny算子边缘检测结果

r1=im(:,:,1);
b1=im(:,:,2);
g1=im(:,:,3);

%% 判断边缘
[w1,h1,k43]=size(im);
for i=1:w1
    for j=1:h1
        if BW6(i,j)==1%是边缘
            % 用红色标出边缘
            r1(i,j)=255;
            b1(i,j)=0;
            g1(i,j)=0;
        end
    end
end
Iegde=zeros(w1,h1,3);
% 合成彩色图
Iegde(:,:,1)=r1;
Iegde(:,:,2)=b1;
Iegde(:,:,3)=g1;
Iegde=double(Iegde/255);%转换为0-1彩色图
figure;
imshow(Iegde);%绘制识别出来的图


子函数imageclose.m

%执行了先膨后胀腐蚀的闭运算
function I_closed = imageclose(im1)
%I=imread('result.bmp');
se=strel('disk',3);
I_closed=imclose(im1,se);
%subplot(1,2,1);
%imshow(im1);
figure;
imshow(I_closed);
title('闭运算后图像');
%imwrite(I_opened,'result1.bmp');
 

子函数 hand_segmentation.m

function [skin,bwycbcr,w,h] = hand_segmentation(im)
%imgrgb=imread('IMG_2755.jpg');
% im=imread('DSC05818.JPG');
[w h]=size(im(:,:,1));
%Laplacian 八邻域模板滤波
h1=[-1,-1,-1;-1,9,-1;-1,-1,-1];
bw1=imfilter(im,h1);
% bw1=im;
[m,n,c]=size(bw1);
% delete strFile,c;
%将RGB色彩空间转换为Ycbcr色彩空间
imgrgb3=rgb2ycbcr(bw1);
y=imgrgb3(:,:,1);
cb=imgrgb3(:,:,2);
cr=imgrgb3(:,:,3);
%==================================
%在Ycbcr色彩空间中分割肤色区域
cb=double(cb);
cr=double(cr);
y=double(y);
bwycbcr=zeros(m,n);
for i=1:m
    for j=1:n
        if y(i,j)<125
            cb1=108+(125-y(i,j))*10/109;
            cr1=154-(125-y(i,j))*10/109;
            wcb=23+(y(i,j)-16)*23.97/109;
            wcr=20+(y(i,j)-16)*18.76/109;
            cb1=(cb(i,j)-cb1)*46.97/wcb+cb1;
            cr1=(cr(i,j)-cr1)*38.76/wcr+cr1;
        elseif y(i,j)>188
            cb1=108+(y(i,j)-188)*10/47;
            cr1=154+(y(i,j)-188)*22/47;
            wcb=14+(235-y(i,j))*32.97/47;
            wcr=10+(235-y(i,j))*28.76/47;
            cb1=(cb(i,j)-cb1)*46.97/wcb+cb1;
            cr1=(cr(i,j)-cr1)*38.76/wcr+cr1;
        else
            cb1=cb(i,j);
            cr1=cr(i,j);
        end
        x1=[-0.819 0.574]*[cb1-109.38;cr1-152.02];
        y1=[-0.574 -0.819]*[cb1-109.38;cr1-152.02];
        if (x1-1.60).^2/644.6521+(y1-2.41).^2/196.8409<=1
            bwycbcr(i,j)=1;
        else bwycbcr(i,j)=0;
        end
    end 
end
%strWrite=strcat('a',strFile1);
%imwrite(bwycbcr,strWrite,'jpg');

figure;
%subplot(2,2,1);
imshow(im);
%title('原始图像');
figure;
%subplot(2,2,2);
imshow(bw1);
figure;
%title('Laplacian滤波');
%subplot(2,2,3);
imshow(bwycbcr); 
% figure;
%title('Ycbcr皮肤颜色模型');
%subplot(2,2,4);
%把bwycbcr拉伸到[0,1]
bw2=imadjust(bwycbcr,[0,1]);
skin=bw2;
%去除少像素连通区域

skin=bwareaopen(skin,round(w*h/1000));
% imshow(skin); 
% title('去除少数像素');

%imwrite(skin,'result.bmp');


子函数Datafind_V1.m

function [Cpx_C_fft_new5]=Datafind_V1(im4)
%im5=imread('result4.bmp');
[Y X]=size(im4);
flag=1;

%寻找链码的起始点
for k=1:Y
    if flag==0
        break;
    end        
    for kk=1:X
        b=im4(k,kk);
          if b==1
            p_x=kk;
            p_y=k;
            flag=0;
            break;
        end
    end
end
imagesc(im4);
colormap(gray);

flag=1;

cur_x=p_x;
cur_y=p_y;
chainCode=[p_y p_x];
im_bak=im4;
while flag==1
im4(cur_y,cur_x)=0;
imblock=im4(cur_y-1:cur_y+1,cur_x-1:cur_x+1);
if sum(sum(imblock))==0 
    if sum(sum(im4))==0 | abs(cur_x-p_x)+abs(cur_y-p_y)<3
        break;
    else
        im_bak(cur_y,cur_x)=0;
        im4=im_bak;
        cur_y=p_y;
        cur_x=p_x;
        chainCode=[];
    end
else
[n_y n_x]=findNb(imblock);
tmp=[n_y+cur_y n_x+cur_x];
chainCode=[chainCode; tmp];
cur_y=tmp(1);
cur_x=tmp(2);
end

end

%将链码出的边缘点组成复数点,并做归一化的傅里叶变换
Cpx_C=chainCode(:,1)+chainCode(:,2)*i;
N=length(Cpx_C);
Cpx_C_fft=1/N*fft(Cpx_C);
figure;plot(real(Cpx_C),imag(Cpx_C));
title('链码点plot图片');
Cpx_C_fft_new5=abs(Cpx_C_fft(2:11));
%save data5.mat Cpx_C_fft_new5 ;
%Cpx_C_new=ifft(Cpx_C_fft_new1);
%figure;plot(real(Cpx_C_new),imag(Cpx_C_new));
%BW=10;

%Cpx_C_fft_new=zeros(1,N);
%Cpx_C_fft_new(1:BW+1)=Cpx_C_fft(1:BW+1);
%Cpx_C_fft_new(N-(BW-1):N)=Cpx_C_fft(N-(BW-1):N);
%Cpx_C_new=ifft(Cpx_C_fft_new);
%figure;plot(real(Cpx_C_new),imag(Cpx_C_new));


子函数boundary_trace.m

%function g=boundary_trace(f)
%g=boundary_trace(f)跟踪目标的外边界,f为输入的二值图像,g为输出的二值图像
%此处f g都是认为是二维矩阵  【行  列】==【y   x】
%此算法只适用于二值图像
%f=imread('result1.bmp');
%去掉整幅图像四周围的像素点,保证图像目标的连通性
function g=boundary_trace(im2)
[YS,XS]=size(im2);
im2(1,1:XS)=0;
im2(YS,1:XS)=0;
im2(1:YS,1)=0;
im2(1:YS,XS)=0;

f=im2bw(im2);
imshow(im2);
offsetr=[-1,0,1,0];
offsetc=[0,1,0,-1];
next_search_dir_table=[4 1 2 3];%搜索方向查找表
next_dir_table=[2 3 4 1];%搜索顺序查找表
start=-1;
boundary=-2;
%找出起始点
[rv,cv]=find((f(2:end-1,:)>0)&(f(1:end-2,:)==0));
%此处可以简化处理,只用找出一个初始点即可。
rv=rv+1;
startr=rv(1);
startc=cv(1);
f=im2double(f);
f(startr,startc)=start;
cur_p=[startr,startc];
init_dir=-1;
done=0;
next_dir=2;  %初始搜索方向
flag=1;
while~done
dir=next_dir;
found_neighbour=0;
for i=1:length(offsetr)   %四邻域上的寻找下一个边缘点
    offset=[offsetr(dir),offsetc(dir)];
    neighbour=cur_p+offset;
    if(f(neighbour(1),neighbour(2)))~=0  %找到新的边缘点
        if(f(cur_p(1),cur_p(2))==start)&(init_dir==-1)
            init_dir=dir;  %记下离开初始点时的方向
            %当前点为初始点且新的边缘点的离开方向为初始离开方向,表明跟踪过程已饶了一圈
        elseif(f(cur_p(1),cur_p(2))==start)&(init_dir==dir)
            done=1;
            found_neighbour=1;
            break;
        end
        next_dir=next_search_dir_table(dir);   %下一个搜索方向
          found_neighbour=1;
          if f(neighbour(1),neighbour(2))~=start
            f(neighbour(1),neighbour(2))=boundary;
          
          end
          cur_p=neighbour;
     
           break;
      end
    dir=next_dir_table(dir);
end
end
bi=find(f==boundary);
f(:)=0;
f(bi)=1;
f(startr,startc)=1;
g=im2bw(f);
figure,imshow(g);
%title('边缘追踪后图像');
%imwrite(g,'result4.bmp');

%[Y,X]=find(g);
%corr=zeros(2,length(X));
%corr(1,:)=X;
%corr(2,:)=Y;

%frac_dim = boxcount(corr, 10,1);

子函数boundary_thin.m

function i_new1=boundary_thin(im3)
%i=imread('result47.bmp');
%imshow(im3);
%i_new=i>128;
%i_new1=bwmorph(i_new,'thin');2
i_new1=bwmorph(im3,'thin');
figure,imshow(i_new1);
title('细化图像');
%imwrite(i_new1,'result5.bmp');

子函数adjustsize.m
 

function I_new1=adjustsize(im1)
%I=imread('result.bmp');
%找到最左边和最右边灰度值不为1点的横坐标
J=sum(im1);
m=size(im1,2);
for i=1:m
    if J(i)~=0
        p=i;
        break;
    else 
        continue;
    end
end
for j=m:-1:1
    if J(j)~=0
        q=j;
        break;
    else
        continue;
    end
end
%找到最左边和最右边灰度值不为1点的纵坐标
I1=im1';
J1=sum(I1);
n=size(I1,2);
for k=1:n
    if J1(k)~=0
        r=k;
        break;
    else 
        continue;
    end
end
for l=n:-1:1
    if J1(l)~=0
        s=l;
        break;
    else
        continue;
    end
end
%剪切出以坐标点(p,r)和(q,s)组成的矩形区域
I_new=imcrop(im1,[p r q-p s-r]);
%figure,imshow(I_new);
I_new1=imresize(I_new,[150 150]);
figure,imshow(I_new1);
title('调整大小为150*150图像');


   程序结果如下:

完整代码见:https://download.csdn.net/download/corn1949/88774968

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/643814.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

image标签展示所有图片

可以使用Vue.js中的v-for指令来循环展示所有的图片。首先&#xff0c;在Vue组件中定义一个数组&#xff0c;数组中存储所有的图片路径。然后&#xff0c;使用v-for指令在模板中循环遍历数组&#xff0c;使用img标签来展示每个图片。 以下是一个示例代码&#xff1a; <temp…

【Spring Boot 3】【JPA】枚举类型持久化

【Spring Boot 3】【JPA】枚举类型持久化 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花…

java面面试面经(面试过程)

一、校招一面面经 1.1 自我介绍(2min) 1.2 要求介绍项目一项目亮点以及做的具体工作 根据介绍项目进行细挖&#xff0c;其中包括方案设计、场景设计等等等 由于项目一种涉及数据库源的转换问题和限流方案&#xff0c;所以面试官拷打的是这两块&#xff0c;其中包括场景题&…

《Linux C编程实战》笔记:信号的发送

信号的发送主要由函数kill、raise、sigqueue、alarm、setitimer以及abort来完成 kill函数 kill函数用来发送信号给指定的进程。 #include<sys/types.h> #include<signal.h> int kill(pid_t pid,int sig); 该函数的行为与第一个参数pid有关&#xff0c;第二个参…

鸿蒙开发-UI-布局-网格

鸿蒙开发-UI-布局 鸿蒙开发-UI-布局-线性布局 鸿蒙开发-UI-布局-层叠布局 鸿蒙开发-UI-布局-弹性布局 鸿蒙开发-UI-布局-相对布局 鸿蒙开发-UI-布局-格栅布局 鸿蒙开发-UI-布局-列表 文章目录 前言 一、基本概念 二、开发布局 1.排列方式 2.设置行列间距 三、应用特性 1.网格数…

android usb2.0 协议基础(2)

2.4 USB逻辑部件 USB 逻辑部件 设备---》 接口 &#xff08;一个或多个&#xff09;&#xff1a;用于描述特定功能&#xff0c;包含多个端点----》端点&#xff08;一个或多个&#xff09;&#xff1a; 传输的最终对象端点号&#xff0c;传输类型传输方向&#xff0c;最大的数据…

设备通过GB28181注册到EasyCVR,平台看不到设备信息的排查方法汇总

智慧安防平台EasyCVR能在复杂的网络环境中&#xff08;专网、局域网、广域网、VPN、公网等&#xff09;将前端海量的设备进行统一集中接入与视频汇聚管理&#xff0c;平台支持设备通过4G、5G、WIFI、有线等方式进行视频流的接入与传输&#xff0c;支持的接入协议包括&#xff1…

大数据开发之Spark(RDD弹性分布式数据集)

第 1 章&#xff1a;rdd概述 1.1 什么是rdd rdd&#xff08;resilient distributed dataset&#xff09;叫做弹性分布式数据集&#xff0c;是spark中最基本的数据抽象。 代码中是一个抽象类&#xff0c;它代表一个弹性的、不可变、可分区、里面的元素可并行计算的集合。 1.1…

Zabbix 微信与钉钉告警配置部署

Zabbix 微信与钉钉告警配置部署 系统环境准备好&#xff1a; Lnmp zabbix-server&#xff1a;172.20.26.167 Mysql主从zabbix-agent&#xff1a;172.20.26.198、172.20.26.24 zabbix的安装部署可以查阅之前的文章&#xff1a;Zabbix 4.0安装部署自动发现及自动注册、自动添…

动态ip代理定义及工作原理

一听到IP代理&#xff0c;咱们有种似曾相识又陌生的感觉。到底IP代理是什么?它的工作原理是怎样的呢? 通常情况下&#xff0c;代理ip网用公网IP接入Int关采取双网卡结构&#xff0c;外网卡使ernet。 网络一(假定为公网internet)的终端A访问网络二(假定为公司内网)的终端B&am…

huggingface学习|云服务器部署Grounded-Segment-Anything:bug总会一个一个一个一个又一个的解决的

文章目录 一、环境部署&#xff08;一&#xff09;模型下载&#xff08;二&#xff09;环境配置&#xff08;三&#xff09;库的安装 二、运行&#xff08;一&#xff09; 运行grounding_dino_demo.py文件&#xff08;二&#xff09;运行grounded_sam_demo.py文件&#xff08;三…

2023年第十六届中国系统架构师大会(SACC2023):核心内容与学习收获(附大会核心PPT下载)

大会以“数字转型 架构演进”为主题&#xff0c;聚焦系统架构在数字化转型中的演进和应用。 与往届相比&#xff0c;本届大会最大的变化是从原来的大会演讲模式变革为专题研讨会模式。专题研讨会主题内容紧扣行业落地实践痛点与难点&#xff0c;多角度聚焦行业的架构演进之路。…

Python requests网络库源码分析(第三篇:通过学习异常模块,了解http协议)

前言 作者在requests包下&#xff0c;定义了exceptions模块&#xff0c;该模块中定义执行http请求过程中常见的错误&#xff0c;熟悉这些错误有助于我们写出健壮的业务程序&#xff0c;同时还能温习http的知识点&#xff0c;本文基于的requests版本为2.27.1 exceptions模块&…

openssl3.2/test/certs - 036 - 768-bit issuer key

文章目录 openssl3.2/test/certs - 036 - 768-bit issuer key概述笔记END openssl3.2/test/certs - 036 - 768-bit issuer key 概述 openssl3.2 - 官方demo学习 - test - certs 笔记 /*! * \file my_openssl_linux_doc_036.txt * \note openssl3.2/test/certs - 036 - 768-…

关于网络安全 的 ARP欺骗 实验操作

实验设备&#xff1a; Windows server 2008 kali 1. vmware--上面菜单栏--虚拟机--设置--网络--NAT 模式 确定靶机与攻击机的连通性&#xff08;互相能 ping 通&#xff09; 靶机查看 arp 表&#xff08;arp -a&#xff09; 查看攻击机(kali)物理地址&#xff08;ip addr&…

SpringBoot整合ElasticSearch实现基础的CRUD操作

本文来说下SpringBoot整合ES实现CRUD操作 文章目录 概述spring-boot-starter-data-elasticsearch项目搭建ES简单的crud操作保存数据修改数据查看数据删除数据 本文小结 概述 SpringBoot支持两种技术和es交互。一种的jest&#xff0c;还有一种就是SpringData-ElasticSearch。根据…

github clone代码修改后上传到自己仓库

1、原理 把远端仓库删除&#xff0c;添加自己的仓库作为remote 仓库 2、步骤 1、创建 .gitingore文件&#xff0c;在里面填入要忽略的文件 doc/* file.txt *.ckpt 2、git命令修改远程仓库 git remote rm origin git remote add 你的仓库地址git commit -m "123"…

Modern C++ 一个例子学习条件变量

目录 问题程序 施魔法让BUG浮出水面 条件变量注意事项 修改程序 问题程序 今天无意中看到一篇帖子&#xff0c;关于条件变量的&#xff0c;不过仔细看看发现它并达不到原本的目的。 程序如下&#xff0c;读者可以先想想他的本意&#xff0c;以及有没有问题&#xff1a; #…

React16源码: React中的renderRoot的错误处理的源码实现

renderRoot的错误处理 1 &#xff09;概述 在 completeWork这个方法之后, 再次回到 renderRoot 里面在 renderRoot 里面执行了 workLoop, 之后&#xff0c;对 workLoop 使用了try catch如果在里面有任何一个节点在更新的过程当中 throw Error 都会被catch到catch到之后就是错误…

安卓之热修复的原理以及解决方案

文章摘要 在当今快速迭代的应用开发环境中&#xff0c;热修复技术&#xff08;Hot Fix&#xff09;成为了一个重要的工具。特别是在Android平台上&#xff0c;热修复提供了一种在运行时修复应用程序缺陷的方法&#xff0c;而无需重新发布应用程序。本文将深入探讨安卓热修复的原…