PyDIP basics

The following are some examples of using the DIPlib Python binding, PyDIP.


In [1]:
import diplib as dip

The image object

Basic image creation. The first tuple is the image size (width, height), and the second argument the number of tensor elements per pixel.


In [2]:
a = dip.Image((10,20), 1)
a.Fill(3)

Indexing into an Image object works as it does for other array types in Python. The first index is x (horizontal), the second one is y (vertical). Note that b is a view of a and shares the same data segment.


In [3]:
b = a[0:4, 4:-1]
b.Fill(55)
a[:3, :10] = 100
a[5:7, 10:15] = 200

Images can be displayed using the Show method. normal sets the range, 0-255 in this case. By default, the image is linearly stretched to the minimum and maximum values.


In [4]:
a.Show('normal')


Operators are generally applied on a per-pixel basis.


In [5]:
m = a >= 100
m.Show()


Images can be indexed by binary images, resulting in a 1D image containing only the selected pixels. Note that the order depends on the internal linear pixel storage order, which is not consistent with any specific (row-major or column-major) order due to operations such as Rotation90 and Mirror.


In [6]:
a[m].Show('normal')


Binary image indexing can also be used for assignment.


In [7]:
a[m] = 176
a.Show('normal')


An Image object uses the NumPy buffer interface. This means that you can use an Image object everywhere where you can use a NumPy array, and you can use a NumPy array anywhere where you would use an Image object.

Here we create a NumPy array and display it like it were an Image (remember that NumPy uses height as the first dimension and width as the second one, this is reverse from how PyDIP does it):


In [8]:
import numpy as np

b = np.random.rand(a.Size(1), a.Size(0))
dip.Show(b)


Then we add the NumPy array to our image:


In [9]:
a += 30 * b
a.Show()


Then we call a NumPy function with an Image as input, and a PyDIP function with a NumPy array as input:


In [10]:
print(np.mean(a))
print(dip.Mean(b)[0][0])


85.22918
0.5026392160016718

Note that the Image object can contain images of any number of dimensions, including 0 (a single pixel). The Show method only displays 1D or 2D images, for images with more dimensions, it will display a projection. Read this method's help to learn how to control the projection mode, etc. Alternatively, use dip.viewer.Show for an interactive image display that shows images with any number of dimensions.

Loading images from file

PyDIP has an image reading function dip.ImageRead, which will use the built-in image readers (ICS, TIFF, JPEG) and, if available, the Bio-Formats image readers (which recognizes hundreds of file types). It is also possible to use matplotlib.pyplot.imread, cv2.imread, etc.


In [11]:
import matplotlib.pyplot as pp

a = dip.ImageRead('../cermet.ics')
a.Show()
b = dip.Image(pp.imread('../erika.tif'))
b.Show()


Color images

Color images are supported too, it's a bit different from what you're likely used to. A 2D color image is seen as 2D, each pixel has three values. This affects indexing! Here we give a little demo, we recommend that you look through the tensor image demo notebook to learn more about images with more than one value per pixel.


In [12]:
a = dip.ImageRead('../DIP.tif')
print(a)
print(a[50:100, :])       # spatial indexing is the same as for other 2D images!
print(a(0))               # this is the red channel
print(a[128, 45])         # this returns a Python list with all the values for the pixel
print(a[128, 45][0])      # this returns the red value of one pixel
print(a(0)[128, 45])      # this also, but as a Python list


Color image (3x1 column vector, 3 elements, RGB):
    data type UINT8
    sizes {256, 256} (2D)
    strides {3, 768}, tensor stride 1
    data pointer:   0x122df4000 (shared among 1 images)
    origin pointer: 0x122df4000

Color image (3x1 column vector, 3 elements, RGB):
    data type UINT8
    sizes {51, 256} (2D)
    strides {3, 768}, tensor stride 1
    data pointer:   0x122df4000 (shared among 2 images)
    origin pointer: 0x122df4096

Scalar image:
    data type UINT8
    sizes {256, 256} (2D)
    strides {3, 768}, tensor stride 1
    data pointer:   0x122df4000 (shared among 2 images)
    origin pointer: 0x122df4000

[210, 177, 18]
210
[210]

PyDIP knows a lot of color spaces. The Show method automatically converts to RGB for display.


In [13]:
print(a.ColorSpace())
b = dip.ColorSpaceManager.Convert(a, 'Lab')
print(b.ColorSpace())
b.Show()
a(2).Show()
b(2).Show()


RGB
Lab

Filtering

There are many image filtering functions available. Because there is not yet any documentation in PyDIP, you will need to explore the DIPlib documentation. Function names and parameters in Python are identical to the names in the DIPlib library, except that the output image is always an output argument, not an input argument. Here we do some simple color filtering.


In [14]:
dip.Gauss(a, 5).Show()



In [15]:
b = dip.BilateralFilter(a, spatialSigmas=5, tonalSigma=30)
b.Show()


Some filters are specific for gray-value images (these are called "scalar images" everywhere in the documentation). For example, all morphological filters currently require a scalar image.


In [16]:
b = dip.ColorSpaceManager.Convert(b, 'gray')
dip.Canny(b, upper=0.99).Show()


Measurement

dip.MeasurementTool can measure quite a lot of features for objects in an image. This is a simple example usage.

We first read the 'cermet' image, and record its pixel size (this is an old example image, the actual pixel size has gotten lost over the years). If an image contains the pixel size in the metadata, it will automatically be recorded in the Image object and used by measurement functions and some other functions. Note that pixels do not need to be isotropic, it is possible to give a different pixel size for each dimension.


In [17]:
a = dip.ImageReadICS('../cermet')
a.SetPixelSize(dip.PixelSize(dip.PhysicalQuantity(1, "um")))
print(a.PixelSize())
a.Show()


{1 µm}

Next, we threshold and label the image, then measure some basic features. Because 'Solidity' depends on the 'ConvexArea' measurement, we get that one too in the output.


In [18]:
b = a < 120
b = dip.EdgeObjectsRemove(b)
b = dip.Label(b, minSize=30)
m = dip.MeasurementTool.Measure(b, a, ['Size', 'Solidity', 'Statistics'])
print(m)


   |       Size |   Solidity |                                            Statistics | ConvexArea | 
-- | ---------- | ---------- | ----------------------------------------------------- | ---------- | 
   |            |            |       Mean |     StdDev |   Skewness | ExcessKurtosis |            | 
   |      (µm²) |            |            |            |            |                |      (µm²) | 
-- | ---------- | ---------- | ---------- | ---------- | ---------- | -------------- | ---------- | 
 1 |      262.0 |     0.9668 |      45.34 |      30.82 |     0.7216 |        -0.6831 |      271.0 | 
 2 |      63.00 |     0.9474 |      86.35 |      13.41 |     0.2313 |        -0.5471 |      66.50 | 
 3 |      243.0 |     0.9293 |      75.09 |      21.16 |     0.1711 |        -0.9723 |      261.5 | 
 4 |      209.0 |     0.9698 |      61.63 |      25.80 |     0.3937 |        -0.7994 |      215.5 | 
 5 |      462.0 |     0.9665 |      62.10 |      20.27 |     0.7329 |         0.1613 |      478.0 | 
 6 |      611.0 |     0.9745 |      81.17 |      17.92 |    -0.3812 |        -0.2219 |      627.0 | 
 7 |      80.00 |     0.9816 |      83.10 |      15.72 |     0.1468 |        -0.7721 |      81.50 | 
 8 |      205.0 |     0.9762 |      52.92 |      32.19 |     0.1556 |         -1.183 |      210.0 | 
 9 |      419.0 |     0.9836 |      41.60 |      30.24 |     0.8653 |        -0.3741 |      426.0 | 
