Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,72 @@ A complete help system was added to the InterestPointExplorer:
- `8994af77` - Initial help window implementation
- `34bff636` - Fixed focus issue for immediate F1 response

## Cross-Correlation Computation for Rotated Views

### Problem Statement
Computing accurate cross-correlation values between views with arbitrary affine transformations (especially rotations) requires special handling. Naive approaches that compare axis-aligned bounding boxes in local coordinate systems fail because:

1. **Simple bounding box intersection** in global space can create overlap regions that extend outside actual image bounds when views are rotated, leading to excessive zero-padding
2. **Independent local overlaps** (sampling in each view separately) find regions with different physical extents that don't actually correspond pixel-by-pixel

### Solution: Hybrid Approach with Resampling

The implementation in `ComputeCrossCorrelationPopup.java` uses a hybrid approach combining:

1. **Accurate Overlap Detection** (via `SimpleBoundingBoxOverlap.getLocalOverlapsUsingPixelValidation`):
- Samples pixels in each view's local space
- Validates they map to valid pixels in the other view
- Accounts for rotations and complex transformations
- Returns tight bounding boxes in each view's local coordinate system

2. **Proper Data Alignment** (via resampling with interpolation):
- Uses View1's overlap region as the reference coordinate system
- Transforms View2 into View1's coordinate system using the full transform chain
- Applies N-linear interpolation for sub-pixel accuracy
- Uses mirror extension (`extendMirrorSingle`) to handle edge pixels gracefully

### Implementation Details

**Key code section** (lines ~379-520 in ComputeCrossCorrelationPopup.java):

```java
// 1. Find accurate overlaps using pixel validation
RealInterval[] localOverlaps = SimpleBoundingBoxOverlap.getLocalOverlapsUsingPixelValidation(
vs1.getSize(), vs2.getSize(), m1, m2);
RealInterval localOverlap1 = localOverlaps[0];

// 2. Extract overlap region from View1
RandomAccessibleInterval<FloatType> overlap1 = Views.interval(img1, dsInterval1);

// 3. Transform View2 into View1's coordinate system
AffineTransform3D view2ToView1 = dsM1.inverse();
view2ToView1.concatenate(dsM2);

// 4. Create interpolated, transformed view of img2
RealRandomAccessible<FloatType> interpolated2 = Views.interpolate(
Views.extendMirrorSingle(img2),
new NLinearInterpolatorFactory<>());
RealRandomAccessible<FloatType> transformed2 = RealViews.transform(interpolated2, view2ToView1);

// 5. Rasterize over the SAME interval as View1
RandomAccessibleInterval<FloatType> overlap2 = Views.interval(
Views.raster(transformed2), dsInterval1);

// 6. Compute correlation on perfectly aligned regions
peak.calculateCrossCorr(overlap1, overlap2);
```

### Why This Works

