Research code for the dissertation project Sparse Representation for Image Classification Using Global and Local Texture Features.
| Item | Information |
|---|---|
| Student | Zixin Ding |
| Student ID | 20513868 |
| Supervisor | Dr. Jianfeng Ren |
| Academic Year | 2025/2026 |
This repository implements Sparse Global-Local Texture Representation Classification (SGLT-RC), a hybrid image-classification framework for small-sample object recognition. It combines a pretrained global deep descriptor, an interpretable local texture descriptor, feature-level fusion, and Lasso-based sparse representation classification.
Image classification has advanced substantially through deep convolutional networks and transfer learning. However, reliable recognition remains challenging when only a limited number of labelled training samples are available for each class. In such settings, pretrained deep descriptors can provide strong semantic representations, while local texture patterns and spatial appearance cues may still contain complementary information that is not fully captured by a global deep feature alone.
Motivated by this gap, this dissertation proposes Sparse Global-Local Texture Representation Classification (SGLT-RC), a hybrid image-classification framework that combines pretrained global representation, interpretable local texture encoding, feature-level fusion, and Lasso-based sparse representation classification.
The implemented main route is:
resnet50 + lbp_basic_spatial25 + src_standard
In this route, the global branch extracts a 2048-dimensional pretrained ResNet50 descriptor, while the local branch extracts a project-authored Basic Shifted-Grid Pyramid Local Binary Pattern descriptor, implemented as lbp_basic_spatial25. The local descriptor is built from a basic 8-neighbor LBP code map, a 4 x 4 main grid, a half-cell shifted 3 x 3 auxiliary grid, and 25 regional histograms, producing a 6400-dimensional local descriptor. The two descriptors are concatenated into an 8448-dimensional fused feature and classified using the standard L1-SRC implementation, src_standard, by comparing class-wise reconstruction residuals.
The repository includes dataset preprocessing, split generation, feature extraction, descriptor caching, evaluation scripts, JSON metric logging, paper-section experiment wrappers, figure-generation scripts, and optional bridges for MATLAB-side dictionary-learning comparisons. Experiments are organized around Caltech-101 and COIL-100, with repeated split protocols, feature ablations, classifier comparisons, sparse-parameter sensitivity checks, runtime recording, and result-table / figure support.
The main SGLT-RC implementation route is:
resnet50 + lbp_basic_spatial25 + src_standard
| Component | Dissertation term | Implementation name | Role |
|---|---|---|---|
| Global branch | ResNet50 global descriptor | resnet50 |
2048-D pretrained deep feature |
| Local branch | Basic Shifted-Grid Pyramid LBP | lbp_basic_spatial25 |
6400-D local texture descriptor |
| Fusion | Global-local feature concatenation | resnet50+lbp_basic_spatial25 |
8448-D fused feature |
| Classifier | L1 sparse representation classifier | src_standard |
class-wise residual prediction |
| Framework | Sparse Global-Local Texture Representation Classification | SGLT-RC | proposed global-local sparse framework |
The local branch is summarized here because it is the main project-specific descriptor design. Detailed feature aliases and comparison variants are listed later in Section 4.1.
RGB image
-> grayscale image
-> Basic LBP code map
-> 4 x 4 main grid + shifted 3 x 3 auxiliary grid
-> 25 regional histograms
-> concatenate + L2 normalize
-> 6400-D local descriptor
In this README, Basic Shifted-Grid Pyramid LBP refers to the implemented lbp_basic_spatial25 descriptor: a basic 8-neighbor LBP code map is partitioned by a 4 x 4 main grid and a half-cell shifted 3 x 3 auxiliary grid, giving 16 + 9 = 25 regions. A 256-bin histogram is computed for each region, and the regional histograms are concatenated into the final 6400-D local descriptor.
Other LBP variants, ridge residual classification, nearest-neighbour classification, and dictionary-learning baselines are included as comparison lines for ablation, robustness checks, and runtime analysis.
The Python pipeline is developed around Python 3.12.
conda create -n fyp-image-cls python=3.12 -y
conda activate fyp-image-cls
python -m pip install --upgrade pip
python -m pip install -r requirements.txtMATLAB is only needed for optional external comparison workflows such as LC-KSVD or D-KSVD. The main SGLT-RC pipeline is implemented in Python.
A quick syntax check after installation or code editing is:
python -m compileall src scriptsThis repository evaluates two object-recognition datasets. The train/test split protocol is aligned with Locality-Aware Discriminative Subspace Learning for Image Classification (LADSL; Meenakshi and Srirangarajan, 2022), while features are re-extracted in this project from the raw images.
| Dataset | Summary | Source | Expected raw path | Split protocol |
|---|---|---|---|---|
Caltech-101 |
101 object categories; around 40-800 images per category |
CaltechDATA | data/raw/caltech101/101_ObjectCategories/ |
Tr = {10, 15, 20, 25}, 10 repeated splits; BACKGROUND_Google excluded |
COIL-100 |
100 objects, 72 views per object, 7,200 color images |
Columbia CAVE | data/raw/coil-100/ |
Tr = {1, 2, 3, 10, 20, 30}, 10 repeated splits |
Raw datasets are not expected to be committed to Git. They should be placed manually under the expected data/raw/ paths before preprocessing.
Preprocessing writes manifests, reusable split CSV files, and dataset-specific cached files under data/processed/ and data/splits/. For COIL-100, the preprocessing code also keeps a protocol-compatible raw32 path with grayscale conversion, 32 x 32 resizing, and unit-norm normalization.
Dataset example figures are expected under:
docs/images/caltech101_examples.png: representative raw images from different Caltech-101 classesdocs/images/coil100_examples.png: representative raw images from different COIL-100 object classes
Regenerate them with:
python scripts/paper/figures/create_dataset_examples_figure.pyThe practical running flow is:
raw dataset folders
-> preprocessing and split CSV generation
-> feature extraction or cache reuse
-> feature fusion through feature expressions
-> classifier evaluation
-> JSON metric files
-> paper figures / summaries
A typical reviewer workflow is:
- install dependencies;
- place raw datasets under
data/raw/; - preprocess the selected dataset;
- run a quick one-split evaluation to verify the pipeline;
- run the main SGLT-RC configuration or paper-section wrappers.
python -m src.preprocessing.run_preprocess --dataset [dataset] --seed [seed]Examples:
python -m src.preprocessing.run_preprocess --dataset caltech101 --seed 42
python -m src.preprocessing.run_preprocess --dataset coil100 --seed 42| Option | Values | Purpose |
|---|---|---|
--dataset |
caltech101, coil100 |
choose dataset-specific preprocessing |
--seed |
integer | control repeated split generation |
--train-counts |
integers | override default train-count protocol |
--repeats |
integer | override number of repeated splits |
--width, --height |
integers | size for the COIL-100 raw32 path |
Expected outputs include:
data/processed/<dataset>/summaries and manifests;data/splits/<dataset>/reusable train/test CSV files.
A lightweight check can use ResNet50 with nearest-neighbour classification and only one split per train-count setting:
python -m src.evaluation.run_evaluation --dataset caltech101 --mode extended --feature resnet50 --classifier nnc --max-splits-per-train-count 1 --seed 42Expected behaviour:
- load the generated split CSV files;
- extract or reuse the selected descriptors;
- write a JSON result under
results/metrics/caltech101/; - record per-split accuracy, aggregate accuracy, command configuration, and timing.
python -m src.evaluation.run_evaluation --dataset [dataset] --mode extended --feature resnet50+lbp_basic_spatial25 --classifier src_standard --lasso-alpha 1e-5 --lasso-max-iter 10000 --seed 42Example main-method runs:
python -m src.evaluation.run_evaluation --dataset caltech101 --mode extended --feature resnet50+lbp_basic_spatial25 --classifier src_standard --lasso-alpha 1e-5 --lasso-max-iter 10000 --seed 42
python -m src.evaluation.run_evaluation --dataset coil100 --mode extended --feature resnet50+lbp_basic_spatial25 --classifier src_standard --lasso-alpha 1e-5 --lasso-max-iter 10000 --seed 42For a shorter test run, add:
--max-splits-per-train-count 1
src_standard can be much slower than nnc or src_ridge, especially for high-dimensional fused features. The JSON outputs support resume-style behaviour: if a compatible result file already exists with completed rows, only missing rows are evaluated.
| Option | Values | Purpose |
|---|---|---|
--dataset |
caltech101, coil100 |
choose dataset |
--mode |
paper_aligned, extended |
paper_aligned restricts to nnc; extended enables all project classifiers |
--feature |
any feature expression from Section 4.1 | choose feature vector or feature fusion |
--classifier |
nnc, src_ridge, src_standard, dksvd, aliases src, src_l1 |
choose classifier |
--lasso-alpha |
float, e.g. 1e-5 |
L1 regularization for src_standard |
--lasso-max-iter |
integer | maximum Lasso iterations for src_standard |
--ridge-lambda |
float, e.g. 1e-3 |
ridge penalty for src_ridge |
--src-standard-n-jobs |
integer, -1, or omitted |
worker count for src_standard; lower values reduce memory pressure |
--src-ridge-n-jobs |
integer, -1, or omitted |
worker count for src_ridge |
--max-splits-per-train-count |
integer | quick-run limiter for each train-count setting |
--output-group |
path fragment | subfolder under results/metrics/<dataset>/ |
--save-predictions |
flag | store labels and predictions for confusion matrices |
python scripts/run_selected_train_count_eval.py --dataset [dataset] --mode extended --train-count [Tr] --max-runs [N] --feature [feature] --classifier [classifier] --output-group [group] --seed [seed]Example:
python scripts/run_selected_train_count_eval.py --dataset caltech101 --mode extended --train-count 10 --max-runs 10 --feature resnet50+lbp_basic_spatial25 --classifier src_standard --lasso-alpha 1e-5 --lasso-max-iter 10000 --output-group paper_sections/01_feature_ablation/20_tr10_clean --seed 42| Option | Values | Purpose |
|---|---|---|
--train-count |
integer | fixed Tr setting, such as 10 for Caltech-101 or 2 for COIL-100 |
--max-runs |
integer | number of repeated splits to run |
--feature |
feature expression | same feature naming as Section 4.1 |
--classifier |
nnc, src_standard, src_ridge |
classifier for this fixed-Tr runner |
--output-group |
path fragment | paper-section subfolder for the JSON output |
--save-predictions |
flag | save per-sample predictions for confusion matrix plotting |
bash scripts/paper/run_paper_local_sections.sh
bash scripts/paper/run_paper_autodl_sections.shFeature dimensions assume the default LBP setting P=8, R=1.0.
Feature naming follows this convention:
globalmeans one histogram is extracted from the whole image.spatial16means the image is divided into a regular4 x 4grid and one histogram is extracted per region.spatial25means the shifted-grid layout used by Basic Shifted-Grid Pyramid LBP: a4 x 4main grid plus a half-cell shifted3 x 3auxiliary grid.basickeeps the standard256-bin LBP code histogram.circular_uniformuses a compact uniform-pattern LBP histogram. It is lower-dimensional and useful as an efficiency-oriented comparison.
| Code name | Descriptor type | Dimension | Notes |
|---|---|---|---|
raw32 |
grayscale raw vector | 1024 |
COIL-100 only; 32 x 32 unit-norm vector |
resnet50 |
global deep descriptor | 2048 |
pretrained ResNet50 feature |
lbp |
basic global LBP | 256 |
legacy alias for lbp_basic_global |
spatial_lbp |
legacy 25-region basic pyramid-LBP | 6400 |
backward-compatible alias, not the preferred method name |
lbp_basic_global |
basic LBP, whole-image histogram | 256 |
local texture without spatial partitioning |
lbp_basic_spatial16 |
basic pyramid-LBP, 4 x 4 regions |
4096 |
16 x 256 regional histograms |
lbp_basic_spatial25 |
Basic Shifted-Grid Pyramid LBP | 6400 |
main local descriptor, 25 x 256 regional histograms |
lbp_basic_spatial25_legacy |
older 25-region basic layout | 6400 |
compatibility check for legacy experiments |
lbp_circular_uniform_global |
circular-uniform LBP, whole-image histogram | 10 |
compact local texture descriptor |
lbp_circular_uniform_spatial16 |
circular-uniform pyramid-LBP, 4 x 4 regions |
160 |
16 x 10 regional histograms |
lbp_circular_uniform_spatial25 |
circular-uniform pyramid-LBP, 25 regions |
250 |
25 x 10 regional histograms |
Feature components can be concatenated with +:
resnet50+lbp_basic_spatial25
raw32+lbp_basic_global
| Code name | Classifier | Main parameters | Use in this project |
|---|---|---|---|
nnc |
nearest-neighbour classifier | none | simple baseline |
src_standard |
L1 sparse representation classifier |
--lasso-alpha, --lasso-max-iter, --src-standard-n-jobs |
main sparse classifier line |
src_ridge |
ridge residual classifier | --ridge-lambda, --src-ridge-n-jobs |
fast residual comparison line |
dksvd |
practical D-KSVD style classifier | --dksvd-atoms, --dksvd-sparsity, --dksvd-iters, --dksvd-code-algorithm |
optional dictionary-learning comparison |
src |
legacy alias | maps to src_ridge in run_evaluation |
compatibility only |
src_l1 |
legacy alias | maps to src_standard in run_evaluation |
compatibility only |
Classifier differences:
nncis the simplest nearest-neighbour baseline. It checks whether the feature itself is discriminative without adding a representation model.src_standardis the main sparse representation classifier. It solves anL1Lasso problem for each test sample, then assigns the class with the lowest reconstruction residual. It is closest to classic SRC, but it is sensitive to--lasso-alphaand can be slow for high-dimensional spatial LBP features.src_ridgereplaces theL1sparse solver with ridge-regularized residual prediction. It is faster and more stable, but it is not strictly sparse, so it is treated as a practical residual-classifier comparison rather than the main method.dksvdis an optional dictionary-learning comparison line. It is included for experimental completeness, not as the core contribution.
Main generated outputs are written to:
| Purpose | Path |
|---|---|
| Manifests, summaries, descriptor caches, gray vectors | data/processed/<dataset>/ |
| Reusable train/test CSV files | data/splits/<dataset>/ |
| Main JSON experiment metrics | results/metrics/<dataset>/ |
| Paper-section organized metrics | results/metrics/<dataset>/paper_sections/ |
| Generated plots and confusion matrices | results/figures/ |
| Method and dataset figures | docs/images/ |
| Optional MATLAB-side exports | results/matlab_exports/<dataset>/ |
The JSON outputs are the primary experiment artifacts. They record:
- dataset and split protocol;
- feature expression and feature components;
- classifier and hyperparameters;
- seed and command line;
- per-split accuracy;
- average accuracy by train-count;
- overall mean and standard deviation;
- timing and completion status.
Many scripts support resume-style behaviour: if a target JSON already exists and has completed rows, only missing rows are filled in. Supporting documentation for comments, input/output data, verification checks, and external-code boundaries is summarized in docs/submission_documentation.md.
Organized by data, implementation, scripts, documentation, and generated results.
Root project
fyp_image_classification_project/
|-- README.md # project overview and running guide
|-- requirements.txt # Python dependency list
|-- .gitignore # ignored generated files and local artifacts
data/ - raw data, processed metadata, and splits
data/
|-- raw/ # user-provided raw dataset copies
| |-- caltech101/ # expected Caltech-101 archive layout
| `-- coil-100/ # expected COIL-100 flat image directory
|-- processed/ # generated summaries, gray vectors, descriptor caches
`-- splits/ # train/test CSV files reused by evaluations
src/ - reusable Python implementation
src/
|-- datasets/ # dataset-specific preprocessing and protocols
|-- preprocessing/ # manifest and split generation utilities
|-- features/ # ResNet50 and LBP-family extractors
|-- classifiers/ # nnc, src_standard, src_ridge, dksvd
|-- evaluation/ # CLI evaluation pipeline and feature routing
|-- bridges/ # helpers for external / cross-runtime workflows
`-- utils/ # path, seed, and result-format helpers
scripts/ - runnable experiment entrypoints
scripts/
|-- run_selected_train_count_eval.py # fixed train-count evaluation runner
|-- precompute/ # preprocessing and descriptor-cache helpers
|-- paper/ # dissertation workflow orchestration and figures
|-- bridge/ # MATLAB export helpers
|-- organize_paper_section_results.py # result organization utility
|-- bootstrap_caltech101_tr10_sections.py
`-- bootstrap_coil100_tr2_sections.py
docs/ and results/ - writing assets and generated outputs
docs/
|-- images/ # method and dataset figures
results/
|-- metrics/ # JSON experiment metrics
|-- figures/ # generated plots and confusion matrices
`-- matlab_exports/ # optional MATLAB-side matrices and summaries
external/ - optional external references
external/ # optional MATLAB references and project wrappers
|-- README.md # external-code boundary and citations
`-- project_wrappers/ # project-authored MATLAB batch wrappers
The core Python pipeline does not require third-party MATLAB code. Only external/README.md and external/project_wrappers/ are intended as project-authored submission material. Third-party LC-KSVD, D-KSVD, KSVDBox, OMPBox, and spatial-pyramid reference folders may exist locally, but they are ignored by Git and are used only for optional comparison workflows.
The project includes explicit seed control through src.utils.reproducibility.set_global_seed, covering Python random, NumPy, and PyTorch when available.
Split generation is deterministic under the chosen seed. Evaluation JSON files also store the command line, seed, classifier settings, feature settings, split paths, runtime, and completion status so that result rows can be traced back to the exact run configuration.
For previously completed result files, check that JSON outputs report:
"completed": trueThe core SGLT-RC pipeline is implemented in Python and does not require external MATLAB packages. Optional MATLAB-side comparison experiments are documented separately in external/README.md and use project-authored wrappers under external/project_wrappers/.
Submission boundary:
- Submit:
external/README.mdandexternal/project_wrappers/ - Do not submit as core code: local third-party folders such as
external/sharingcode-LCKSVD/,external/face-recognition-using-DKSVD-master/,external/incrementallearning_LCKSVD_shared/, andexternal/spatialpyramidfeatures4caltech101/
Method references:
- LC-KSVD: Jiang, Z., Lin, Z., & Davis, L. S. (2011). Learning a discriminative dictionary for sparse coding via label consistent K-SVD. CVPR. https://zhuolinumd.github.io/projectlcksvd.html
- D-KSVD: Zhang, Q., & Li, B. (2010). Discriminative K-SVD for dictionary learning in face recognition. CVPR.
- SRC: Wright, J., Yang, A. Y., Ganesh, A., Sastry, S. S., & Ma, Y. (2009). Robust face recognition via sparse representation. IEEE TPAMI.
