Bit width of image

Ganga: <p>how can i know  my image pixel bit width ?</p>

Kushaj: <p>It is same as the number channels of the image * 8.</p>

ptrblck: <p>As <a class="mention" href="/u/kushaj">@Kushaj</a> said, True color RGB images will use a bit depth of 24 (8 for each channel).<br>
However, your images can of course come from another domain, which might use another bit depth value.<br>
E.g. depth images often use a single channel with 16 bits, while Dicom images might use 12 bits.</p>
<p>If you can load the image via <code>PIL</code>, you could check the <code>image.depth</code> or <code>image.mode</code> attributes.</p>

Ganga: <p>But my maximum and minimum value of my image pixel are 151.47 and -119.675,basically if we keep 1bit for signbit and again we require more than 8bit  for integer bit itself<br>
there is a bitoverflow here</p>

ptrblck: <p>If you max and min values are 151.47 and -119.675, respectively, your image would be encoded in a floating point format, not a 8bit integer.<br>
I don’t fully understand the use case. What did <code>image.depth</code> or <code>image.mode</code> return?</p>

Ganga: <p>Sorry <a class="mention" href="/u/ptrblck">@ptrblck</a> for very late reply,I am getting <strong>mode as RGB</strong> ,and for <strong>depth</strong> I am getting <strong>AttributeError: ‘JpegImageFile’ object has no attribute 'depth’</strong></p>

ptrblck: <p>It’s a bit strange, that Jpeg images in RGB return floating point values, as I would assume they are encoded using <code>uint8</code>. Could you post the results of:</p>
<pre><code class="lang-python">img = # load image
a = np.array(img)
print(np.max(a), np.min(a), a.dtype)
</code></pre>

Ganga: <pre><code class="lang-auto">img = Image.open("/content/XNOR-Net-PyTorch/ImageNet/networks/data/val/n01440764/ILSVRC2012_val_00002138.JPEG")

    a = np.array(img)

    print(np.max(a),np.min(a),a.dtype) -&gt; (255, 0, dtype('uint8'))</code></pre>

ptrblck: <p>Thanks for the update.<br>
How do these min and max values fit to your previously reported values of <code>151.47</code> and <code>-119.675</code>?</p>

Ganga: <p>my image undergoes transforms,so I guess from that i am getting those values</p>
<pre><code class="lang-auto">val_loader = torch.utils.data.DataLoader(
                datasets.ImageFolder(valdir, transforms.Compose([
                    transforms.Resize((256, 256)),
                    transforms.CenterCrop(input_size),
                    transforms.ToTensor(),
                    normalize,
                    ])),
                batch_size=args.batch_size, shuffle=False,
                num_workers=args.workers, pin_memory=True)```</code></pre>

ptrblck: <p><code>ToTensor</code> normalizes <code>unit8</code> images to the range <code>[0, 1]</code>, so the <code>normalize</code> transformation would need to use a really small <code>std</code> to blow these values up again.</p>
<p>Anyway, as you can see from your previous post, the bit width is 8bit for your images: <code>dtype('uint8')</code>.</p>

Ganga: <ul>
<li>as ’  uint8 suggest all pixel values must be positive right? but after undergoing transforms my input has a negative value</li>
</ul>

ptrblck: <p><code>transforms.Normalize</code> subtracts the <code>mean</code> and divides by the <code>std</code> so negative and positive values are expected. However, they are usually smaller in magnitude than your reported values, so feel free to post a full code snippet to reproduce these values.</p>

Ganga: <ul>
<li>here is the code where i am getting input</li>
</ul>
<pre><code class="lang-auto">def validate(val_loader, model, criterion):
    batch_time = AverageMeter()
    losses = AverageMeter()
    top1 = AverageMeter()
    top5 = AverageMeter()

    # switch to evaluate mode
    model.eval()

    end = time.time()
    bin_op.binarization()
    for i, (input, target) in enumerate(val_loader):
        target = target.cuda(async=True)
        with torch.no_grad():
            input_var = torch.autograd.Variable(input)
            target_var = torch.autograd.Variable(target)
            print(input_var)
 

        # compute output
        output = model(input_var)
        loss = criterion(output, target_var)```

* this is how my input sample look like,I am getting **floating point** as input altough it is in encoded in **uint8**

* So i round it off to nearest integer as to get 8 bit value

print(input_var)

