MATLAB 像素画绘制APP

1 前言

比较难过的是MALAB GUI功能将要被移除,很多很好用的功能和函数MATLAB APP都还没有实现方式,这里尝试使用编程的方式调用APP控件制作像素画绘制APP。

2 绘画效果

在这里插入图片描述
像素画绘制效果:
在这里插入图片描述
图中的左侧是画板部分,只需要对网格中的空隙进行点击,便可填充颜色,可以选择增强网格或弱化网格,效果如下:
弱化网格:
在这里插入图片描述
增强网格:
在这里插入图片描述

3 颜色选择

首先界面的右上角有一调色盘,只需要通过滑动条调整蓝色所占比例,再点击调色盘即可调整颜色,图中白叉位置即为所选颜色:
在这里插入图片描述
同时程序支持直接对RGB颜色的数字进行调整,调色盘中白叉位置和数值调整面板中数值会同步变化:
在这里插入图片描述

4 图片的储存

非常难过,对于uifigure,无论是imwrite,saveas都无法使用,对于uiaxes,getframe也无法使用,而toolbar我们又难以内部调用,这导致我们如果想要通过按钮存储图片,只能将uifirgue转化为figure,将uiaxes转化为axes,再使用相应的函数进行储存,
因此,即使我编写了图像存储按钮,我依旧的推荐将笔刷调整至橡皮,再使用uiaxes自带的toolbar进行图片储存,如图右上角所示:
在这里插入图片描述

5 后续更新

当前版本界面(2.0)
在这里插入图片描述
更新内容:
1.可通过输入十六进制码改变颜色。
在这里插入图片描述
2.输入框输入精度限制为整数。
3.增添微调器,方便快速微调数值。
在这里插入图片描述

6 完整代码

版本(2.0)

function pixelPicApp
global pixelPicFig pixelPicAxes1 pixelPicAxes2 pixelPicSlider
global pixelPicLabelR pixelPicNumericR pixelPicLabelG pixelPicNumericG pixelPicLabelB pixelPicNumericB
global pixelPicLabel16 pixelPicNumeric16
global pixelPicLabel4 pixelPicNumeric4 pixelPicPresentColorLabrl pixelPicPresentColor
global colorMapPic colorMapPos pixelPos pixelColor presentColor
global pixelPicBrushExchange pixelPicClearAll pixelPicBoldGrid pixelPicSavePic
pixelPicFig=uifigure('units','pixels',...
    'position',[320 100 880 520],...
    'Numbertitle','off',...
    'menubar','none',...
    'resize','off',...
    'name','pixelPic 2.0 | by slandarer',...
    'color',[0.95 0.95 0.95]);
TickLabelcoe=zeros(1,33);
TickLabelcoe=num2cell(TickLabelcoe);
for i=1:33,TickLabelcoe{i}=[];end
pixelPicAxes1=uiaxes('Units','pixels',...
      'parent',pixelPicFig,...
      'PlotBoxAspectRatio',[1 1 1],...
      'Position',[20 20 480 480],...
      'Color',[0.99 0.99 0.99],...
      'Box','on', ...
      'XLim',[0 480],...
      'YLim',[0 480], ...
      'YDir','reverse', ...
      'XColor',[0.5,0.5,0.5],'YColor',[0.5,0.5,0.5],...
      'XTickLabel',TickLabelcoe,...
      'YTickLabel',TickLabelcoe,...
      'XTick',0:15:480,'YTick',0:15:480,...
      'Tag','drawboard',...
      'XGrid','on','YGrid','on',...
      'GridColor',[0.5,0.5,0.5],'GridColorMode','manual');
pixelPicAxes2=uiaxes('Units','pixels',...
      'parent',pixelPicFig,...
      'PlotBoxAspectRatio',[1 1 1],...
      'Position',[500 205 300 300],...
      'Color',[0.98 0.98 0.98],...
      'XLim',[0 255],...
      'YLim',[0 255], ...
      'YDir','reverse', ...
      'XColor',[0.95 0.95 0.95],'YColor',[0.95 0.95 0.95],...
      'Tag','pallet');
