图像质量评估系统的Matlab GUIDE实现(二)——处理

在导入完图像后,接下来是选择参与的算法,GUIDE默认点击让该多选框的value改变,不用自己挨个写在callback函数里。

三、评估按钮(pushbutton3):

点击后会将右侧的图像和导入参考图像按钮隐藏掉(腾出空间显示结果和日志)。使用warning('off')关闭警告,使用tic,toc计时。使用diary('xxxx.txt')用来写入运行时在命令行窗口显示的中间结果、提示等,diary on开始写入 diary off停止。首先,对于全局图像I1(和I2),可能存在图像过大或过小的问题,首先将图像缩放到合适的大小,如果是全参考方法可能存在两个图不一样大的问题,首先在pushbutton3的callback中调用自定义函数prepossess进行图像的如预处理:
 

function prepossess(hObject, eventdata, handles)
if exist('rs.mat')
    
else
    scale=1;
    save('rs.mat','scale');
end
load('rs.mat')
global I1;
global I1_s;
global I2;
global I2_s;
scale_s=power(2,scale-1);
I1_s=imresize(I1,1/(scale_s));
if get(handles.radiobutton1,'Value')
    I2_s=imresize(I2,1/(scale_s));
end
%将I2调整到I1 相同大小
% 大于1000或小于100则调整
[m1 n1 d1]=size(I1_s);
if m1<100 
    I1_s=imresize(I1_s,[500,500/m1*n1],'bicubic');
elseif m1>1000
    I1_s=imresize(I1_s,[500,500/m1*n1],'bicubic');
end

if get(handles.radiobutton1,'Value')
    [m2 n2 d2]=size(I2_s);
    if sum(abs(size(I1_s)-size(I2_s)))~=0
        if size(I1_s,1)

I1_s和I2_s为I1、2处理后的图像,后续评估的都是处理后的图像,该函数前半截先读取rs.mat(如果没有那就把1写入)数据先缩放(下采样)[在之后介绍],之后根据大小,如果高小于100或大于1000,那么等比例双三次插值(bicubic)缩放到高为500,如果两个图不一样大(sum(abs(size-size))~=0),那么高度稍大的图像会调整到另一图像等大。

2.调用完prepossess后,buttonpush3_callback函数使用全局图像I1_s,I2_s,

(1)如果是全参考(RF),添加路径(addpath,用于读取算法)检查checkbox的值,用来创建存放结果的元组stringcell【使用元组原因:每个元素的类型可以不同,每行的列数可以不同】。遍历时控件名的获取:

                                          eval(strcat('handles.checkbox',num2str(i)))

如果该checkbox的value为1,则计数+1,(代码中出现i为多少,再次加1,是因为有的checkbox对应多个算法,即如果该checkbox打勾,就输出多个算法的结果)。

置stringcell的下标index为0,再次遍历每个checkbox是否打勾,由于每个checkbox对应的算法和处理结果不尽相同,所以是挨个写的。如果该checkbox打勾:index自增1,然后进度条更新:

mywaitbar(index/num,handles,['Start to Calculate MSE and PSNR     ',num2str(floor(index*100/num)),'%']);

num为算法总数,[]内为显示的文字和百分数。

之后调用对应的算法(放于某目录下),获得返回值,写入stringcell的第index行,一共四列,分别为算法名,分数,最高分数(手动赋值),归一化后分数(线性映射到【0,1】区间,0最低,1最高)。

遍历结束后,执行mywaitbar(1,handles,'Calculate success.');显示计算完成。

(2)无参考同理(NF)

执行完后,toc计时结束,diary off写入结束。调用自定义函数possess处理

(3)possess:

大致目的:读取rs.mat【之后提到】,获得三个值radp(决定保留几位),ef(有效数字),fn(是否强制归一化),如果不存在mat则写入。对里边的数进行有效数字(vpa)和小数点后保留位数(round)的处理,并根据fn的值对一些不可归一化(最大值不存在或趋向于某个值)的归一化分数那列置为“---”,并在stringcell的第五列(新的一列)写入可修改的数值(其他列不可修改),数值为1/行数,也就是权值,默认为平均,用户可在界面修改。如果修改的数值不为数字,则会弹出提示并清空。最后显示在uitable。(令uitable的data为string_s),string_s为stringcell处理后的元组。

