Image Lib

Orientation Image Maps

These orientation maps are exposed through:

  • bundle_image2DIntensity_orientation_factory

They currently operate on intensity images and use raw Sobel derivatives internally.

using UTCGP
using ImageCore: N0f8

function orientation_vertical_step_array(n::Int = 30)
    img = zeros(Float64, n, n)
    img[:, fld(n, 2)+1:end] .= 1.0
    return img
end

function orientation_horizontal_step_array(n::Int = 30)
    img = zeros(Float64, n, n)
    img[fld(n, 2)+1:end, :] .= 1.0
    return img
end

function orientation_diag45_step_array(n::Int = 30)
    img = zeros(Float64, n, n)
    for i in 1:n, j in 1:n
        img[i, j] = j >= i ? 1.0 : 0.0
    end
    return img
end

orientation_intensity_image(arr::AbstractMatrix{<:Real}) =
    UTCGP.SImageND(UTCGP.IntensityPixel{N0f8}.(Float64.(arr)))

img = orientation_intensity_image(orientation_vertical_step_array())
grad_mag = UTCGP.bundle_image2DIntensity_orientation_factory[:grad_magnitude].fn(typeof(img))
grad_ori = UTCGP.bundle_image2DIntensity_orientation_factory[:grad_orientation].fn(typeof(img))

(typeof(grad_mag), typeof(grad_ori))
(typeof(UTCGP.image2D_orientation.var"grad_magnitude_image2D_SImage2D{30, 30, IntensityPixel{FixedPointNumbers.N0f8}, Matrix{IntensityPixel{FixedPointNumbers.N0f8}}}"), typeof(UTCGP.image2D_orientation.var"grad_orientation_image2D_SImage2D{30, 30, IntensityPixel{FixedPointNumbers.N0f8}, Matrix{IntensityPixel{FixedPointNumbers.N0f8}}}"))

grad_magnitude

Gradient magnitude computed from Sobel x/y derivatives.

img = asset_img
fn = UTCGP.bundle_image2DIntensity_orientation_factory[:grad_magnitude].fn(typeof(img))
fn(img)
192×256 SImage2D{192, 256, IntensityPixel{FixedPointNumbers.N0f8}, Matrix{IntensityPixel{FixedPointNumbers.N0f8}}}:
 IntensityPixel{N0f8}(0.031)  …  IntensityPixel{N0f8}(0.051)
 IntensityPixel{N0f8}(0.059)     IntensityPixel{N0f8}(0.039)
  IntensityPixel{N0f8}(0.09)     IntensityPixel{N0f8}(0.024)
 IntensityPixel{N0f8}(0.129)     IntensityPixel{N0f8}(0.024)
 IntensityPixel{N0f8}(0.243)     IntensityPixel{N0f8}(0.106)
 IntensityPixel{N0f8}(0.161)  …   IntensityPixel{N0f8}(0.29)
 IntensityPixel{N0f8}(0.027)       IntensityPixel{N0f8}(0.4)
  IntensityPixel{N0f8}(0.02)     IntensityPixel{N0f8}(0.043)
 IntensityPixel{N0f8}(0.027)     IntensityPixel{N0f8}(0.008)
 IntensityPixel{N0f8}(0.039)     IntensityPixel{N0f8}(0.004)
                           ⋮  ⋱                            ⋮
   IntensityPixel{N0f8}(0.0)     IntensityPixel{N0f8}(0.043)
   IntensityPixel{N0f8}(0.0)     IntensityPixel{N0f8}(0.012)
   IntensityPixel{N0f8}(0.0)  …  IntensityPixel{N0f8}(0.004)
   IntensityPixel{N0f8}(0.0)     IntensityPixel{N0f8}(0.004)
   IntensityPixel{N0f8}(0.0)     IntensityPixel{N0f8}(0.004)
   IntensityPixel{N0f8}(0.0)     IntensityPixel{N0f8}(0.004)
   IntensityPixel{N0f8}(0.0)     IntensityPixel{N0f8}(0.004)
   IntensityPixel{N0f8}(0.0)  …  IntensityPixel{N0f8}(0.008)
   IntensityPixel{N0f8}(0.0)     IntensityPixel{N0f8}(0.008)
grad_magnitude original grad_magnitude output

grad_orientation

Gradient orientation map encoded in [0, 1] over [0, π].

