assess_sharpness() scores a 112x112 crop on variance-of-Laplacian, a contrast-normalised variant, Tenengrad, a spectral high-frequency ratio and dir_min_tenengrad, over a fixed 64x64 window on the face interior. The window excludes the corners because studio headshots are routinely shot at a wide aperture, and background bokeh measured over the whole crop would drag the score down on the sharpest images in the set. Five rather than one because AR-029's threshold has to be located, not chosen: VR-012 ranks them by how well each predicts real identity loss. The T1 ladders drove two corrections during development. The spectral ratio applied its Hann window before removing the mean, so the DC term smeared into the low-frequency bins and the "ratio" tracked absolute brightness (a 20/255 brightening moved it 23%). And no measure taken from the literature survived directional blur: normalising by total energy divides out the loss being measured, so both ratio measures are U-shaped in motion-blur length and score a 21 px smear about as sharp as a 3 px one. dir_min_tenengrad exists to fix that -- a low-frequency contrast denominator that blur leaves alone, and the worse of the two Sobel axes rather than their sum. The tests pin the disqualifying behaviours as well as the desirable ones, so a change that makes var_laplacian contrast-free is a deliberate act rather than an accident. They also record that every candidate falls under downscale-upscale as well as under blur: the aligned crop is scale-normalised geometrically, not informationally. Exposed through sae_embed alongside the AR-030 alignment residual, so a study scores through shipped code rather than a numpy copy -- the same argument that already applies to the calibration. TRACES: AR-028, AR-029 | SR-002
71 lines
2.9 KiB
CMake
71 lines
2.9 KiB
CMake
# ── Unit tests ────────────────────────────────────────────────────────────────
|
|
# Pure, GPU-free, model-free tests. The similarity tests compile the GEMM backend
|
|
# directly with SAE_GEMM_CPU so the suite builds and runs on a machine without a
|
|
# GPU regardless of the main build's SAE_GEMM_BACKEND selection.
|
|
|
|
find_package(Catch2 3 QUIET)
|
|
if(NOT Catch2_FOUND)
|
|
include(FetchContent)
|
|
FetchContent_Declare(
|
|
Catch2
|
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
|
GIT_TAG v3.5.3
|
|
)
|
|
FetchContent_MakeAvailable(Catch2)
|
|
endif()
|
|
|
|
add_executable(sae_tests
|
|
test_similarity.cpp
|
|
test_calibration.cpp
|
|
test_gallery_store.cpp
|
|
test_face_utils.cpp
|
|
test_quality.cpp
|
|
test_track_gallery.cpp
|
|
test_face_tracker.cpp
|
|
test_track_registry.cpp
|
|
test_replay_fixtures.cpp
|
|
test_audio_signature.cpp
|
|
${CMAKE_SOURCE_DIR}/src/backends/gemm_backend.cpp
|
|
${CMAKE_SOURCE_DIR}/src/gallery/gallery_store.cpp
|
|
${CMAKE_SOURCE_DIR}/src/audio_signature.cpp
|
|
${CMAKE_SOURCE_DIR}/src/gallery/embedder_stamp.cpp
|
|
)
|
|
target_include_directories(sae_tests PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
|
# SAE_GEMM_CPU: build the CPU reference GEMM regardless of the main backend.
|
|
# SAE_MODELS_DIR: config.hpp (pulled in by track_gallery.hpp) bakes model paths.
|
|
# SAE_TEST_FIXTURES_DIR: the audio golden vector is read from the source tree,
|
|
# not copied, so the file the plugin repo shares is the file under test.
|
|
# AR-026/AR-027: exercise the same kernel CI actually runs. Without this the
|
|
# suite compiles the scalar fallback while the CPU builder image links OpenBLAS,
|
|
# so the tested path and the shipped path would differ.
|
|
find_package(PkgConfig QUIET)
|
|
if(PkgConfig_FOUND)
|
|
pkg_check_modules(OPENBLAS_T QUIET openblas)
|
|
endif()
|
|
if(OPENBLAS_T_FOUND)
|
|
target_include_directories(sae_tests PRIVATE ${OPENBLAS_T_INCLUDE_DIRS})
|
|
target_link_libraries(sae_tests PRIVATE ${OPENBLAS_T_LINK_LIBRARIES})
|
|
endif()
|
|
|
|
target_compile_definitions(sae_tests PRIVATE
|
|
$<$<BOOL:${OPENBLAS_T_FOUND}>:SAE_GEMM_CBLAS>
|
|
SAE_GEMM_CPU
|
|
SAE_MODELS_DIR="${SAE_MODELS_DIR}"
|
|
SAE_TEST_FIXTURES_DIR="${CMAKE_CURRENT_SOURCE_DIR}/fixtures")
|
|
# gallery_store.cpp + gallery_calibration.hpp use nlohmann/json and HDF5
|
|
# (galleries are HDF5-native, see src/gallery/gallery_store.cpp); face_utils.hpp
|
|
# and the calibration GEMM pull in OpenCV (calib3d/imgproc/core) via types.hpp.
|
|
# ffmpeg_libs: audio_signature.cpp decodes the golden fixture (avformat/avcodec/
|
|
# avutil/swresample). Still GPU-free — the audio path is pure CPU.
|
|
target_link_libraries(sae_tests PRIVATE
|
|
Catch2::Catch2WithMain
|
|
nlohmann_json::nlohmann_json
|
|
ffmpeg_libs
|
|
${OpenCV_LIBS}
|
|
${HDF5_CXX_LIBRARIES})
|
|
target_include_directories(sae_tests PRIVATE ${HDF5_INCLUDE_DIRS})
|
|
|
|
include(CTest)
|
|
include(Catch)
|
|
catch_discover_tests(sae_tests)
|