Skip to content

Commit da5a816

Browse files
authored
Merge pull request #2431 from SCIInstitute/oblique_python
Ensure images are axis aligned when loading
2 parents ddc59f9 + e335ed9 commit da5a816

File tree

12 files changed

+186
-100
lines changed

12 files changed

+186
-100
lines changed

.github/workflows/build-linux-debug.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,30 @@ jobs:
6161
shell: bash -l {0}
6262
run: .github/workflows/gha_conda.sh
6363

64+
- name: Restore Dependencies Cache
65+
id: cache-deps-restore
66+
uses: actions/cache/restore@v3
67+
with:
68+
path: /github/home/install
69+
key: ${{ runner.os }}-deps-debug-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
70+
restore-keys: |
71+
${{ runner.os }}-deps-
72+
6473
- name: Check space4
6574
run: df -h
6675

6776
- name: Build Dependencies
77+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
6878
shell: bash -l {0}
6979
run: .github/workflows/gha_deps.sh
7080

81+
- name: Save Dependencies Cache
82+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
83+
uses: actions/cache/save@v3
84+
with:
85+
path: /github/home/install
86+
key: ${{ runner.os }}-deps-debug-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
87+
7188
- name: Check space5
7289
run: df -h
7390

.github/workflows/build-linux.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,32 @@ jobs:
5959
shell: bash -l {0}
6060
run: .github/workflows/gha_conda.sh
6161

62+
- name: Restore Dependencies Cache
63+
id: cache-deps-restore
64+
uses: actions/cache/restore@v3
65+
with:
66+
path: /github/home/install
67+
key: ${{ runner.os }}-deps-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
68+
restore-keys: |
69+
${{ runner.os }}-deps-
70+
6271
- name: try import vtk
6372
shell: bash -l {0}
6473
run: conda activate shapeworks && python -c "import vtk"
6574

75+
6676
- name: Build Dependencies
77+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
6778
shell: bash -l {0}
6879
run: .github/workflows/gha_deps.sh
6980

81+
- name: Save Dependencies Cache
82+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
83+
uses: actions/cache/save@v3
84+
with:
85+
path: /github/home/install
86+
key: ${{ runner.os }}-deps-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
87+
7088
- name: Check space4
7189
run: df -h
7290

.github/workflows/build-mac-arm64.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,27 @@ jobs:
5050
shell: bash -l {0}
5151
run: .github/workflows/gha_conda.sh
5252

53+
- name: Restore Dependencies Cache
54+
id: cache-deps-restore
55+
uses: actions/cache/restore@v3
56+
with:
57+
path: /Users/runner/install
58+
key: ${{ runner.os }}-arm64-deps-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
59+
restore-keys: |
60+
${{ runner.os }}-deps-
61+
5362
- name: Build Dependencies
63+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
5464
shell: bash -l {0}
5565
run: .github/workflows/gha_deps.sh
5666

67+
- name: Save Dependencies Cache
68+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
69+
uses: actions/cache/save@v3
70+
with:
71+
path: /Users/runner/install
72+
key: ${{ runner.os }}-arm64-deps-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
73+
5774
- name: cmake
5875
shell: bash -l {0}
5976
run: conda activate shapeworks && mkdir build && cd build && cmake -DCMAKE_LIBTOOL=/usr/bin/libtool -DCMAKE_CXX_FLAGS="-g -Wno-enum-constexpr-conversion" -DCMAKE_PREFIX_PATH=$HOME/install -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPython3_ROOT_DIR:FILEPATH=${CONDA_PREFIX} -DUSE_OPENMP=OFF -DBuild_Studio=ON -DCMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/shapeworks-install -DBUILD_DOCUMENTATION=ON -DGA_MEASUREMENT_ID=$GA_MEASUREMENT_ID -DGA_API_SECRET=$GA_API_SECRET ..

.github/workflows/build-mac.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,27 @@ jobs:
5151
shell: bash -l {0}
5252
run: .github/workflows/gha_conda.sh
5353

54+
- name: Restore Dependencies Cache
55+
id: cache-deps-restore
56+
uses: actions/cache/restore@v3
57+
with:
58+
path: /Users/runner/install
59+
key: ${{ runner.os }}-intel-deps-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
60+
restore-keys: |
61+
${{ runner.os }}-deps-
62+
5463
- name: Build Dependencies
64+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
5565
shell: bash -l {0}
5666
run: .github/workflows/gha_deps.sh
5767

68+
- name: Save Dependencies Cache
69+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
70+
uses: actions/cache/save@v3
71+
with:
72+
path: /Users/runner/install
73+
key: ${{ runner.os }}-intel-deps-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
74+
5875
- name: cmake
5976
shell: bash -l {0}
6077
run: conda activate shapeworks && mkdir build && cd build && cmake -DCMAKE_LIBTOOL=/usr/bin/libtool -DCMAKE_CXX_FLAGS=-g -DCMAKE_PREFIX_PATH=$HOME/install -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPython3_ROOT_DIR:FILEPATH=${CONDA_PREFIX} -DUSE_OPENMP=OFF -DBuild_Studio=ON -DCMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/shapeworks-install -DBUILD_DOCUMENTATION=ON -DGA_MEASUREMENT_ID=$GA_MEASUREMENT_ID -DGA_API_SECRET=$GA_API_SECRET ..

.github/workflows/build-windows.yml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,26 @@ jobs:
8787
shell: bash -l {0}
8888
run: .github/workflows/gha_conda.sh
8989

90+
- name: Restore Dependencies Cache
91+
id: cache-deps-restore
92+
uses: actions/cache/restore@v3
93+
with:
94+
path: C:\deps
95+
key: ${{ runner.os }}-deps-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
96+
restore-keys: |
97+
${{ runner.os }}-deps-
98+
9099
- name: Build Dependencies
100+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
91101
shell: bash -l {0}
92102
run: .github/workflows/gha_deps.sh
103+
104+
- name: Save Dependencies Cache
105+
if: steps.cache-deps-restore.outputs.cache-hit != 'true'
106+
uses: actions/cache/save@v3
107+
with:
108+
path: C:\deps
109+
key: ${{ runner.os }}-deps-${{ hashFiles('.github/workflows/gha_deps.sh', 'install_shapeworks.sh', 'python_requirements.txt', 'build_dependencies.sh') }}
93110