img = asset_img
fn = UTCGP.bundle_image2DIntensity_orientation_factory[:grad_orientation].fn(typeof(img))
fn(img)
192×256 SImage2D{192, 256, IntensityPixel{FixedPointNumbers.N0f8}, Matrix{IntensityPixel{FixedPointNumbers.N0f8}}}:
 IntensityPixel{N0f8}(0.604)  …  IntensityPixel{N0f8}(0.722)
 IntensityPixel{N0f8}(0.635)     IntensityPixel{N0f8}(0.475)
 IntensityPixel{N0f8}(0.682)     IntensityPixel{N0f8}(0.118)
 IntensityPixel{N0f8}(0.643)     IntensityPixel{N0f8}(0.427)
  IntensityPixel{N0f8}(0.58)     IntensityPixel{N0f8}(0.643)
 IntensityPixel{N0f8}(0.612)  …  IntensityPixel{N0f8}(0.424)
 IntensityPixel{N0f8}(0.275)     IntensityPixel{N0f8}(0.486)
 IntensityPixel{N0f8}(0.396)     IntensityPixel{N0f8}(0.549)
 IntensityPixel{N0f8}(0.557)     IntensityPixel{N0f8}(0.353)
 IntensityPixel{N0f8}(0.153)     IntensityPixel{N0f8}(0.251)
                           ⋮  ⋱                            ⋮
 IntensityPixel{N0f8}(0.157)     IntensityPixel{N0f8}(0.549)
 IntensityPixel{N0f8}(0.157)     IntensityPixel{N0f8}(0.502)
 IntensityPixel{N0f8}(0.157)  …    IntensityPixel{N0f8}(1.0)
 IntensityPixel{N0f8}(0.157)     IntensityPixel{N0f8}(0.604)
 IntensityPixel{N0f8}(0.157)     IntensityPixel{N0f8}(0.749)
 IntensityPixel{N0f8}(0.157)     IntensityPixel{N0f8}(0.251)
 IntensityPixel{N0f8}(0.157)     IntensityPixel{N0f8}(0.749)
 IntensityPixel{N0f8}(0.157)  …    IntensityPixel{N0f8}(1.0)
 IntensityPixel{N0f8}(0.157)       IntensityPixel{N0f8}(1.0)
grad_orientation original grad_orientation output

orientation_select

Keep only gradient responses whose orientation is near a target angle.

img = asset_img
fn = UTCGP.bundle_image2DIntensity_orientation_factory[:orientation_select].fn(typeof(img))
fn(img, 0.25, 0.1)
192×256 SImage2D{192, 256, IntensityPixel{FixedPointNumbers.N0f8}, Matrix{IntensityPixel{FixedPointNumbers.N0f8}}}:
   IntensityPixel{N0f8}(0.0)  …    IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)  …    IntensityPixel{N0f8}(0.0)
 IntensityPixel{N0f8}(0.043)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)     IntensityPixel{N0f8}(0.004)
                           ⋮  ⋱                            ⋮
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)  …    IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)     IntensityPixel{N0f8}(0.004)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)  …    IntensityPixel{N0f8}(0.0)
   IntensityPixel{N0f8}(0.0)       IntensityPixel{N0f8}(0.0)
orientation_select original orientation_select output

Block Pooling Functions

In this set of bundles we currently find:

  • avgpool_blocks
  • maxpool_blocks
  • minpool_blocks
  • avgpool_cross_blocks
  • maxpool_cross_blocks
  • minpool_cross_blocks

The pooling functions are exposed through the typed image pooling bundles:

  • bundle_image2DIntensity_pool_factory
  • bundle_image2DBinary_pool_factory
  • bundle_image2DSegment_pool_factory

These functions use non-overlapping block windows scanned from left to right and top to bottom. Each block is reduced to a single value, and that value is written back over the covered block. There is no padding; the last block on the right or bottom may be partial if the image size is not divisible by k.

To obtain a callable function, first select the function from the bundle, then specialize it on the concrete image type.

using UTCGP
using ImageCore: N0f8

img = UTCGP.SImageND(UTCGP.IntensityPixel{N0f8}.(rand(4, 4)))
avg_intensity = UTCGP.bundle_image2DIntensity_pool_factory[:avgpool_blocks].fn(typeof(img))
max_intensity = UTCGP.bundle_image2DIntensity_pool_factory[:maxpool_blocks].fn(typeof(img))

(typeof(avg_intensity), typeof(max_intensity))
(typeof(UTCGP.image_pool.var"avgpool_blocks_image2D_SImage2D{4, 4, IntensityPixel{FixedPointNumbers.N0f8}, Matrix{IntensityPixel{FixedPointNumbers.N0f8}}}"), typeof(UTCGP.image_pool.var"maxpool_blocks_image2D_SImage2D{4, 4, IntensityPixel{FixedPointNumbers.N0f8}, Matrix{IntensityPixel{FixedPointNumbers.N0f8}}}"))

Avg Pool

UTCGP.image_pool.avgpool_blocks_image2D_factoryFunction
avgpool_blocks_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create average-pooling methods specialized on the given image type.

The output preserves the original image size by average-pooling block windows and writing the pooled value back over each source block.

source

Intensity image, k = 2

pooled = avg_intensity(img_intensity, 2)

Intensity image, k = 10

pooled = avg_intensity(img_intensity, 10)

Binary image, > 0.3, k = 5

pooled = avg_binary(img_binary, 5)

Segmented image from fastscanning_image2D, k = 5

pooled = avg_segment(img_segment, 5)

Max Pool

UTCGP.image_pool.maxpool_blocks_image2D_factoryFunction
maxpool_blocks_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create max-pooling methods specialized on the given image type.

The output preserves the original image size by max-pooling block windows and writing the pooled value back over each source block.

source

Intensity image, k = 2

pooled = max_intensity(img_intensity, 2)

Intensity image, k = 10

pooled = max_intensity(img_intensity, 10)

Binary image, > 0.3, k = 5

pooled = max_binary(img_binary, 5)

Segmented image from fastscanning_image2D, k = 5

pooled = max_segment(img_segment, 5)

Min Pool

UTCGP.image_pool.minpool_blocks_image2D_factoryFunction
minpool_blocks_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create min-pooling methods specialized on the given image type.

The output preserves the original image size by min-pooling block windows and writing the pooled value back over each source block.

source

Intensity image, k = 2

pooled = min_intensity(img_intensity, 2)

Intensity image, k = 10

pooled = min_intensity(img_intensity, 10)

Binary image, > 0.3, k = 5

pooled = min_binary(img_binary, 5)

Segmented image from fastscanning_image2D, k = 5

pooled = min_segment(img_segment, 5)

Cross Pooling Functions

Avg Cross Pool

UTCGP.image_pool.avgpool_cross_blocks_image2D_factoryFunction
avgpool_cross_blocks_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create cross-shaped average-pooling methods specialized on the given image type.

Within each block window, only the center row and center column are averaged. The pooled value is then written back over the full source block.

source

Custom 10x10 intensity image, k = 3

pooled = avg_cross_intensity(img_cross_demo, 3)

Custom 10x10 intensity image, k = 5

pooled = avg_cross_intensity(img_cross_demo, 5)

Binary image, > 0.3, k = 10

pooled = avg_cross_binary(img_binary, 10)

Segmented image from fastscanning_image2D, k = 10

pooled = avg_cross_segment(img_segment, 10)

Max Cross Pool

UTCGP.image_pool.maxpool_cross_blocks_image2D_factoryFunction
maxpool_cross_blocks_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create cross-shaped max-pooling methods specialized on the given image type.

Within each block window, only the center row and center column are reduced. The pooled value is then written back over the full source block.

source

Custom 10x10 intensity image, k = 3

pooled = max_cross_intensity(img_cross_demo, 3)

Custom 10x10 intensity image, k = 5

pooled = max_cross_intensity(img_cross_demo, 5)

Binary image, > 0.3, k = 10

pooled = max_cross_binary(img_binary, 10)

Segmented image from fastscanning_image2D, k = 10

pooled = max_cross_segment(img_segment, 10)

Min Cross Pool

UTCGP.image_pool.minpool_cross_blocks_image2D_factoryFunction
minpool_cross_blocks_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create cross-shaped min-pooling methods specialized on the given image type.

Within each block window, only the center row and center column are reduced. The pooled value is then written back over the full source block.

source

Custom 10x10 intensity image, k = 3

pooled = min_cross_intensity(img_cross_demo, 3)

Custom 10x10 intensity image, k = 5

pooled = min_cross_intensity(img_cross_demo, 5)

Binary image, > 0.3, k = 10

pooled = min_cross_binary(img_binary, 10)

Segmented image from fastscanning_image2D, k = 10