function possess(hObject, eventdata, handles,stringcell)
if exist('var.mat')%存在 则读入
    
else
    radp=4;%小数点后保留几位数字
    ef=8;%总有效数字
    fn=1;%强制归一化
    save('var.mat','radp','ef','fn');
end
load('var.mat')
[m,n]=size(stringcell);
string_s=cell(m,n+1);
for i=1:m
    string_s{i,5}=1/m;
    string_s{i,1}=stringcell{i,1};%名
    if fn==0 &&(strcmp(string_s{i,1},'CNR_NSS') || strcmp(string_s{i,1},'UIQM') || strcmp(string_s{i,1},'PSNR') || strcmp(string_s{i,1},'JND'))%默认为归一化 如果 不采用强制归一化则把对应设置为'---'
        string_s{i,2}=char(vpa(round(stringcell{i,2},radp),ef));
        string_s{i,3}='---';
        string_s{i,4}='---';
    else 
        string_s{i,2}=char(vpa(round(stringcell{i,2},radp),ef));
        if ischar(stringcell{i,3})
            string_s{i,3}=stringcell{i,3};
        else
            string_s{i,3}=char(vpa(round(stringcell{i,3},radp),ef));
        end
        if ischar(stringcell{i,4})
            string_s{i,4}=stringcell{i,4};
        else
            string_s{i,4}=char(vpa(round(stringcell{i,4},radp),ef));
        end
    end
end
set(handles.uitable,'Visible','on');
set(handles.uitable,'Data',string_s);
set(handles.uitable,'ColumnEditable',[false,false,false,false,true]);%只有最后一列可编辑
set(handles.pushbutton5,'Visible','on');

(4)总的push_callbutton3代码:

function pushbutton3_Callback(hObject, eventdata, handles)%执行按钮
set(handles.pushbutton2,'Visible','off');
warning('off');
diary('D:\log_run.txt');
diary on;
tic;
prepossess(hObject, eventdata, handles);
global I1_s;
global I2_s;

if get(handles.radiobutton1,'Value')%关闭第二个图的显示
    set(handles.axes2,'Visible','off')
    set(handles.pushbutton2,'Visible','off')
end
index=0;%stringcell 的 下索引
%%%%%RF%%%%%%%

if get(handles.radiobutton1,'Value')
    addpath('RF')
    addpath('RF/mallat')
    addpath('RF/vif')
    addpath('RF/sift2')
    num=0;
    for i=1:8 %检查8个checkbox打勾情况
        if get(eval(strcat('handles.checkbox',num2str(i))),'Value')
            num=num+1;
            if i==1 || i==6
                num=num+1;
            end
        end
    end
    stringcell=cell(num,4); %多行字符串 num行2列 第一列  算法名字 第二列 分数 第五列 可编辑的加权
    if get(handles.checkbox1,'Value')%第一个方法
        mywaitbar(index/num,handles,['Start to Calculate MSE and PSNR     ',num2str(floor(index*100/num)),'%']);
        [PSNR, MSE] = mseandpsnr(I1_s, I2_s);
        index=index+1;
        stringcell{index,1}='MSE';
        stringcell{index,2}=MSE;
        stringcell{index,3}=0;%mse  最高分 0 最低分 255*255
        stringcell{index,4}=(65025-MSE)/65025;
        index=index+1;
        stringcell{index,1}='PSNR';
        stringcell{index,2}=PSNR;
        stringcell{index,3}=Inf;
        stringcell{index,4}=strcat(num2str(PSNR),'/Inf');
        mywaitbar(index/num,handles,['MSE and PSNR Get      ',num2str(floor(index*100/num)),'%']);
    end
    %第二个方法
    if get(handles.checkbox2,'Value')
        mywaitbar(index/num,handles,['Start to Calculate JND     ',num2str(floor(index*100/num)),'%']);
        JND=mallat(I1_s);
        JND2=mallat(I2_s);
        index=index+1;
        stringcell{index,1}='JND';
        stringcell{index,2}=JND;
        stringcell{index,3}=JND2;
        stringcell{index,4}=JND/JND2;
        mywaitbar(index/num,handles,['JND Get      ',num2str(floor(index*100/num)),'%']);
    end
    if get(handles.checkbox4,'Value')
        K = [0.05 0.05];
        window = ones(8);
        L = 100;
        mywaitbar(index/num,handles,['Start to Calculate SSIM     ',num2str(floor(index*100/num)),'%']);
        [mssim, ~] = ssim(rgb2gray(I1_s), rgb2gray(I2_s), K, window, L);
        index=index+1;
        stringcell{index,1}='SSIM';
        stringcell{index,2}=mssim;
        stringcell{index,3}=1;
        stringcell{index,4}=mssim;
        mywaitbar(index/num,handles,['SSIM Get      ',num2str(floor(index*100/num)),'%']);
    end
    if get(handles.checkbox5,'Value')
        mywaitbar(index/num,handles,['Start to Calculate SIExt     ',num2str(floor(index*100/num)),'%']);
        [SIExT] = SIExt(I1_s,I2_s);
        index=index+1;
        stringcell{index,1}='SIExt';
        stringcell{index,2}=SIExT;
        stringcell{index,3}=1;
        stringcell{index,4}=SIExT;
        mywaitbar(index/num,handles,['SIExt Get      ',num2str(floor(index*100/num)),'%']);
    end
    if get(handles.checkbox6,'Value')
        mywaitbar(index/num,handles,['Start to Calculate QILV     ',num2str(floor(index*100/num)),'%']);
        [QILV] = qilv(I1_s,I2_s);
        index=index+1;
        stringcell{index,1}='QILV';
        stringcell{index,2}=QILV;
        stringcell{index,3}=1;
        stringcell{index,4}=QILV;
        mywaitbar(index/num,handles,['QILV Get      ',num2str(floor(index*100/num)),'%']);
        mywaitbar(index/num,handles,['Start to Calculate PCQI     ',num2str(floor(index*100/num)),'%']);
        [mpcqi,~] = PCQI(I1_s,I2_s);
        index=index+1;
        stringcell{index,1}='PCQI';
        stringcell{index,2}=mpcqi;
        stringcell{index,3}=1;
        stringcell{index,4}=mpcqi;
        mywaitbar(index/num,handles,['PCQI Get      ',num2str(floor(index*100/num)),'%']);
        
    end
    if get(handles.checkbox7,'Value')
        mywaitbar(index/num,handles,['Start to Calculate VIF     ',num2str(floor(index*100/num)),'%']);
        vif=FR_VIF(double(rgb2gray(I1_s)),double(rgb2gray(I2_s)));
        index=index+1;
        stringcell{index,1}='VIF';
        stringcell{index,2}=vif;
        stringcell{index,3}=1;
        stringcell{index,4}=vif;
        mywaitbar(index/num,handles,['VIF Get      ',num2str(floor(index*100/num)),'%']);
    end
    if get(handles.checkbox8,'Value')
        mywaitbar(index/num,handles,['Start to Calculate FD     ',num2str(floor(index*100/num)),'%']);
        fd=FD(I1_s,I2_s);
        index=index+1;
        stringcell{index,1}='FD';
        stringcell{index,2}=fd;
        stringcell{index,3}=1;
        stringcell{index,4}=fd;
        mywaitbar(index/num,handles,['FD Get      ',num2str(floor(index*100/num)),'%']);
    end
    mywaitbar(1,handles,'Calculate success.');
end
%%%%NF%%%%
if get(handles.radiobutton2,'Value')
    num=0;
    for i=1:5 %检查4个checkbox打勾情况
        if get(eval(strcat('handles.checkbox',num2str(i))),'Value')
            num=num+1;
            if i==5
                num=num+3;
            end
        end
    end
    stringcell=cell(num,4); 
    addpath('NF')
    addpath('NF/BRISQUE')
    addpath('NF/ContrastNoReference_NSS');
    if get(handles.checkbox1,'Value')%第一个方法BRISQUE
        mywaitbar(index/num,handles,['Start to Calculate BRISQUE     ',num2str(floor(index*100/num)),'%']);
        [brisque] = BRI(I1_s);
        index=index+1;
        stringcell{index,1}='BRISQUE';
        stringcell{index,2}=brisque;
        stringcell{index,3}=1;
        stringcell{index,4}=brisque;
        mywaitbar(index/num,handles,['BRISQUE Get      ',num2str(floor(index*100/num)),'%']);
    end
    if get(handles.checkbox2,'Value')%ContrastNoReference NSS
        mywaitbar(index/num,handles,['Start to Calculate CNR_NSS     ',num2str(floor(index*100/num)),'%']);
        [nss] = CNR_NSS(I1_s);
        index=index+1;
        stringcell{index,1}='CNR_NSS';
        stringcell{index,2}=nss;
        stringcell{index,3}=4;
        stringcell{index,4}=nss/4;
        mywaitbar(index/num,handles,['CNR_NSS Get      ',num2str(floor(index*100/num)),'%']);
    end
    if get(handles.checkbox4,'Value')%uciqe
        mywaitbar(index/num,handles,['Start to Calculate UCIQE     ',num2str(floor(index*100/num)),'%']);
        Coe_Metric=[0.4680    0.2745    0.2576]; 
        uciqe=UCIQE(I1_s,Coe_Metric);
        index=index+1;
        stringcell{index,1}='UCIQE';
        stringcell{index,2}=uciqe;
        stringcell{index,3}=1;
        stringcell{index,4}=uciqe;
        mywaitbar(index/num,handles,['UCIQE Get      ',num2str(floor(index*100/num)),'%']);
    end
    if get(handles.checkbox5,'Value')%uciqe
        mywaitbar(index/num,handles,['Start to Calculate UIQM     ',num2str(floor(index*100/num)),'%']);
        [UIQM_norm, colrfulness, sharpness, contrast] = UIQM(I1_s);
        index=index+1;
        stringcell{index,1}='UIQM';
        stringcell{index,2}=UIQM_norm;
        stringcell{index,3}=1.5;
        stringcell{index,4}=UIQM_norm/1.5;
        mywaitbar(index/num,handles,['UIQM Get      ',num2str(floor(index*100/num)),'%']);
        index=index+1;
        stringcell{index,1}='UIQM:colorfulness';
        stringcell{index,2}=colrfulness;
        stringcell{index,3}='---';
        stringcell{index,4}='---';
        mywaitbar(index/num,handles,['colorfulness Get      ',num2str(floor(index*100/num)),'%']);
        index=index+1;
        stringcell{index,1}='UIQM:sharpness';
        stringcell{index,2}=sharpness;
        stringcell{index,3}='---';
        stringcell{index,4}='---';
        mywaitbar(index/num,handles,['sharpness Get      ',num2str(floor(index*100/num)),'%']);
        index=index+1;
        stringcell{index,1}='UIQM:contrast';
        stringcell{index,2}=contrast;
        stringcell{index,3}='---';
        stringcell{index,4}='---';
        mywaitbar(index/num,handles,['contrast Get      ',num2str(floor(index*100/num)),'%']);
    end
    mywaitbar(1,handles,'Calculate success.');
end

toc;
diary off;
axes(handles.axes2);
cla;%关闭图二的显示
possess(hObject, eventdata, handles,stringcell);

四、显示运行日志(pushbutton4)

点击时,如果日志(text2)为开,那么将text2关闭,滑动条关闭(slider1),并置pushbutton4的String为“显示运行日志”,否则,显示text2和slider1,置string为“关闭工作日志”,从指定路径读取(fopen)txt,读取有点麻烦,在这里就不说了,需要配合slider,否则只能显示第一页。

function pushbutton4_Callback(hObject, eventdata, handles)% to display the running log
if strcmp(get(handles.text2,'Visible'),'off') %if close ,then open ;else close
    set(handles.text2,'Visible','on')
    set(handles.slider1,'Visible','on')
    set(handles.pushbutton4,'String','关闭运行日志')
    f=fopen('D:\log_run.txt');
    ch=textscan(f,'%s');

    global strcell;
    strcell=cell(floor(length(ch{1})/10),1);
    str='';
    c=1;
    len=0;
    for i=1:length(ch{1})
        str=strcat(str,32,ch{1}{i});
        len=len+1;
        if (len>10)
            len=0;
            strcell{c}=str;
            str='';
            c=c+1;
        end
    end
    set(handles.text2,'HorizontalAlignment','left')
    set(handles.text2,'String',strcell);
    row=floor(length(ch{1})/10); 
    ex=strcell;
    if row>18 % 24假设为最大显示行数        
        set(handles.text2,'String',ex(1:18));        
        % 设置滑动条位置 不能取整       
        x=18/row;        
        set(handles.slider1,'Value',(1-x));    
    else
        set(handles.text2,'String',ex);        % 设置滑动条位置        
        set(handles.slider1,'Value',0);  
    end
