MATLAB | 如何使用MATLAB一键生成拼豆图纸

最近迷上玩拼豆,就想着能不能写个MATLAB版本的拼豆图纸生成器,目前还是一个很简易版本,只支持生成方形图纸,且不太适合生成超大图(色号显示不清晰),大家可以自行添加功能,或做成App designer 形式。

注意这里如果图像四周如果不是透明的,那么白色像素也会被计数,因此底下显示H1色号会需要非常多,因此代码还有改进的空间,之后可以通过检测白色的连通区域,然后看看是否被其他颜色完全包围来决定是否被统计。。。此外之后可能会尝试对轮廓线条进行自动加粗后再生成图纸。。


1 属性设置

代码就直接点击运行,然后选择想要生成图纸的图片即可,图片如果是非正方形会被自动切割。

代码的最前面几行是:

matlab 复制代码
% 像素画大小; 最大颜色数量
pixN = 50; maxC = 60;
% 是否显示色号, 字体大小
showCName = true; fontSZ = 7;
% 读取色卡
% CData = load('mard188.mat');
CData = load('mard221.mat');
% 色号位置 'bottom'/'right'
palettePos = 'right';

是否显示色号

showCName可以被设置为 true/false,分别有以下效果:

画布尺寸和颜色数量

maxC为最大颜色数量,以下是分别设置为32和8的效果:


pixN是画布尺寸,不建议设置50以上,以下为设置为30的效果:

色卡

色卡这里给了一个188色的mard色卡和一个221色mard色卡,想要用其他牌子的拼豆可以自己制作一个mat文件。

色号位置

可以选择显示在下方还是右侧:


2 其他效果图展示

由于没写轮廓加粗的代码,所以本代码比较适合边缘没那么清晰的图像,此外mard牌子蓝紫色种类比较少,蓝紫色图像绘制效果会稍微差一些:

也可以制作一些游戏角色的拼豆图纸:


3 完整代码

完整代码无配色包文件无法运行,建议从文末链接直接下载包含配色包的压缩包,这里给出代码纯属凑字数。

matlab 复制代码
% 像素画大小; 最大颜色数量
pixN = 50; maxC = 60;
% 是否显示色号, 字体大小
showCName = true; fontSZ = 7;
% 读取色卡
% CData = load('mard188.mat');
CData = load('mard221.mat');
% 色号位置 'bottom'/'right'
palettePos = 'right';


% 读取图片并预处理
[filename, filepath] = uigetfile({'*.jpg;*.png;*.bmp;*.tiff', 'Image Files'}, 'Select an Image');
[img, ~, alp] = imread(fullfile(filepath, filename));
[M, N, ~] = size(img); img = double(img)./255; alp = double(alp)./255;
szN = min(M, N) - mod(min(M, N), pixN);
img = img((1:szN) + round((M - szN)/2), (1:szN) + round((N - szN)/2), :);
szB = round([szN, szN]/pixN); 
imgBR = blockproc(img(:,:,1), szB, @(block) mean(block.data(:)));
imgBG = blockproc(img(:,:,2), szB, @(block) mean(block.data(:)));
imgBB = blockproc(img(:,:,3), szB, @(block) mean(block.data(:)));

if ~isempty(alp)
    alp = alp((1:szN) + round((M - szN)/2), (1:szN) + round((N - szN)/2), :);
    alpB = blockproc(alp, szB, @(block) mean(block.data(:)));
    imgBR(alpB < .5) = 1; imgBG(alpB < .5) = 1; imgBB(alpB < .5) = 1;
end

