原始 MediaWiki 页面

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

图像库处理器

自迁移出 MediaWiki 以来,本页内容尚未经过审查。如果您愿意帮忙,请查看帮助指南

The following article describes a method of ImageJ 1.x/ImageJ2 integration we explored in 2010, revolving around an ij.process.ImageProcessor extension called ImgLibProcessor which would enable additional transparent usage of ImgLib2 from within ImageJ 1.x, thus greatly expanding the available pixel types and storage strategies. However, after discussion with Wayne Rasband, we settled on a different method of backwards compatibility known as ImageJ Legacy. The text below is preserved only for historical reasons.

设计

ImgLibProcessor操作操作利用来实现功能。这里不是一个类,而只是一个概念。如果你想象一个处理器类,那么操作实际上是作用于处理器数据的方法,并且作为单独的类而不是在处理器类方法中。这样做是为了降低§§2存在§§§的复杂性。最初的动机是进行可以链接在一起的操作。(不知道这个动机实现得如何)

操作将迭代的概念和对指定用户区域上的数据的操作联系。典型操作的示例,我将一起讨论 imagej.process.operation.SingleCursorRoiOperation。这个抽象类作为管理单个 imglib 的迭代。这是它的主要迭代循环:

/** runs the operation. does the iteration and calls subclass methods as appropriate */
public void execute()
{
    if (this.observer != null)
        observer.init();
         
    final LocalizableByDimCursor<T> imageCursor =
        this.image.createLocalizableByDimCursor();
 
    final RegionOfInterestCursor<T> imageRoiCursor =
        new RegionOfInterestCursor<T>( imageCursor, this.origin, this.span );
         
    beforeIteration(imageRoiCursor.getType());
         
    //iterate over all the pixels, of the selected image plane
    for (T sample : imageRoiCursor)
    {
        // note that the include() method call below passes null as position. This
        // operation is not positionally aware for efficiency. Use a positional
        // operation in the imagej.process.operation package if needed.
             
        if ((this.selector == null) ||
            (this.selector.include(null, sample.getRealDouble())))
            insideIteration(sample);
 
        if (this.observer != null)
            observer.update();
    }
         
    afterIteration();
         
    imageRoiCursor.close();
    imageCursor.close();
 
    if (this.observer != null)
        observer.done();
}

关键思想包括:

  • 迭代被封装在这个类中。该类的子类实现beforeIteration()insideIteration()afterIteration()。(稍后我会讨论继承)
  • 迭代可以通过一个函数来约束,该函数使用迭代器指向样本的当前值和位置来确定是否调用insideIteration()
  • 迭代可以被其他类观察到

例如,我们将查看imagej.process.operation.MinMaxOperation。这是它的完整实现:

public class MinMaxOperation<T extends RealType<T>> extends SingleCursorRoiOperation<T>
{
    private double min, max, negInfinity, posInfinity;
     
    public MinMaxOperation(Image<T> image, int[] origin, int[] span)
    {
        super(image,origin,span);
    }
     
    public double getMax() { return this.max; }
    public double getMin() { return this.min; }
     
    @Override
    protected void beforeIteration(RealType<T> type)
    {
        this.min = type.getMaxValue();
        this.max = type.getMinValue();
        // CTR: HACK: Workaround for compiler issue with instanceof and generics.
        //if (type instanceof FloatType)
        if (FloatType.class.isAssignableFrom(type.getClass()))
        {
            this.posInfinity = Float.POSITIVE_INFINITY;
            this.negInfinity = Float.NEGATIVE_INFINITY;
        }
        else
        {
            this.posInfinity = Double.POSITIVE_INFINITY;
            this.negInfinity = Double.NEGATIVE_INFINITY;
        }
    }
     
    @Override
    protected void insideIteration(RealType<T> sample)
    {
        double value = sample.getRealDouble();
         
        if (value >= this.posInfinity) return;
        if (value <= this.negInfinity) return;
         
        if ( value > this.max )
            this.max = value;
 
        if ( value < this.min )
            this.min = value;
    }
     
    @Override
    protected void afterIteration()
    {
    }
}

您可以看到MinMaxOperation非常简单。它创建当前的迭代值非常简单并且顶部。以这种方式定义操作很简单,并且最终得到了很好的封装。然而,为了争取组合而不是继承,我尝试最小化操作类的数量。