else
    set(handles.text2,'Visible','off')
    set(handles.slider1,'Visible','off')
    set(handles.pushbutton4,'String','显示运行日志')
end

五、滑动条(slider1)

系统给的滑动条只能滑动,但无法根据滑动的大小来改变某个地方的显示,所以需要自己写函数,在这里就用简单地实现了一下:

function slider1_Callback(hObject, eventdata, handles)
f=fopen('D:\log_run.txt');
ch=textscan(f,'%s');
global strcell;
ex=strcell;
row=floor(length(ch{1})/10);
if row>18
%     set(hObject,'Value',1-24/row);
    slider = get(hObject,'Value');
    x1=1-slider;
    % 取得当前需要显示的数据量
    num=round(row*x1);
    if num>18
        % 显示对应数据
        set(handles.text2,'String',ex(num-18:num));
    end
else
     % 显示对应数据
     set(handles.text2,'String',ex(1:row));
     set(hObject,'Value',0);
end


% --- Executes during object creation, after setting all properties.
function slider1_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

六、进度条(axes3模拟,通过mywaitbar函数调用):

x取值为[0,1],显示进度,varargin为列矩阵,存放标题名和进度数。

function mywaitbar(x,handles,varargin)
if nargin < 1
    error('Input arguments not valid');
end
set(0,'CurrentFigure',gcf);
fAxes = handles.axes3;
set(gcf,'CurrentAxes',fAxes);
if nargin > 1
    hTitle = handles.text3;
    set(hTitle,'String',varargin{1});
end
fractioninput = x;
x = max(0,min(100*x,100));
if fractioninput == 0    
    cla
    pause(0.5) % 暂停小会清除上次使用进度 
    xpatch = [0 x x 0];
    ypatch = [0 0 1 1];
    xline = [100 0 0 100 100];
    yline = [0 0 1 1 0];
    patch(xpatch,ypatch,'b','EdgeColor','b','EraseMode','none');
    set(gcf,'UserData',fractioninput);
    l = line(xline,yline,'EraseMode','none');
    set(l,'Color',get(gca,'XColor'));   
else
    p = findobj(gcf,'Type','patch');
    l = findobj(gcf,'Type','line');
    if (get(gcf,'UserData') > fractioninput)
        set(p,'EraseMode','normal');
    end
    xpatch = [0 x x 0];
    set(p,'XData',xpatch);
    xline = get(l,'XData');
    set(l,'XData',xline);  
end
drawnow;

七、计算综合权值按钮(pushbutton5):

点击时首先弹出提示来说明(errordlg),在外侧套用uiwait,需要关闭才会继续执行。如果修改的权值不为数字的话会变为nan【在uitable里设置第五列为数字的效果】,判断是否有nan,如果没有就计算,然后通过errordlg弹出最终结果,否则弹出错误提示,不计算。

function pushbutton5_Callback(hObject, eventdata, handles)
uiwait(errordlg('由于部分算法不可归一化,综合分数计算将使用原始算法分数。','Notice'))
data=get(handles.uitable,'Data');
[m,~]=size(data);
for i=1:m
    %if isnan(str2double(data{i,5}))%检查是否不为数字
    if isnan(data{i,5}) %最后一列设为数值 若不为数值会变为nan 如果采用默认格式则按上式判断
        text=strcat('第',num2str(i),'个参数输入不为数字,请重新输入。');
        errordlg(text);
        return
    end
end
score=0;
for i=1:m
    score=score+data{i,5}*str2double(data{i,2});
end
text=strcat('最后的加权评估分数为',num2str(score));
errordlg(text,'结果');

 

你可能感兴趣的:(图像质量)