MATLAB数独的识别与计算

MATLAB 自动数独求解器(导入图片自动求解)

基础知识
1、不用事先对变量的类型进行定义或说明 ,系
统会根据变量被赋值的类型自动进行类型识别
2、元胞数组
{ }大括号,用于cell型的数组的分配或引用。
(1)创建:
方法一:{}

>> a={[2 4 7;3 9 6;1 8 5], 'Li Si',2+3i,1:2:10}

a =[3x3 double] ‘Li Si’ [2.0000 + 3.0000i] [1x5 double]

方法二:利用 cell 函数创建元胞数组

>> a=cell(3,3)

a = [] [] []
[] [] []
[] [] []

>>a=cell(1,4);a={'winter',123,'coming','哈哈'};

(2)组成它的元素是元胞 (cell)
(3)元胞数组的每个单元可以储存不同的数据类型。
(4)操作——提取、删除、转换、显示
A.提取
访问元胞:利用元素地址

>> a{1,2}
%查看元胞数组第 1行第 2 列的元胞元素

查看元胞内容:deal 函数

>> [a b c d]=deal(a{:})
%用 deal 函数查看元胞数组内容
%对于矩阵,冒号表示该维度上的所有元素。

a = winter
b =123
c = coming
d = 哈哈

B.删除
对单元数组向量下标赋空值即可删除单元数组的行或列

C.转换
num2cell 函数
mat2cell 函数

D.显示
显示单元内容 : celldisp 函数

与普通矩阵,数组的主要区别在于:通过()访问cell数组时访问到的是cell单元,通过{}访问cell数组时访问到的是cell单元储存的内容
视频的笔记
!!!多注释多讲解预警

总体的思路:
第一步 数字的识别(有数字填入数字,没有数字就填入0)
第二步 计算
第三步 数字的回填

对每一块代码的讲解,在代码块之后

壹、

%%清屏
clear;clc;close all
%%进入工作目录
cd F:\科技树\MustbeDone\2020.02.06_线上课程\11_2020.02.22
XBD = imread('simple.jpg');%实验成功了

函数语法
[…] = imread(filename)

%%数独图片标准化
Original_Size=[441,441];%标准化数独9*9大小,有时候会小一点点
XBD=imresize(XBD,Original_Size);%标准化
imshow(XBD)
title('原始图像');

imshow(I,[low high]) 显示灰度图像 I,以二元素向量 [low high] 形式指定显示范围。

%%二值化提取特征
V_thresh = graythresh(XBD);%自动阈值
im_2v=im2bw(XBD,V_thresh);
imshow(im_2v);
title('二值化图像');

对每一行进行切割
一行切9块,每块大小相等
矩阵,二值化。黑色代表0,白色代表1
没有数的矩阵,就是全为1的矩阵,对应的是空矩阵。
有数的矩阵,矩阵不全为1。
判断矩阵中,是否有数字。意义:有数字的位置就可以确定了。
不能太大,会碰到边界,边界是1。

im2bw:基于阈值,将图像转变成二进制图像。

BW = im2bw(I, level):将灰度图像I转变成二级制图像BW

level:阈值等级,取值范围【0,1】

BW: 逻辑型

%%分割图像,图像存储在Img_num_all,对应位置存储在Index_sudo
H=size(im_2v,1);
L=size(im_2v,2);
Img_num_all={'' };%数字图像存储
Index_sudo=[]%数独中数字对应的位置 n行2列,n是数字的个数
count_space = 0;%记录有几个空的宫格
count_num = 1;%存储位置
adj_n=8;
for i=1:9
	for j=1:9
		in_num=im_2v(floor(H/9)*(i-1)+adj_n:floor(H/9)*i-adj_n,floor(L/9)*(j-1)+adj_n:floor(L/9)*j-adj_n);%见讲解一
		imshow(im_num)%见讲解二
		if all(im_num(:)==1)%表示为空,没有数字
			count_space=count_space+1;
		else
			[a,b]=find(im_num == 0)%找出数字对应范围
			Min_a = min(a);Max_a = max(a);
			Min_b = min(b);Max_a = max(b);
			Img_num_s = im_num([Min_a:Max_a],[Min_b:Max_b]);%见讲解三
			Index_num_all{count_num,1} = Img_num_s;%存储所有数字,但是又重复,需要删除
			Index_sudo = [Index_sudo;i j];%记录对应宫格位置
			count_num = count_num + 1;
		end
	end
close all;			

讲解一

floor(H/9)*(i-1)+adj_n
floor(H/9)i-adj_n

floor(L/9)
(j-1)+adj_n
floor(L/9)*j-adj_n

i=1,j=1时,即第一行第一列
floor(H/9)*(i-1)+adj_n = 8
floor(H/9)*i-adj_n =41
全满时1-49,此时是8-41

i=1,j=2时,即第一行第二列

讲解二
只有两种格子,一种带数字,一种是白的
白的 all(im_num(:)==1)的结果是是
带数字 all(im_num(:)==1)的结果是否

讲解三
在这里插入图片描述
Img_num_s这个矩阵,存下了带数字的小格子,存的是图像
count_num 起始为1

讲解四
在这里插入图片描述
Index_sudo存的是对应的位置

%%样本simple.jpg查看,看完关掉,主要是方面确定
Num_simples = size(Img_num_all,1);
for i=1:Num_simples%查看样本
	subplot(5,8,i)
	imshow(Img_num_all{i,1})
	size(Img_num_all{i,1})%大致查看了所有数字对应的矩阵大小,指定一个统一规格
end

%%数字对应索引位置,提取1到9的样本图片,运行一次就好
Num_simple_index = [16 11 7 4 15 1 2 8 9];%对应的是
for i=1:9%查看样本,1和6位是重复的可以进行试验
	subplot(3,3,i)
	imshow(Img_num_all{Num_simple_index(i),1});title(['数字样本:',num2str(i)])
	size(Img_num_all{Num_simple_index(i),1})
	imwrite(Img_num_all{Num_simple_index(i),1},[num2str(i),'.jpg'])%存储样本,运行一次就好
end

Num_simple_index(i)索引的位置
在这里插入图片描述
Nun_simple_index中,
第一个16代表着,第16个是1
第二个11代表着,第11个是2
第三个7代表着,第7个是3
第四个4代表着,第4个是4
第五个15代表着,第15个是5
第六个1代表着,第1个是6
第七个2代表着,第2个是7
第八个8代表着,第8个是8
第九个9代表着,第9个是9
执行完这段代码之后,就能够知道每一个数字的图像是什么样子了,为之后的比对做准备。

%%数独矩阵化
0	imshow(Img_num_all{2,1})
1	Index_sudo;%数独中数字对应的位置
2	picSize=[26,20];%标准化大小,经过实验测定
3	SUDO = zeros(9,9);%数独矩阵初始化
4	for i_sudo=1:size(Img_num_all,1)
5	matchrs=[];
6	p = Img_num_all{i_sudo};
7	p = imresize(p,picSize);%需要识别的数独中数字匹配矩阵标准化
8	imshow(p)%和下面for循环中的数,要进行比较
9	for i_simple=1:9
10		q=imread([num2str(i_simple),'.jpg]);
11		q=imresize(q,picSize);%标记后样本数字标准化
12		imshow(p)
13		matchrs(i_simple)=corr2(p,q);
14	end
15	[m,n]=max;%获取最大值m和对应位置n,n对应1到9
16	SUDO(Index_sudo(i_sudo,1),Index_sudo(i_sudo,2)) = n;
17	end
%标准化大小

Img_num_all;%数字图像存储
Index_sudo;%对应宫格坐标
Img_num_all、Index_sudo一一对应

第7行和第11行进行标准化,是为了使用corr2函数,p和q都得是m行n列
corr2(A,B)相关系数越接近1相关性越大,相关系数越接近-1相关性越小

0.9459最接近1,所以这个数字应该是6

15行
m是相关系数中最大的值;n是几当前的数字就是几。

16行
把i行 Index_sudo(i_sudo,1)j列 Index_sudo(i_sudo,2)
右侧的图是原始的题目,左侧的矩阵是我们写的,和左侧的一样(除了空格的地方我们补为了0)

%%利用SUDO作为基础解算数据,解算数独,调用函数sodoku
S=sodoku(SUDO);%用育有的函数解算数独

%%填写结算数据到对应位置,用到Index_sudo函数
%1)获取所有空格位置索引Sudo_index
B_exclude=sub2ind(size(S),Index_sudo(:,1),Index_sudo(:,2));%sub2ind函数是matlab中对矩阵索引号检索的函数
[row col]=ind2sub([9 9], 1:81);%利用ind2sub构造行列坐标,[9 9]表示9行9列,1:81对应索引数字9*9=81
%ind2sub把数组或者矩阵的线性索引转化为相应的下标
%sub2ind则正好相反,将下标转化为线性索引
S_index=[row' col'];
k=ismember(S_index,Index_sudo,'rows');%判断Index_sudo在S_index中的位置,Index_sudo是有数字的
kr=not(k);%0和1呼唤,针对01矩阵
Sudo_index=S_index(kr,:);%对应的是所有空格子位置索引
%2)填入数字像素到test.jpg图像XBD中
Blue_num=[0 0 255];%数字颜色
Background=[255 255 0];%数字背景颜色
%%存储1到9数字图像,变换颜色
Color_NUM={''};
for i_n=1:9
Img_num=imread([num2str(i_n),'.jpg']);%灰度图
imshow(Img_num);
matrix=(Img_num<50);%选择黑色像素点,逻辑值为1,之前选择60没扣干净
[a,b]=find(matix==1);%找出所有黑色像素位置索引a,b
Img_color_num=Img_num;
for i = 1:size(a)
	Img_color_num(a(i),b(i),1) = 0;
	Img_color_num(a(i),b(i),2) = 0;
	Img_color_num(a(i),b(i),3) = 255;%纯蓝