pooled = min_cross_segment(img_segment, 10)

Sliding Window Poolers

In this set of bundles we currently find:

  • meanpool
  • maxpool
  • minpool
  • stdpool
  • medianpool
  • uniquecountpool
  • argmaxcountpool
  • argmincountpool
  • iqrpool

These functions use full sliding k × k windows with no padding. Only windows that fully fit in the image are reduced, using the provided stride, and the reduced image is then resized back to the original size with nearest-neighbor sampling.

The sliding-window poolers are exposed through:

  • bundle_image2DIntensity_pooler_factory
  • bundle_image2DBinary_pooler_factory
  • bundle_image2DSegment_pooler_factory
using UTCGP
using ImageCore: N0f8

img = UTCGP.SImageND(UTCGP.IntensityPixel{N0f8}.(rand(8, 8)))
mean_intensity = UTCGP.bundle_image2DIntensity_pooler_factory[:meanpool].fn(typeof(img))
iqr_intensity = UTCGP.bundle_image2DIntensity_pooler_factory[:iqrpool].fn(typeof(img))

(typeof(mean_intensity), typeof(iqr_intensity))
(typeof(UTCGP.image_pooler.var"meanpool_image2D_SImage2D{8, 8, IntensityPixel{FixedPointNumbers.N0f8}, Matrix{IntensityPixel{FixedPointNumbers.N0f8}}}"), typeof(UTCGP.image_pooler.var"iqrpool_image2D_SImage2D{8, 8, IntensityPixel{FixedPointNumbers.N0f8}, Matrix{IntensityPixel{FixedPointNumbers.N0f8}}}"))

Mean Pool

UTCGP.image_pooler.meanpool_image2D_factoryFunction
meanpool_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create mean sliding-window pooling methods specialized on the given image type.

The image is reduced over full k × k windows using the provided stride, without padding, then nearest-neighbor resized back to the original image size.

source

Intensity image, k = 3, stride = 1

pooled = pooler_intensity[:meanpool](img_intensity, 3, 1)

Intensity image, k = 5, stride = 2

pooled = pooler_intensity[:meanpool](img_intensity, 5, 2)

Binary image, k = 5, stride = 2

pooled = pooler_binary[:meanpool](img_binary, 5, 2)

Segmented image from fastscanning_image2D, k = 5, stride = 2

pooled = pooler_segment[:meanpool](img_segment, 5, 2)

Max Pool

UTCGP.image_pooler.maxpool_image2D_factoryFunction
maxpool_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create max sliding-window pooling methods specialized on the given image type.

The image is reduced over full k × k windows using the provided stride, without padding, then nearest-neighbor resized back to the original image size.

source

Intensity image, k = 3, stride = 1

pooled = pooler_intensity[:maxpool](img_intensity, 3, 1)

Intensity image, k = 5, stride = 2

pooled = pooler_intensity[:maxpool](img_intensity, 5, 2)

Binary image, k = 5, stride = 2

pooled = pooler_binary[:maxpool](img_binary, 5, 2)

Segmented image from fastscanning_image2D, k = 5, stride = 2

pooled = pooler_segment[:maxpool](img_segment, 5, 2)

Min Pool

UTCGP.image_pooler.minpool_image2D_factoryFunction
minpool_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create min sliding-window pooling methods specialized on the given image type.

The image is reduced over full k × k windows using the provided stride, without padding, then nearest-neighbor resized back to the original image size.

source

Intensity image, k = 3, stride = 1

pooled = pooler_intensity[:minpool](img_intensity, 3, 1)

Intensity image, k = 5, stride = 2

pooled = pooler_intensity[:minpool](img_intensity, 5, 2)

Binary image, k = 5, stride = 2

pooled = pooler_binary[:minpool](img_binary, 5, 2)

Segmented image from fastscanning_image2D, k = 5, stride = 2

pooled = pooler_segment[:minpool](img_segment, 5, 2)

Std Pool

UTCGP.image_pooler.stdpool_image2D_factoryFunction
stdpool_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create std sliding-window pooling methods specialized on the given image type.

The image is reduced over full k × k windows using the provided stride, without padding, then nearest-neighbor resized back to the original image size.

source

Intensity image, k = 3, stride = 1

pooled = pooler_intensity[:stdpool](img_intensity, 3, 1)

Intensity image, k = 5, stride = 2

pooled = pooler_intensity[:stdpool](img_intensity, 5, 2)

