Reading Images in .mat format in Python

Adnan_Farooq: <p>Hello I have recently moved from MATLAB to python for deep learning task. I have Matlab saved images in .mat format.<br>
I found this code which has folder structure for labelling the data similar to mine. So I decide to adopt that code and modify it to read .mat files.<br>
Each .mat file has the size 256x256x11 (11 is the number of channels.). I also found that I can load the .mat files using Scipy.io.loadmat(). But I am not sure where I have to add that and what other things I need to change.</p>
<p><a href="https://github.com/aymericdamien/TensorFlow-Examples/blob/master/examples/5_DataManagement/build_an_image_dataset.py?fbclid=IwAR3CINDwgtv7WkencdJj_yBYEbrYkLOLw88aaxh-csQwEvEKmmh5_KsdzA8" rel="nofollow noopener">https://github.com/aymericdamien/TensorFlow-Examples/blob/master/examples/5_DataManagement/build_an_image_dataset.py?fbclid=IwAR3SQfEkXimVUlUsExcVxuoIsCSd2hhVn0WmhgJibnyojujOKWgMQX_ZZE8</a></p>

Swarchal: <p>I think writing a custom Dataset class with <code>scipy.io.loadmat()</code> in your <code>__getitem__()</code> method would be the easiest option. Although with 11 channels you won’t be able to convert/transform them with PIL.</p>
<p>It depends how you have your dataset structured but something like this:</p>
<pre><code class="lang-python">class MyDataset(Dataset):
    """custom dataset for .mat images"""

    def __init__(self, list_of_urls):
        self.list_of_urls = list_of_urls

    def __len__(self):
        return len(self.list_of_urls)

    def __getitem__(self, index):
        image_url = self.list_of_urls[index]
        image = scipy.io.loadmat(image_url)
        label = ...
        ...
       
</code></pre>

Adnan_Farooq: <p>The Functions you have defined is working like first readig the list of files in a folder then extracting from files from that folder one by one?</p>
<p>The other solution I was thinking In on main root directory I have 7 folder (7 classes). Each folder have 100 images. So reading each images folder by folder and putting it in one 4D array… 256x256x11x700 or seven different arrays</p>
<blockquote>
<p>import glob<br>
DATASET_PATH = ‘D:/Dataset/Multi-resolution_data/Visual/High/’  # the dataset file or root folder path.<br>
files = [f for f in glob.glob(DATASET_PATH + “**/*.mat”, recursive= True)]<br>
for f in files:<br>
print(files[1])</p>
</blockquote>

Swarchal: <aside class="quote no-group" data-username="Adnan_Farooq" data-post="3" data-topic="55016">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/adnan_farooq/48/8879_2.png" class="avatar"> Adnan_Farooq:</div>
<blockquote>
<p>The Functions you have defined is working like first readig the list of files in a folder then extracting from files from that folder one by one?</p>
</blockquote>
</aside>
<p>Yes, although using the <code>Dataset</code> class you can pass this to a <code>DataLoader</code> and use multiple workers to load and perform any pre-processing in parallel.</p>
<aside class="quote no-group" data-username="Adnan_Farooq" data-post="3" data-topic="55016">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/adnan_farooq/48/8879_2.png" class="avatar"> Adnan_Farooq:</div>
<blockquote>
<p>The other solution I was thinking In on main root directory I have 7 folder (7 classes). Each folder have 100 images. So reading each images folder by folder and putting it in one 4D array… 256x256x11x700 or seven different arrays</p>
</blockquote>
</aside>
<p>That’s also an option if you have enough memory to load the 256*256*11*n array at once, and will be much quicker than lazily loading images from disk.</p>
<p>Since you have your classes in separate folders, there is also the option of sub-classing <a href="https://pytorch.org/docs/stable/torchvision/datasets.html#imagefolder" rel="noopener nofollow ugc"><code>ImageFolder</code></a> to load .mat files, though I’ve never tried this.</p>

Adnan_Farooq: <p>I have tried the ImageFolder class but it only supports image formats not working with .mat files.<br>
Can you pls give me how can i make a loop to read the files from directory and store in 4D array?</p>

Swarchal: <p>If you really want to go the 4D array route this is how I would approach it (might not be optimal).<br>
Note that <code>scipy.io.loadmat()</code> returns a dictionary so you’ll need to know the name of the variable stored within it.</p>
<pre><code class="lang-python">import glob
import os

DATASET_PATH = "D:/Dataset/Multi-resolution_data/Visual/High/"
VARIABLE_NAME = "example"
files = glob.glob(DATASET_PATH + “**/*.mat”, recursive= True)

class_labels = [i.split(os.sep)[-2] for i in files]
class_dict = {label: index for index, label in enumerate(set(class_labels))}
class_idxs = [class_dict[label] for label in class_labels]

array_store = []
 
for f in files:
    mat_dict = scipy.io.loadmat(f)
    img = mat_dict[VARIABLE_NAME]
    array_store.append(img)

stacked_array = np.stack(array_store, axis=3)

# convert to torch.tensor ...
</code></pre>

Adnan_Farooq: <p>When I just simply try to load any single file like<br>
As you mentioned earlier that it gives a dictionary so i thought to check it. Its actually an image of 256x256x11. Is there any other way i can chage the format of data and load in python easily?<br>
from <a href="http://scipy.io" rel="nofollow noopener">scipy.io</a> import loatmat<br>
img = loadmat(‘D:/Dataset/Multi-resolution_data/Visual/High/1/image100_256.mat’)</p>
<p>It gives an error:</p>
<pre><code class="lang-auto">Traceback (most recent call last):

  File "&lt;ipython-input-28-d42e90ca2d13&gt;", line 1, in &lt;module&gt;
    mat_dict = loadmat('D:/Dataset/Multi-resolution_data/Visual/High/1/image100_256.mat');

  File "d:\python\python37\lib\site-packages\scipy\io\matlab\mio.py", line 217, in loadmat
    MR, _ = mat_reader_factory(f, **kwargs)

  File "d:\python\python37\lib\site-packages\scipy\io\matlab\mio.py", line 78, in mat_reader_factory
    raise NotImplementedError('Please use HDF reader for matlab v7.3 files')

NotImplementedError: Please use HDF reader for matlab v7.3 files</code></pre>

Adnan_Farooq: <aside class="quote no-group quote-modified" data-username="Swarchal" data-post="6" data-topic="55016">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/swarchal/48/4477_2.png" class="avatar"> Swarchal:</div>
<blockquote>
<p>class_dict = {label: index for label, index in enumerate(set(class_labels)}</p>
</blockquote>
</aside>
<p>This line is showing syntax error and i am not exactly getting what it is doing.</p>

Swarchal: <p>Ah good catch, that line is all kinds of wrong. It was supposed to convert your class labels into integers, but it looks like you already have them labelled as integers so it is redundant.</p>
<p>As for opening matlab v7.3 it looks like scipy will not work and you will have to use <code>h5py</code> instead.</p>

skjerns: <p>I’ve implemented a library that can read the <code>mat 7.3</code> files, have a look here:</p>
<p><a href="https://github.com/skjerns/mat7.3" rel="nofollow noopener">https://github.com/skjerns/mat7.3</a></p>
<p>or install via pip <code>pip install mat73</code> and load with</p>
<pre><code class="lang-auto">import mat73
data_dict = mat73.loadmat('data.mat')
</code></pre>