Save data structure in existing .mat-file without nesting

671 Views Asked by At

I have created a simple GUI that when I press a button (SAVE), the system takes the value of some fields, calculates a certain function and saves the results in a data structure. I would like this data structure to be external to the program, that is to say it remains at the exit of Matlab and at the next opening of the program this data structure must be available and upgradable.

To do this I used a global data variable that I save and load when needed.

The problem is that it doesn't work properly, the data structure is filled strangely.

I show you a gif that is perhaps more explanatory: enter image description here

The saved structure is this: enter image description here

As you can see, there is a structure within the other and not a list of elements. Why?

I would like to have a data structure that contains n elements (where n is the number of images) and each element consists of 9 fields (name, category, siftOctaves, siftLevels, siftPeak, siftEdge, numFeatures, siftFeatures, siftDescriptors).

This is a piece of code:

%% SAVE BUTTON
function pushSiftSave_Callback(hObject, eventdata, handles)
    % hObject    handle to pushSiftSave (see GCBO)
    % eventdata  reserved - to be defined in a future version of MATLAB
    % handles    structure with handles and user data (see GUIDATA)
    global data;

    try
        % Vector of string = name of all possible images 
        imgs = createListOfImages('../img/');
        % Get selected image
        imgName = get(handles.listbox, 'Value');
        imgPath = strcat('../img/', imgs(imgName));
        imgPath = imgPath{1};
        I_or = imread(imgPath);
        I = single(rgb2gray(I_or));

        % Get some parameters enter by user
        [siftOctaves, siftLevels, siftPeak, siftEdge] = takeSiftParameters(handles.editSiftOctaves, handles.editSiftLevels, handles.editSiftPeakTh, handles.editSiftEdgeTh, I_or);  

        % Sift function
        [f, d] = vl_sift(I, 'Octaves', siftOctaves, 'Levels', siftLevels, 'PeakThresh', siftPeak, 'EdgeThresh', siftEdge);

        % Number of features
        perm = randperm(size(f, 2));
        numFeatures = size(perm, 2);

        % Check if file exists
        if exist('../data/data.mat', 'file') == 2 
            data = load('../data/data');
        else
            data = struct;
        end
        % Insert information in data structure
        data = saveSiftInformation(data, imgs, imgPath, siftOctaves, siftLevels, siftPeak, siftEdge, f, d, numFeatures);

    catch
        ErrorMessage = lasterr;
        msgbox(ErrorMessage);
        disp(ErrorMessage);
    end



function [data] = saveSiftInformation(data, imgs, imgPath, siftOctaves, siftLevels, siftPeak, siftEdge, features, descriptors, numFeatures)
    imgPath = imgPath(8 : end);

    % Find index of image
    i = find((ismember(imgs, imgPath)));

    % Update data structure
    data(i).name = imgPath;
    data(i).category = imgPath(1 : end-6);
    data(i).siftOctaves = siftOctaves;
    data(i).siftLevels = siftLevels;
    data(i).siftPeak = siftPeak;
    data(i).siftEdge = siftEdge;
    data(i).numFeatures = numFeatures;
    data(i).siftFeatures = features;
    data(i).siftDescriptors = descriptors;

    % Save data 
    save('../data/data', 'data');
end


%% SAVE & QUIT BUTTON.
function pushQuit_Callback(hObject, eventdata, handles)
    % hObject    handle to pushQuit (see GCBO)
    % eventdata  reserved - to be defined in a future version of MATLAB
    % handles    structure with handles and user data (see GUIDATA)
    global data;
    assignin('base', 'data', data);

Thanks!

2

There are 2 best solutions below

0
On BEST ANSWER

The problem you're facing is generated when you load the data.mat file.

Also, using data as the name of variable reurned by load contributes to generating confusion.

The instruction

data = load('../data/data')

reads the data.mat and stores the "data" it contains in a struct named data therefore, your struct is actually a filed of the struct data returned by load.

You can test it by setting a breakpoint just after the load call and inspecting the varialbe data.

You can fix the problem by extracting the data field from the structure when loading the .mat file.

if(exist('data.mat', 'file') == 2)
%    data = load('data');
   tmp = load('data');
   data=tmp.data
else
   data = struct;
end

Hope this helps,

Qapla'

2
On

By using the output variable of the load function you are storing the variable data from your .mat-file to a struct called data - so it gets nested. Just use load without any output and it will work.

if exist('data.mat', 'file') == 2 
    %// data = load('data');  % does not work!
    load('data');  % does work!
else
    data = struct;
end

data(1).a = 42;
data(2).a = 3;
data(1).b = 41;
data(2).b = 4;

%// make sure you just store what you want to store, in this case "data"
save('data.mat','data')

Also I would avoid declaring data a global variable. Instead you could use the fact, that all functions of your GUI are part of the same figure window and therefore have the figure handle available:

hFig = gcf;

It is further allowed to add dynamic properties do your instance of figure, so just store your data in the figure handle itself:

hFig = gcf;
addprop(hFig,'globalData')

data = struct;
hFig.globalData = data;

% ...

and in the next function you just do:

data = hFig.globalData