通过SelectionFunctions的定义,使用组合来增强各种操作的能力成为可能。回想一下SingleCursorRoiOperationexecute()方法,您可以使用选择器来限制哪些样本将进行进一步处理。循环中的选择器是SelectionFunction。其签名在imagej.selection.SelectionFunction中定义:

public interface SelectionFunction
{
    boolean include(int[] position, double sample);
}

您可以定义任何您喜欢的函数,根据样本的值和在其父代中的位置来区分样本Image。然后,§§§1§§通过operation.setSelector(selectionFunction)附加到操作。

请注意,SelectionFunction不在imagej.process包中。我认为根据样本的价值和位置来区分样本的能力是ImageJ的广泛需求。我知道这对于支持罗伊斯会有很大帮助。目前,imagej.selection包中有用于组合复合选择函数的代码。因此做出任何复杂的选择。

一旦我们定义了选择函数,我们就可以以更强大的方式将它们用于操作。例如定义这个选择函数:

class Selector implements SelectionFunction
{
    public boolean include(int[] position, double sample)
    {
        if (sample value in range I desire)
            if (position within a rotated ellipse centered at x,y with params z)
                return true;
        return false;
    }
}

创建 MinMaxOperation 并附加此选择函数。当您运行operation.execute()时,您可以轻松且顶部地选择标准内找到的位置。

有些操作还可以更改基础数据。 Imagej.process.operation.UnaryTransformOperation就是一个例子。将通过使用当前Image作为输入的函数计算替换数据来更改图像基础的数据。该函数定义为UnaryFunction并传递给UnaryTransformOperationImagej.process.function.unary.UnaryFunction看起来像这样:

public interface UnaryFunction {
    double compute(double input);
}

UnaryFunction 的一个示例是 sqr() 函数,compute() 方法将返回输入的平方。要对图像的值求平方,您创建一个 UnaryTransformOperation,传递一个 sqr() UnaryFunction,然后运行​​其operation.execute()。其后,UnaryFunction任何可以复杂的,具有自己的一组参数,只要依赖于图像中的一个输入值。

定义了一些不可更改数据的操作。 Imagej.process.operation.QueryOperation 就是这样一个操作。 QueryOperationInfoCollector函数计算用户指定的数据。Imagej.process.query.InfoCollector外观如下:

/** the InfoCollector interface is used to define queries that can be passed to an
 *  imagej.process.operation.QueryOperation.*/
public interface InfoCollector
{
    /** this method called before the actual query takes place allowing the InfoCollector to initialize itself */
    void init();
     
    /** this method is called at each position of the original dataset allowing data to be collected */
    void collectInfo(int[] position, double value);
     
    /** this method is called when the query is done allowing cleanup and tabulation of results */
    void done();
}

当一个人使用QueryOperation时,就可以以任何想要的方式收集信息。

请注意,所有操作(转换、查询等)都可以修改为仅适用于用户定义的区域,然后进一步受值和位置选择函数的约束。可以应用用户可以定义的任何功能。

操作不限于一个数据集。定义了可用于同步数据集(1、2和N)的各种组合的操作类。

这些概念在 ImgLibProcessor 的整个实施过程中得到运用:

一个简单的一元改造侵犯 -

public void abs()
{
    AbsUnaryFunction function = new AbsUnaryFunction();
 
    nonPositionalTransform(function);  // a private method that does quickest SingRoiOp
}

使用选择函数的更复杂的示例 -

/** fills the current ROI area of the current plane of data with the fill color wherever the input mask is nonzero */
@Override
public void fill(ImageProcessor mask)
{
    if (mask==null) {
        fill();
        return;
    }
 
    int[] origin = originOfRoi();
 
    int[] span = spanOfRoiPlane();
 
    byte[] byteMask = (byte[]) mask.getPixels();
 
    FillUnaryFunction fillFunction = new FillUnaryFunction(this.fillColor);
 
    UnaryTransformPositionalOperation<T> transform =
        new UnaryTransformPositionalOperation<T>(this.imageData, origin, span,
                                fillFunction);
 
    SelectionFunction selector = new MaskOnSelectionFunction(origin, span, byteMask);
 
    transform.setSelectionFunction(selector);
 
    transform.execute();
}

使用 SelectionFunction 的两个图像操作 -

