我知道编辑这个网站吗?
the Fiji distribution of ImageJ本页介绍与 the Fiji distribution of ImageJ 相关的内容。点击徽标查看详情。

如何为 TrackMate 编写自己的点特征分析器算法

简介

该系列的第三篇文章致力于扩展 TrackMate,涉及点特征分析器。这是您可以创建的三种特征分析器中的最后一种,它专注于斑点或检测。

点特征通常根据点位置和图像数据来计算。例如,有一个点特征报告点半径内的平均强度。您需要知道光点位置、半径和图像数据来计算它。

在本教程中,我们将生成一个不直接根据图像数据计算的分析器。这将使我们能够跳过介绍 ImgLib2 API,这将大大增加本系列的长度。但这种选择不仅仅是为了培养我的懒惰:我们将使我们的功能依赖于其他功能,这将允许我们引入分析器优先级

但在此之前,让我们先了解一下现场特征分析器的特性。

点分析仪和点分析仪工厂

在前两篇文章中,我们讨论了 edgetrack 分析器。我们可以将它们放在一个类中,并且该类嵌入了以下代码

  • TrackMate 集成(功能名称、尺寸、声明等);
  • 和实际特征计算。

对于点分析仪来说,两者是分开的。

您必须首先创建一个SpotAnalyzerFactory。该工厂将负责 TrackMate 集成。该接口扩展了 TrackMateModuleFeatureAnalyzer 接口。您需要使用 SciJava 注释来注释该类,以便自动发现。

但它还负责实例化 SpotAnalyzers。正如你所看到的,这个接口只是扩展了 ImgLib2 Algorithm,所以所有参数都必须在构造函数中传递,这可以是你想要的,这要归功于工厂。我们不需要返回值方法,因为结果直接存储在 Spot 对象内。但我们稍后会看到这一点。

让我们开始我们的例子。

现场分析仪工厂

我们想要生成一个分析器来计算每个点的平均强度与标准强度的比率。因此,如果该特征的标准强度等于平均值,则该特征的值为 1,等等… 我们可以让分析仪实际计算每个点的像素强度,取平均值和标准差。 但是,有一个分析仪已经计算了光斑强度,我们可以重复使用它。检查SpotIntensityMultiCAnalyzerFactory

在我们的计算中重用这个值是一个好主意,既可以提高开发速度,又可以提高运行时性能。但如果我们这样做,我们必须确保我们所依赖的功能在新分析器运行时可用。有一种方法可以做到这一点,这要归功于优先级的概念,我们将在稍后讨论。

现在,让我们关注工厂类本身。没什么好说的:它的内容类似于我们迄今为止看到的所有特征分析器。因此,我将跳过详细信息,并向您指出完整的源代码here

一个有趣的部分是负责实例化 SpotAnalyzer 的工厂方法:

	@Override
	public SpotAnalyzer< T > getAnalyzer( final ImgPlus< T > img, final int frame, final int channel )
	{
		// Don't make an analyzer for other channels than the first.
		if ( channel != 0 )
			return SpotAnalyzer.dummyAnalyzer();

		return new MeanStdIntensityRatioSpotAnalyzer<>();
	}

以下是有关此方法的一些重要信息。 正如 javadoc 中所述:

此方法将在源图像的每个时间点和每个通道调用一次。如果一个特征是独立于通道定义的,那么在多个通道上调用时,实现必须注意跳过生成多个相同的特征。

这也意味着特征计算将逐帧、逐通道重新切片。 但该方法的第一个参数是 5D 源图像。 实施分析器有责任重新切片该图像以仅产生感兴趣的通道和帧。

由于我们想要构建一个不需要图像数据的特征,因此构造函数只是跳过图像引用。 而且因为我们很懒,所以我们只会计算第一个通道的特征,因此我们返回一个虚拟分析器,它对非第一个通道(索引为 0)的所有通道不执行任何操作。

就是这样。我们现在必须转向分析器本身来实现特征计算逻辑。

现场分析仪

正如您在上述方法中所指出的,每个分析器仅在一个帧上运行。 这允许多线程: 工厂将被要求生成与可用线程一样多的分析器,并且它们将同时运行。 当我们构建分析器时,我们不必担心并发问题。

