⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 poker.m

📁 一个基于MATLAB环境开发的扑克牌识别程序
💻 M
字号:
function varargout = poker(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @poker_OpeningFcn, ...
                   'gui_OutputFcn',  @poker_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin & isstr(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% --------------------------------------------------------------------
function poker_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
guidata(hObject, handles);

global IMAGE;global POKER;global GRAY;global BW;global BWSTR;
IMAGE=0;
POKER=0;
GRAY=0;
BW=0;
BWSTR=0;%全局变量初始化为0
% --------------------------------------------------------------------
function varargout = poker_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
% --------------------------------------------------------------------
function file_Callback(hObject, eventdata, handles)
% --------------------------------------------------------------------function new_Callback(hObject, eventdata, handles)global IMAGE;
global POKER;
global GRAY;
global BW;
global BWSTR;

name=0;[name,path]=uigetfile({'*.bmp';'*.jpg';'*,tif'},'打开图像');
if name==0;
    return;%没有打开图像
end

IMAGE=imread(strcat(path,name));%成功打开图像
POKER=0;GRAY=0;BW=0;BWSTR=0;%其他图像复位

subplot(1,1,1),imshow(IMAGE),title('扑克纸牌图像');% --------------------------------------------------------------------function operate_Callback(hObject, eventdata, handles)
% --------------------------------------------------------------------function rectify_Callback(hObject, eventdata, handles)global IMAGE;
global POKER;

if IMAGE==0;%未打开图像
    msgbox('请先打开一幅扑克图像','错误','error');
else
    tic;%计算校正与定位用时
    POKER=rectify(IMAGE);
    if toc>5%设置超时时间为3秒
        msgbox('图像校正定位超时','错误','error');
        return;
    end
    time=num2str(toc);
    str=strcat('校正与定位耗时',time,'秒');
    subplot(1,1,1),imshow(POKER),title('扑克纸牌');
    msgbox(str,'消息');
end% --------------------------------------------------------------------function gray_Callback(hObject, eventdata, handles)global IMAGE;
global POKER;
global GRAY;

if IMAGE==0%未打开图像
    msgbox('请先打开一幅扑克图像','错误','error');
elseif POKER==0%未进行图像校正
    msgbox('请先对图像进行校正定位','错误','error');
else
    GRAY=rgb2gray(POKER);
    subplot(1,1,1),imshow(GRAY),title('图像灰度化');
end% --------------------------------------------------------------------function binary_Callback(hObject, eventdata, handles)global IMAGE;
global POKER;
global GRAY;
global BW;
if IMAGE==0%未打开图像
    msgbox('请先打开一幅扑克图像','错误','error');
elseif POKER==0%未进行图像校正
    msgbox('请先对图像进行校正定位','错误','error');
elseif GRAY==0%未进行图像灰度化
    msgbox('请先对图像进行灰度化','错误','error');
else
    bw=im2bw(GRAY,ostu(GRAY));
    BW=logical(abs(double(bw)-1));
    subplot(1,1,1),imshow(BW),title('图像二值化');
end
% --------------------------------------------------------------------
function getsymstr_Callback(hObject, eventdata, handles)
global IMAGE;
global POKER;
global GRAY;
global BW;
global BWSTR;

if IMAGE==0%未打开图像
    msgbox('请先打开一幅扑克图像','错误','error');
elseif POKER==0%未进行图像校正
    msgbox('请先对图像进行校正定位','错误','error');
elseif GRAY==0%未进行图像灰度化
    msgbox('请先对图像进行灰度化','错误','error');
elseif BW==0%未进行图像二值化
    msgbox('请先对图像进行二值化','错误','error');
else   
    [m,n]=size(GRAY);
    pokerstr=GRAY(2:m/2,n/20:n/5.5);%字符粗略定位
    bw=im2bw(pokerstr,ostu(pokerstr));
    bw1=bwmorph(bw,'clean');%清除孤立点
    bw2=logical(abs(double(bw)-1));%二值图像反色
    bw3=reduce(bw2);%清除连续不跳变边缘影响,自定义函数reduce
    [m,n]=size(bw3);
    temp=sum(bw3);shadow(2:n+1)=temp;shadow(1)=0;shadow(n+2)=0;
    for i=2:n+1
        if shadow(i)~=0&shadow(i-1)==0&shadow(i+1)==0%出现孤立线条
            for j=1:m
                bw3(j,i-1)=0;%删除孤立线条列
            end
        end
    end
    [m,n]=find(bw3);
    BWSTR=bw3(min(m):max(m),min(n):max(n));
    subplot(1,1,1),imshow(BWSTR),title('纸牌特征字符');
end% --------------------------------------------------------------------function recognition_Callback(hObject, eventdata, handles)global IMAGE;
global POKER;
global GRAY;
global BW;
global BWSTR

%纸牌字符模板,34*22投影
str1=[6 6 6 6 8 8 10 10 10 10 8 8 8 8 10 10 8 8 8 8 12 12 16 16 12 12 8 8 8 8 16 16 16 16];%A
str2=[10 10 16 16 12 12 12 12 12 12 6 6 4 4 8 8 8 8 6 6 6 6 6 6 6 6 8 8 10 10 22 22 22 22];%2
str3=[22 22 14 14 10 10 8 8 8 8 8 12 12 14 14 6 6 4 4 4 4 4 4 4 4 8 8 8 12 12 18 18 12 12];%3
str4=[2 2 4 4 6 6 8 8 10 10 12 12 10 10 10 10 8 8 10 10 12 12 20 20 22 22 6 6 6 6 6 6 8 8];%4
str5=[18 18 16 16 4 4 4 4 4 16 16 16 16 6 6 4 4 4 4 4 4 4 4 4 4 10 12 12 16 16 12 12 2 2];%5
str6=[9 9 15 15 7 7 5 5 3 3 5 5 14 14 18 18 12 12 9 9 9 9 11 11 11 11 7 7 10 10 14 14 11 11];%6
str7=[15 15 22 22 14 14 9 9 5 5 5 5 5 5 4 4 4 4 6 6 4 4 4 4 6 6 4 4 4 4 4 4 4 4];%7
str8=[10 10 16 16 10 10 6 6 8 8 6 6 12 12 14 14 14 14 10 10 8 8 8 8 8 8 8 8 14 14 18 18 10 10];%8
str9=[14 14 16 16 8 8 8 8 12 12 12 10 10 12 12 12 12 18 18 16 16 4 4 4 4 6 6 6 12 12 14 14 8 8];%9
str10=[10 10 16 16 14 14 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 16 16 16 16 10 10];%10
str11=[13 13 11 11 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 9 9 9 9 14 14 13 13 4 4];%J
str12=[11 11 10 10 10 10 6 6 6 6 6 6 6 6 6 6 6 10 10 14 14 16 16 12 12 10 10 10 10 10 18 18 12 12];%Q
str13=[20 20 20 20 12 12 10 10 10 10 10 10 8 8 12 12 12 12 12 12 10 10 10 10 10 10 8 8 10 10 18 18 20 20];%K
STR=[str1;str2;str3;str4;str5;str6;str7;str8;str9;str10;str11;str12;str13];

%纸牌花形模板,24*20投影
style1=[4 4 6 6 8 8 12 12 16 16 16 16 20 20 20 20 20 20 14 14 6 6 6 6];%黑桃
style2=[12 12 20 20 20 20 20 20 18 18 16 16 14 14 12 12 8 8 6 6 4 4 2 2];%红桃
style3=[4 4 8 8 10 10 10 10 8 8 16 16 20 20 20 20 20 20 12 12 4 4 4 4];%梅花
style4=[2 2 4 4 6 6 12 12 16 16 20 20 20 20 16 16 12 12 6 6 6 6 2 2];%方片
STYLE=[style1;style2;style3;style4];

if IMAGE==0%未打开图像
    msgbox('请先打开一幅扑克图像','错误','error');
elseif POKER==0%未进行图像校正
    msgbox('请先对图像进行校正定位','错误','error');
elseif GRAY==0%未进行图像灰度化
    msgbox('请先对图像进行灰度化','错误','error');
elseif BW==0%未进行图像二值化
    msgbox('请先对图像进行二值化','错误','error');
elseif  BWSTR==0%未提取特征
    msgbox('请先提取图像字符','错误','error');
else
    sym=imclose(BWSTR,strel('disk',3));%粗略估算特征面积大小
    shadow=sum(sym);
    if max(shadow)>=40%面积过大,识别为为JOKER
        result=strcat('识别结果:','JOKER');
        msgbox(result,'消息','warn');
    else
        sym=bwmorph(BWSTR,'clean');%清除孤立点
        shadow=(sum(sym,2))';%侧面投影
        len=length(shadow);
        for i=2:len-1%搜索数字符号与花形符号的分界点
            if shadow(i)~=0&shadow(i+1)==0%检测到靠近数字一边的边界
                bonder1=i+1;
                i=bonder1;
                continue;
            end
            if shadow(i)<=1&shadow(i+1)>1%检测到靠近花形一边的边界
                bonder2=i;
                break;
            end
        end
        bonder=(bonder1+bonder2)/2;%取两个边界的中间作为符号分界线
        SYM1=sym(1:bonder,:);%数字符号
        [m,n]=find(SYM1);
        SYM1=SYM1(min(m):max(m),min(n):max(n));
        SYM1=imresize(SYM1,[34 22]);%模板归一化
        
        SYM2=sym(bonder:len,:);%花形符号
        [m,n]=find(SYM2);
        SYM2=SYM2(min(m):max(m),min(n):max(n));
        SYM2=imresize(SYM2,[24,20]);%模板归一化
        
        shadow1=(sum(SYM1,2))';shadow2=(sum(SYM2,2))';
        
        %字符匹配
        errormean=50;sn1=0;
        for i=1:13%搜索最佳匹配的模板
            temp=STR(i,:);
            error=abs(shadow1-temp);
            error=mean(error,2);%求绝对均差
            if error<errormean;
                sn1=i;errormean=error;
            end
        end
        if errormean>=3;%误差过大
            sn1=0;
        end
        
        %花形匹配
        errormean=50;sn2=0;
        for i=1:4%搜索最佳匹配的模板
            temp=STYLE(i,:);
            error=abs(shadow2-temp);
            error=mean(error,2);%求绝对均差
            if error<errormean;
                sn2=i;errormean=error;
            end
        end
        if errormean>=3;%误差过大
            sn2=0;
        end
        
        %特征映射
        switch sn1
            case 0
                result1='-不能识别出字符'
            case 1
                result1='A';
            case 10
                result1='10';
            case 11
                result1='J';
            case 12
                result1='Q';
            case 13
                result1='K';
            otherwise
                result1=num2str(sn1);
        end
        switch sn2
            case 1
                result2='黑桃';
            case 2
                result2='红桃';
            case 3
                result2='梅花';
            case 4
                result2='方片';
            otherwise
                result2='不能识别出花形';
       end
       result=strcat('识别结果:',result2,result1);
       msgbox(result,'消息','warn');
    end
end
% --------------------------------------------------------------------
function about_Callback(hObject, eventdata, handles)
msgbox('欢迎交流:luotiancheng7299@hotmail.com','关于','help');
% --------------------------------------------------------------------
function exit_Callback(hObject, eventdata, handles)
global IMAGE;global POKER;global GRAY;global BW;global BWSTR;
clear IMAGE;clear POKER;clear GRAY;clear BW;clear BWSTR;%清除全局变量
close poker;
% --------------------------------------------------------------------
function figure1_DeleteFcn(hObject, eventdata, handles)
global IMAGE;global POKER;global GRAY;global BW;global BWSTR;
clear IMAGE;clear POKER;clear GRAY;clear BW;clear BWSTR;%清楚全局变量













% -----------------------以下为自定义函数-----------------------------
function str=reduce(bwstr);
%去除边缘
[m,n]=size(bwstr);
temp=ones(m,n);
num=1;
for j=1:n
    count=0;
    for i=1:m
        if bwstr(i,j)==0;
            count=0;continue;
        else
            count=count+1;%连续不跳变点数增加
            if count>=m/3;%连续不跳变长度约为1.5个字符宽
                break;
            end
        end
    end
    if count>=m/3
        line(num)=j;
        num=num+1;%记录扫描到的最后一行边框
    end
end
for i=1:num-1%扫描到的最后一行边框以上的行置为背景
    for j=1:m
        temp(j,line(i))=0;
    end
end
str=logical(double(bwstr).*temp);
%--------------------------------------------------------------------------
function level=ostu(IMAGE)
%最大类间方差ostu算法,求最佳阈值
[m,n,s]=size(IMAGE);
if s==1
    image=IMAGE;
end
if s==3
    image=RGB2gray(IMAGE);
end
ranks=256;
counts=imhist(image,ranks);
p=counts/sum(counts);omega=cumsum(p);
mu=cumsum(p.*(0:ranks-1)');mu_t = mu(end);
sigma2=0;%otsu类间方差
T=0;%threshold
h=0;
Hmax=0;
w0=0;w1=0;
u0=0;u1=0;
HStore=zeros(1,256);
for i=1:ranks
    if (omega(i)==0)|((1-omega(i))==0)
        continue;
    end;
    w0=omega(i);w1=1-w0;
    u0=mu(i)/w0;u1=(mu_t-mu(i))/w1;
    sigma2=w0*(u0-mu_t).^2+w1*(u1-mu_t).^2;
    h=sigma2;HStore(i)=h;
end
Hmax = max(HStore);
isfinite_maxval = isfinite(Hmax);
if isfinite_maxval
    idx = mean(find(HStore == Hmax));
    level = (idx - 1) / (ranks - 1);
else
    level = 0.0;
end
%--------------------------------------------------------------------------
function poker=rectify(rgbimage)
%扑克目标校正且定位函数
grey=rgb2gray(rgbimage);%灰度化图像
ed1=edge(grey,'sobel','both');%灰度化图象边缘化
bw1=imclose(ed1,strel('disk',20));%形态学闭操作填充区域,选择圆形结构体
%以上形态学操作为了模糊纸牌内部的线条结构
%从而减小A,J,Q,K,JOKER纸牌等内部复杂边缘对定位的影响
ed2=edge(bw1,'sobel','both');%对纸牌的物理边缘进行检测
bw2=bwmorph(ed2,'dilate');%形态学结构性膨胀,加强边缘效果

hough=radon(bw2,-90:90);%-90到90度的hough变换
[m,n]=size(hough);
rotate=0;%倾斜角值
sline=0;%最长直线长度
for i=1:m
    for j=1:n
        if hough(i,j)>sline;
            rotate=j-1;sline=hough(i,j);
        end
    end
end
ed3=bwmorph(ed2,'clean',10);
bw3=imrotate(ed3,-rotate);%预测校正
[m,n]=find(bw3);%预测校正后的目标位置
rgb=imrotate(rgbimage,-rotate,'bilinear');%倾斜校正
poker=rgb(min(m):max(m),min(n):max(n),:);%定位
[m,n]=size(poker);
if n>m
    poker=imrotate(poker,90,'bilinear');
end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -