Per channel Normalization

username: zehranrgi
cooked: <p>Hi,<br>
For the medical images, I have to normalize each image’s channel one by one. So for that, I created this code :</p>
<pre><code class="lang-auto">def normalizeImage(paths):
    img = cv2.imread(paths)
    normImg = np.zeros(img.shape)
    k = 0

    for i in range(img.shape[2]):
        if(img[:, :, i].std() != 0):
            normImg[:, :, i] = (img[:, :, i] - img[:, :, i].mean()) / (img[:, :, i].std())
            k +=1
            # print(k)
            if k ==3:
                array_list.append(normImg)
    return normImg
</code></pre>
<p>then converting them to tensors:</p>
<pre><code class="lang-auto">tensor_x = torch.Tensor(np.array(array_list))
tensor_y = ....
my_dataset = TensorDataset(tensor_x,tensor_y) 
my_dataloader = DataLoader(my_dataset,batch_size=16)
</code></pre>
<p>However, I couldn’t continue after that. I have three directories:<br>
train: wound/ no_wound<br>
test<br>
val</p>
<p>I am open to applying new methods. How can I do that for the whole dataset?</p>
<pre><code class="lang-auto">        if(img[:, :, i].std() != 0):
            normImg[:, :, i] = (img[:, :, i] - img[:, :, i].mean()) / (img[:, :, i].std())
</code></pre>

username: ParGG
cooked: <p>For a single image you can use this which is more efficient.</p>
<pre><code class="lang-python">def normalizeImage(path: str) -&gt; torch.Tensor:
        img = cv2.imread(paths)
        img_tensor = torch.tensor(img, dtype= torch.float)
        return (img_tensor - img_tensor.mean([0, 1])) / img_tensor.std([0, 1])
</code></pre>
<p>To apply it to the whole dataset, just add it to the <code>__getitem__</code> method of your dataset. <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>

username: zehranrgi
cooked: <p>But the formula that you shared is not the same thing. It doesn’t update each channel, does it? <img src="https://discuss.pytorch.org/images/emoji/apple/frowning.png?v=12" title=":frowning:" class="emoji" alt=":frowning:" loading="lazy" width="20" height="20"></p>

username: ParGG
cooked: <aside class="quote no-group" data-username="ParGG" data-post="2" data-topic="156719">
<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/pargg/48/50503_2.png" class="avatar"> ParGG:</div>
<blockquote>
<p><code>(img_tensor - img_tensor.mean([0, 1])) / img_tensor.std([0, 1])</code></p>
</blockquote>
</aside>
<p>It does, here you can see that the returned tensor has the mean for each channel subtracted and then it’s divided channel-wise by the std (broadcasting takes care of the dimensionality). You can store the returned tensor in a variable and check that the mean and std for each channel are 0 (approximately, it will be really small) and 1 respectively.</p>
<p>Maybe you can add an epsilon to the std just to avoid divisions by zero.</p>

username: zehranrgi
cooked: <pre><code class="lang-auto">    def __getitem__(self, idx):
        img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
        image = read_image(img_path) // or cv2.imread()
        label = self.img_labels.iloc[idx, 1]
       
        img_tensor = torch.tensor(image , dtype= torch.float)
        image=  (img_tensor - img_tensor.mean([0, 1])) / img_tensor.std([0, 1]
        return image, label
</code></pre>
<p>Is it true implementation?</p>

username: ParGG
cooked: <p>I cannot guarantee about the first 3 lines of code, but yes. It looks correct <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>Just make sure that the layout is the same, openCV returns (H,W,C). If you use <code>read_image</code>, make sure that the layout is also like that, otherwise you won’t normalise with respect to the channels but to another dimension.</p>