关于预期执行上下文的一些说明: 正如您所注意到的,TrackMate GUI 是按步骤操作的。首先,检测步骤生成斑点,然后对它们进行过滤,然后对它们进行跟踪,等等…… 因此,当我前面说整个模型可供计算时,这并不完全正确。 使用 GUI 时,点数字特征用于在检测到点后对其进行过滤。 所以这个阶段还没有曲目。 甚至没有被过滤的斑点。点功能不能依赖于这些对象,这是 TrackMate 的内置限制。因此,请谨慎考虑您的数字特征所依赖的内容。

SpotAnalyzer界面非常简单:

public void process( final Iterable< Spot > spots );

该方法接收要计算特征的点上的迭代。 该迭代是在 TrackMate 的其他地方准备的,包含要按预期更新单个时间点的点。 不一定是时间点上的所有景点。 在检测、跟踪所有点后,使用相同的方法更新点值。 事实上,当您手动修改或创建一个点时,它的特征会自动重新计算。 当发生这种情况时,会调用相同的方法,但可迭代对象仅包含已修改的点而不是整个时间点。

由于一个点的特征值不依赖于任何其他点,因此我们可以进一步简化我们的工作,并从一个实用程序类派生出我们的分析器,该实用程序类负责多线程部分,并且只要求我们实现一个点的特征计算逻辑。 该实用程序类是AbstractSpotFeatureAnalyzer。 多亏了它,分析器的主体非常简洁:

package plugin.trackmate.examples.spotanalyzer;

import fiji.plugin.trackmate.Spot;
import fiji.plugin.trackmate.features.spot.AbstractSpotFeatureAnalyzer;
import net.imglib2.type.numeric.RealType;

public class MeanStdIntensityRatioSpotAnalyzer< T extends RealType< T > > extends AbstractSpotFeatureAnalyzer< T >
{
	@Override
	public void process( final Spot spot )
	{
		// See below.
	}
}
// etc

所有计算逻辑都必须在 process(Spot) 方法中进行。 不需要有一个方法来返回计算结果,因为点对象可以存储自己的特征值,这要归功于 Spot.putFeature(feature, value) 方法。

以下是平均值/标准差分析器的 process() 方法:

	@Override
	public void process( final Spot spot )
	{
		/*
		 * Get the feature values created by the other spot analyzer for the
		 * first channel only.
		 * 
		 * These values will be null if the spot intensity analyzer has not been
		 * called before. This is controlled via the priority flag in the
		 * annotation of the factory,
		 * 
		 * The channel number for feature keys are 1-based, so we need to add to
		 * the channel number we received in the constructor.
		 */
		final Double mean = spot.getFeature( "MEAN_INTENSITY_CH1" );
		final Double std = spot.getFeature( "STD_INTENSITY_CH1" );

		// Compute mean / std.
		final double ratio = mean.doubleValue() / std.doubleValue();

		// Store results.
		final String featureName = MeanStdIntensityRatioSpotAnalyzerFactory.MEAN_OVER_STD;
		spot.putFeature( featureName, Double.valueOf( ratio ) );

		// That's it!
	}

全班代码为here

使用 SciJava 优先级来确定执行顺序

现在是时候讨论依赖这个微妙的话题了。

如上所述,我们的新分析器依赖于一些其他功能来计算。因此,计算这些其他特征的分析器需要在我们的分析器之前运行。否则您将随机下注 NullPointerExceptions。

TrackMate 不提供真正深入的模块依赖性管理。由于SciJava插件优先级参数,它只是提供确定分析器执行的顺序。

例如,如果您检查点分析器工厂的注释部分,您可以看到有一个额外的参数,priority

@Plugin( type = SpotAnalyzerFactory.class, priority = -1. )

此优先级参数接受 double 作为值,该值确定执行顺序。小心,该规则与优先级的意义相反:

Feature analyzers are executed in order according to increasing priority. This means that analyzers with the greatest priority are executed first.

按照惯例,如果您的特征分析器依赖于其他 N 个分析器计算的特征,则您将采用这些分析器中最低的优先级,并删除 1。 在我们的例子中,我们依赖于 SpotIntensityAnalyzerFactory,其优先级为 0(如果未指定参数则为默认值)。 因此,从逻辑上讲,我们将分析器的优先级设置为 -1。 这确保了正确的执行顺序。

总结

除了优先级和执行顺序的讨论之外,没有太多可说的。有用!

/media/plugins/trackmate/trackmate-customspotanalyzer-01.png

Jean-Yves Tinevez 2014年3月11日 - 2021年7月23日