%pixelPicAxes1.Toolbar.Visible='off';
pixelPicAxes2.Toolbar.Visible='off';

pixelPicSlider=uislider('parent',pixelPicFig,...
      'value',150,'Limits',[0 255],...
      'Orientation','vertical',...
      'ValueChangedFcn',@moveSlider,...
      'Position',[815 265 3 230]);
%==========================================================================
pixelPicBrushExchange=uibutton('parent',pixelPicFig,...
    'position',[700,170,170,40],...
    'Text','切换至 橡皮',...
    'FontWeight','bold',...
    'FontColor',[0.27 0.25 0.25],...
    'tag','brush',...
    'ButtonPushedFcn',@bruchExchange,...
    'BackgroundColor',[0.98 0.99 0.94],...
    'FontSize',15);
pixelPicClearAll=uibutton('parent',pixelPicFig,...
    'position',[700,120,170,40],...
    'Text','清除全部图像',...
    'FontWeight','bold',...
    'FontColor',[0.27 0.25 0.25],...
    'ButtonPushedFcn',@clearAll,...
    'BackgroundColor',[0.98 0.99 0.94],...
    'FontSize',15);
pixelPicBoldGrid=uibutton('parent',pixelPicFig,...
    'position',[700,70,170,40],...
    'Text','增强网格线',...
    'FontWeight','bold',...
    'tag','NORM',...
    'ButtonPushedFcn',@boldGrid,...
    'FontColor',[0.27 0.25 0.25],...
    'BackgroundColor',[0.98 0.99 0.94],...
    'FontSize',15);
pixelPicSavePic=uibutton('parent',pixelPicFig,...
    'position',[700,20,170,40],...
    'Text','存储当前图像',...
    'FontWeight','bold',...
    'ButtonPushedFcn',@savePic,...
    'FontColor',[0.27 0.25 0.25],...
    'BackgroundColor',[0.98 0.99 0.94],...
    'FontSize',15);
%==========================================================================
pixelPicLabel16=uilabel('parent',pixelPicFig,'Text',' 十六进制码:',...
    'FontSize',15,'BackgroundColor',[0.85 0.85 0.85],'position',[527,133,165,26]);
pixelPicNumeric16=uieditfield(pixelPicFig,'Value','#000096',...
    'ValueChangedFcn',@input16Data,'position',[615,136,73,20],'HorizontalAlignment','right');

pixelPicLabelR=uilabel('parent',pixelPicFig,'Text',' R:',...
    'FontSize',15,'BackgroundColor',[0.85 0.85 0.85],'position',[527,80+15,130,27]);
pixelPicNumericR=uispinner(pixelPicFig,'Value',0,'limit',[0 255],...
    'ValueDisplayFormat','%.0f','ValueChangedFcn',@editData,'position',[570,81+15,85,25]);

pixelPicLabelG=uilabel('parent',pixelPicFig,'Text',' G:',...
    'FontSize',15,'BackgroundColor',[0.85 0.85 0.85],'position',[527,50+7.5,130,27]);
pixelPicNumericG=uispinner(pixelPicFig,'Value',0,'limit',[0 255],...
    'ValueDisplayFormat','%.0f','ValueChangedFcn',@editData,'position',[570,51+7.5,85,25]);

pixelPicLabelB=uilabel('parent',pixelPicFig,'Text',' B:',...
    'FontSize',15,'BackgroundColor',[0.85 0.85 0.85],'position',[527,20,130,27]);
pixelPicNumericB=uispinner(pixelPicFig,'Value',150,'limit',[0 255],...
    'ValueDisplayFormat','%.0f','ValueChangedFcn',@editData,'position',[570,21,85,25]);

pixelPicLabel4=uilabel('parent',pixelPicFig,...
    'Text',' B:',...
    'BackgroundColor',[0.85 0.85 0.85],...
    'position',[810,229,62,22]);
