Skip to content

Zernike moments#64

Open
Eesha-Jain wants to merge 12 commits intomainfrom
zernike-moments
Open

Zernike moments#64
Eesha-Jain wants to merge 12 commits intomainfrom
zernike-moments

Conversation

@Eesha-Jain
Copy link
Copy Markdown

@Eesha-Jain Eesha-Jain commented Feb 25, 2026

Description

Implementing the ZernikeEdgeDetectionAlgorithm, which ngests a pixel level edge detection algorithm to obtain a pixel level approximation of the edge of earth and then performs a sub-pixel edge correction using the moment based edge-orientation and offset. This leverages Zernike polynomials, which is a mathematical pattern defined in polar coordinates.

This algorithm is based on Christian (2017) "Accurate Planetary Limb Localization" (https://www.researchgate.net/publication/317742756_Accurate_Planetary_Limb_Localization_for_Image-Based_Spacecraft_Navigation)

Artifacts for PR #64 (DO NOT CHANGE)

Copilot AI review requested due to automatic review settings February 25, 2026 05:33
Comment thread src/distance/edge.hpp
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Zernike-moment-based edge refinement algorithm and accompanying (visualization-oriented) test utilities, along with build-system updates to pull in required headers/libs.

Changes:

  • Introduce ZernikeEdgeDetectionAlgorithm (Zernike moments A₁₁/A₂₀) to refine edge points to sub-pixel accuracy.
  • Add test executables that load points from JSON and generate side-by-side visualizations (including a “thicker” variant).
  • Update build tooling (CMake/Makefile) to fetch nlohmann/json and stb_image_write, and adjust ignores/output artifacts.

Reviewed changes

Copilot reviewed 10 out of 12 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
src/distance/edge.hpp Declares ZernikeEdgeDetectionAlgorithm and helper APIs.
src/distance/edge.cpp Implements Zernike kernel generation, moment computation, and refinement loop.
test/distance/edge-test/zernike-performance-test.cpp Adds JSON loading + visualization/perf-oriented gtests and image writing.
test/distance/edge-test/zernike-single-asset-test.cpp Adds per-asset visualization tests across multiple window sizes.
test/common/common.hpp Changes the example_earth1 asset path used broadly by tests.
src/common/decimal.hpp Adds DECIMAL_EPSILON macro.
CMakeLists.txt Fetches nlohmann_json and downloads stb_image_write.h for tests.
Makefile Downloads nlohmann/json.hpp and stb_image_write.h, adds include paths for tests.
.gitignore Ignores test/common/assets/zernike/.
simple_edges.txt Adds a tracked edge-point dump output file.
zernike_edges.txt Adds a tracked edge-point dump output file.
Comments suppressed due to low confidence (1)

test/common/common.hpp:175

  • example_earth1 now points to test/common/assets/example_earth3.JPG, but this constant is used across integration tests as the canonical “earth1” asset. This effectively changes the meaning of many existing tests and may break environments where only example_earth1.png is expected. Suggest keeping example_earth1 unchanged and introducing a separate example_earth3 asset constant (or updating all tests/assets consistently).
const ImageData example_earth1(
    "test/common/assets/example_earth3.JPG",
    85e-3,
    20e-6,
    {DegToRad(140), 0, 0},
    {DECIMAL(10378137), 0, 0}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/distance/edge.cpp Outdated
Comment thread test/distance/edge-test/zernike-single-asset-test.cpp Outdated
Comment thread test/distance/edge-test/zernike-performance-test.cpp Outdated
Comment thread Makefile Outdated
Comment thread simple_edges.txt Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread test/distance/edge-test/zernike-performance-test.cpp Outdated
Comment thread CMakeLists.txt Outdated
Comment thread CMakeLists.txt Outdated
Comment thread Makefile Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread test/distance/edge-test/zernike-performance-test.cpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp
@j4lando
Copy link
Copy Markdown
Contributor

j4lando commented Mar 3, 2026

Nice work making the changes from last time! You're almost there. Hope these comments help. We'll talk soon at the meeting.

Comment thread src/distance/edge.cpp Outdated
Copy link
Copy Markdown
Collaborator

@nguy8tri nguy8tri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job on beginning the implementation of this complicated algorithm. However, your tests are failing, and normally I don't immediately provide feedback, but I think for your case it would be nice. Please fix my workflow before the next thing comes in. Most concerning is the lack of tests - We don't know if your algorithm does what it intends unless we test it.

Mostly some preliminary notes I've created. I'm also more interested in understanding the algorithm. Thanks!

Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.cpp Outdated
Comment thread src/distance/edge.hpp
Comment thread src/distance/edge.hpp Outdated
Comment thread src/distance/edge.hpp
@nguy8tri
Copy link
Copy Markdown
Collaborator

Please also fill out the description

@Eesha-Jain Eesha-Jain requested a review from nguy8tri March 26, 2026 18:34
Copy link
Copy Markdown
Collaborator

@nguy8tri nguy8tri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job addressing my comments, I have a few more changes I'd like to request!

@@ -12,34 +12,41 @@ namespace found {
///////// VECTOR CLASSES //////////
///////////////////////////////////

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will disappear once Eigen is merged, but is necessary for now.

///////////////////////////////////

Vec2 Midpoint(const Vec2 &vec1, const Vec2 &vec2) {
Vec2<> Midpoint(const Vec2<> &vec1, const Vec2<> &vec2) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really valid to have empty brackets? Shouldn't there be a template? Is this C++'s version of a wildcard (like in Java)?

Comment thread src/distance/edge.cpp
decimal pixelWidth = DECIMAL(2.0) / maskSize_;
decimal offset = DECIMAL(1.0) - DECIMAL(1.0) / maskSize_;

constexpr int samplesPerPixel = 1028;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If its in a function I much prefer a macro

Comment thread src/distance/edge.cpp
decimal sum11 = 0;
decimal sum20 = 0;

for (int si = 0; si < samplesPerPixel; si++) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to do this inner double loop as a simple summation instead of a loop? Is there a way to figure out whether the condition of the pixel being in the unit disk applies? Notice how u and v increase with every iteration. You might be able to figure out what values will work using algebra or something.

Comment thread src/distance/edge.cpp
////// Zernike Edge Detection Algorithm //////

std::pair<std::unique_ptr<ComplexNumber[]>, std::unique_ptr<ComplexNumber[]>>
ZernikeEdgeDetectionAlgorithm::computeZernikeKernels() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered using a set Zernike kernel? Accepting that as an optional parameter might be in your best interest as 1028*1028 is a lot of iterations.

Comment thread src/distance/edge.cpp
return {ComplexNumber{A11Real, A11Imag}, ComplexNumber{A20Val, 0}}; // A_20 is real-only
}

decimal ZernikeEdgeDetectionAlgorithm::extractEdgeAngle(const ComplexNumber &A11) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline this

Comment thread src/distance/edge.cpp
return DECIMAL_ATAN2(A11.imag, A11.real); // Eq.(56)
}

decimal ZernikeEdgeDetectionAlgorithm::extractEdgeOffset(decimal A11Prime, decimal A20) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline this too

Comment thread src/distance/edge.cpp
return l;
}

Vec2<int> ZernikeEdgeDetectionAlgorithm::applyEdgeCorrection(const Vec2<int>& maskCenter, decimal l, decimal psi) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be inlined

Comment thread src/distance/edge.hpp
*
* @return a pair of ComplexNumbers (A_11, A_20)
*/
std::pair<ComplexNumber, ComplexNumber> computeZernikeMoments(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This operation is similar, but not the same as a convolution. Might be helpful to add a note that this is the same as "applying" the kernel"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants