A Cross-Language Reference Library for Visual Just-Noticeable-Difference Estimation
π GitHub: https://github.com/Terriao/OpenJND
πͺ OpenI Mirror: https://openi.pcl.ac.cn/OpenDatasets/OpenJND?lang=en-US
OpenJND is a reference implementation collection of eight representative Just-Noticeable-Difference (JND) models for visual content, made available under a single calling convention in MATLAB, Python, and C++.
The library is built around three observations the field has tolerated for too long:
- JND code lives where its author put it. Reference code typically ships as a single MATLAB folder bundled with the original publication. Re-running it later, or porting it into a Python/C++ pipeline, is each user's private headache.
- There is no shared yardstick. Different works report on different test images at different resolutions, sometimes with bespoke metrics. Reading them in sequence does not give a consistent picture of which method does what.
- Method choice is complex. Pixel-domain and transform-domain models answer different questions, and the right choice depends on the downstream task (codec, watermarking, rendering, IQA).
OpenJND addresses all three by re-implementing each method against a fixed I/O contract, evaluating the eight models on the same input, and documenting both the idea and the cost of every model.
Open-source dependency note. Every method in OpenJND has a Python implementation that runs end-to-end on the open-source SciPy / NumPy / OpenCV stack with no MATLAB required. The MATLAB and C++ ports are provided alongside as authoritative reference implementations and as building blocks for performance-sensitive integrations.
The library accompanies the paper "OpenJND: A Comprehensive Open Source Library for Just Noticeable Difference" (ACM MM 2026, Open Source Software Track, under review). See Citation.
- Concept primer
- Methodological lineage
- Method index
- Unified calling convention
- Method catalogue
- Evaluation protocol
- Qualitative comparison
- Runtime analysis
- Choosing a method
- Getting started
- Extending the library
- Roadmap
- Citation
- Community
- License
- Acknowledgements
- Contributors and contact
A Just-Noticeable-Difference (JND) threshold is the minimum signal change that a human observer can reliably detect. In the visual domain, it is determined by the Human Visual System (HVS) reacting to factors such as background luminance, local contrast, edge structure, texture density, pattern regularity, and (for video) motion. Below the threshold, modifications are perceptually invisible; above it, they become noticeable distortions.
Computational JND modelling produces a JND map β one threshold per pixel (pixel-domain models) or per transform coefficient (transform-domain models) β that downstream systems can use as a budget for invisible modification:
- Compression spends bitrate first where the JND budget is smallest.
- Watermarking embeds energy just below the JND boundary: invisible, but hard to remove.
- Quality assessment weights distortions by their visibility instead of their raw magnitude.
- Rendering (VR/AR, HDR) allocates compute where the eye actually looks.
Two methodological families dominate the literature:
| Family | Operating domain | Strengths | Typical limitations |
|---|---|---|---|
| Pixel-domain | Original image plane | Intuitive, edge/texture-aware | Edges and textures can be conflated; no native frequency story |
| Transform-domain | DCT / DWT / KLT coefficients | Plugs directly into block-based codecs, principled CSF | Block artefacts in the JND map; harder to interpret pixel-wise |
OpenJND covers both β five pixel-domain models and three transform-domain models.
JND modelling has matured along a clear intellectual trajectory. Each model in the library answers a question that the previous generation could not β and being part of an established lineage is precisely why these models continue to anchor modern perceptual codecs, watermarking schemes, and IQA systems. The library presents them as a working catalogue rather than a chronology:
Foundational β Chou & Li
ββ Temporal extension β Yang et al.
ββ Subband refinement β Zhang et al.
ββ DCT formulation β Jia et al.
Decomposition era β Liu et al. (separates edge / texture)
Cognitive-inspired β Wu et al. (free energy) (predicts ordered content)
Pattern-aware β Wu et al. (pattern complexity) (orientation diversity)
Top-down learning β Jiang et al. (data-driven CPL boundary)
The lineage is converging, not branching: later models do not invalidate earlier ones, they sharpen specific aspects. Several state-of-the-art method still call into Chou-style or Zhang-style estimators for their simplicity, while research pipelines combine them with the cognitive- and pattern-aware refinements. OpenJND ships all generations so the user can pick the right tool.
| # | Method | Lineage | Domain | Distinguishing idea | MATLAB | Python | C++ |
|---|---|---|---|---|---|---|---|
| 5.1 | Chou & Li Β· π | Foundational | Pixel | Luminance adaptation + texture masking; introduces PSPNR | β | β | β |
| 5.2 | Yang et al. Β· π | Temporal extension Β· NAMM | Pixel | NAMM combiner with edge-adaptive masking weight | β | β | β |
| 5.3 | Zhang et al. Β· π | Subband refinement | Transform (DCT) | Parabolic LA + block-classified CM (PLAIN/EDGE/TEXTURE) | β | β | β |
| 5.4 | Jia et al. Β· π | DCT formulation | Transform (DCT) | Spatio-temporal CSF with eye-movement compensation | β | β | β |
| 5.5 | Liu et al. Β· π | Decomposition era | Pixel | TV decomposition separating edge and texture masking | β | β | β |
| 5.6 | Wu et al. (free energy) Β· π | Cognitive-inspired | Pixel | Predicted-vs-residual split: ordered branch + disorderly residual | β | β | β |
| 5.7 | Wu et al. (pattern complexity) Β· π | Pattern-aware | Pixel | Orientation diversity as masking strength | β | β | β |
| 5.8 | Jiang et al. Β· π | Top-down learning | Transform (KLT) | Data-driven CPL prediction | β | β | β |
Legend β β upstream open-source reference; β this repository's ported implementation; β not yet implemented.
Every method in the library exposes the same minimal interface across all three languages:
INPUT : grayscale image (uint8 / float, H Γ W)
method-specific options (struct in MATLAB, dict in Python, std::map in C++)
OUTPUT : JND map of the same H Γ W shape (float, same range as input)
The actual entry-point function name follows the reference code of each method β JND_pixel for Chou/Yang, JND_dct for Zhang, JND_video for Jia, JND_ID for Liu, KLT_JND for Jiang, func_JND_modeling_pattern_complexity for Wu (TIP), and a short script-style pipeline for Wu (TMM). Each method's subdirectory README documents its specific signature; the I/O contract above is the same throughout.
This design lets you swap methods by changing a single function name β invaluable for ablations and downstream-task benchmarking.
For each method we give the context that motivated it, the modelling step that distinguishes it from its predecessors, and a one-line characterisation of the JND map it produces.
Foundational pixel-domain model Β· luminance adaptation + texture masking π Subproject: https://github.com/Terriao/OpenJND/tree/main/Chou%20and%20Li
The cornerstone pixel-domain JND model around which the rest of the catalogue is organised. It estimates a per-pixel visibility budget from two HVS factors β how bright the background is (luminance adaptation), and how busy the local neighbourhood is (texture masking from the maximum weighted gradient over a 5Γ5 neighbourhood) β combined into a single per-pixel threshold. The companion paper also introduces PSPNR, a fidelity metric that ignores distortion components falling below the threshold.
Behaviour of the resulting map: large budgets on dark and on busy regions; relatively conservative near isolated edges. A flag in the implementation lets users switch between the bare foundational form and an edge-adaptive variant used elsewhere in the catalogue.
Nonlinear additive masking (NAMM) Β· edge-adaptive masking weight π Subproject: https://github.com/Terriao/OpenJND/tree/main/Yang%20et%20al
Replaces the foundational max-rule combiner with a nonlinear additive masking model: JND = LA + TM β C_TG Β· min(LA, TM), with C_TG = 0.3 for the Y channel β the partial-overlap regime between the foundational max-rule (C_TG = 1) and pure linear addition (C_TG = 0). An edge-adaptive weight map is layered onto the texture-masking term: Canny detection on the input (threshold 0.5), disk-6 morphological dilation, attenuation by 0.95, and 7Γ7 Gaussian smoothing (Ο = 0.8) produce a mask that drops sharply along visible edges and stays near 1 elsewhere β actively suppressing the budget where distortion is most visible.
Behaviour: smoother handling of edges than the foundational max-rule; the additive-with-overlap combination gives a larger budget than the max-rule where LA and TM are comparable, translating into more perceptually-lossless redundancy at matched visual quality. The OpenJND release covers the NAMM combiner and the edge-adaptive weighting on the Y channel.
DCT-domain subband refinement Β· parabolic luminance adaptation Β· block-classified contrast masking π Subproject: https://github.com/Terriao/OpenJND/tree/main/Zhang%20et%20al
Builds on the spatial-CSF model and DCTune, and sharpens two specific weaknesses of those estimators. The luminance-adaptation base threshold is recast as a parabolic two-branch function of the block DC coefficient β higher in very dark and very bright regions, lowest around mid-grey β which mainly improves accuracy below gray level 128 where DCTune is least faithful. The contrast-masking elevation factor is then conditioned on an explicit block classification step (PLAIN / EDGE / TEXTURE) derived from the texture energy of the medium- and high-frequency DCT bands; LF/MF coefficients of EDGE blocks are excluded from intra-band masking, which is precisely what prevents the JND over-estimation that DCTune produces around edges. The same JND profile drives a perceptual distortion metric (subband error normalised by the per-coefficient threshold) and a JPEG-compatible quantizer.
Behaviour: the map carries the imprint of the 8Γ8 block grid by construction β well-matched to block-based codecs, and noticeably better aligned with subjective scores than DCTune in dark regions and around object boundaries.
DCT-domain formulation Β· spatio-temporal CSF Β· eye-movement-aware π Subproject: https://github.com/Terriao/OpenJND/tree/main/Jia%20et%20al
The first model in the catalogue designed natively in the DCT domain that the codecs themselves use. Combines a spatio-temporal contrast sensitivity function (KellyβDaly form, with constants c0..c4 calibrated per the paper) with eye-movement compensation β the retinal velocity is the image-plane velocity minus what smooth-pursuit can cancel, capped between a drift floor of 0.15 deg/s and a saccadic ceiling of 80 deg/s. The same JND framework as Zhang et al. supplies the parabolic LA branch and the PLAIN/EDGE/TEXTURE block-classified masking, so the model handles still frames and frame pairs with motion through a single code path.
Behaviour: when applied to a frame pair with translation, the JND map cleanly reflects both the motion field and the underlying 8Γ8 block structure β a useful diagnostic property. For still images it reduces to a spatial-CSF JND with LA and CM.
Decomposition era Β· edge / texture separation π Subproject: https://github.com/Terriao/OpenJND/tree/main/Liu%20et%20al
Earlier contrast-masking estimators tend to lump strong gradients into a single "high-frequency" bucket, so textured regions are routinely misclassified as edges and assigned an artificially low budget. Liu et al. propose a clean fix: split the image into a structural component (used for edge masking) and a textural component (used for texture masking), then estimate the two masking terms from the two components independently and combine them with W_e = 0.7, W_t = 1.4 so that texture masking weighs heavier than edge masking.
Behaviour: textures recover their rightful, larger JND budget; edges remain protected. The cost is a non-trivial decomposition step β the MATLAB reference uses Wotao Yin's TV-LΒΉ parametric-max-flow solver; the Python port substitutes a Gaussian-blur surrogate to keep the dependency footprint small.
Cognitive-inspired Β· free-energy principle Β· ordered vs. disordered split π Subproject: https://github.com/Terriao/OpenJND/tree/main/Wu%20et%20al%20%28TMM%29
A conceptually distinct entry in the catalogue. Drawing on the free-energy framework from theoretical neuroscience, the HVS is modelled as attempting to predict the orderly content of an image; whatever cannot be predicted is disordered content that the eye tolerates much more freely. A non-local-means reconstruction over a 21Γ21 search window with adaptive smoothing supplies the predicted image; the absolute residual is the free-energy map, and JND is computed separately for ordered and disordered branches, then combined via NAMM (twice).
Behaviour: substantially elevated JND in disordered regions (foliage, fabric, noise), while ordered regions stay conservative.
Pattern-aware Β· orientation diversity π Subproject: https://github.com/Terriao/OpenJND/tree/main/Wu%20et%20al%20%28TIP%29
Contrast alone is a poor predictor of masking strength: two regions with identical contrast can mask very different amounts of distortion depending on whether their local patterns are regular (e.g. a brick wall) or irregular (e.g. crumpled fabric). Pattern complexity is quantified here as the number of distinct local orientation bins (Lβ norm of an orientation histogram, with a 12Β°-wide bin) sampled over an 8-neighbour ring, and combined with a luminance-contrast transducer through a max dominance rule, with edge protection applied to the pattern-masking branch only. The final JND merges the luminance-adaptation and visual-masking branches via NAMM. Code lives in Wu et al (TIP).
Behaviour: irregular-pattern regions receive a higher JND budget than regular-pattern regions of the same contrast. A natural successor to texture-masking models for high-resolution natural imagery.
Top-down learning Β· data-driven CPL prediction Β· KLT-domain π Subproject: https://github.com/Terriao/OpenJND/tree/main/Jiang%20et%20al
The catalogue's only top-down model. Instead of summing low-level masking factors, the model asks the more direct question: at what point does distortion start to be noticed? Subjective experiments on 500 natural images locate this critical perceptually-lossless (CPL) point for each image; the cumulative normalised KLT-coefficient energy at the CPL is well approximated by a Weibull distribution with Ξ² = 894.16 and Ξ· = 0.99805. For a new image, the model predicts its CPL counterpart by inverse-KLT using only the leading components, and reports the absolute difference β multiplied by an edge-protect mask β as JND.
Behaviour: low budgets near edges (where humans really do notice distortion early) and high budgets in busy textured regions β qualitatively consistent with the bottom-up models, but reached by a completely different route.
To keep the comparison reproducible:
- Image pool. The 24 colour images of the Kodak photographic dataset, converted to grayscale, together with three classical grayscale test images (
Lena,Actor,Lighthouse). All images are resized to 512 Γ 512 when their native resolution differs. The bundledtest_data/directory contains enough imagery to reproduce every figure in this README. - Aggregation. Runtime is reported as the mean over the full pool, on a fixed hardware platform.
- Visualisation. A single image β grayscale
Actor(512 Γ 512) β is shown for every method, side by side, so the reader can compare maps at a glance. - Defaults. Every method is run with the parameter settings reported in its original publication.
We do not report a single "winner" metric: JND maps are intermediate signals, and the right yardstick depends on the downstream application (compression bitrate, watermark robustness, IQA correlation, β¦).
Comparing the eight maps side-by-side on the same Actor input makes the family-level differences immediate. A model-by-model walkthrough:
-
Chou & Li (Fig. b). The combined spatial-masking effect is reduced to the larger of two factors β luminance adaptation or texture masking. The consequence is visible along the brim of Actor's hat, where the max-rule allocates a too-generous budget at the very pixels the eye fixates on.
-
Yang et al. (Fig. c). The nonlinear additive combiner replaces the max-rule, and an explicit edge-vs-textured distinction is introduced into the masking weight. The edge-region over-allocation that Chou's map exhibits is correspondingly dampened.
-
Zhang et al. (Fig. d). The estimator moves into the DCT subband domain. Operating block-wise leaves a clearly visible 8Γ8 grid imprint in the JND map β a feature, not a bug, for block-based codecs that consume the map directly.
-
Jia et al. (Fig. e). A motion-aware DCT-domain estimator: with a horizontally translated second frame of Actor as input, the resulting map encodes both the per-block translation field and the same block-grid signature seen in Zhang's output, demonstrating the spatio-temporal extension at work.
-
Liu et al. (Fig. f). Splits the image into structural and textural components before computing the masking budget, and weights texture masking more strongly than edge masking. The textured regions β most clearly Actor's hair β receive a noticeably higher budget than under Yang's combiner, recovering the masking capacity that an undecomposed model under-counts.
-
Wu et al. β free energy (Fig. g). Adds a disorder dimension that purely contrast-based estimators miss. Ordered textures get tight budgets β the eye can read their structure β while disordered regions get loose budgets, reflecting the harder-to-resolve content that the HVS only roughly perceives.
-
Wu et al. β pattern complexity (Fig. h). Pushes the same intuition further by quantifying pattern regularity through local orientation diversity. Regular patterns yield mild masking; irregular ones yield strong masking, and the resulting map shows the largest budgets exactly in the irregular-pattern regions.
-
Jiang et al. (Fig. i). Sidesteps the explicit-masking-factor route entirely. The model is fit top-down against subjective CPL annotations, and the resulting map nevertheless agrees with the bottom-up consensus on the structure of perceptual budgets β low at edges (where distortion is easily noticed), high in textured regions β arriving there via a completely different route.
A few cross-cutting takeaways:
- Bottom-up pixel-domain models tend to agree on the shape of the map but disagree on the amplitude in edge and texture regions.
- The two transform-domain bottom-up models (Zhang, Jia) carry the imprint of the underlying block grid by construction.
- The top-down map looks qualitatively similar to the bottom-up consensus despite being derived without any explicit masking decomposition β evidence that the two philosophies converge on broadly consistent perceptual budgets.
Each method is run in MATLAB, Python, and C++ on the same hardware and the same image pool. The figure below shows the average per-image runtime for each (method Γ language) pair.
The rankings vary across methods, which we attribute to the interaction between each method's dominant operation and the language stack it runs on. Five patterns emerge:
- Chou and Yang β
MATLAB βͺ Python β² C++. These methods rely on explicit per-pixel iteration; MATLAB's JIT vectorises them automatically, whereas our ports do not, leaving Python and C++ roughly tied at the bottom. - Zhang β
MATLAB < C++ < Python. The bottleneck is DCT throughput. MATLAB's BLAS/MKL-backed DCT is markedly faster than SciPy's, and the C++ port sits between them by avoiding the Python interpreter overhead but lacking hand-tuned kernels. - Jia β
MATLAB β Python. The workload is evenly distributed across linear-algebra primitives that NumPy and MATLAB invoke through similarly tuned backends, so the two stacks finish within margin of each other. - Liu and Jiang β
Python βͺ C++ βͺ MATLAB. Two different reasons converge on the same ordering. The Liu port replaces the original parametric-max-flow decomposition with a Gaussian-blur surrogate, cutting algorithmic complexity. The Jiang port leans on heavily optimised OpenCV / NumPy primitives for PCA and convolution; the C++ port also uses OpenCV but its PCA and inner loops are not fully tuned. - Wu (pattern complexity) β
Python < MATLAB < C++. Python wins via vectorised orientation statistics; the C++ port loses ground to OpenMP synchronisation overhead and per-block dynamic allocation.
Two takeaways:
- "C++ is always fastest" is folklore. For numerical-array workloads dominated by BLAS / DCT / image primitives, MATLAB or vectorised Python regularly beats hand-rolled C++.
- Port fidelity matters as much as language. Where we deliberately simplified a costly step (TV-LΒΉ in Liu) we say so explicitly; the numbers are honest about the trade.
A rough decision tree for downstream users:
| If your application is β¦ | Start with β¦ |
|---|---|
| Still-image compression, codec-agnostic | Wu (pattern complexity) or Liu |
| Block-based codec (JPEG, HEVC, AVS) | Zhang or Jia |
| Video coding with motion compensation | Jia (Yang's temporal pathway is on the roadmap) |
| Watermarking with imperceptibility constraint | Wu (free energy) or Wu (pattern complexity) |
| IQA / perceptual quality metric design | Jiang (top-down) for alignment with subjective tests |
| Teaching / first reproducible baseline | Chou (the most thoroughly documented foundational model) |
When in doubt, run the methods you are considering on a few of your own images and inspect the maps. Visual inspection at this stage saves a lot of downstream confusion.
OpenJND is organised as one top-level directory per method:
Chou and Li/
Yang et al/
Zhang et al/
Jia et al/
Liu et al/
Wu et al (TIP)/ # pattern complexity
Wu et al (TMM)/ # free-energy
Jiang et al/
Each method directory contains the available language ports (MATLAB / Python / C++) and a method-specific entry point. Function names follow each method's reference code β see each subdirectory README for the exact signature.
git clone https://github.com/Terriao/OpenJND.git
cd OpenJNDA typical Python run looks like this β example shown for Wu et al. (pattern complexity):
cd "Wu et al (TIP)/Python"
pip install numpy scipy opencv-python Pillow matplotlib
python main.pyOther Python ports follow the same pattern: open the method directory, install the standard scientific Python stack, run the entry script. Each method directory contains its own README with method-specific parameters and the exact function name to call programmatically.
Open MATLAB, navigate to a method directory, and call its top-level function. For example:
cd 'Chou and Li/MATLAB'
img = imread('../../test_data/lena.png');
jnd = JND_pixel(img, 'Chou');
imshow(mat2gray(jnd));Function names per method:
| Method | MATLAB entry point |
|---|---|
| Chou & Li / Yang | JND_pixel(I, type) |
| Zhang | JND_dct(I) |
| Jia | JND_video(Y1, Y2) |
| Liu | JND_ID(I, lambda) |
| Wu (TMM) | main (script-style pipeline) |
| Wu (TIP) | func_JND_modeling_pattern_complexity(img) |
| Jiang | KLT_JND(im, ed_pro, L) |
The MATLAB ports do not depend on the Python or C++ ports β each is independently runnable. A platform note: the Liu et al. MATLAB port depends on Wotao Yin's ParaMaxFlow MEX library, currently provided pre-compiled for 64-bit Windows only; Linux / macOS users should either rebuild from the upstream source at http://www.caam.rice.edu/~wy1/ParaMaxFlow/ or use the Python port, which carries no such dependency.
C++ ports ship as zipped sources inside each method directory. Unpack the archive and build with CMake:
cd "Chou and Li/C++"
unzip cpp_source.zip -d build_src
cd build_src
cmake -S . -B build && cmake --build build -j
./build/openjnd_chou test_data/lena.pngRefer to the README inside each unpacked C++ source tree for the exact target name and CLI flags.
The fastest path to a new method is the unified interface: implement a single function (or class) that takes an image plus a config struct and returns a JND map of the same shape. The boilerplate is identical to existing methods, so it can be copied from the closest cousin in the catalogue.
Suggested additions especially welcome:
- Learning-based JND models (deep-network predictors, perceptual GAN-style approaches)
- Colour-aware JND (the current catalogue is grayscale-first)
- Native temporal-masking branches that take frame pairs without external motion estimation
- 360-degree, light-field, or stereoscopic JND
For non-trivial contributions please open an Issue first so we can align on the interface and integration. See CONTRIBUTING.md for the full workflow.
- Continually broaden the catalogue with learning-based JND models as the field produces them
- Subjective validation harness (PSPNR; noise injection at the JND boundary; controlled user study scripts)
- Colour JND extensions β beginning with the YCbCr branch of Yang et al. and extending to CIELAB / opponent-channel masking
- Native temporal-masking branches (Yang et al.'s
f(ild)curve; cross-platform Linux/macOS MEX builds for Liu et al.) - Bridge to deep-learning IQA codebases (LPIPS, DISTS, PieAPP) for JND-weighted variants
- Mirrored multilingualism documentation
If OpenJND supports your research, please cite:
@misc{openjnd2026,
title = {OpenJND: A Comprehensive Open Source Library for Just Noticeable Difference},
author = {Gao, Wenxu and Peng, Changhao and Su, Jingxuan and Gao, Wei},
year = {2026},
howpublished = {\url{https://github.com/Terriao/OpenJND}}
}When you use a specific method, please also cite the corresponding original paper, listed in the Method catalogue.
OpenJND is released under the MIT License and hosted on GitHub, with a synchronised mirror on the OpenI platform maintained by Peng Cheng Laboratory.
The repository follows standard open-source engineering practice:
- Contributor onboarding. The repository ships a CONTRIBUTING.md, structured issue templates (bug report, feature request, new-method proposal), and a pull-request template that prompts for the unified interface, validation against the original paper, and accompanying documentation.
- Open governance of the catalogue. New methods are proposed via the "Propose a new JND method" issue template and discussed in the open before any code is merged.
- Documentation by method. Beyond this top-level README, each method directory carries its own README explaining the implementation, parameters, and a worked example.
Contributions are welcomed on any of the items listed in the Roadmap, and especially on completing the language ports currently marked β in the Method index.
Source code is released under the MIT License. Individual method subdirectories may carry additional notices inherited from their upstream reference implementations; please consult the respective LICENSE files before commercial use.
OpenJND would not exist without the authors of the eight methods we re-implement here, who made their reference code available and patiently answered our reproduction questions. We thank the MATLAB, NumPy/SciPy, and OpenCV communities for the numerical primitives this work stands on, and Peng Cheng Laboratory together with the OpenI platform for compute resources and a public mirror of the repository.
We also acknowledge the broader psychophysics and HVS-modelling traditions β going back decades β that made any of this possible.
| Role | Name | Affiliation |
|---|---|---|
| Coordinator | Asso. Prof. Wei Gao | Peking University & Peng Cheng Laboratory |
| Contributor | Wenxu Gao | Peking University & Peng Cheng Laboratory |
| Contributor | Changhao Peng | Peking University |
| Contributor | Jingxuan Su | Peking University |
For questions, suggestions, and access to push privileges on the OpenI mirror, please contact:
Asso. Prof. Wei Gao β gaowei262@pku.edu.cn
Bug reports and feature requests are tracked via GitHub Issues.