pixelPicNumeric4=uieditfield(pixelPicFig,'numeric',...
    'Editable','off','Value',150,...
    'ValueDisplayFormat','%.0f',...
    'position',[830,230,40,20]);
pixelPicPresentColorLabrl=uilabel('parent',pixelPicFig,...
    'Text',' 当前颜色:',...
    'BackgroundColor',[0.85 0.85 0.85],...
    'FontSize',15,...
    'position',[527,171,165,38]);
pixelPicPresentColor=uieditfield('parent',pixelPicFig,...
    'Editable','off','Value','',...
    'BackgroundColor',[0 0 1],...
    'position',[615,176,73,28]);
%==========================================================================
set(pixelPicFig,'WindowButtonDownFcn',@whileclickfcn)
pixelPos=[0 0];pixelPos(1,:)=[];
pixelColor=[0 0 0];pixelColor(1,:)=[];
[colorMapXgrid,colorMapYgrid]=meshgrid(linspace(0,1,256),linspace(0,1,256));
colorMapPic(:,:,1)=colorMapXgrid;
colorMapPic(:,:,2)=colorMapYgrid;
colorMapPic(:,:,3)=ones(256,256).*150./255;
imshow(colorMapPic,'Parent',pixelPicAxes2)
presentColor=[0 0 1];
colorMapPos=[0 0];
%==========================================================================
function savePic(~,~)
    try
    new_fig=figure('units','pixels',...
    'position',[0 0 460 460],...
    'Numbertitle','on',...
    'menubar','none',...
    'visible','off',...
    'resize','off',...
    'color',[0.95 0.95 0.95]);
    new_axes=axes('Units','pixels',...
    'parent',new_fig,...
    'PlotBoxAspectRatio',[1 1 1],...
    'Position',[1.5 1.5 459.5 459.5],...
    'Color',[0.99 0.99 0.99],...
    'Box','on', ...
    'XLim',[0 480],...
    'YLim',[0 480], ...
    'YDir','reverse', ...
    'XColor',[0.5,0.5,0.5],'YColor',[0.5,0.5,0.5],...
    'XTickLabels',TickLabelcoe,...
    'YTickLabels',TickLabelcoe,...
    'XTick',0:15:480,'YTick',0:15:480,...
    'XGrid','on','YGrid','on',...
    'GridAlpha',get(pixelPicAxes1,'GridAlpha'),...
    'GridColor',get(pixelPicAxes1,'GridColor'),'GridColorMode','manual');
    hold on
    scatter(new_axes,pixelPos(:,1),pixelPos(:,2),185,'s','filled','CData',pixelColor)
    [filename, pathname] = uiputfile({'*.jpg;*.png','All Image Files';...
            '*.jpg','JPG';'*.png','PNG' });
    saveas(new_fig,[pathname,filename]);
    catch
    end
end
function clearAll(~,~)
    pixelPos=[0 0];pixelPos(1,:)=[];
    pixelColor=[0 0 0];pixelColor(1,:)=[];
    scatter(pixelPicAxes1,pixelPos(:,1),pixelPos(:,2),185,'s','filled','CData',pixelColor)
end
function boldGrid(~,~)
    switch 1
        case strcmp(get(pixelPicBoldGrid,'tag'),'BOLD')
            set(pixelPicBoldGrid,'tag','NORM')
            set(pixelPicBoldGrid,'Text','增强网格线')
            set(pixelPicAxes1,'GridColor',[0.5,0.5,0.5])
            set(pixelPicAxes1,'GridAlpha',0.15)
        case strcmp(get(pixelPicBoldGrid,'tag'),'NORM')
            set(pixelPicBoldGrid,'tag','BOLD')
            set(pixelPicBoldGrid,'Text','弱化网格线')
            set(pixelPicAxes1,'GridColor',[0 0 0])
            set(pixelPicAxes1,'GridAlpha',0.65)
    end