- **Pixel-by-pixel correspondence**: Both overlap regions use the same interval (from View1's coordinate system), ensuring perfect alignment
- **Rotation handling**: The transformation and interpolation properly handle arbitrary rotations without introducing misalignment
- **Edge handling**: Mirror extension prevents low correlation due to zero-padding at boundaries
- **Efficient**: Only processes the actual overlapping region, not entire images

### Results

This approach produces accurate correlation values (typically >0.9 for good alignments) across all view pairs, regardless of relative rotation or transformation complexity.

## Important Notes

- **Never commit without explicit user consent**
Expand Down
171 changes: 171 additions & 0 deletions dependency-reduced-pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>pom-scijava</artifactId>
<groupId>org.scijava</groupId>
<version>43.0.0</version>
<relativePath>pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>net.preibisch</groupId>
<artifactId>multiview-reconstruction</artifactId>
<name>Multiview Reconstruction</name>
<version>8.1.2-SNAPSHOT</version>
<description>Software for the reconstruction of multi-view microscopic acquisitions
like Selective Plane Illumination Microscopy (SPIM) Data.</description>
<url>https://github.com/JaneliaSciComp/multiview-reconstruction</url>
<issueManagement>
<system>GitHub Issues</system>
<url>https://github.com/JaneliaSciComp/multiview-reconstruction/issues</url>
</issueManagement>
<ciManagement>
<system>GitHub Actions</system>
<url>https://github.com/JaneliaSciComp/multiview-reconstruction/actions</url>
</ciManagement>
<inceptionYear>2012</inceptionYear>
<mailingLists>
<mailingList>
<name>Image.sc Forum</name>
<archive>https://forum.image.sc/tag/multiview-reconstruction</archive>
</mailingList>
</mailingLists>
<developers>
<developer>
<id>StephanPreibisch</id>
<name>Stephan Preibisch</name>
<url>https://imagej.net/people/StephanPreibisch</url>
<roles>
<role>founder</role>
<role>lead</role>
<role>developer</role>
<role>debugger</role>
<role>reviewer</role>
<role>support</role>
<role>maintainer</role>
</roles>
</developer>
<developer>
<id>hoerldavid</id>
<name>David Hoerl</name>
<url>https://imagej.net/people/hoerldavid</url>
<roles>
<role>developer</role>
<role>debugger</role>
<role>reviewer</role>
<role>support</role>
<role>maintainer</role>
</roles>
</developer>
</developers>
<contributors>
<contributor>
<name>Tobias Pietzsch</name>
<url>https://imagej.net/people/tpietzsch</url>
<properties>
<id>tpietzsch</id>
</properties>
</contributor>
<contributor>
<name>Curtis Rueden</name>
<url>https://imagej.net/people/ctrueden</url>
<properties>
<id>ctrueden</id>
</properties>
</contributor>
</contributors>
<licenses>
<license>
<name>GNU General Public License v2+</name>
<url>https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<connection>scm:git:https://github.com/JaneliaSciComp/multiview-reconstruction</connection>
<developerConnection>scm:git:git@github.com:JaneliaSciComp/multiview-reconstruction</developerConnection>
<url>https://github.com/JaneliaSciComp/multiview-reconstruction</url>
</scm>
<organization>
<name>Preibisch Lab</name>
<url>http://preibischlab.mdc-berlin.de</url>
</organization>
<profiles>
<profile>
<id>fatjar</id>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<transformers>
<transformer>
<resource>META-INF/json/mpicbg.spim.data.generic.sequence.ImgLoaderIo</resource>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<relocations>
<relocation>
<pattern>org.apache.commons.compress</pattern>
<shadedPattern>org.janelia.saalfeldlab.org.apache.commons.compress</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
<repository>
<id>scijava.public</id>
<url>https://maven.scijava.org/content/groups/public</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.15</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>activation</artifactId>
<groupId>javax.activation</groupId>
</exclusion>
<exclusion>
<artifactId>logback-core</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<imglib2.version>8.0.0</imglib2.version>
<package-name>net.preibisch.mvrecon</package-name>
<imglib2-cache.version>1.0.0-beta-20</imglib2-cache.version>
<license.copyrightOwners>Multiview Reconstruction developers.</license.copyrightOwners>
<bigdataviewer-core.version>10.6.5</bigdataviewer-core.version>
<ijp-kheops.version>0.6.2</ijp-kheops.version>
<generic-archiver.version>1.1.0</generic-archiver.version>
<license.licenseName>gpl_v2</license.licenseName>
<releaseProfiles>sign,deploy-to-scijava</releaseProfiles>
<pyramidio.version>1.1.0</pyramidio.version>
</properties>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
import net.preibisch.mvrecon.fiji.spimdata.explorer.popup.BDVPopup;
import net.preibisch.mvrecon.fiji.spimdata.explorer.popup.BakeManualTransformationPopup;
import net.preibisch.mvrecon.fiji.spimdata.explorer.popup.BoundingBoxPopup;
import net.preibisch.mvrecon.fiji.spimdata.explorer.popup.ComputeCrossCorrelationPopup;
import net.preibisch.mvrecon.fiji.spimdata.explorer.popup.DeconvolutionPopup;
import net.preibisch.mvrecon.fiji.spimdata.explorer.popup.DetectInterestPointsPopup;
import net.preibisch.mvrecon.fiji.spimdata.explorer.popup.DisplayFusedImagesPopup;
Expand Down Expand Up @@ -694,6 +695,7 @@ public ArrayList< ExplorerWindowSetable > initPopups()
popups.add( new BDVPopup() );
popups.add( new DisplayRawImagesPopup() );
popups.add( new DisplayFusedImagesPopup() );
popups.add( new ComputeCrossCorrelationPopup() );
popups.add( new VisualizeNonRigid() );
popups.add( new MaxProjectPopup() );
popups.add( new Separator() );
Expand Down
Loading