/** sets the current ROI area data to that stored in the snapshot wherever the mask is nonzero */
@Override
public void reset(ImageProcessor mask)
{
    if (mask==null || this.snapshot==null)
        return;
 
    Rectangle roi = getRoi();
 
    if ((mask.getWidth() != roi.width) || (mask.getHeight() != roi.height))
        throw new IllegalArgumentException(maskSizeError(mask));
 
    Image<T> snapData = this.snapshot.getStorage();
 
    int[] snapOrigin = Index.create(roi.x, roi.y,
                        new int[snapData.getNumDimensions()-2]);
 
    int[] snapSpan = Span.singlePlane(roi.width, roi.height,
                        snapData.getNumDimensions());
 
    int[] imageOrigin = originOfRoi();
    int[] imageSpan = spanOfRoiPlane();
 
    CopyInput2BinaryFunction copyFunction = new CopyInput2BinaryFunction();
 
    BinaryTransformPositionalOperation<T> resetOp =
        new BinaryTransformPositionalOperation<T>(this.imageData, imageOrigin,
                imageSpan, snapData, snapOrigin, snapSpan, copyFunction);
 
    MaskOffSelectionFunction maskOff =
        new MaskOffSelectionFunction(imageOrigin, imageSpan, (byte[])mask.getPixels());
 
    resetOp.setSelectionFunctions(maskOff, null);
 
    resetOp.execute();
 
    if (!this.isUnsignedByte)
    {
        this.min = this.snapshotMin;
        this.max = this.snapshotMax;
    }
}

ImgLibProcessor还公开了功能API以供进一步使用。具体来说,各种assign()transform()方法允许根据需要改变ImgLibProcessor的图像数据传递函数。

这些都可以在插件演示中结合在一起。以下代码适用于值范围在 0 到 1 之间的浮点图像。运行插件时,当前窗口图像的数据将被转换。更了解用户真正想在图像上做什么的人可以根据需要扩展它。

import ij.IJ;
import ij.ImagePlus;
import ij.WindowManager;
import ij.plugin.PlugIn;
import imagej.function.UnaryFunction;
import imagej.ij1bridge.process.ImgLibProcessor;
import imagej.selection.SelectionFunction;
 
import java.util.Random;
  
public class FunctionalPlugin implements PlugIn {
  
    private class MyFunction implements UnaryFunction
    {
        Random rng = new Random();
          
        public double compute(double value)
        {
            return rng.nextDouble();
        }
    }
  
    private class MySelector implements SelectionFunction
    {
        public boolean include(int[] position, double sample)
        {
            if (sample < 0.2) return false;
            if (sample > 0.8) return false;
            if (position[0] % 3 != 0) return false;
            if (position[1] % 2 != 0) return false;
            return true;
        }
    }
  
    public void run(String arg) {
        ImagePlus imp = WindowManager.getCurrentImage();
        ImgLibProcessor<?> proc = (ImgLibProcessor<?>)imp.getProcessor();
        MyFunction function = new MyFunction();
        MySelector selector = new MySelector();
        proc.transform(function, selector);
        imp.updateAndDraw();
    }
 
}

杂项注释

  • 如果需要,我们可以通过向其传递一个实现执行 before()inside()after() 接口的类来消除操作的继承(例如,在SingleCursorRoiOperation中)。这相当于ObserverInfoCollector,我们在这里可以做一些简化
  • 根据您的迭代方式以及同时使用的数据集数量,有许多不同的操作。还有一个内置的限制,即迭代器是同步的。我已经编写了概念验证代码来进行迭代,允许将迭代器组合为同步或迭代迭代器,消除一元/二元/NAry函数之间的分割等。未完成/尚未测试,但接近工作。
  • 我们可能希望将 SelectionFunction 拆分为 ValueFunctionPositionFunction。需要多思考

需要对 IJ1 进行更改以适应 ImgLibProcessor

本文档描述了 ImageJ 1.x 源代码所需的更改,这些更改将有助于在提供 ImgLib 支持的数据时实现正确的行为。它分为 5 个部分。

第 1 节概述了我们对 IJ 1.44l9 源代码的本地副本所做的更改。这些更改可以根据需要集成到 ImageJ 轴线中。
第 2 节概述了完全支持新图像类型 ImagePlus.OTHER 所需的进一步更改。
第 3 节概述了兼容支持新处理器类型所需的进一步更改。
第 4 节概述了与第 ImagePlus::getBitDepth() 上的案例逻辑切换相关的进一步更改。
第 5 节包含杂项注释

已进行更改以允许 IJ1 正确更新 ImgLib 数据

反映截至2010年12月17日的来源代码已更改

包 ij:

  • 图片加号 Added another image type : ImagePlus.OTHER Updated getBitDepth() to calc bits per pixel for OTHER type images
    Updated getBytesPerPixel() to calc number of bytes per pixel for OTHER type images
    Added double getActualBytesPerPixel() to support non-byte-aligned pixel types
    Updated setType() to allow OTHER type
    Updated getFileInfo() to populate self when dealing with OTHER type images
    Updated copy(boolean cut) to use getActualBytesPerPixel() in data byte use calculations
    Updated getPixel() to encode pixel data for OTHER type images

    包 ij.gui:

  • 图像清晰 Updated setDrawingColor() to have a subcase for OTHER type images
  • 图像窗口 Updated createSubtitle() to calc bit depth and image size from ImagePlus rather than by type
  • 魔杖 Change code to not use primitive array access for obtaining pixel values. To do so needed to make
    minor changes to constructor, minor change to autoOutline(), and rewrote getPixel().

    包 ij.io:

  • 文件信息 Added file type GRAY64_SIGNED
    Modified getBytesPerPixel() to support GRAY64_SIGNED and GRAY12_UNSIGNED
    Modified getType() to return values for GRAY64_SIGNED and GRAY12_UNSIGNED
  • 导入对话框 Added “12-bit Unsigned” to static class variable “types”.
    Updated getFileInfo() to identify GRAY12_UNSIGNED type files

    包 ij.measure:

  • 规划 Added a method called isSameAs(Calibration other). We rely on this for numerous tests.

    包 ij.plugin:

  • 文件夹打开器 Made minor change to the run() method to support OTHER type images
    Modified setStackInfo() to use new bytesPerPixel calculation methods
  • 虚拟堆栈列表 Updated showDialog() to use new bytesPerPixel calculation methods
    ###包ij.plugin.filter:
  • 图像数学 Many small edits to use setf()/getf() rather than direct float[] access. Also rather than instanceof
    FloatProcessor use ip.isFloatingType().
    Modify applyMacro case logic to test instanceof SomeProcessor rather than using getBitDepth()
  • 粒子分析仪 Added a type called OTHER. Made many small edits to support.
    Moved away from direct primitive array access for pixel values and rather use getf()/etc. as needed.
    There some places tagged with “WAYNE PLEASE CHECK” for further review
    Changed setThresholdLevels() to identify images of OTHER type and also set fillColor correctly
    Changed getStatistics() to delegate to ip.getStatistics() rather than checking image type
  • 插件FilterRunner Updated checkImagePlus() to have a switch case for images of type OTHER
    ###包ij.plugin.frame:
  • 解决调节器 Minor edit of setupNewImage() case logic to support OTHER type images
    Minor edit of reset() case logic to support OTHER type images
    Update the calculation of decimal places to display for OTHER type images in setMinAndMax() Update the calculation of decimal places to display for OTHER type images in setWindowLevel() ###包ij.process:
  • 图像处理器 Changed visibility of showProgress to public. We have a ProgressTracker class in IJ2 that updates an ip’s progress indicator.
    Changed visibility of getBilinearInterpolatedPixel() to public
    Changed visibility of resetPixels() to protected
    Changed visibility of create8BitImage() to protected
    Added abstract methods for all processors to support:
       int getBitDepth();  
       double getBytesPerPixel();  
       ImageStatistics getStatistics(int mOptions, Calibration cal);  
       boolean isFloatingType();  
       boolean isUnsignedType();  
       double getMinimumAllowedValue();  
       double getMaximumAllowedValue();  
       String getTypeName();  
       double getd(int x, int y);  
       double getd(int index);
    

    添加了几个 set/get 方法,以便我们的新 ImageProcessor 类型可以根据需要操作实例变量
    受保护的布尔值getSnapshotCopyMode() 公共整数getFgColor() 公共§§3§§§ 公共颜色getDrawingColor()

添加了仅在 ImagePlus::getPixel() 的其他类型的处理器上调用的方法 public void encodePixelInfo(int[] destination, int x, int y)

  • 字节内存 implementation of the new abstract methods of the ImageProcessor interface
  • 色彩内存 implementation of the new abstract methods of the ImageProcessor interface
  • 浮点处理器 implementation of the new abstract methods of the ImageProcessor interface
  • 短内存 implementation of the new abstract methods of the ImageProcessor interface
  • 图像统计 Made a few methods with package access into protected methods
    calculateStdDev(), setup(), fitEllipse(), calculateMedian() Changed getStatistics() to delegate to passed in ImageProcessor’s getStatistics() method rather than
    switching on processor type and hatching a type appropriate ImageStatistics
  • 类型转换器 Added support for OTHER image types with new package level access methods:
      ByteProcessor convertOtherToByte()  
      ShortProcessor convertOtherToShort()  
      FloatProcessor convertOtherToFloat().  
    

    ImagePlus::getType() 使用的地方需要更新

  • ij.gui.Roi - showStatus() 如果没有简单的修复,对于某些 Imglib 类型,显示的小数位数将不正确。
  • ij.io.FileOpener - setCalibration() 需要进行细微更改,以确保处理器的最小和最大设置正确。
  • ij.io.FileSaversaveAsJpeg()getDescriptionString()需要小的大小写逻辑更改。应检查各种 saveAsXXX() 插件是否适用于 ImgLibProcessor 支持的类型。
  • ij.macro.Functions - setPixel()getpixel() - 需要对大小写逻辑进行细微更改以支持其他类型
  • ij.measure.Calibration - setImage() 需要对大小写逻辑进行细微更改以支持其他类型
  • ij.plugin.filter.Calibrator - run()calibrate()doCurveFitting() - 支持其他类型所需的案例逻辑的细微更改
  • ij.plugin.filter.Filters - §§§20§§§ 有较小的大小写逻辑更改,需要支持其他类型
  • §§§21§§§ - §§§22§§§ 需要 §§§23§§§ 的子案例。局部变化较小。
  • §§§24§§§ - §§§25§§§ 如果图像是浮点类型,则需要对大小写逻辑进行较小的更改来设置小数位数
  • §§§26§§§ – §§§27§§§、§§§28§§§,也许§§§29§§§需要小案例逻辑调整
  • §§§30§§§ - §§§31§§§ - 细微更改以确定不是 8 位图像
  • §§§32§§§需要更彻底的类型检查以支持其他类型的图像。就目前情况而言,可以尝试并连接两个具有完全不同像素格式的 OTHER 类型图像。也不能将 §§§33§§§ 和 §§§34§§§ 与 16 位支持数据连接起来。
  • §§§35§§§ - §§§36§§§ 有一行需要更改以支持其他类型
  • §§§37§§§ – §§§38§§§ 需要一些重要的更改来支持其他类型
  • §§§39§§§ – §§§40§§§需要浮动检查而不是§§§41§§§。简单修复。
  • §§§42§§§ 的问题与§§§43§§§ 类似。
  • §§§44§§§ 具有与§§§45§§§类似的问题
  • §§§46§§§ – §§§47§§§ 需要稍作修改以支持其他类型
  • §§§48§§§ – §§§49§§§测试§§§50§§§而不是§§§51§§§。修复起来很简单。
  • §§§52§§§需要大量工作来支持其他类型
  • §§§53§§§需要大量工作来支持其他类型
  • §§§54§§§: - §§§55§§§ 需要进行细微更改(从 §§§56§§§ 测试到 §§§57§§§ 测试)
  • §§§58§§§ – 其他类型所需的菜单条目。并且§§§59§§§应该使用新的字节使用计算例程。

