Convert image tensor to numpy image array

M_S: <p>Hi, let’s say I have a an image tensor (not a minibatch), so its dimensions are (3, X, Y).<br>
I want to convert it to numpy, for applying an opencv manipulation on it (writing text on it).<br>
Calling .numpy() works fine, but then how do I rearrange the dimensions, for them to be in numpy convention (X, Y, 3)?<br>
I guess I can use img.transpose(0, 1).transpose(1, 2) but just wondering if there’s any smoother bridge to numpy.</p>

jmandivarapu1: <p>I have below implementation which can flatten and unflatten both the net itself.Hopefully you can use some of that.</p>
<pre><code class="lang-auto">import numpy as np

#############################################################################
# Flattening the NET
#############################################################################
def flattenNetwork(net):
    flatNet = []
    shapes = []
    for param in net.parameters():
        #if its WEIGHTS
        curr_shape = param.cpu().data.numpy().shape
        shapes.append(curr_shape)
        if len(curr_shape) == 2:
            param = param.cpu().data.numpy().reshape(curr_shape[0]*curr_shape[1])
            flatNet.append(param)
        elif len(curr_shape) == 4:
            param = param.cpu().data.numpy().reshape(curr_shape[0]*curr_shape[1]*curr_shape[2]*curr_shape[3])
            flatNet.append(param)
        else:
            param = param.cpu().data.numpy().reshape(curr_shape[0])
            flatNet.append(param)
    finalNet = []
    for obj in flatNet:
        for x in obj:
            finalNet.append(x)
    finalNet = np.array(finalNet)
    return finalNet,shapes


#############################################################################
# UN-Flattening the NET
#############################################################################
def unFlattenNetwork(weights, shapes):
    #this is how we know how to slice weights

    begin_slice = 0
    end_slice = 0
    finalParams = []
    #print(len(weights))
    for idx,shape in enumerate(shapes):
        if len(shape) == 2:
            end_slice = end_slice+(shape[0]*shape[1])
            curr_slice = weights[begin_slice:end_slice]
            param = np.array(curr_slice).reshape(shape[0], shape[1])
            finalParams.append(param)
            begin_slice = end_slice
        elif len(shape) == 4:
            end_slice = end_slice+(shape[0]*shape[1]*shape[2]*shape[3])
            curr_slice = weights[begin_slice:end_slice]
            #print("shape: "+str(shape))
            #print("curr_slice: "+str(curr_slice.shape))
            param = np.array(curr_slice).reshape(shape[0], shape[1], shape[2], shape[3])
            finalParams.append(param)
            begin_slice = end_slice
        else:
            end_slice = end_slice+shape[0]
            curr_slice = weights[begin_slice:end_slice]
            param = np.array(curr_slice).reshape(shape[0],)
            finalParams.append(param)
            begin_slice = end_slice
    finalArr = np.array(finalParams)
    return np.array(finalArr)
</code></pre>
<pre><code class="lang-auto"> flat_weights,shapes=flattenNetwork(model)
unFlattenNetwork(flat_weights,shapes) --Gives you Numpy n-dimensional array in your case the image which you can directly assign to a variable
</code></pre>

ptrblck: <p>You have to permute the axes at some point. Usually I do: <code>x.permute(1, 2, 0).numpy()</code> to get the numpy array.<br>
If I recall correctly, <code>np.transpose</code> should also take multiple axis indices.</p>
<p>As an alternative, you could use a transform from torchvision, e.g. <code>torchvision.transforms.ToPILImage()(x)</code> and maybe use a <code>PIL</code> function to draw on your image.</p>

M_S: <p>Some excellent ideas here, thanks</p>

mathematics: <p>How to reverse the action of<code> .unsqueeze(0)</code><br>
I have tried to use<br>
<code>torchvision.transforms.ToPILImage()(x)</code></p>
<p>to change tensor to PIL .<br>
In 3rd dimension , it works correctly giving right output</p>
<pre><code class="lang-auto">torch.Size([3, 224, 224])
(224, 224, 3)
</code></pre>
<p>but when using 4 dimension tensor gives error saying<br>
torch.Size([1, 3, 224, 224])<br>
<code>ValueError: pic should be 2/3 dimensional. Got 4 dimensions.</code></p>
<p>How can i reverse tensor [1, 3, 224, 224] to [3, 224, 224]  ?<br>
Thank you for helping <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

ptrblck: <p><code>tensor = tensor.squeeze(0)</code> should work.</p>

mathematics: <p>Oh thank you  , I hadnt seen if squeeze() before. Now  squeeze()  working. <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

Hayat_Ullah: <p>if x is a tensor image, you can simply do this using x[0], which will give you [3,224,224].</p>

Hae_Yong_Kim: <p>It seems that you have to use np.swapaxes (instead of transpose). If you have a tensor image ten [3, 32, 32], then:<br>
img=ten.numpy()<br>
img=np.swapaxes(img,0,1)<br>
img=np.swapaxes(img,1,2)<br>
will convert it to numpy image img [32, 32, 3].</p>

MarketMaster: <p>Very Very useful Tips!<br>
I love your gorgeous comment! <img src="https://discuss.pytorch.org/images/emoji/apple/slightly_smiling_face.png?v=12" title=":slightly_smiling_face:" class="emoji" alt=":slightly_smiling_face:" loading="lazy" width="20" height="20"><br>
Thx!!</p>

bpfrd: <p>Usually, tensor images are float and between 0 to 1 but np images are uint8 and pixels between 0 to 255. So you need to do an extra step:<br>
np.array(x.permute(1, 2, 0)*255, dtype=np.uint8)</p>