-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
started refactoring of the extraction of gt
- Loading branch information
1 parent
e09829e
commit 0692f57
Showing
3 changed files
with
121 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,24 @@ | ||
from java.awt import Color | ||
from ij import IJ | ||
from ij.gui import NewImage | ||
from ij import ImagePlus | ||
from ij.gui import Roi | ||
from ij.gui import PolygonRoi | ||
from ij.gui import Overlay | ||
from ij.plugin.filter import ThresholdToSelection | ||
from inra.ijpb.morphology import Strel | ||
from inra.ijpb.morphology.filter import Closing | ||
from inra.ijpb.morphology.filter import InternalGradient | ||
from inra.ijpb.morphology.filter import Dilation | ||
|
||
from fr.cnrs.mri.cialib.tree_rings import TreeTrunkGroundTruthHelper | ||
|
||
INTERVAL = 50 | ||
CLOSING = 2 | ||
GRADIANT = 2 | ||
DILATION = 1 | ||
RING_MASKS_ONLY = True | ||
|
||
|
||
def main(): | ||
image = IJ.getImage() | ||
mask = createMask(image) | ||
treeTrunkGTHelper = TreeTrunkGroundTruthHelper(image) | ||
treeTrunkGTHelper.interval = INTERVAL | ||
treeTrunkGTHelper.closing_radius = CLOSING | ||
treeTrunkGTHelper.gradiant_radius = GRADIANT | ||
treeTrunkGTHelper.dilation_radius = DILATION | ||
treeTrunkGTHelper.ringsOnly = RING_MASKS_ONLY | ||
mask = treeTrunkGTHelper.createMaskFromRois() | ||
mask.show() | ||
|
||
def createMask(image): | ||
mask = NewImage.createByteImage ("mask of rings", image.getWidth(), image.getHeight(), 1, NewImage.FILL_BLACK) | ||
mask.setOverlay(Overlay()) | ||
overlay = image.getOverlay() | ||
rois = [] | ||
|
||
closing = Closing(Strel.Shape.OCTAGON.fromRadius(2)) | ||
internalGradient = InternalGradient(Strel.Shape.DISK.fromRadius(2)) | ||
dilation = Dilation(Strel.Shape.DISK.fromRadius(1)) | ||
|
||
for i in range(0, overlay.size()): | ||
tmp = NewImage.createByteImage ("tmp mask of rings", image.getWidth(), image.getHeight(), 1, NewImage.FILL_BLACK) | ||
roi = overlay.get(i) | ||
print("roi " + str(i) + ", type: ", roi.getTypeAsString()) | ||
poly = roi.getInterpolatedPolygon(50, True) | ||
if not poly.xpoints[-1] == poly.xpoints[0] or not poly.ypoints[-1] == poly.ypoints[0]: | ||
poly.addPoint(poly.xpoints[0], poly.ypoints[0]) | ||
roi = PolygonRoi(poly, Roi.POLYGON) | ||
tmp.setRoi(roi) | ||
tmpMask = tmp.createRoiMask() | ||
ip = closing.process(tmpMask) | ||
tmp.setProcessor(ip) | ||
ip = internalGradient.process(ip) | ||
ip = dilation.process(ip) | ||
ip.setThreshold(1, 255) | ||
tmp.setProcessor(ip) | ||
roi = ThresholdToSelection().run(tmp) | ||
print("roi", roi) | ||
rois.append(roi) | ||
|
||
|
||
smallestIndex = -1 | ||
biggestIndex = -1 | ||
smallestLength = image.getWidth() * image.getHeight() | ||
biggestLength = 0 | ||
|
||
if RING_MASKS_ONLY: | ||
for index, roi in enumerate(rois): | ||
length = roi.getLength() | ||
if length < smallestLength: | ||
smallestLength = length | ||
smallestIndex = index | ||
if length > biggestLength: | ||
biggestLength = length | ||
biggestIndex = index | ||
|
||
toBeRemoved = [smallestIndex, biggestIndex] | ||
for index, roi in enumerate(rois): | ||
if index in toBeRemoved: | ||
continue | ||
mask.getOverlay().add(roi) | ||
|
||
|
||
mask.setRoi(None) | ||
mask.getOverlay().fill(mask, Color.WHITE, Color.BLACK) | ||
mask.setOverlay(None) | ||
return mask | ||
|
||
main() |
18 changes: 18 additions & 0 deletions
18
volker/toolsets/tree_ring_segmentation/mri_tree_ring_tools.ijm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* Tools to measure pith, bark and annual rings in stained sections of tree trunks. | ||
* | ||
* (c) 2024, INSERM | ||
* written by Volker Baecker (INSERM) at Montpellier RIO Imaging (www.mri.cnrs.fr) | ||
* | ||
** | ||
*/ | ||
|
||
var _URL = "https://github.com/MontpellierRessourcesImagerie/imagej_macros_and_scripts/wiki/Tree-Ring-Tools"; | ||
|
||
macro "MRI Tree Ring Tool Help Action Tool - C000D16D17D18D19D24D25D26D27D28D29D2aD2bD33D34D3bD3cD42D43D4cD4dD52D57D58D5dD61D62D65D66D67D68D69D6aD6dD6eD71D72D75D76D79D7aD7dD7eD81D82D85D8aD8dD8eD91D92D95D96D99D9aD9dD9eDa1Da2Da6Da7Da8Da9DadDb2Db3DbcDbdDc2Dc3Dc4DcbDccDd3Dd4Dd5Dd6Dd7Dd8Dd9DdaDdbDe5De6De7De8De9" { | ||
run('URL...', 'url='+_URL); | ||
} | ||
|
||
macro "extract masks Action Tool - C000T4b12e" { | ||
run("extract masks") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
from java.awt import Color | ||
from ij.gui import NewImage | ||
from ij.gui import Roi | ||
from ij.gui import PolygonRoi | ||
from ij.gui import Overlay | ||
from ij.plugin.filter import ThresholdToSelection | ||
from inra.ijpb.morphology import Strel | ||
from inra.ijpb.morphology.filter import Closing | ||
from inra.ijpb.morphology.filter import InternalGradient | ||
from inra.ijpb.morphology.filter import Dilation | ||
|
||
|
||
|
||
class TreeTrunkGroundTruthHelper: | ||
|
||
|
||
def __init__(self, image): | ||
self.image = image | ||
self.ringsOnly = True | ||
self.closing_radius = 2 | ||
self.gradiant_radius = 2 | ||
self.dilation_radius = 1 | ||
self.interval = 50 | ||
self.closing = Closing(Strel.Shape.OCTAGON.fromRadius(self.closing_radius)) | ||
self.internalGradient = InternalGradient(Strel.Shape.DISK.fromRadius(self.gradiant_radius)) | ||
self.dilation = Dilation(Strel.Shape.DISK.fromRadius(self.dilation_radius)) | ||
|
||
|
||
def createMaskFromRois(self): | ||
mask, overlay = self.createMaskWithOverlay() | ||
rois = [] | ||
for i in range(0, overlay.size()): | ||
roi = self.interpolateAndMakeBand(overlay.get(i)) | ||
rois.append(roi) | ||
if self.ringsOnly: | ||
rois = self.removeSmallestAndBiggestRing(rois) | ||
for roi in rois: | ||
overlay.add(roi) | ||
mask.setRoi(None) | ||
mask.getOverlay().fill(mask, Color.WHITE, Color.BLACK) | ||
mask.setOverlay(None) | ||
return mask | ||
|
||
|
||
def removeSmallestAndBiggestRing(self, rois): | ||
newRois = [] | ||
smallestIndex = -1 | ||
biggestIndex = -1 | ||
smallestLength = self.image.getWidth() * self.image.getHeight() | ||
biggestLength = 0 | ||
for index, roi in enumerate(rois): | ||
length = roi.getLength() | ||
if length < smallestLength: | ||
smallestLength = length | ||
smallestIndex = index | ||
if length > biggestLength: | ||
biggestLength = length | ||
biggestIndex = index | ||
toBeRemoved = [smallestIndex, biggestIndex] | ||
for index, roi in enumerate(rois): | ||
if index in toBeRemoved: | ||
continue | ||
newRois.append(roi) | ||
return newRois | ||
|
||
|
||
def interpolateAndMakeBand(self, roi): | ||
tmp = NewImage.createByteImage ("tmp mask of rings", image.getWidth(), image.getHeight(), 1, NewImage.FILL_BLACK) | ||
poly = roi.getInterpolatedPolygon(self.interval, True) | ||
self.closePolygon(poly) | ||
roi = PolygonRoi(poly, Roi.POLYGON) | ||
tmp.setRoi(roi) | ||
tmpMask = tmp.createRoiMask() | ||
ip = self.closing.process(tmpMask) | ||
ip = self.internalGradient.process(ip) | ||
ip = self.dilation.process(ip) | ||
ip.setThreshold(1, 255) | ||
tmp.setProcessor(ip) | ||
roi = ThresholdToSelection().run(tmp) | ||
return roi | ||
|
||
|
||
def createMaskWithOverlay(self): | ||
mask = NewImage.createByteImage ("mask of rings", self.image.getWidth(), self.image.getHeight(), 1, NewImage.FILL_BLACK) | ||
overlay = Overlay() | ||
mask.setOverlay(overlay) | ||
return mask, overlay | ||
|
||
|
||
def closePolygon(self, polygon): | ||
if not polygon.xpoints[-1] == polygon.xpoints[0] or not polygon.ypoints[-1] == polygon.ypoints[0]: | ||
polygon.addPoint(poly.xpoints[0], poly.ypoints[0]) |