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

压缩包

相关推荐
Dev7z16 小时前
基于 MATLAB 的铣削切削力建模与仿真
开发语言·matlab
fengfuyao98518 小时前
基于MATLAB的表面织构油润滑轴承故障频率提取(改进VMD算法)
人工智能·算法·matlab
机器学习之心18 小时前
基于随机森林模型的轴承剩余寿命预测MATLAB实现!
算法·随机森林·matlab
rit843249921 小时前
基于MATLAB的环境障碍模型构建与蚁群算法路径规划实现
开发语言·算法·matlab
hoiii18721 小时前
MATLAB SGM(半全局匹配)算法实现
前端·算法·matlab
yong99901 天前
MATLAB面波频散曲线反演程序
开发语言·算法·matlab
yugi9878381 天前
基于MATLAB的一键式EMD、EEMD、CEEMD和SSA信号去噪实现
开发语言·matlab·信号去噪
youcans_1 天前
【STM32-MBD】(15)Simulink 模型开发之三相互补 PWM
stm32·单片机·嵌入式硬件·matlab·foc
机器学习之心1 天前
基于CNN-GRU(卷积神经网络-门控循环单元)的多变量负荷预测模型MATLAB代码
matlab·cnn·gru
3GPP仿真实验室1 天前
【Matlab源码】6G候选波形:OFDM-IM 索引调制仿真平台
开发语言·matlab