instanceof SomeProcessor 使用的地方需要更新

  • ij.io.TextEncoder – 需要进行细微更改(使用!ip.isFloatingType())以支持其他类型
  • ij.macro.FunctionsgetStatistics() 假设您只有 8 和 16 位图像/直方图。需要一些修改来支持其他类型。
  • ij.plugin.filter.BackgroundSubtracter – 需要扩展一些实质性工作以支持其他类型的处理器
  • ij.plugin.Convolver – 各种方法对可以存在哪些类型的处理器做出假设。似乎还依赖FloatProcessor。需要一些重要的工作来支持其他类型
  • ij.plugin.filter.ImageMath – 在run()方法中,对签名数据进行不安全检查。简单修复。对于浮点数据还有一些不安全的检查。又是一个简单的修复。
  • ij.plugin.filter.MaximumFinder – 确定数据是否为浮点类型所需的简单修复
  • ij.plugin.filter.ParticleAnalyzer – 做出不安全的假设。我已经大部分更新了。韦恩可能需要做出更大的改变。将与韦恩讨论这一问题。
  • ij.plugin.filter.PluginFilterRunner – 测试与FloatProcessor。可能不需要任何改变。可能可以工作,但对于 float 类型的 ImgLibProcessors 可能效率低下。多学习。
  • ij.plugin.frame.ContrastAdjuster – 做出一些类型假设。我想我已经在第 \_ij1-patches 中修复了它。
  • ij.plugin.frame.ThresholdAdjusterupdateLabels()ShortProcessor 进行测试。可能需要修复。 DoSet()需要将instanceof §§§20§§§替换为§§§21§§§。 §§§22§§§需要用§§§23§§§替换instanceof FloatProcessor。
  • §§§24§§§ – 做出一些类型假设。可能需要一些更大的返工。
  • §§§25§§§ – 标头设置依赖于§§§26§§§ 或§§§27§§§。可能需要询问其他类型需要什么。 §§§28§§§仅做浮动和短路。不支持由花车和短裤支持的其他类型图像。
  • §§§29§§§ – 对处理器类型做出许多假设。需要重要的更新来支持其他类型。
  • §§§30§§§ – 假设只有当前处理器会存在。需要进行重要的更新才能工作。
  • ij.process.FloodFiller – 构造函数需要简单更改才能使用ip.isFloatingType()
  • ij.process.ImageStatistics – 我想我已经在\_ij1-patches中进行了所有需要的更改
  • ij.process.TypeConverter – 我想我已经在\_ij1-patches中进行了所有需要的更改
  • ij.ImagePlus - 我想我已经在\_ij1-patches中进行了所有需要的更改

