Monty.Frameworks.Utils.EdgeDetection.StructureTensor (ExTbpMonty.Core v0.1.0)

Copy Markdown View Source

A structure tensor at one point: the 2×2 symmetric matrix [[xx, xy], [xy, yy]].

Mirrors tbp/monty/frameworks/utils/edge_detection.py::StructureTensor.

Its four numbers are what an edge looks like in a patch of gradients: how strongly the brightness changes along x, the same along y, and how much the two move together. The eigenvalues of the matrix are the strengths along the dominant and the perpendicular direction; an edge is a matrix with one large eigenvalue and one small one, and a corner is a matrix with two.

Summary

Functions

How oriented the tensor is, in [0, 1]: 1 is a single clean edge, 0 is a patch with no direction at all.

The edge direction in [0, π]: perpendicular to the gradient.

How strong the strongest edge in the tensor is: the root of the larger eigenvalue, floored at zero because a numerically tiny negative eigenvalue is noise, not a negative edge.

The smallest and the largest eigenvalue, {lambda_min, lambda_max}.

The gradient direction in radians, normal to the dominant edge.

The two, from the three numbers.

Types

t()

@type t() :: %Monty.Frameworks.Utils.EdgeDetection.StructureTensor{
  xx: float(),
  xy: float(),
  yy: float()
}

Functions

coherence(tensor)

@spec coherence(t()) :: float()

How oriented the tensor is, in [0, 1]: 1 is a single clean edge, 0 is a patch with no direction at all.

(lambda_max - lambda_min) / (lambda_max + lambda_min). Two eigenvalues a hair apart are a round patch, not an edge, and Monty calls that zero rather than letting rounding turn noise into confidence.

edge_angle(tensor)

@spec edge_angle(t()) :: float()

The edge direction in [0, π]: perpendicular to the gradient.

edge_strength(tensor)

@spec edge_strength(t()) :: float()

How strong the strongest edge in the tensor is: the root of the larger eigenvalue, floored at zero because a numerically tiny negative eigenvalue is noise, not a negative edge.

eigenvalues(structure_tensor)

@spec eigenvalues(t()) :: {float(), float()}

The smallest and the largest eigenvalue, {lambda_min, lambda_max}.

Monty asks numpy for both; the closed form for a symmetric 2×2 is the same answer and says what it is: their sum is the trace and their product the determinant, so they are mean ± sqrt(mean² - determinant) with mean = (xx + yy) / 2.

gradient_theta(structure_tensor)

@spec gradient_theta(t()) :: float()

The gradient direction in radians, normal to the dominant edge.

In (-π/2, π/2]: an orientation, not a heading, because the tensor cannot tell one side of an edge from the other.

new(xx, yy, xy)

@spec new(float(), float(), float()) :: t()

The two, from the three numbers.