Search code examples
image-processingjuliaijulia-notebook

How to import a integer tif file in Julia


I have a tif image in which its pixel are integers. I want to import it to Julia and process it further. I used in IJulia:

using FileIO
using Images
using ImageView
path_seed = joinpath(@__DIR__,"seed.tif")
seed = load(path_seed);

When I enter seed and enter I will get an image while I want the matrix of elements. If I use:

mat = convert(Array{Float32}, seed)

I will get a matrix but there are two problems:

1- Its entries are all float but not an integer.

2- The value of the float does not correspond to the value of integers I expect. For example, in my images there are values 0,1,2,3,4 (the image is a mask and each connected component have values of 0,1,2,3,4) but I get floats 0.0, 0.011764707, 0.015686275, 0.007843138, 0.003921569.

How can I import the image as a matrix of integers? Here is the sample image:

http://s000.tinyupload.com/index.php?file_id=21432720633236092551


Solution

  • When you load that file, you're seeing the effects of two of the key abstractions of JuliaImages:

    • every pixel is a single entry in an array (not, e.g., 3 entries if it's an RGB image)
    • numbers mean what they say they are. In particular, 255 ≠ 1.0.

    When you load your seed.tif image, you'll note that the returned values are of type Gray{N0f8}. The Gray part means it has been interpreted as a grayscale image---had it been a color image, they might have been elements like RGB{N0f8}(1.0, 0.8, 0.4). In either case, accessing img[i,j] returns all the information about that whole pixel.

    The part you're probably most concerned about is the N0f8. In most image-processing frameworks, the meaning of a number depends on its representation (e.g., https://scikit-image.org/docs/stable/user_guide/data_types.html). "White" is 255 if your numbers are encoded as UInt8, but white is 1.0 if your numbers are encoded as Float32. When you want to change the representation, you have to remember to use special conversion functions that also change the values of the pixels. In no other field of mathematics am I aware of the equality 255 == 1.0.

    To stop encouraging bad mathematics, JuliaImages has gone to the trouble to define new number types that harmonize these notions. In JuliaImages, white is always 1. But to support 8-bit images, we define a new number type, N0f8, with 8 bits whose maximum value is 1. These are internally represented just like UInt8, they are just interpreted as if they have been divided by 255. Similarly, there are N0f16 for 16-bit images, and even special types like N4f12 that are useful, e.g., if you're collecting images with a 12-bit camera. This means it's possible to detect image saturation simply by looking for pixels with value 1.

    Of course, sometimes you might want to look at things differently. JuliaImages supports several "views" that provide an alternative interpretation of the same bitwise data. In your case,

    rawview(channelview(seed))
    

    would return an array of UInt8 values which might be what you're expecting.

    Note, however, that if you want to save an array of integers that shouldn't really be interpreted as an image, there are possibly better formats such as HDF5. Image formats are sometimes subject to compression that can corrupt the values you save. TIFF is often called lossless, but in fact it's possible to use lossy compression (https://en.wikipedia.org/wiki/TIFF).