Binary image, k = 5, stride = 2

pooled = pooler_binary[:stdpool](img_binary, 5, 2)

Segmented image from fastscanning_image2D, k = 5, stride = 2

pooled = pooler_segment[:stdpool](img_segment, 5, 2)

Median Pool

UTCGP.image_pooler.medianpool_image2D_factoryFunction
medianpool_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create median sliding-window pooling methods specialized on the given image type.

The image is reduced over full k × k windows using the provided stride, without padding, then nearest-neighbor resized back to the original image size.

source

Intensity image, k = 3, stride = 1

pooled = pooler_intensity[:medianpool](img_intensity, 3, 1)

Intensity image, k = 5, stride = 2

pooled = pooler_intensity[:medianpool](img_intensity, 5, 2)

Binary image, k = 5, stride = 2

pooled = pooler_binary[:medianpool](img_binary, 5, 2)

Segmented image from fastscanning_image2D, k = 5, stride = 2

pooled = pooler_segment[:medianpool](img_segment, 5, 2)

Unique Count Pool

UTCGP.image_pooler.uniquecountpool_image2D_factoryFunction
uniquecountpool_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create unique-count sliding-window pooling methods specialized on the given image type.

The image is reduced over full k × k windows using the provided stride, without padding, then nearest-neighbor resized back to the original image size.

source

Intensity image, k = 3, stride = 1

pooled = pooler_intensity[:uniquecountpool](img_intensity, 3, 1)

Intensity image, k = 5, stride = 2

pooled = pooler_intensity[:uniquecountpool](img_intensity, 5, 2)

Binary image, k = 5, stride = 2

pooled = pooler_binary[:uniquecountpool](img_binary, 5, 2)

Segmented image from fastscanning_image2D, k = 5, stride = 2

pooled = pooler_segment[:uniquecountpool](img_segment, 5, 2)

Argmax Count Pool

UTCGP.image_pooler.argmaxcountpool_image2D_factoryFunction
argmaxcountpool_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create argmax-count sliding-window pooling methods specialized on the given image type.

The image is reduced over full k × k windows using the provided stride, without padding, then nearest-neighbor resized back to the original image size.

source

Intensity image, k = 3, stride = 1

pooled = pooler_intensity[:argmaxcountpool](img_intensity, 3, 1)

Intensity image, k = 5, stride = 2

pooled = pooler_intensity[:argmaxcountpool](img_intensity, 5, 2)

Binary image, k = 5, stride = 2

pooled = pooler_binary[:argmaxcountpool](img_binary, 5, 2)

Segmented image from fastscanning_image2D, k = 5, stride = 2

pooled = pooler_segment[:argmaxcountpool](img_segment, 5, 2)

Argmin Count Pool

UTCGP.image_pooler.argmincountpool_image2D_factoryFunction
argmincountpool_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create argmin-count sliding-window pooling methods specialized on the given image type.

The image is reduced over full k × k windows using the provided stride, without padding, then nearest-neighbor resized back to the original image size.

source

Intensity image, k = 3, stride = 1

pooled = pooler_intensity[:argmincountpool](img_intensity, 3, 1)

Intensity image, k = 5, stride = 2

pooled = pooler_intensity[:argmincountpool](img_intensity, 5, 2)

Binary image, k = 5, stride = 2

pooled = pooler_binary[:argmincountpool](img_binary, 5, 2)

Segmented image from fastscanning_image2D, k = 5, stride = 2

pooled = pooler_segment[:argmincountpool](img_segment, 5, 2)

IQR Pool

UTCGP.image_pooler.iqrpool_image2D_factoryFunction
iqrpool_image2D_factory(i::Type{I}) where {I<:SizedImage2D}

Create interquartile-range sliding-window pooling methods specialized on the given image type.

The image is reduced over full k × k windows using the provided stride, without padding, then nearest-neighbor resized back to the original image size.

source

Intensity image, k = 3, stride = 1

pooled = pooler_intensity[:iqrpool](img_intensity, 3, 1)

Intensity image, k = 5, stride = 2

pooled = pooler_intensity[:iqrpool](img_intensity, 5, 2)

Binary image, k = 5, stride = 2

pooled = pooler_binary[:iqrpool](img_binary, 5, 2)

Segmented image from fastscanning_image2D, k = 5, stride = 2

pooled = pooler_segment[:iqrpool](img_segment, 5, 2)