<jupyter_start><jupyter_text>Mathematical morphology Get ImageJ ready and prepare both grey image and binary image for processing.<jupyter_code>#@ImageJ ij
import net.imglib2.algorithm.neighborhood.HyperSphereShape
import net.imglib2.FinalInterval
import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory

clown = ij.io().open("http://imagej.net/images/clown.png")

// get grayimage

// crop image
scaleFactors = [0.5, 0.5, 1] // Reduce X and Y to 50%; leave C dimension alone.
interpolationStrategy = new NLinearInterpolatorFactory()

// crop to only one channel left
image = ij.op().run("scaleView", clown, scaleFactors, interpolationStrategy)
w = image.dimension(0); h = image.dimension(1)
slice = FinalInterval.createMinSize(0, 0, 0, w, h, 1)
grayImage = ij.op().run("crop", image, slice, true)


// get binary image
threshImage = grayImage

// Secondary parameter values. These are wild guesses.
contrastThreshold = 10
halfMaxValue = 10

import net.imglib2.type.logic.BitType
bernsenImages = [:]
radius = 15
binaryImage = ij.op().run("create.img", threshImage, new BitType())
ij.op().threshold().localBernsenThreshold(binaryImage, threshImage, new HyperSphereShape(radius),
                                            contrastThreshold, halfMaxValue)
bernsenImages.put("gray", grayImage)
bernsenImages.put("binary", binaryImage)
[bernsenImages]<jupyter_output><empty_output><jupyter_text>Ops includes operators for mathematical morphology in both binary and grayscale. The two most basic morphological operators are:    erosion – reducing bright pixels at the borders    dilation - growing bright pixels at the bordersThe next three most basic are:    opening - dilation of the erosion    closing - erosion of the dilationThese latter two are not strictly necessary, since you can simply call erode followed by dilate or vice versa, but they are convenient as a shorthand.<jupyter_code>// HINT: Try different binary images here!
morphImage = binaryImage

// We will use the smallest radius: a single pixel.
import net.imglib2.algorithm.neighborhood.HyperSphereShape
shape = new HyperSphereShape(1)

erode = ij.op().morphology().erode(morphImage, shape)
dilate = ij.op().morphology().dilate(morphImage, shape)
open = ij.op().morphology().open(morphImage, [shape])
close = ij.op().morphology().close(morphImage, [shape])
// Let's also check whether open and close visually match what we expect.
manualOpen = ij.op().morphology().dilate(erode, shape)
manualClose = ij.op().morphology().erode(dilate, shape)

[["erode":erode, "dilate":dilate, "open":open, "close":close, "manual open":manualOpen, "manual close":manualClose]]<jupyter_output><empty_output><jupyter_text>The open and close look good—they match their respective definitions.Let's quickly try some [grayscale morphological operations](https://en.wikipedia.org/wiki/Mathematical_morphologyGrayscale_morphology) as well. This time we also invoke the [top-hat transform](https://en.wikipedia.org/wiki/Top-hat_transform).<jupyter_code>morphImage = grayImage

// We will use a larger radius of 3 for our neighborhood this time.
import net.imglib2.algorithm.neighborhood.HyperSphereShape
shape = new HyperSphereShape(3)

erode = ij.op().morphology().erode(morphImage, shape)
dilate = ij.op().morphology().dilate(morphImage, shape)
open = ij.op().morphology().open(morphImage, [shape])
close = ij.op().morphology().close(morphImage, [shape])
blackTopHat = ij.op().morphology().blackTopHat(morphImage, [shape])
whiteTopHat = ij.op().morphology().topHat(morphImage, [shape])

[["erode":erode, "dilate":dilate, "open":open, "close":close, "black tophat":blackTopHat, "white tophat":whiteTopHat]]<jupyter_output><empty_output><jupyter_text>Ops also provide hit-and-miss operations, more specifically, approaches for thinning. * _GuoHall_ * _Hilditch_* _Morphological_* _zhangSuen_<jupyter_code>import net.imagej.ops.morphology.thin.ThinGuoHall
import net.imagej.ops.morphology.thin.ThinHilditch
import net.imagej.ops.morphology.thin.ThinMorphological
import net.imagej.ops.morphology.thin.ThinZhangSuen
// HINT: Try different binary images here!
morphImage = binaryImage

GuoHall = ij.op().run(ThinGuoHall.class, morphImage)
Hilditch = ij.op().run(ThinHilditch.class, morphImage)
Morphological = ij.op().run(ThinMorphological.class, morphImage)
zhangSuen = ij.op().run(ThinZhangSuen.class, morphImage)

[["GuoHall":GuoHall, "Hilditch":Hilditch, "Morphological":Morphological, "zhangSuen":zhangSuen]]<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12094264117385504, 'fraction_numerical': 0.006224988883948421, 'mean_word_length': 5.9536321483771255, 'pattern_counts': {'":': 16, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '654601', 'license': 'CC0-1.0', 'n_tokens_mistral': 1531, 'n_tokens_neox': 1454, 'n_words': 355, 'path': 'notebooks/1_-_Using_ImageJ/ImageJ_Ops/12_-_Mathematical_Morphology.ipynb', 'repo_name': 'fjug/tutorials', 'size': '4498'}