end
imshow(Img_color_num);
[a,b]=find(matix==1);%找出所有黑色像素位置索引a,b
for i = 1:size(a)
	Img_color_num(a(i),b(i),1) = 255;
	Img_color_num(a(i),b(i),2) = 255;%纯黄
	Img_color_num(a(i),b(i),3) = 0;
end
imshow(Img_color_num);%完成数字颜色置换 
Color_NUM={i_n,1}=Img_color_num;%获取所有的换色1到9图像(RGB)
end
%%插入Color_NUM中图像,用到位置Sudo_index与数值
for i_last=1:size(Sudo_index,1)
	i=Sudo_index(i_last,1);j=Sudo_index(i_last,2);%对那个数独的行列坐标
	H_a=size(XBD,1);L_a=size(XBD_cell,2);
	XBD_cell=XBD(floor(H_a/9)*(i-1)+1:floor(H_a/9)*i,floor(L_a/9)*(j-1)+1:floor(L_a/9)*j,:);%获取对应空
	H=size(XBD_cell,1);L=size(XBD_cell,2);%大方格行列范围
	num_input=Color_NUM{S(i,j),1};%插入需要的数字图像
	h1=ceil((H-size(num_input,1))/2);%向上取整,行对应位置1,近似让数字图像位于中间
	h2=floor((H-size(num_input,1))/2);%向下取整,行对应位置2
	l1=ceil((L-size(num_input,2))/2);
	l2=floor((L-size(num_input,2));
	XBD_cell(h1+1:H-h2,l1+1,L-l2,:)=num_input;%插入图像
	XBD(floor(H_a/9)*(i-1)+1:floor(H_a/9)*i,floor(L_a/9)*(j-1)+1:floor(L_a/9)*j,:)=XBD_cell;%插入回去
end
close all
imshow(XBD)
function S = sodoku(M,S)
%[S,Mout] = sodoku(M,[S])
%
%A recursive program that solves 'sodoku' puzzles.
%
%Inputs:  M  partially filled 9x9 matrix with zeros in 'blank' cells
%         S  list of solutions (only used during recursive calls)
%
%Outputs: S  list of solutions
%
%Example:
%
%M = [0,0,1,9,0,0,0,0,8;6,0,0,0,8,5,0,3,0;0,0,7,0,6,0,1,0,0;...
%     0,3,4,0,9,0,0,0,0;0,0,0,5,0,4,0,0,0;0,0,0,0,1,0,4,2,0;...
%     0,0,5,0,7,0,9,0,0;0,1,0,8,4,0,0,0,7;7,0,0,0,0,9,2,0,0];
%
%S = sodoku(M)
%
%Written by G.M. Boynton, 6/3/05

%If this is the first call, then zero out the solution matrix
if ~exist('S','var')
    S = zeros([size(M),0]);
end

%find the first blank cell, or zero
firstId = find(M(:)==0, 1 );
if isempty(firstId)  %If there aren't any zeros, then we have a solution!
    S(:,:,size(S,3)+1) = M;  %save it
else %calculate the list of all valid numbers that can go into this cell
    [i,j] = ind2sub([9,9],firstId);
    for k=1:9  %loop through all 9 possibilities
        ii = (ceil(i/3)-1)*3+1;
        jj = (ceil(j/3)-1)*3+1;
        mm = M(ii:ii+2,jj:jj+2); %these are the indices into the 3x3 block containing that cell
        if sum(M(i,:)==k)==0 && sum(M(:,j)==k)==0 && sum(mm(:)==k)==0  %OK for column, row, and 3x3 block
            M(i,j) = k;  %put this number in,
            S = sodoku(M,S); %and call this function recursively!
        end
    end
end

出处

第一运行完,这两个部分需要关掉
在这里插入图片描述

参考资料:
1、
{}
2、元胞数组讲解
3、视频地址
4、im2bw

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值