本文介绍如何用matlab控制Excel画画。

对于matlab和Excel你的认识不能仅仅停留在xlsread和xlswrite这两个函数上,其实matlab对Excel的操作远远不止于此,详情请见matlab和Excel的交互。

所谓在Excel中画画,无非就是通过填充Excel单元格的背景色实现像素点的表达,都可以通过matlab中的Excel.Application实现。

try   % 打开Excel
    Excel=actxGetRunningServer('Excel.Application');
catch 
Excel=actxserver('Excel.application');
end

% 设置Excel可见

Excel.visible=1;

添加工作簿和工作表

Workbook=Excel.Workbooks.Add;
Sheet1=Workbook.Sheets.Item(1);

下面实现图像的读取,这里用到了imread函数,可以读取图片的RGB值,用三维的数组存储,数据格式为uint8,但是Excel中是用24位的二进制表示颜色,前8位为B,中间8位为G,后8位为R,所以需要先用double强制转换数据类型。

A=imread('图片路径');
A=double(A);

然后就是分别得到R,G,B:

column=size(A,2);
row=size(A,1);
Red=A(:,:,1);
Green=A(:,:,2);
Blue=A(:,:,3);

为了使得颜色设置更加方便,这里我自己写了一个RGB函数,用于将RGB转换成Excel的格式:

function out=RGB(Red,Green,Blue)
if nargin~=3
    error('输入参数错误,RGB输入参数为3个,分别为RGB,0~255')
end
if length(Red)==length(Green)&length(Blue)==length(Green)
Red=Red;
Green=Green*2^8;
Blue=Blue*2^16;
out=Red+Green+Blue;
else
    error('输入维度不匹配');
end
end

得到的输出能够直接给Excel使用。

修改Excel单元格的背景色可以使用以下代码:

Sheet1.Range(范围).Interior.Color = RGB;   
% 其中Sheet1为工作表,Range内为范围 格式为 'A1' 或‘A1:C3’

为了能够更方便得到范围的正确格式,我也自己写了一个格式转换的函数,将坐标值转换成字母组合:

function Range=Cells(first,second)
% ======================================================================
% 输入参数为单个坐标或者左上角以及右上角坐标,返回结果可用于Excel的Range输入
% Cells(first, second);
% first = n second = m; 或 first = [n1,m1],second = [n2 m2]
% ======================================================================
% 返回结果:
% Cells(1,2)---------------------------'A2'
% Cells([26*2 1],[26*27 1])------------ 'AZ1:ZZ1'
if nargin ==1
    if length(first)==2
        second=first(2);
        first=first(1);
    end
elseif nargin>2
    error('Cells输入错误,输入单元格坐标或区域的对角坐标');
end
if length(first)==length(second)&&length(first)==1
    if first<=0||second<=0
        error('坐标不能小于1')
    end
    if first<=26
        charNum=1;
    elseif first<=26*26+26
        charNum=2;
    else
        error('图片像素过大,请剪辑');
    end
    switch charNum
        case 1
            if mod(first,26)==0
                Column1='Z';
            else
                Column1=char('@'+mod(first,26));
            end
            Range=[Column1 num2str(second)];
            
        case 2
            first=first-26;
            if mod(first,26*26)==0
                Column1='Z';
            else
            Column1=char(floor(first/26)+'A');
            end
            if mod(first,26)==0
                Column2='Z';
                Column1=char(floor(first/26)+'@');
            else
                Column2=char('@'+mod(first,26));
            end
            Range=[Column1 Column2 num2str(second)];
    end
    
elseif length(first)==length(second)&&length(first)==2
    if first(1)<second(1)
        error('左上角坐标在右下角坐标前');
    end
    if sum(first>0)+sum(second>0)<4
        error('坐标不能小于1')
    end
    if first(1)<=26
        charNum1=1;
    elseif first(1)<=26*26+26
        charNum1=2;
    else
        error('图片像素过大,请剪辑');
    end
    switch charNum1
        case 1
            if mod(first(1),26)==0
                Column11='Z';
            else
                Column11=char('@'+mod(first(1),26));
            end
            Range1=[Column11 num2str(first(2))];
        case 2
            first(1)=first(1)-26;
            if mod(first(1),26*26)==0
                Column11='Z';
            else
            Column11=char(floor(first(1)/26)+'A');
            end
            if mod(first(1),26)==0
                Column12='Z';
                Column11=char(floor(first(1)/26)+'@');
            else
                Column12=char('A'+mod(first(1),26));
            end
            Range1=[Column11 Column12 num2str(first(2))];
    end
    if second(1)<=26
        charNum2=1;
    elseif second(1)<=26*26+26
        charNum2=2;
    else
        error('图片像素过大,请剪辑');
    end
    switch charNum2
        case 1
            if mod(second(1),26)==0
                Column21='Z';
            else
                Column21=char('@'+mod(second(1),26));
            end
            Range2=[Column21 num2str(second(2))];
        case 2
            second(1)=second(1)-26;
            if mod(second(1),26*26)
                Column21='Z';
            else
            Column21=char(floor(second(1)/26)+'A');
            end
            if mod(second(1),26)==0
                Column22='Z';
                Column21=char(floor(second(1)/26)+'@');
            else
                Column22=char('A'+mod(second(1),26));
            end
            Range2=[Column21 Column22 num2str(second(2))];
    end
    Range=[Range1 ':' Range2];
else
    error('Cells输入错误,输入单元格坐标或区域的对角坐标');
end


最后通过一个二维的for循环即可实现自动填充,效果如下图:

0001.png

完整代码如下:

try
    Excel=actxGetRunningServer('Excel.Application');
catch 
Excel=actxserver('Excel.application');
end
% 设置Excel可见
Excel.visible=1;
Workbook=Excel.Workbooks.Add;
Sheet1=Workbook.Sheets.Item(1);
A=imread('图片路径');
A=double(A);
column=size(A,2);
row=size(A,1);
Red=A(:,:,1);
Green=A(:,:,2);
Blue=A(:,:,3);
color=RGB(Red,Green,Blue);
tic
for a=1:size(color,2) % a为列数
    for b=1:size(color,1) % b为行数
Sheet1.Range(Cells(a,b)).Interior.Color =color(b,a);
    end
end
toc
Excel.Quit; % 关闭 Excel
Excel.delete; % 删除对象