matlab利用字符作画(汉字绘画)

编程入门 行业动态 更新时间:2024-10-22 22:52:41

matlab利用字符作画(<a href=https://www.elefans.com/category/jswz/34/1769833.html style=汉字绘画)"/>

matlab利用字符作画(汉字绘画)

matlab利用字符作画(汉字绘画)

  • 1 算法实现原理
  • 2 实现
  • 3 动图和视频的实现
  • 3 尝试更少的字符表现更高的分辨率
  • 4 尝试利用边缘线条实现字符作画

1 算法实现原理

算法的原理比较简单,就是利用不同字符具有不同的密度,比如字符“一”具有较低的密度,字符“曩”具有较高的密度。对于白底黑字来说,密度越高意味着该点附近具有较高的灰度值,这样文字就与图像的灰度值建立了一一对应的关系。

所以算法主要包括两个部分,一个是建立一个字符库,包含字符与其密度之间的关系;一个是实现字符密度和图像灰度值之间转换的方法。

2 实现

这里我使用的字符库为常用汉字5000个,图像采用cameraman作为要转换的图像。
常用汉字5000个地址:


之后将5000个汉字输出在一个文字框中,统计汉字图像中的黑色部分的比例。
具体代码如下,其中str5000为之间保存的5000汉字,strH_gray为每个字符的密度值:

%字符转密度值
clear
load('str5000.mat')
strH=str5000;N=length(strH);
strH_gray=zeros(N,1);
figure('color',[1 1 1])%白色背景
%循环5000个字
for j=1:N%绘制文字
text(0,0,strH(j),'FontUnits','normalized','FontSize',0.9,'verticalAlignment','bottom');
xlim([0,0.5]);ylim([0,0.5]);
set(gcf,'Position',[488 342 375 420]);
set(gca,'Position',[0.0 0.0 1 1]);
axis off%获取文字图像信息
F = getframe;
strdata=F.cdata;
imshow(F.cdata)%计算文字所占密度
strdata1=strdata(:,:,1);
strdata1=uint8((strdata1~=255));
n=length(strdata1(:));
s=sum(strdata1(:));
strH_gray(j)=s/n;clf%清空图像
end%最后保存文字密度表strH_gray

之后拥有文字表和对应的文字密度表后,就可以创建文字密度和图像灰度值之间一一对应的关系了。具体代码如下:

clear
load('str5000_gray.mat')%文字密度表
load('str5000.mat')%文字表strH=[str5000];
strH_gray=[str5000_gray];x=imread('camera.jpg');
x=imresize(x,[32,32]);
x=double(x);%uint8格式不能表示0-1小数
strid=zeros(size(x(:,:,1)));%将RGB转换为灰度。可以用rgb2gray简化处理
im_gray = ((x(:,:,1)).^2.2 * 0.2973 + (x(:,:,2)).^2.2 * 0.6274 + (x(:,:,3)).^2.2 * 0.0753).^(1/2.2);
im_gray=1-im_gray/255;%由于文字最大密度也不能到100%,而图像却可以很暗,所以需要对文字的密度值进行一定缩放
enlarge=max(im_gray(:))/max(strH_gray(:));%对每一个像素点的灰度值与文字密度进行匹配,记录下对应的文字编码
for j=1:length(im_gray(:))
im_g_j=im_gray(j);
[~,minid]=min(abs(im_g_j-strH_gray*enlarge));
strid(j)=minid;
end%按照行进行每行的文字输出
n=size(im_gray,1);
str_img=cell(1,n);
figure('color',[1 1 1])
for j=1:nstr_img=strH(strid(j,:));%由于默认matlab中text的行间距太大,这里人为约束固定每一行位置text(0,1-1/n*j,str_img,'FontUnits','normalized','FontSize',1/n,...'verticalAlignment','bottom','HorizontalAlignment','center');
end
xlim([-1,1]);%将文字居中
axis off%获取gcf
F = getframe;
strdata=F.cdata;
imwrite(strdata,'A.png');

64×64个字符下的字符画:

32×32个字符下的字符画:

3 动图和视频的实现

动图的实现原理与普通图片的实现原理没有区别,但是细节上需要对格式进行整合,需要对每一帧都输出成字符画。

这里用猫和老鼠的一个动图作为具体的实现展示。


将这幅动图转换为字符画的代码如下:

clear
%载入文字库
load('str5000_gray.mat')
load('str5000.mat')
strH=[str5000];
strH_gray=[str5000_gray];
%载入gif动图
[A,map]=imread('E:\期末复习\研一下\寒假\文字作图\tomandjerry.gif', 'gif','frame','all'); 
C=squeeze(A);%把动图变为灰度图,并调整尺寸
sizeimgnew=[116,160];
DRGB=zeros([size(C,1),size(C,2),3]);
D_gray2=zeros([sizeimgnew,size(C,3)]);
for k=1:size(C,3)RGB=ind2rgb(C(:,:,k),map);D_gray=rgb2gray(RGB);DRGB(:,:,1)=D_gray;DRGB(:,:,2)=D_gray;DRGB(:,:,3)=D_gray;DRGB2=imresize(DRGB,sizeimgnew);D_gray2(:,:,k)=DRGB2(:,:,1);
endD_gray2(D_gray2>1)=1;
D_gray2=1-D_gray2;%按比例线性填充至01区间
D_gray2=(D_gray2-min(D_gray2(:)))/(max(D_gray2(:))-min(D_gray2(:)));
strH_gray=(strH_gray-min(strH_gray(:)))/(max(strH_gray(:))-min(strH_gray(:)));%逐个扫描像素,转换为对应标号
strid=zeros(size(D_gray2));
for j=1:length(D_gray2(:))
im_g_j=D_gray2(j);
[~,minid]=min(abs(im_g_j-strH_gray));
strid(j)=minid;
end%逐帧输出每一副图像
n=size(D_gray2,1);
figure('color',[1 1 1])
for k=1:size(D_gray2,3)for j=1:n%逐行扫描文字str_img=strH(strid(j,:,k));text(0,1-1/n*j,str_img,'FontUnits','normalized','FontSize',1/n,...'verticalAlignment','bottom','HorizontalAlignment','center');endxlim([-1,1]);axis offpause(0.1)F = getframe;strdata=F.cdata;[I,map] = rgb2ind(strdata,32); %将真彩色图像转化为索引图像if k==2imwrite(I,map,'A.gif','gif','Loopcount',inf,'DelayTime',0.05);elseif k>2&&k<=23imwrite(I,map,'A.gif','gif','WriteMode','append','DelayTime',0.05);%DelayTime:帧与帧之间的时间间隔endclf
end

输出的结果如下:

3 尝试更少的字符表现更高的分辨率

由于文字具有不同的形状,所以根据这个原理可以减少使用文字的量。比如说“品”字上半部分具有较低的密度,下半部分具有较高的密度。比如文字“缸”的左半边密度就要大于右半边密度。

这样,就需要调整一下之前的算法,第一步需要将文字划分为4个部分,保存每个部分的密度;第二步需要根据4个图像像素和同一文字的4个密度,进行向量匹配,根据图像找到最接近的文字向量。

第一部分的文字密度向量的算法如下:

%字符转密度值4向量版
clear
load('str5000.mat');strH=str5000;
N=length(strH);
strH_gray=zeros(N,4);
figure('color',[1 1 1])for j=1:N
text(0,0,strH(j),'FontUnits','normalized','FontSize',0.9, 'verticalAlignment','bottom','HorizontalAlignment','center');
xlim([-0.5,0.5]);ylim([0,0.5]);
set(gcf,'Position',[488 342 373 419]);set(gca,'Position',[0.0 0.0 1 1]);
axis offF = getframe;strdata=F.cdata;
imshow(F.cdata)%计算灰度值
strdata1=strdata(:,:,1);
strdata1=uint8((strdata1~=255));%其实可以不转换格式
[m,n]=size(strdata1);
%四个不同的密度向量
mn=m*n/4;
s1=sum(sum(strdata1(1:m/2,1:n/2)));%左上
s2=sum(sum(strdata1(1:m/2,n/2+1:end)));%右上
s3=sum(sum(strdata1(m/2+1:end,1:n/2)));%左下
s4=sum(sum(strdata1(m/2+1:end,n/2+1:end)));%右下strH_gray(j,1)=s1/mn;
strH_gray(j,2)=s2/mn;
strH_gray(j,3)=s3/mn;
strH_gray(j,4)=s4/mn;clf
end

将图片转换为文字的代码如下:

clear
load('str5000_gray4.mat')%之前的strH_gray保存的结果
load('str5000.mat')strH=[str5000];
strH_gray=[str5000_gray4];x=imread('camera.jpg');
x=imresize(x,[64,64]);
x=double(x);
%转换为灰度值
im_gray = ((x(:,:,1)).^2.2 * 0.2973 + (x(:,:,2)).^2.2 * 0.6274 + (x(:,:,3)).^2.2 * 0.0753).^(1/2.2);
im_gray=1-im_gray/255;
%按比例线性填充至01区间
im_gray=(im_gray-min(im_gray(:)))/(max(im_gray(:))-min(im_gray(:)));
strH_gray=(strH_gray-min(strH_gray(:)))/(max(strH_gray(:))-min(strH_gray(:)));
%匹配
%转换成4角格式
im_gray4=im2im4corner(im_gray);
[m,n]=size(im_gray4(:,:,1));
strid=zeros([m,n]);
%进行匹配
for j=1:m*n[I,J] = ind2sub([m,n],j);im_g_j=reshape(im_gray4(I,J,:),1,4);cospdist=pdist2(strH_gray,im_g_j,'euclidean');%利用欧拉距离值匹配[~,minid]=min(cospdist);strid(j)=minid;
end%输出text
n=size(im_gray4,1);
str_img=cell(1,n);
figure('color',[1 1 1])
for j=1:nstr_img{j}=strH(strid(j,:));text(0,1-1/n*j,str_img{j},'FontUnits','normalized','FontSize',1/n,...'verticalAlignment','bottom','HorizontalAlignment','center');
end
xlim([-1,1]);
axis off%获取gcf
F = getframe;
strdata=F.cdata;
imwrite(strdata,'A2.png');%脚本后置函数
function A4=im2im4corner(A)
%用于将图片转换为和文字密度匹配的4角格式
[m,n]=size(A);
A4=zeros(floor((m-2)/2)+1,floor((n-2)/2)+1,4);
for j=1:2:m-1for k=1:2:n-1A4((j+1)/2,(k+1)/2,1)=A(j,k);%左上A4((j+1)/2,(k+1)/2,2)=A(j,k+1);%右上A4((j+1)/2,(k+1)/2,3)=A(j+1,k);%左下A4((j+1)/2,(k+1)/2,4)=A(j+1,k+1);%右下end
end
end

和之前64字符的进行对比,可以看到向量法(左图)对边缘的刻画过渡更加平滑,但是对于灰度值的描述就不如直接灰度法描述的好。比如4角向量的方式,衣服内部的文字几乎相同,灰度值信息丢失较多。

向量法的细节图,在不同灰度变化较大的交接处,大量使用逐、罐、必、趟、茂等密度不对称的字,来增加边缘处整体的平滑度。

4 尝试利用边缘线条实现字符作画

利用edge函数可以提取边缘,进而利用边缘的图像来作画。
例如下图:

这里代码和之前第3节的代码几乎相同,就是文字库由汉字更换成为特殊符号,边缘检测利用matlab自带的approxcanny方法。具体代码就不放上了。其中edge的使用方法如下:

im_gray = edge(x2,'approxcanny')

详情参见官方文档:.html

这里要注意特殊符号库的选取,要统一全角、半角,不能混着搭配,否则会出现文字排版混乱。比如下图,就是不小心用了半角的空格“ ”而不是全角的空格“ ”。当然如果混用的话也可以,但是估计要修改 text函数的x坐标,固定每个符号的中心位置。

更多推荐

matlab利用字符作画(汉字绘画)

本文发布于:2024-03-23 18:07:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1741204.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:汉字   字符   matlab

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!