% 颜色识别 
% 首先识别每个像素最接近哪种颜色,统计各种颜色出现次数
% 之后舍去出现次数少的颜色重新再识别一次
RGB = CData.rgb; CN = size(RGB, 1);
dis = + (repmat(imgBR(:), [1, CN]) - repmat(RGB(:,1).', [pixN^2, 1])).^2 ...
      + (repmat(imgBG(:), [1, CN]) - repmat(RGB(:,2).', [pixN^2, 1])).^2 ...
      + (repmat(imgBB(:), [1, CN]) - repmat(RGB(:,3).', [pixN^2, 1])).^2;
[~, indC] = min(dis, [], 2);
countC = sum(repmat(indC, [1, CN]) == repmat(1:CN, [pixN^2, 1]), 1);
[countNC, indNC] = sort(countC, 'descend');
indNC = sort(indNC(1:min(find(countNC > 0, 1, 'last'), maxC)));
CName = CData.palette(indNC, 1); RGB = CData.rgb(indNC, :); CN = length(indNC);

dis = + (repmat(imgBR(:), [1, CN]) - repmat(RGB(:,1).', [pixN^2, 1])).^2 ...
      + (repmat(imgBG(:), [1, CN]) - repmat(RGB(:,2).', [pixN^2, 1])).^2 ...
      + (repmat(imgBB(:), [1, CN]) - repmat(RGB(:,3).', [pixN^2, 1])).^2;
[~, indC] = min(dis, [], 2);
countC = sum(repmat(indC, [1, CN]) == repmat(1:CN, [pixN^2, 1]), 1);

% 创建图窗
fig = figure('WindowState', 'maximized');
ax = axes('Parent',fig, 'DataAspectRatio',[1,1,1], 'NextPlot','add', ...
    'Position',[0,0,1,1], 'XColor','none', 'YColor','none');

% 绘制像素
for i = 1:length(indNC)
    if all(RGB(i, :) == 1)
    else
        tind = find(indC == i);
        [ti, tj] = ind2sub([pixN, pixN], tind);
        ii = repmat(ti, [1, 4]); jj = repmat(tj, [1, 4]); 
        xx = jj - repmat([0,1,1,0], [size(jj,1), 1]);
        yy = pixN + 1 - ii - repmat([0,0,1,1], [size(ii,1), 1]);
        fill(xx.', yy.', RGB(i,:))
        textC = (mean(RGB(i,:)) < .5).*[1,1,1];
        if showCName
        text(tj - .5, pixN + .5 - ti, CName{i}, 'FontSize',fontSZ, 'Color',textC, ...
            'FontName','Times New Roman', 'HorizontalAlignment','center')
        end
    end
end
fill([-1,pixN,pixN,-1], [-1,-1,0,0], [17,112,189]./255, 'EdgeColor','none')
fill([-1,-1,0,0], [-1,pixN,pixN,-1], [17,112,189]./255, 'EdgeColor','none')
for i = 1:pixN
    text([-.5; i - .5], [i - .5; -.5], num2str(i), 'FontSize',fontSZ+1, 'Color','w', ...
        'FontName','Times New Roman', 'HorizontalAlignment','center')
end

% 绘制网格线
xx = [-1:pixN; -1:pixN; nan(1, pixN + 2)]; 
yy = [zeros(1, pixN + 1) - 1; ones(2, pixN + 1).*pixN];
plot([xx(:); yy(:)], [yy(:); xx(:)], 'LineWidth',.5, 'Color',[0,0,0])
xx = [-1, 0:5:pixN; -1, 0:5:pixN; nan(1,length(0:5:pixN)+1)]; 
yy = [zeros(1,length(0:5:pixN)+1) - 1; ones(2,length(0:5:pixN)+1).*pixN];
plot([xx(:); yy(:)], [yy(:); xx(:)], 'LineWidth',1, 'Color',[0,0,0])

if strcmp(palettePos, 'bottom')
    colN = floor((pixN + 1.5)/(3.5));
    for i = 1:length(indNC)
        fill([-1,2,2,-1] + mod(i - 1, colN)*3.5, [-1.5,-1.5,-2.5,-2.5] - floor((i-1)/colN)*1.5, RGB(i,:))
        textC = (mean(RGB(i,:)) < .5).*[1,1,1];
        text(mod(i - 1, colN)*3.5 + .5, - 2 - floor((i-1)/colN)*1.5, [CName{i}, ' (',num2str(countC(i)),')'], ...
            'FontSize',fontSZ+1, 'Color',textC, ...
            'FontName','Times New Roman', 'HorizontalAlignment','center')
    end
else
    rowN = floor((pixN + 1.5)/(1.5)); 
    for i = 1:length(indNC)
        fill([0,3,3,0] + pixN + .5 + floor((i-1)/rowN)*3.5, pixN + [0,0,-1,-1] - mod(i - 1, rowN)*1.5, RGB(i,:))
        textC = (mean(RGB(i,:)) < .5).*[1,1,1];
        text(pixN + 2 + floor((i-1)/rowN)*3.5, pixN -.5 - mod(i - 1, rowN)*1.5, [CName{i}, ' (',num2str(countC(i)),')'], ...
            'FontSize',fontSZ+1, 'Color',textC, ...
            'FontName','Times New Roman', 'HorizontalAlignment','center')
    end
end

axis tight

压缩包

相关推荐
机器学习之心3 小时前
MATLAB基于PSO-GA的铁路工程施工进度计划多目标优化研究
matlab·多目标优化
kaikaile19955 小时前
34节点配电网牛顿-拉夫逊潮流计算 + 分布式电源(DG)多场景分析的 MATLAB
开发语言·分布式·matlab
gihigo199810 小时前
MATLAB数值分析方程求解方法详解
算法·机器学习·matlab
轻微的风格艾丝凡11 小时前
Simulink 在汽车工业中的深度应用与技术实践
matlab·汽车·simulink
ghie909016 小时前
MATLAB/Simulink水箱水位控制系统实现
开发语言·算法·matlab
hoiii18717 小时前
基于交替方向乘子法(ADMM)的RPCA MATLAB实现
人工智能·算法·matlab
fengfuyao98517 小时前
MATLAB的加权K-means(Warp-KMeans)聚类算法
算法·matlab·kmeans
fie888919 小时前
基于循环谱分析的盲源分离信号处理MATLAB
开发语言·matlab·信号处理
yong999019 小时前
MATLAB倍频转换效率分析与最佳匹配角模拟
开发语言·前端·matlab