94111
- name: Create Build Environment
95112
# Some projects don't allow in-source building, so create a separate build directory
@@ -167,4 +184,4 @@ jobs:
167184
prerelease: true
168185
title: "Development Build for Windows"
169186
files: |
170-
d:/a/ShapeWorks/ShapeWorks/artifacts/*.exe
187+
d:/a/ShapeWorks/ShapeWorks/artifacts/*.exe

Libs/Groom/Groom.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,6 @@ bool Groom::image_pipeline(std::shared_ptr<Subject> subject, size_t domain) {
216216

217217
//---------------------------------------------------------------------------
218218
bool Groom::run_image_pipeline(Image& image, GroomParameters params) {
219-
// ensure axis aligned
220-
image.toAxisAligned();
221-
222219
// isolate
223220
if (params.get_isolate_tool()) {
224221
image.isolate();
@@ -1141,17 +1138,13 @@ Mesh Groom::get_mesh(int subject, int domain, bool transformed, MeshSource sourc
11411138
}
11421139
path = subjects[subject]->get_original_filenames()[domain];
11431140
domain_type = project_->get_original_domain_types()[domain];
1144-
SW_DEBUG("Getting original mesh for subject {}, domain {}: {}", subject, domain, path);
1145-
SW_DEBUG("Domain type: {}", static_cast<int>(domain_type));
11461141
} else {
11471142
if (domain >= subjects[subject]->get_groomed_filenames().size()) {
11481143
throw std::out_of_range("domain index out of range");
11491144
}
11501145
path = subjects[subject]->get_groomed_filenames()[domain];
11511146

11521147
domain_type = ProjectUtils::determine_domain_type(path);
1153-
SW_DEBUG("Getting groomed mesh for subject {}, domain {}: {}", subject, domain, path);
1154-
SW_DEBUG("Domain type: {}", static_cast<int>(domain_type));
11551148
}
11561149

11571150
auto constraint_filename = subjects[subject]->get_constraints_filenames();

Libs/Groom/Groom.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ class Groom {
8787

8888
Mesh get_mesh(int subject, int domain, bool transformed = false, MeshSource source = MeshSource::Groomed);
8989

90-
9190
vtkSmartPointer<vtkPoints> get_landmarks(int subject, int domain);
9291

9392
int find_reference_landmarks(std::vector<vtkSmartPointer<vtkPoints>> landmarks);

Libs/Image/Image.cpp

Lines changed: 2 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ Image::ImageType::Pointer Image::read(const std::string& pathname) {
140140
img = orienter->GetOutput();
141141
}
142142

143+
img = ImageUtils::make_axis_aligned(img);
144+
143145
return img;
144146
}
145147

@@ -431,90 +433,6 @@ Image& Image::resize(Dims dims, Image::InterpolationType interp) {
431433
return resample(IdentityTransform::New(), origin(), dims, spacing, coordsys(), interp);
432434
}
433435

434-
435-
Image& Image::toAxisAligned(InterpolationType interp) {
436-
// Check if image is already axis-aligned
437-
auto direction = itk_image_->GetDirection();
438-
bool is_oblique = false;
439-
for (unsigned int i = 0; i < 3; i++) {
440-
for (unsigned int j = 0; j < 3; j++) {
441-
double expected = (i == j) ? 1.0 : 0.0;
442-
if (std::abs(direction(i, j) - expected) > 1e-6) {
443-
is_oblique = true;
444-
break;
445-
}
446-
}
447-
}
448-
449-
// If already axis-aligned, return immediately
450-
if (!is_oblique) {
451-
return *this;
452-
}
453-
454-
// The key insight: we need to create a transform that represents
455-
// the DIFFERENCE between the oblique and axis-aligned coordinate systems
456-
457-
using TransformType = itk::AffineTransform<double, 3>;
458-
auto transform = TransformType::New();
459-
460-
// The direction matrix rotates from index space to physical space
461-
// To go from new axis-aligned indices to old oblique physical space,
462-
// we need: newPhysical = identity * newIndex
463-
// oldIndex = direction^-1 * oldPhysical
464-
// So: oldIndex = direction^-1 * identity * newIndex = direction^-1 * newIndex
465-
466-
TransformType::MatrixType matrix;
467-
for (int i = 0; i < 3; i++) {
468-
for (int j = 0; j < 3; j++) {
469-
matrix(i, j) = direction(i, j);
470-
}
471-
}
472-
transform->SetMatrix(matrix);
473-
474-
// Get bounding box
475-
auto size = itk_image_->GetLargestPossibleRegion().GetSize();
476-
auto spacing = itk_image_->GetSpacing();
477-
auto origin = itk_image_->GetOrigin();
478-
479-
Point3 minPt, maxPt;
480-
for (int i = 0; i < 3; i++) {
481-
minPt[i] = std::numeric_limits<double>::max();
482-
maxPt[i] = std::numeric_limits<double>::lowest();
483-
}
484-
485-
for (int corner = 0; corner < 8; corner++) {
486-
Coord index;
487-
index[0] = (corner & 1) ? size[0] - 1 : 0;
488-
index[1] = (corner & 2) ? size[1] - 1 : 0;
489-
index[2] = (corner & 4) ? size[2] - 1 : 0;
490-
491-
Point3 point;
492-
itk_image_->TransformIndexToPhysicalPoint(index, point);
493-
494-
for (int dim = 0; dim < 3; dim++) {
495-
minPt[dim] = std::min(minPt[dim], point[dim]);
496-
maxPt[dim] = std::max(maxPt[dim], point[dim]);
497-
}
498-
}
499-
500-
ImageType::DirectionType identityDir;
501-
identityDir.SetIdentity();
502-
503-
ImageType::SizeType outputSize;
504-
for (int i = 0; i < 3; i++) {
505-
outputSize[i] = static_cast<size_t>(std::ceil((maxPt[i] - minPt[i]) / spacing[i])) + 1;
506-
}
507-
508-
Vector3 spacingVec;
509-
Dims dims;
510-
for (int i = 0; i < 3; i++) {
511-
spacingVec[i] = spacing[i];
512-
dims[i] = outputSize[i];
513-
}
514-
515-
return resample(transform, minPt, dims, spacingVec, identityDir, interp);
516-
}
517-
518436
bool Image::compare(const Image& other, bool verifyall, double tolerance, double precision) const {
519437
if (tolerance > 1 || tolerance < 0) {
520438
throw std::invalid_argument("tolerance value must be between 0 and 1 (inclusive)");

Libs/Image/Image.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,6 @@ class Image {
105105
/// resamples image using isotropic physical spacing
106106
Image& resample(double isoSpacing = 1.0, InterpolationType interp = Linear);
107107

108-
/// resamples image to be axis-aligned (i.e., identity direction matrix) if needed
109-
Image& toAxisAligned(InterpolationType interp = NearestNeighbor);
110-
111108
/// changes logical image size, computing new physical spacing based on this size (i.e., physical image size remains
112109
/// the same)
113110
Image& resize(Dims logicalDims, InterpolationType interp = Linear);

0 commit comments

Comments
 (0)