end
function bruchExchange(~,~)
    switch 1
        case strcmp(get(pixelPicBrushExchange,'tag'),'brush')
            set(pixelPicBrushExchange,'tag','eraser')
            set(pixelPicBrushExchange,'Text','切换至 笔刷')
        case strcmp(get(pixelPicBrushExchange,'tag'),'eraser')
            set(pixelPicBrushExchange,'tag','brush')
            set(pixelPicBrushExchange,'Text','切换至 橡皮')
    end
end
function editData(~,~)
    set(pixelPicSlider,'value',get(pixelPicNumericB,'value'));
    set(pixelPicNumeric4,'value',get(pixelPicNumericB,'value'));
    colorMapPic(:,:,3)=ones(256,256).*get(pixelPicSlider,'value')./255;
    colorMapPos=[get(pixelPicNumericR,'value'),get(pixelPicNumericG,'value')];
    imshow(colorMapPic,'Parent',pixelPicAxes2)   
    hold(pixelPicAxes2,'on')
    scatter(pixelPicAxes2,colorMapPos(1),colorMapPos(2),120,'w+','LineWidth',1)
    hold(pixelPicAxes2,'off')
    presentColor=[get(pixelPicNumericR,'value'),get(pixelPicNumericG,'value'),get(pixelPicNumericB,'value')]./255;
    tempMat=[get(pixelPicNumericR,'value'),get(pixelPicNumericG,'value'),get(pixelPicNumericB,'value')];
    tempString=ten2sixteen(tempMat);
    set(pixelPicNumeric16,'value',tempString);  
    set(pixelPicPresentColor,'BackgroundColor',presentColor);
end
function moveSlider(~,~)
    set(pixelPicNumeric4,'value',get(pixelPicSlider,'value'));
    colorMapPic(:,:,3)=ones(256,256).*get(pixelPicSlider,'value')./255;   
    imshow(colorMapPic,'Parent',pixelPicAxes2)  
    hold(pixelPicAxes2,'on')
    scatter(pixelPicAxes2,colorMapPos(1),colorMapPos(2),120,'w+','LineWidth',1)
    hold(pixelPicAxes2,'off')
end
function whileclickfcn(~,~)
        xy=get(pixelPicFig,'CurrentPoint');
        x=xy(1);y=xy(2);
        switch 1
            case x>=20&&x<=500&&y>=0&&y<=500&&strcmp(get(pixelPicBrushExchange,'tag'),'brush')
                xyIndrawboard=get(pixelPicAxes1,'CurrentPoint');
                xIndrawboard=round((xyIndrawboard(1,1)+7.5)/15)*15-7.5;
                yIndrawboard=round((xyIndrawboard(1,2)+7.5)/15)*15-7.5;
                pixelPos=[pixelPos;[xIndrawboard,yIndrawboard]];
                pixelColor=[pixelColor;presentColor];
                scatter(pixelPicAxes1,pixelPos(:,1),pixelPos(:,2),185,'s','filled','CData',pixelColor)
            case x>=500&&x<=800&&y>=205&&y<=505
                xyInpallet=get(pixelPicAxes2,'CurrentPoint');
                xyInpallet=round(xyInpallet);
                xyInpallet=xyInpallet(1,1:2);
                xyInpallet(xyInpallet>255)=255;
                xyInpallet(xyInpallet<0)=0;
                colorMapPos=xyInpallet;     
                imshow(colorMapPic,'Parent',pixelPicAxes2)   
                hold(pixelPicAxes2,'on')
                scatter(pixelPicAxes2,colorMapPos(1),colorMapPos(2),120,'w+','LineWidth',1)
                hold(pixelPicAxes2,'off')
                presentColor=[xyInpallet,get(pixelPicSlider,'value')]./255;
                tempMat=[xyInpallet,round(get(pixelPicSlider,'value'))];
                tempString=ten2sixteen(tempMat);
                set(pixelPicNumeric16,'value',tempString);      
                set(pixelPicPresentColor,'BackgroundColor',presentColor);
                set(pixelPicNumericR,'value',xyInpallet(1));
                set(pixelPicNumericG,'value',xyInpallet(2));
                set(pixelPicNumericB,'value',round(get(pixelPicSlider,'value'))); 
            case x>=20&&x<=500&&y>=0&&y<=500&&strcmp(get(pixelPicBrushExchange,'tag'),'eraser')
                xyIndrawboard=get(pixelPicAxes1,'CurrentPoint');
                xIndrawboard=round((xyIndrawboard(1,1)+7.5)/15)*15-7.5;
                yIndrawboard=round((xyIndrawboard(1,2)+7.5)/15)*15-7.5;
                tempPos=[xIndrawboard,yIndrawboard];
                tempcoe=sum(abs(pixelPos-tempPos),2)==0;
                pixelPos(tempcoe,:)=[];
                pixelColor(tempcoe,:)=[];
                scatter(pixelPicAxes1,pixelPos(:,1),pixelPos(:,2),185,'s','filled','CData',pixelColor)
        end       
