finitedepth.coatinglayer#
Analyze coating layer and similarity measures [1] [2].
Module Contents#
Classes#
Abstract base class for coating layer object. |
|
Basic implementation of coating layer without any analysis. |
|
Coating layer over rectangular substrate. |
Functions#
|
Perform subtraction between two images by XOR operation. |
|
Perform subtraction between two images by AND and XOR operations. |
|
Interpolate points with equidistant new points. |
|
Return parallel curve of curve with offset distance dist. |
|
Compute accumulated cost matrix from local cost matrix. |
|
Compute optimal warping path from accumulated cost matrix. |
|
Approximate integral Fréchet distance over uniform grid [4]. |
- class finitedepth.coatinglayer.CoatingLayerBase(image, substrate, *, tempmatch=None)[source]#
Bases:
abc.ABC,Generic[SubstTypeVar,DataTypeVar]Abstract base class for coating layer object.
Coating layer object stores
SubstrateBaseobject and target image, which is a binary image of coated substrate. The role of coating layer object is to acquire coating layer region by template matching and analyze its shape.External API can use the following members to get analysis results of concrete subclasses.
- Parameters:
image (numpy.typing.NDArray[numpy.uint8]) – Binary target image.
substrate (SubstTypeVar) – Substrate instance storing binary reference image.
tempmatch (tuple[tuple[int, Ellipsis], float] | None) – Pre-computed template matching result. External constructor can pass this argument to force the template matching result. If not passed,
match_template()performs matching.
- property image: numpy.typing.NDArray[numpy.uint8][source]#
Binary target image.
For immutability, this image is not writable.
- Return type:
numpy.typing.NDArray[numpy.uint8]
- property substrate: SubstTypeVar[source]#
Substrate instance which contains substrate and reference information.
- Return type:
SubstTypeVar
- property tempmatch: tuple[tuple[int, Ellipsis], float][source]#
Template matching location and score.
- DataType: type[DataTypeVar][source]#
Return type of
analyze.Concrete subclass must assign this attribute with dataclass type.
- match_template(image, template)[source]#
Perform template matching between image and template.
Template matching is performed using
cv2.matchTemplate()withcv2.TM_SQDIFF_NORMED. Subclass may override this method to apply other algorithm.
- substrate_point()[source]#
Upper left point of the substrate image in target image.
- Returns:
Coordinates in
(x, y).- Return type:
numpy.typing.NDArray[numpy.int32]
- coated_substrate()[source]#
Coated substrate region.
- Returns:
Target image without artifacts, e.g., bath surface.
- Return type:
numpy.typing.NDArray[numpy.bool_]
- extract_layer()[source]#
Coating layer region extracted from target image.
- Return type:
numpy.typing.NDArray[numpy.bool_]
- abstract valid()[source]#
Return if the analysis can be performed as expected.
Sometimes, the coating layer instance should be constructed but not analyzed at all. For example, the coating video may contains frames where the capillary bridge is not ruptured yet. This method allows analyzer to skip such instances.
- Return type:
- class finitedepth.coatinglayer.CoatingLayer(image, substrate, *, tempmatch=None)[source]#
Bases:
CoatingLayerBase[finitedepth.substrate.SubstrateBase,CoatingLayerData]Basic implementation of coating layer without any analysis.
- Parameters:
Examples
Construct substrate instance first.
>>> import cv2 >>> from finitedepth import get_sample_path, Reference, Substrate >>> img = cv2.imread(get_sample_path("ref.png"), cv2.IMREAD_GRAYSCALE) >>> _, bin = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) >>> ref = Reference(bin, (10, 10, 1250, 200), (100, 100, 1200, 500)) >>> subst = Substrate(ref) >>> import matplotlib.pyplot as plt >>> plt.imshow(subst.draw())
Then, construct coating layer instance.
>>> from finitedepth import CoatingLayer >>> img = cv2.imread(get_sample_path("coat.png"), cv2.IMREAD_GRAYSCALE) >>> _, bin = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) >>> coat = CoatingLayer(bin, subst) >>> plt.imshow(coat.draw())
- draw(subtraction_mode='none', layer_color=(255, 0, 0), layer_thickness=-1)[source]#
Subtract the template match result and paint the coating layer.
- Parameters:
subtraction_mode ({‘none’, ‘template’, ‘substrate’, ‘full’}) – Subtraction mode. ‘template’ and ‘substrate’ removes overlapping template region and substrate region, respectively. ‘full’ removes both.
layer_color (tuple[int, int, int]) – Layer color for
cv2.drawContours().layer_thickness (int) – Layer thickness for
cv2.drawContours().
- Return type:
numpy.typing.NDArray[numpy.uint8]
- class finitedepth.coatinglayer.RectLayerShape(image, substrate, opening_ksize, reconstruct_radius, roughness_measure, ifd_gsize=None, *, tempmatch=None)[source]#
Bases:
CoatingLayerBase[finitedepth.substrate.RectSubstrate,RectLayerShapeData]Coating layer over rectangular substrate.
- Parameters:
image (numpy.typing.NDArray[numpy.uint8]) – Binary target image.
substrate (finitedepth.substrate.RectSubstrate) – Substrate instance.
opening_ksize (tuple[int, int]) – Kernel size for morphological operation. Elements must be zero or odd number.
reconstruct_radius (int) – Radius of the “safe zone” for noise removal. Imaginary circles with this radius are drawn on bottom corners of the substrate. Connected components not passing these circles are regarded as image artifacts.
roughness_measure (str) –
Similarity measure to quantify roughness.
- ’DTW’
Dynamice time warping.
- ’SDTW’
Root mean square of dynamic time warping.
- ’IFD’
Approximated integral Fréchet distance. Requires ifd_gsize.
ifd_gsize (float | None) – Grid size to approximate integral Fréchet distance. Ignored if roughness_measure is not ‘IFD’.
tempmatch (tuple[tuple[int, Ellipsis], float] | None) – Pre-computed template matching result.
Examples
Construct substrate instance first.
>>> import cv2 >>> from finitedepth import get_sample_path, Reference, RectSubstrate >>> img = cv2.imread(get_sample_path("ref.png"), cv2.IMREAD_GRAYSCALE) >>> _, bin = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) >>> ref = Reference(bin, (10, 10, 1250, 200), (100, 100, 1200, 500)) >>> subst = RectSubstrate(ref, 3.0, 1.0, 0.01) >>> import matplotlib.pyplot as plt >>> plt.imshow(subst.draw())
Then, construct coating layer instance.
>>> from finitedepth import RectLayerShape >>> img = cv2.imread(get_sample_path("coat.png"), cv2.IMREAD_GRAYSCALE) >>> _, bin = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) >>> coat = RectLayerShape(bin, subst, (1, 1), 50, "IFD", 3) >>> plt.imshow( ... coat.draw(conformality_step=10, roughness_step=5) ... )
- property ifd_gsize: float | None[source]#
Grid size to quantify roughness if
roughness_measureis IFD.- Return type:
float | None
- layer_contours()[source]#
Find contours of coating layer region.
This method finds external contours of
extract_layer(). Each contour encloses each discrete region of coating layer.- Return type:
tuple[numpy.typing.NDArray[numpy.int32], Ellipsis]
- interfaces()[source]#
Find solid-liquid interfaces.
A substrate can have contact with multiple discrete coating layer regions, and a single coating layer region can have multiple contacts to the substrate. This method returns indices for
contour()where solid-liquid interfaces start and stop.- Returns:
tuple of arrays.
i-th array representsi-th coating layer region inlayer_contours(). Shape of the array is(N, 2), whereNis the number of contacts the coating layer region makes. Each column represents starting and ending indices for the interface interval in substrate contour.- Return type:
tuple[numpy.typing.NDArray[numpy.int64], Ellipsis]
Note
Each interval describes continuous patch on the substrate contour covered by the layer. To acquire the interface points, slice
substrate’scontour()with the indices.
- contour()[source]#
Contour of the entire coated substrate.
- Return type:
numpy.typing.NDArray[numpy.int32]
- capbridge_broken()[source]#
Check if capillary bridge is ruptured.
As substrate is withdrawn from fluid bath, capillary bridge forms between the coating layer and bulk fluid and then ruptures.
- Return type:
- extract_layer()[source]#
Coating layer region extracted from target image.
Error pixels are removed by performing morphological operation and removing the disconnected components that are far from the substrate.
- Return type:
numpy.typing.NDArray[numpy.bool_]
- surface()[source]#
Liquid-gas interface of the coating layer.
Substrate surface exposed to air is considered to be covered by coating layer with zero thickness.
- Returns:
Starting and ending indices for the surface interval in coated substrate contour.
- Return type:
tuple[numpy.int64, numpy.int64]
Note
To acquire the surface points, slice
contour()with the indices.
- uniform_layer()[source]#
Imaginary uniform layer.
Uniform layer is a parallel curve [3] of substrate surface which has the same cross-sectional area as the actual coating layer.
- Returns:
Thickness and polyline vertices of the uniform layer.
- Return type:
tuple[numpy.float64, numpy.typing.NDArray[numpy.float64]]
[3]
- max_thickness()[source]#
Regional maximum thicknesses.
Coating layer is segmented using
RectSubstrate.sideline_intersections(). Points on layer surface and sideline for maximum distance in each region are found.- Returns:
tuple of two arrays. The first array contains maximum thickness values on left, bottom, and right region. Value of
0indicates no coating layer on that region. The second array contains points on layer surface and substrate lines for the maximum thickness. Shape of the array is(3, 2, 2); 1st axis indicates left, bottom and right region, 2nd axis indicates layer surface and substrate line, and 3rd axis indicates(x, y)coordinates.- Return type:
tuple[numpy.typing.NDArray[numpy.float64], numpy.typing.NDArray[numpy.float64]]
- draw(background_mode='image', subtraction_mode='none', layer_color=(255, 0, 0), layer_thickness=-1, contactline_color=(0, 255, 0), contactline_thickness=1, maxthickness_color=(0, 255, 0), maxthickness_thickness=1, uniformlayer_color=(0, 0, 255), uniformlayer_thickness=1, conformality_color=(0, 0, 255), conformality_thickness=1, conformality_step=1, roughness_color=(0, 0, 255), roughness_thickness=1, roughness_step=1)[source]#
Visualize the analysis result.
Draw the substrate with by
PaintMode.Display the template matching result with
SubtractionMode.Draw coating layer and contact line.
If capillary bridge is broken, draw regional maximum thicknesses, uniform layer, conformality pairs and roughness pairs.
- Parameters:
background_mode ({‘image’, ‘empty’}) – Determine how background is drawn. ‘image’ draws original background image while ‘empty’ draws on empty frame.
subtraction_mode ({‘none’, ‘template’, ‘substrate’, ‘full’}) – Subtraction mode. ‘template’ and ‘substrate’ removes overlapping template region and substrate region, respectively. ‘full’ removes both.
layer_color (tuple[int, int, int]) – Layer contour’s color for
cv2.drawContours().layer_thickness (int) – Layer contour’s thickness for
cv2.drawContours().contactline_color (tuple[int, int, int]) – Contact line’s color for
cv2.line().contactline_thickness (int) – Contact line’s thickness for
cv2.line().maxthickness_color (tuple[int, int, int]) – Regional maximum thickness line’s color for
cv2.polylines().maxthickness_thickness (int) – Regional maximum thickness line’s thickness for
cv2.polylines().uniformlayer_color (tuple[int, int, int]) – Imaginary uniform layer’s color for
cv2.polylines().uniformlayer_thickness (int) – Imaginary uniform layer’s thickness for
cv2.polylines().conformality_color (tuple[int, int, int]) – Conformality pairs’ color for
cv2.polylines().conformality_thickness (int) – Conformality pairs’ thickness for
cv2.polylines().conformality_step (int) – Step size to skip conformality pairs.
roughness_color (tuple[int, int, int]) – Roughness pairs’ color for
cv2.polylines().roughness_thickness (int) – Roughness pairs’ thickness for
cv2.polylines().roughness_step (int) – Step size to skip roughness pairs.
- Return type:
numpy.typing.NDArray[numpy.uint8]
- finitedepth.coatinglayer.images_XOR(img1, img2, point=(0, 0))[source]#
Perform subtraction between two images by XOR operation.
- Parameters:
img1 (numpy.typing.NDArray[numpy.bool_]) – Image from which img2 is subtracted.
img2 (numpy.typing.NDArray[numpy.bool_]) – Image patch which is subtracted from img1.
point (tuple[int, int]) – Location in img1 where img2 is subtracted.
- Return type:
numpy.typing.NDArray[numpy.bool_]
- finitedepth.coatinglayer.images_ANDXOR(img1, img2, point=(0, 0))[source]#
Perform subtraction between two images by AND and XOR operations.
- Parameters:
img1 (numpy.typing.NDArray[numpy.bool_]) – Image from which img2 is subtracted.
img2 (numpy.typing.NDArray[numpy.bool_]) – Image patch which is subtracted from img1.
point (tuple[int, int]) – Location in img1 where img2 is subtracted.
- Return type:
numpy.typing.NDArray[numpy.bool_]
- finitedepth.coatinglayer.equidistant_interpolate(points, n)[source]#
Interpolate points with equidistant new points.
- Parameters:
points – Points that are interpolated. The shape must be
(N, 1, D)whereNis the number of points andDis the dimension.n – Number of new points.
- Returns:
Interpolated points. If
Nis positive number, the shape is(n, 1, D). IfNis zero, the shape is(n, 0, D).- Return type:
numpy.typing.NDArray[numpy.float64]
- finitedepth.coatinglayer.parallel_curve(curve, dist)[source]#
Return parallel curve of curve with offset distance dist.
- Parameters:
curve (numpy.typing.NDArray) – Vertices of a polyline. The shape is
(V, 1, D), whereVis the number of vertices andDis the dimension.dist (float) – offset distance of the parallel curve.
- Returns:
Round-joint parallel curve of shape
(V, 1, D).- Return type:
numpy.typing.NDArray
- finitedepth.coatinglayer.acm(cm)[source]#
Compute accumulated cost matrix from local cost matrix.
- Parameters:
cm (numpy.typing.NDArray[numpy.float64]) – Local cost matrix.
- Returns:
Accumulated cost matrix. The element at [-1, -1] is the total sum along the optimal path. If cm is empty, return value is an empty array.
- Return type:
numpy.typing.NDArray[numpy.float64]
- finitedepth.coatinglayer.owp(acm)[source]#
Compute optimal warping path from accumulated cost matrix.
- Parameters:
acm (numpy.typing.NDArray[numpy.float64]) – Accumulated cost matrix.
- Returns:
Indices for the two series to get the optimal warping path.
- Return type:
numpy.typing.NDArray[numpy.int32]
- finitedepth.coatinglayer.integfrechet_G1(T1, T2, sigma)[source]#
Approximate integral Fréchet distance over uniform grid [4].
- Parameters:
T1 (numpy.typing.NDArray) – Polyline vertices. shape=(nodes, 2).
T2 (numpy.typing.NDArray) – Polyline vertices. shape=(nodes, 2).
sigma (float) – Grid size.
- Returns:
Approximated integral Fréchet distance between two polygonal curves, its optimal path in parameter space, and its point pairs in curve space.
- Return type:
tuple[float, numpy.typing.NDArray[numpy.int32], numpy.typing.NDArray[numpy.float64]]
[4] (1,2) Maheshwari, A., Sack, J. R., & Scheffer, C. (2018).