ImagePlus::getBitDepth() 使用的地方需要更新

  • ij.io.FileSaverokForFits() 应测试imp.getType() 而不是imp.getBitDepth()。简单的。
  • ij.io.ImportDialog – 而不是测试bitDepth(),它应该测试getType()而不是ByteColor。简单的。
  • ij.macro.FunctionssetColor() 需要对 16 位有符号数据进行较小的大小写逻辑更改,以避免不必要地引发异常。 GetHistogram()setLut()setMinAndMax() 应测试 getType() 而不是 getBitDepth()。简单的。
  • ij.plugin.filter.FFTCustomFilterdoInverseTransform() 对暗示某些类型处理器的位深度做出了一些假设。需要仔细观察。
  • ij.plugin.filter.FFTFilterfilter() 对暗示某些类型处理器的位深度做出了一些假设。需要仔细观察。
  • §§§20§§§ – §§§21§§§ 的“div”情况假设 32 位意味着浮点类型数据。简单修复。 §§§22§§§和§§§23§§§应该与§§§24§§§而不是§§§25§§§进行测试。简单的。
  • §§§26§§§ – §§§27§§§ 应测试§§§28§§§ 而不是§§§29§§§。简单的。
  • §§§30§§§ – §§§31§§§ 在应该测试§§§32§§§时测试位深度。简单的。
  • §§§33§§§ - §§§34§§§ 在应该测试§§§35§§§时测试位深度。简单的。
  • §§§36§§§ - §§§37§§§ 在应该测试§§§38§§§时测试位深度。简单的。
  • §§§39§§§ – 在少数地方应该使用§§§40§§§时使用 bitDepth。简单的修复。
  • §§§41§§§ – §§§42§§§ 假定 24 位意味着 §§§43§§§。简单修复。
  • §§§44§§§ – §§§45§§§、§§§46§§§、§§§47§§§、§§§48§§§和§§§49§§§在应测试§§§50§§§时测试位深度。简单的。
  • §§§51§§§ – §§§52§§§ 和 §§§53§§§ 假定 32 位为浮点型。使用§§§54§§§的简单修复。
  • §§§55§§§ – 构造函数应测试§§§56§§§。 §§§57§§§和§§§58§§§假设32位是浮点数。请改用§§§59§§§。简单的。
  • §§§60§§§ – §§§61§§§ 有一些非常小的 16 位特殊情况逻辑。不知道为什么。需要进一步调查。
  • §§§62§§§ – §§§63§§§ 在应该使用 §§§65§§§ 时使用了 §§§64§§§。简单的。
  • §§§66§§§ – §§§67§§§和§§§68§§§在应该使用§§§70§§§时使用§§§69§§§。简单的。
  • §§§71§§§在应该使用§§§73§§§时使用了§§§72§§§。简单的。
  • §§§74§§§在应该使用§§§76§§§时使用了§§§75§§§。简单的。
  • §§§77§§§ – 一些问题。进一步调查
  • §§§78§§§在应该使用§§§80§§§时使用了§§§79§§§。仍然有点破损,因为它使用从其他地方复制的§§§81§§§。我们希望消除对位深度的依赖来确定我们拥有哪种处理器。
  • §§§82§§§在可以使用§§§84§§§时使用§§§83§§§。该方法记录了instanceof 的问题。方法需要更仔细的检查。
  • §§§85§§§ 多次依赖 bitDepth。需要进一步调查。
  • §§§86§§§ – §§§87§§§ 在应使用§§§88§§§时依赖于位深度。修复起来很简单。
  • §§§89§§§ – §§§90§§§ 在应使用§§§91§§§时依赖于位深度。修复起来很简单。
  • §§§92§§§ – 不适用于 OTHER 类型的图像,因为它依赖于 §§§93§§§,后者只知道少数预定义的图像类型。可能需要方法来覆盖现有的 IJ,以便我们可以挂钩我们自己的 §§§94§§§。还依赖于 §§§95§§§,它也具有有限的位深度支持。否则,§§§96§§§对于此类来说使用是没问题的。
  • §§§97§§§ – §§§98§§§ 依赖于位深度而不是§§§99§§§。修复起来很简单。
  • §§§100§§§ – 很大程度上依赖于位深度。原样不适用于其他类型的图像。仔细看看这个。
  • §§§101§§§ – 非常依赖位深度。假设仅存在少数处理器类型。需要创建处理器。我们可能需要 Wayne 创建一个我们可以覆盖的处理器工厂。仔细看看这个。
  • §§§102§§§ – §§§103§§§ 在可以很容易避免的情况下使用位深度。
  • §§§104§§§ – §§§105§§§ 在可以很容易避免的情况下使用位深度。
  • ij.plugin.ResizerzScale() 不必要地使用位深度。简单的。 ResizeZ()zScaleHyperStack()都使用位深度来调用IJ.createImage()。所以我们再次需要以某种方式覆盖。
  • ij.plugin.RGBStackMergemergeStacks()mergeHyperStacks() 需要一定的位深度访问。但也假设 24 位是 RGB。删除这个假设很简单。
  • ij.plugin.ScalershowDialog() 在可以使用 getType() 时使用位深度。简单的。
  • ij.plugin.SlicerresliceHyperStack() 使用位深度调用createHyperStack()。需要覆盖。CreateOutputStack()使用位深度调用NewImage.createImage()。再次需要覆盖。GetOutputStackSize()使用bitDepth来计算数据使用大小。使用新的字节计算方法。
  • ij.plugin.Straightenerstraighten()、§§§20§§§ 和 §§§21§§§ 均假设 24 位 == RGB。修复起来很简单。
  • §§§22§§§在可以使用§§§24§§§的地方使用§§§23§§§。简单的。
  • §§§25§§§在可以使用§§§27§§§的地方使用§§§26§§§。简单的。
  • §§§28§§§在可以使用§§§30§§§的地方使用§§§29§§§。简单的。
  • §§§31§§§在可以使用§§§33§§§的地方使用§§§32§§§。简单的。
  • §§§34§§§在可以使用§§§36§§§的地方使用§§§35§§§。简单的。
  • §§§37§§§ – 构造函数和§§§38§§§依赖于位深度。24位的东西可以使用§§§39§§§代替。但8号和16号的情况可能没问题。进一步调查。
  • §§§40§§§ – 构造函数假设 24 位 == RGB。简单修复。
  • §§§41§§§ – §§§42§§§ 和 §§§43§§§ 使用位深度但为 8 位情况。所以可能是安全的,但最好更换。简单修复。
  • §§§44§§§ – §§§45§§§开放位深度。仅支持8、16、24和32。从外观上看这可能还可以。

杂项注释

ImageProcessor和子类中所需的附加方法:

  • 双重支持:通过setd()按(x,y)或按索引设置
  • 长期支持:通过getl()/setl()按(x,y)或索引获取/设置

进一步更改:

  • 在需要时将 ImagePlus::getBytesPerPixel() 替换为 ImagePlus::getActualBytesPerPixel()