end
function input16Data(~,~)
    tempString=get(pixelPicNumeric16,'value');
    tempNum=sixteen2ten(tempString);
    if ~isnan(tempNum)
        presentColor=tempNum./255;
        set(pixelPicPresentColor,'BackgroundColor',presentColor);
        set(pixelPicNumericR,'value',tempNum(1));
        set(pixelPicNumericG,'value',tempNum(2));
        set(pixelPicNumericB,'value',tempNum(3)); 
        colorMapPic(:,:,3)=ones(256,256).*tempNum(3)./255;
        colorMapPos=tempNum(1:2);
        imshow(colorMapPic,'Parent',pixelPicAxes2)   
        hold(pixelPicAxes2,'on')
        scatter(pixelPicAxes2,colorMapPos(1),colorMapPos(2),120,'w+','LineWidth',1)
        hold(pixelPicAxes2,'off')
        set(pixelPicNumeric4,'value',tempNum(3));
        set(pixelPicSlider,'value',tempNum(3));
    end
end
function num=sixteen2ten(string)
    exchange_list='0123456789ABCDEF#';
    ismember(string,exchange_list)
    num=zeros(1,3);
    if all(ismember(string,exchange_list))
        for ii=1:3
            tempCoe1=find(ismember(exchange_list,string(ii*2))==1)-1;
            tempCoe2=find(ismember(exchange_list,string(ii*2+1))==1)-1;
            num(ii)=16*tempCoe1+tempCoe2;
        end
    else
        num=nan;
    end
end
function string=ten2sixteen(num)
%the num should be a 1x3 Integer mat limited in [0 255]
exchange_list={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
string='#';
for ii=1:3
    temp_num=num(ii);
    string(1+ii*2-1)=exchange_list{(temp_num-mod(temp_num,16))/16+1};
    string(1+ii*2)=exchange_list{mod(temp_num,16)+1};
end
end
end
7 更新日志
日期版本号更新内容
2020.7.41.01.将想法最初使用的axes及figure,使用UIaxes及UIfigure替代。
2.实现绘画版像素绘画功能。
3.通过meshgrid构造三维矩阵,并通过imshow将其以图片形式展示,实现了调色板的基本功能。
4.初步完成按钮及数值输入框的外形塑造, 实现基础功能。
2020.7.51.51.通过转化为axes及figure方式实现存储图片功能。
2.调整了数值输入框及滑动条的精度,令其保留小数点后一位。
2020.7.72.01.完成了通过输入十六进制码改变颜色的模块
2.调整了数值输入框及滑动条的精度,令其保留整数。
3.为数值输入框增添微调按钮,方便快速微调数值。
8 作品展示

只是画着玩呀,不要吐槽色不准,真想要颜色准确,我不是还有个颜色提取程序嘛
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

slandarer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值