```27.325001 13.325003 -56.674995 -62.674999 -66.675003 -70.675003
    -64.675003 -57.674995 -18.675001 18.325003 -2.675003 3.324996
    12.325003 16.325003 25.325001 -14.675002 1.324996 -12.675002
    -27.674999 -38.674999 -23.675001 -23.675001 -37.674999 -16.675001
    57.324997 -46.674999 -72.675003 -74.675003 -78.675003 -102.674995
    -98.675003 -81.675003 19.325003 104.324989 101.324989 125.324989
    125.324989 120.324989 125.324989 128.324982 127.324989 128.324982
    125.324989 121.324989 123.324989 126.324989 126.324989 108.324989
    110.324989 128.324982 128.324982 129.324982 129.324982 129.324982
    129.324982 127.324989 129.324982 127.324989 122.324989 125.324989
    129.324982 129.324982 127.324989 127.324989 129.324982 128.324982
    129.324982 129.324982 130.324982 130.324982 128.324982 127.324989
    128.324982 126.324989 128.324982 129.324982 128.324982 128.324982
    127.324989 128.324982 128.324982 130.324982 129.324982 130.324982
    130.324982 131.324982 131.324982 129.324982 129.324982 129.324982
    129.324982 129.324982 129.324982 129.324982 127.324989 128.324982
    128.324982 117.324989 14.325003 15.325003 21.325001 51.324997
    -5.675003 -97.675003 -96.675003 -94.675003 -93.675003 -81.675003
    60.324997 121.324989 119.324989 119.324989 121.324989 125.324989
    125.324989 120.324989 119.324989 127.324989 128.324982 127.324989
    118.324989 2.324996 -84.675003 -90.675003 -95.675003 -96.675003
    -97.675003 -68.675003 33.325001 -0.675003 59.324997 103.324989```</code></pre>

jiapei100: <p>What if it’s <strong>NOT uint8</strong>, <strong>BUT uint16</strong> ?<br>
Will <code>ToTensor()</code> normalize <code>uint16 images</code> to <code>[0,1]</code> also?</p>

ptrblck: <p>No, I don’t think so as seen here:</p>
<pre><code class="lang-python">a = np.random.randint(0, 65535, (224, 224, 3), dtype=np.uint16)
img = PIL.Image.fromarray(a, 'I;16')

transform = transforms.ToTensor()
out = transform(img)
print(out.min(), out.max())
# tensor(-32767, dtype=torch.int16) tensor(32767, dtype=torch.int16)
</code></pre>
<p>As you can see, it’ll also transform the data to <code>int16</code> <a href="https://github.com/pytorch/vision/blob/d0d7058a36fb4ea702dcb6c92c03d90ca91d8281/torchvision/transforms/functional.py#L163">here</a> as <code>uint16</code> is an unsupported tensor type.</p>
<p>CC <a class="mention" href="/u/fmassa">@fmassa</a> <a class="mention" href="/u/vfdev-5">@vfdev-5</a> <a class="mention" href="/u/pmeier">@pmeier</a><br>
I guess this is intentional due to the lack of <code>uint16</code> support in <code>torch.from_numpy</code>?</p>

dsethz: <p><a class="mention" href="/u/ptrblck">@ptrblck</a> what is the reason that <code>torch</code> does not support <code>uint16</code>?</p>

ptrblck: <p>I would guess <code>uint16</code> wasn’t added as a <code>dtype</code> because the demand for it might not be that huge since you could use e.g. <code>int32</code> with a memory overhead.<br>
Since these integer types are also used for inputs mainly (the model won’t be able to train with these <code>dtype</code>s directly) the memory overhead might also be negligible.<br>
Adding a new <code>dtype</code> would need to be piped through all methods increasing the binary size significantly, which is another argument against adding new types unless their use cases justify it.</p>

dsethz: <p>Makes sense.</p>
<p>Just for your information: probably a niche domain, but 16bit grayscale images are commonly used in microscopy imaging.</p>

ptrblck: <p>Yes, I agree that 16bit image formats are used, but do you think a native <code>dtype</code> would be still needed to be added via <code>uint16</code> to PyTorch?<br>
I would assume the common approach would be to load these images (e.g. via <code>PIL</code>, <code>OpenCV</code>, or another image library which supports this format), and transform it to a floating point format tensor (<code>float32</code> by default) which is then used to train the model.<br>
Which operations would you like to apply directly on the <code>uint16</code> image in PyTorch?</p>