10 |      363.0 |     0.9041 |      71.56 |      22.25 |    -0.2541 |        -0.5946 |      401.5 | 
11 |      487.0 |     0.9740 |      57.81 |      25.17 |    0.05945 |        -0.4846 |      500.0 | 
12 |      383.0 |     0.9746 |      53.10 |      24.60 |     0.6360 |        -0.3009 |      393.0 | 
13 |      250.0 |     0.9709 |      50.21 |      30.08 |     0.6251 |        -0.8159 |      257.5 | 
14 |      137.0 |     0.9786 |      64.47 |      22.41 |     0.5215 |        -0.8983 |      140.0 | 
15 |      378.0 |     0.9668 |      64.85 |      21.35 |     0.3866 |        -0.5561 |      391.0 | 
16 |      392.0 |     0.9043 |      48.06 |      31.20 |     0.4776 |        -0.8514 |      433.5 | 
17 |      230.0 |     0.9746 |      70.43 |      23.68 |    -0.2813 |        -0.6269 |      236.0 | 
18 |      262.0 |     0.9686 |      62.26 |      25.31 |     0.3051 |        -0.7452 |      270.5 | 
19 |      637.0 |     0.9245 |      52.94 |      23.86 |     0.8441 |       -0.08530 |      689.0 | 
20 |      341.0 |     0.9757 |      54.94 |      25.06 |     0.8843 |        -0.3705 |      349.5 | 
21 |      501.0 |     0.9747 |      51.85 |      24.15 |     0.9221 |       -0.05920 |      514.0 | 
22 |      556.0 |     0.8580 |      60.65 |      22.53 |     0.5287 |        -0.3121 |      648.0 | 
23 |      592.0 |     0.8889 |      58.28 |      29.00 |     0.1195 |         -1.026 |      666.0 | 
24 |      172.0 |     0.9718 |      68.47 |      23.14 |     0.3064 |        -0.9392 |      177.0 | 
25 |      566.0 |     0.9792 |      41.71 |      30.85 |     0.7348 |        -0.5709 |      578.0 | 
26 |      842.0 |     0.9268 |      53.14 |      26.75 |     0.1291 |        -0.4931 |      908.5 | 
27 |      209.0 |     0.9676 |      56.00 |      26.01 |     0.5350 |        -0.8241 |      216.0 | 
28 |      147.0 |     0.9545 |      65.14 |      24.51 |     0.3733 |        -0.9707 |      154.0 | 
29 |      375.0 |     0.9766 |      71.89 |      21.69 |    0.06353 |        -0.7623 |      384.0 | 
30 |      385.0 |     0.9637 |      51.05 |      27.73 |     0.6729 |        -0.5471 |      399.5 | 
31 |      223.0 |     0.9612 |      63.78 |      25.31 |     0.1825 |        -0.4636 |      232.0 | 
32 |      347.0 |     0.9734 |      55.33 |      26.30 |     0.5900 |        -0.7111 |      356.5 | 
33 |      604.0 |     0.9527 |      50.44 |      26.84 |     0.6709 |        -0.5829 |      634.0 | 
34 |      354.0 |     0.9739 |      42.53 |      33.74 |     0.6403 |        -0.9280 |      363.5 | 
35 |      543.0 |     0.9696 |      50.64 |      24.14 |      1.068 |         0.3071 |      560.0 | 
36 |      147.0 |     0.9515 |      67.05 |      22.61 |     0.2393 |        -0.5154 |      154.5 | 
37 |      405.0 |     0.9000 |      83.24 |      23.60 |    -0.9721 |      0.0003058 |      450.0 | 
38 |      577.0 |     0.9714 |      30.64 |      31.71 |      1.246 |         0.2249 |      594.0 | 
39 |      497.0 |     0.9717 |      61.73 |      18.86 |      1.101 |         0.3655 |      511.5 | 
40 |      525.0 |     0.9813 |      34.06 |      31.89 |      1.047 |        -0.1825 |      535.0 | 
41 |      803.0 |     0.9634 |      54.23 |      25.55 |     0.4471 |        -0.5974 |      833.5 | 
42 |      253.0 |     0.9750 |      59.83 |      25.32 |     0.4961 |        -0.8077 |      259.5 | 
43 |      193.0 |     0.9772 |      65.91 |      23.49 |     0.4554 |        -0.8702 |      197.5 | 

The dip.Measurement object m can be indexed in three levels: the measurement name ('Statistics'), the object number (30), and the measurement value within the selected measurement (2):


In [19]:
print(m['Statistics'][30])
print(m['Statistics'][30][2])
print(m[30]['Statistics'][2])


[51.05454545454547, 27.733471736251396, 0.6729066879016448, -0.5471176839610813]
0.6729066879016448
0.6729066879016448

Leaving out one of the indices returns the full row or column:


In [20]:
print(m[30])
print(m['Solidity'])


<MeasurementObject with 4 features for object 30>
<MeasurementFeature for feature Solidity and 43 objects>

These objects can be indexed further as above, or be converted to a NumPy array:


In [21]:
import numpy as np

print(np.array(m[30]))
print(np.array(m['Solidity']).transpose())


[[385.           0.96370463  51.05454545  27.73347174   0.67290669
   -0.54711768 399.5       ]]
[[0.96678967 0.94736842 0.9292543  0.96983759 0.9665272  0.97448166
  0.98159509 0.97619048 0.98356808 0.90410959 0.974      0.97455471
  0.97087379 0.97857143 0.96675192 0.90426759 0.97457627 0.96857671
  0.9245283  0.97567954 0.97470817 0.85802469 0.88888889 0.97175141
  0.97923875 0.92680242 0.96759259 0.95454545 0.9765625  0.96370463
  0.9612069  0.97335203 0.95268139 0.9738652  0.96964286 0.95145631
  0.9        0.97138047 0.971652   0.98130841 0.96340732 0.97495183
  0.97721519]]

We can paint the objects with one of the measurements, which can be useful for display:


In [22]:
c = dip.ObjectToMeasurement(b, m['Solidity'])
c.Show(colormap='viridis')



In [ ]: