Paper · 2021-02-16 · cs.CV
Focal Inverse Distance Transform Maps for Crowd Localization
Trains a point-supervised HRNet regressor to output a Focal Inverse Distance Transform (FIDT) map, whose local maxima mark head centres. A 3x3 max-pool with a threshold at 100/255 of the peak extracts them, and an I-SSIM loss on 30x30 regions sharpens the peaks. Author-reported: best localization F-measure on NWPU-Crowd (75.5 at sigma_l) and several other crowd datasets.
Density map regressionStructural similarity (SSIM-style comparison of maps)Distance transformcrowd-localizationcrowd-countingpoint-annotationsdistance-transformloss-function
arXivPDFCodeMarkdown19 min read
AI-compiled by claude-haiku-5-5 on 2026-11-09, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Counting people in a dense crowd is easier than finding where each one is. The usual trick is to train a network to paint a soft blob on each head and add up the paint. In a packed crowd the blobs run into each other, so the paint peaks no longer sit on heads.
This method paints a different picture. Each pixel gets a value that is high close to a head and falls off with distance, and the falloff is shaped so that the value drops to nearly zero in empty background. Every head is then a sharp peak with no overlap with its neighbours, so finding the heads means finding the peaks. A simple local-maximum check does that, and the number of peaks is the count.
The authors also add a loss that looks at small patches around each person, so the network learns the shape of each peak rather than only its height. They report that this gives better head locations than earlier methods, including on very dense and on empty scenes, and that it needs only point labels, not bounding boxes.
TL;DR
Train a regressor (HRNet-w48 in the release) to output a Focal Inverse Distance Transform map: each head is a local maximum, and the map has no overlap in dense regions §3.1 eq. 3. Train it with MSE plus an I-SSIM term over one 30x30 region per person §3.3 eq. 8. At test time, take the 3x3 local maxima above 100/255 of the peak, and call the image empty if the peak is below 0.10 §3.2.2 alg. 1. Author-reported: state-of-the-art localization on six crowd datasets and one vehicle dataset, using point labels only §5 tab. 1. The released training script does not include the I-SSIM term train_baseline.py.
Problem
Density-map regression (Gaussian blobs summed for the count) is blurry, and in dense crowds neighbouring blobs overlap, so the local maxima of the map no longer sit on heads §1 fig. 1. Detectors need box labels, which are costly in dense crowds §1 §2.1. Pseudo boxes built from nearest-neighbour distances do not match real head sizes well §1. Segmentation-style and binary maps need hand-set thresholds, and connected components can merge into one blob when heads are close §1 §2.1. The method assumes only point annotations per head §1 §4.2.
Method
Overview. A regressor predicts a FIDT map. Training uses MSE plus the I-SSIM loss. Testing finds local maxima with LMDS. Box sizes come from a k-nearest- neighbour rule, used only for visualisation §3 fig. 2.
Step 1: Euclidean distance transform. For a pixel (x, y), let P be the distance to its nearest annotated head. The authors define P over the set B of all head positions §3.1 eq. 1:
P(x,y) = \min_{(x',y') \in B} \sqrt{(x-x')^2 + (y-y')^2} \qquad [\text{eq. 1}]
Step 2: inverse distance (IDT). The raw distance has a very large range, so the authors take its inverse with a constant C that avoids division by zero §3.1 eq. 2. The paper calls this a special case of the iKNN map of Olmschenk et al. with K = 1 §3.1. Its response decays too fast near a head and stays too high in background §3.1 fig. 3.
I' = \frac{1}{P(x,y) + C} \qquad [\text{eq. 2}]
Step 3: focal IDT (FIDT). The exponent of the distance is made to grow with the distance, which slows the decay near the head and pushes background to near zero §3.1 eq. 3. The paper fixes alpha = 0.02, beta = 0.75 and C = 1 §3.1 §4 tab. 9.
I = \frac{1}{P(x,y)^{\,(\alpha P(x,y) + \beta)} + C} \qquad [\text{eq. 3}]
The FIDT ground truth is built from head points as follows §3.1 eq. 1 eq. 3:
# FIDT ground-truth map [§3.1] [eq. 1] [eq. 3]
# Input: image size (H, W); head points, each (x, y)
# Output: fidt map (H, W), float in [0, 1]
def fidt_map(height, width, points):
# Distance from each pixel to its nearest head [eq. 1]
distance = nearest_head_distance(height, width, points)
# Focal inverse distance with C = 1; alpha = 0.02, beta = 0.75 [eq. 3]
exponent = 0.02 * distance + 0.75
fidt = 1 / (distance ** exponent + 1)
return fidtStep 4: network. The regressor is HRNet, with one convolution and two transposed convolutions added as the representation head §3.2.1. The high-resolution branch is needed because each map peak must sit on a single head centre §3.2.1. The paper says any crowd regressor could be used instead, naming CSRNet and BL §3.2.1.
Step 5: local maxima detection (LMDS). Take a 3x3 max-pool. Keep pixels equal to their pooled value (the candidate peaks M). If the largest candidate is below T_f = 0.10, the image is treated as negative and the count is 0. Otherwise keep candidates at or above T_a = 100/255 times the largest candidate. Each kept pixel is one head, and the count is the number kept §3.2.2 alg. 1 §5.4 tab. 12.
# Local-Maxima-Detection-Strategy (LMDS) [alg. 1] [§3.2.2]
# Input: predicted FIDT map (H, W)
# Output: head coordinates (N, 2); count N = number of rows
def lmds(fidt_pred):
# Keep only pixels equal to their 3x3 neighbourhood maximum [alg. 1]
pooled = max_pool2d(fidt_pred, kernel=3, stride=1, padding=1)
candidates = fidt_pred * (pooled == fidt_pred)
peak = max(candidates)
# Negative image if the peak is below T_f = 0.10 [§3.2.2] [§5.4]
if peak < 0.10:
return empty_coordinates()
# Adaptive threshold T_a = 100/255 * max(M) [alg. 1] [§3.2.2]
threshold = 100 / 255 * peak
keep = candidates >= threshold
return nonzero_coordinates(keep)Step 6: I-SSIM loss. Standard SSIM eq. 5 is computed with lambda_1 = 0.0001 and lambda_2 = 0.0009 and turned into a loss as 1 minus SSIM eq. 6 §3.3. The authors argue that a global SSIM rewards background structure and creates false peaks §3.3. The I-SSIM loss applies SSIM to small regions, one per person, averaged over the N persons eq. 7 §3.3. The region size is 30x30 for all datasets §3.3 tab. 11. The total objective is MSE plus I-SSIM, with weight 1 on each eq. 8 §3.3.
SSIM(E,G) = \frac{(2\mu_E\mu_G + \lambda_1)(2\sigma_{EG} + \lambda_2)}{(\mu_E^2 + \mu_G^2 + \lambda_1)(\sigma_E^2 + \sigma_G^2 + \lambda_2)} \qquad [\text{eq. 5}]
L_S(E,G) = 1 - SSIM(E,G) \qquad [\text{eq. 6}]
L_{I\text{-}S} = \frac{1}{N} \sum_{n=1}^{N} L_S(E_n, G_n) \qquad [\text{eq. 7}]
L = L_{MSE} + L_{I\text{-}S} \qquad [\text{eq. 8}]
The training step, as the paper describes it §3.3 eq. 8:
# One training step: MSE plus per-person I-SSIM [§3.3] [eq. 8]
# Input: images (B, 3, H, W); fidt_targets (B, H, W); points per image
# Output: scalar loss
def training_step(images, fidt_targets, points):
# Predict a FIDT map at input resolution [§3.2.1]
# [code: train_baseline.py#L169-L176]
predicted = model(images)
# Pixel-wise MSE over the whole map; reduction not stated [eq. 8]
mse_term = mse(predicted, fidt_targets)
# One 30x30 region per person; centring not stated [§3.3] [tab. 11]
region_losses = []
for person in persons_in(points):
# Local crop around the person [§3.3]
region_pred = crop(predicted, person, size=30)
region_gt = crop(fidt_targets, person, size=30)
# SSIM loss on that region, lambda_1 = 1e-4, lambda_2 = 9e-4 [eq. 5]
region_losses.append(1 - ssim(region_pred, region_gt))
# Average over the N persons [eq. 7]
ssim_term = mean(region_losses)
return mse_term + ssim_term # weight 1 on each term [eq. 8]Step 7: box sizes (visualisation only). Each head's square size is s = min(f times the mean distance to its k nearest heads, 0.05 times the shorter image side), with k = 4 and f = 0.1 §4 eq. 4. The paper says the boxes do not affect localization §3.2.2 §5.1.
s_{(x,y)} = \min\left\{ f \cdot \frac{1}{k}\sum_{i=1}^{k} d^{\,k}_{(x,y)},\ \min(img\_w, img\_h) \cdot 0.05 \right\} \qquad [\text{eq. 4}]
Step 8: counting. The count is the number of LMDS points, and the result is 0 for negative images §3.2.2 §5.2 alg. 1.
Hyperparameters
| Name | Value | Where | Notes |
|---|---|---|---|
| optimiser | Adam | §4 | code: torch.optim.Adam train_baseline.py |
| learning rate | 1e-4 | §4 | code default config.py; no schedule in the training script train_baseline.py |
| weight decay | 5e-4 | §4 | code default config.py |
| batch size | 16 | §4 | code default config.py |
| training crop | 256 x 256 (Part A, Part B); 512 x 512 (other datasets) | §4 | code default is 256 config.py; the 512 setting is not shown in a script |
| augmentation | random crop; horizontal flip | §4 | flip p = 0.5 dataset.py; crop dataset.py |
| image resize | longer side below 2048 (NWPU-Crowd, JHU-Crowd++, UCF-QNRF) | §4 | resizing code is not in the release; pre-resized images_2048 folders are used make_npydata.py |
| alpha, beta (FIDT) | 0.02, 0.75 | §3.1 §4 tab. 9 | matches the release generator fidt_generate_sh.py |
| C (FIDT) | 1 | §3.1 eq. 2 | matches the release generator fidt_generate_sh.py |
| I-SSIM constants | lambda_1 = 0.0001; lambda_2 = 0.0009 | §3.3 eq. 5 | |
| I-SSIM region | 30 x 30, all datasets | §3.3 tab. 11 | the 20 and 40 settings are in tab. 11 |
| loss weights | MSE 1, I-SSIM 1 | eq. 8 | |
| LMDS max-pool | 3 x 3 | alg. 1 §3.2.2 | |
| LMDS adaptive threshold | 100/255 times the peak | alg. 1 §3.2.2 tab. 12 | |
| LMDS negative threshold T_f | 0.10 | §3.2.2 §5.4 | set from NWPU validation maxima §5.4 fig. 9 |
| box k-NN | k = 4 | §4 eq. 4 | |
| box factor f | 0.1 | §4 eq. 4 | |
| box cap | 0.05 x shorter side | eq. 4 | |
| regressor | HRNet-w48, ImageNet-pretrained | §3.2.1 | paper says "HRNET"; w48 and the pretrained path are in the code seg_hrnet_w48.yaml config.py |
| regressor head | 1x1 conv, BN, ReLU, two transposed convs | §3.2.1 | paper: "one convolution and two transposed convolution layers"; the code's layers are at seg_hrnet.py |
| training epochs | not stated | code default 3000 config.py | |
| random seed | not stated | code default 1 config.py | |
| ImageNet pretraining | not stated | §3.2.1 | code loads ImageNet HRNet-w48 weights seg_hrnet.py |
Results
Author-reported. Localization is scored by precision, recall and F-measure at distance thresholds (see §4.1). Setup: NWPU-Crowd (test set from the online benchmark), JHU-Crowd++, UCF-QNRF, ShanghaiTech Part A and Part B, UCF_CC_50, TRANCOS (vehicles). Baselines are from the NWPU benchmark, from their official code, or trained by the authors where marked §5.1 §5.3.
Table 1: NWPU-Crowd localization tab. 1. Columns: validation and test sets, each at sigma_l and sigma_s (eqs. 9 and 10), giving F, P and R in percent.
| Method | Labels | Val sigma_l F | Val sigma_l P | Val sigma_l R | Val sigma_s F | Val sigma_s P | Val sigma_s R | Test sigma_l F | Test sigma_l P | Test sigma_l R | Test sigma_s F | Test sigma_s P | Test sigma_s R |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Faster RCNN | Box | 7.3 | 96.4 | 3.8 | 6.8 | 90.0 | 3.5 | 6.7 | 95.8 | 3.5 | 6.3 | 89.4 | 3.3 |
| TinyFaces | Box | 59.8 | 54.3 | 66.6 | 55.3 | 50.2 | 61.7 | 56.7 | 52.9 | 61.1 | 52.6 | 49.1 | 56.6 |
| TopoCount | Box | - | - | - | - | - | - | 69.1 | 69.5 | 68.7 | 60.1 | 60.5 | 59.8 |
| VGG+GPR | Point | 56.3 | 61.0 | 52.2 | 46.0 | 49.9 | 42.7 | 52.5 | 55.8 | 49.6 | 42.6 | 45.3 | 40.2 |
| RAZ_Loc | Point | 62.5 | 69.2 | 56.9 | 54.5 | 60.5 | 49.6 | 59.8 | 66.6 | 54.3 | 51.7 | 57.6 | 47.0 |
| Crowd-SDNet | Point | - | - | - | - | - | - | 63.7 | 65.1 | 62.4 | - | - | - |
| AutoScale* | Point | 66.8 | 70.1 | 63.8 | 60.0 | 62.9 | 57.3 | 62.0 | 67.3 | 57.4 | 54.4 | 59.1 | 50.4 |
| GL | Point | - | - | - | - | - | - | 66.0 | 80.0 | 56.2 | - | - | - |
| SCALNet | Point | 72.4 | 73.5 | 71.4 | 66.9 | 67.9 | 65.9 | 69.1 | 69.2 | 63.6 | 63.6 | 63.7 | 63.6 |
| Ours | Point | 78.9 | 82.2 | 75.9 | 73.7 | 76.7 | 70.9 | 75.5 | 79.7 | 71.7 | 70.5 | 74.4 | 66.9 |
* as printed in the source. Baseline rows for Crowd-SDNet and GL are reported as published; the source gives no validation figures for them tab. 1.
Table 2: UCF-QNRF localization (average over thresholds 1 to 100 pixels) tab. 2.
| Method | Av. precision | Av. recall | F-measure |
|---|---|---|---|
| MCNN | 59.93% | 63.50% | 61.66% |
| CL | 75.80% | 59.75% | 66.82% |
| LCFCN | 77.89% | 52.40% | 62.65% |
| Method in Ribera et al. 2019 | 75.46% | 49.87% | 60.05% |
| LSC-CNN | 74.62% | 73.50% | 74.06% |
| GL | 78.20% | 74.80% | 76.30% |
| TopoCount | 81.77% | 78.96% | 80.34% |
| Ours | 84.49% | 80.10% | 82.23% |
Table 3: JHU-Crowd++ localization tab. 3.
| Method | sigma=4 P | sigma=4 R | sigma=4 F | sigma=8 P | sigma=8 R | sigma=8 F |
|---|---|---|---|---|---|---|
| TopoCount | 31.5% | 28.8% | 30.1% | 63.6% | 58.3% | 60.8% |
| Ours | 38.9% | 38.7% | 38.8% | 62.5% | 62.4% | 62.4% |
Table 4: ShanghaiTech Part A and Part B localization tab. 4.
| Method | A sigma=4 P | A sigma=4 R | A sigma=4 F | A sigma=8 P | A sigma=8 R | A sigma=8 F | B sigma=4 P | B sigma=4 R | B sigma=4 F | B sigma=8 P | B sigma=8 R | B sigma=8 F |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LCFCN | 43.3% | 26.0% | 32.5% | 75.1% | 45.1% | 56.3% | - | - | - | - | - | - |
| Method in Ribera et al. 2019 | 34.9% | 20.7% | 25.9% | 67.7% | 44.8% | 53.9% | - | - | - | - | - | - |
| LSC-CNN | 33.4% | 31.9% | 32.6% | 63.9% | 61.0% | 62.4% | 29.7% | 29.2% | 29.5% | 57.5% | 56.7% | 57.0% |
| TopoCount | 41.7% | 40.6% | 41.1% | 74.6% | 72.7% | 73.6% | 63.4% | 63.1% | 63.2% | 82.3% | 81.8% | 82.0% |
| Ours | 59.1% | 58.2% | 58.6% | 78.2% | 77.0% | 77.6% | 64.9% | 64.5% | 64.7% | 83.9% | 83.2% | 83.5% |
Table 5: UCF_CC_50 localization tab. 5. Rows marked with a dagger were trained by the authors tab. 5.
| Method | sigma=4 P | sigma=4 R | sigma=4 F | sigma=8 P | sigma=8 R | sigma=8 F |
|---|---|---|---|---|---|---|
| LSC-CNN (dagger) | 37.7% | 39.5% | 38.6% | 57.8% | 61.1% | 59.4% |
| AutoScale (dagger) | 37.8% | 40.5% | 39.1% | 59.0% | 62.3% | 60.6% |
| TopoCount (dagger) | 39.5% | 42.0% | 40.7% | 62.5% | 66.9% | 64.6% |
| Ours | 46.5% | 49.0% | 47.7% | 67.0% | 70.6% | 68.7% |
Table 6: NWPU-Crowd counting tab. 6. The S0 to S4 columns are MAE by scene level (0; (0,100]; (100,500]; (500,5000]; >5000). Position output: the method returns coordinates.
| Method | Position | Val MAE | Val MSE | Test MAE | Test MSE | Test avg MAE | S0/S1/S2/S3/S4 MAE |
|---|---|---|---|---|---|---|---|
| C3F-VGG | no | 105.79 | 504.39 | 127.0 | 439.6 | 666.9 | 140.9/26.5/58.0/307.1/2801.8 |
| CSRNet | no | 104.89 | 433.48 | 121.3 | 387.8 | 522.7 | 176.0/35.8/59.8/285.8/2055.8 |
| CAN | no | 93.58 | 489.90 | 106.3 | 386.5 | 612.2 | 82.6/14.7/46.6/269.7/2647.0 |
| SCAR | no | 81.57 | 397.92 | 110.0 | 495.3 | 718.3 | 122.9/16.7/46.0/241.7/3164.3 |
| BL | no | 93.64 | 470.38 | 105.4 | 454.2 | 750.5 | 66.5/8.7/41.2/249.9/3386.4 |
| SFCN | no | 95.46 | 608.32 | 105.7 | 424.1 | 712.7 | 54.2/14.8/44.4/249.6/3200.5 |
| KDMG | no | - | - | 100.5 | 415.5 | 632.7 | 77.3/10.3/38.5/259.4/2777.9 |
| NoisyCC | no | - | - | 96.9 | 534.2 | 608.1 | 218.7/10.7/35.2/203.2/2572.8 |
| DM-Count | no | 70.5 | 357.6 | 88.4 | 388.6 | 498.0 | 146.6/7.6/31.2/228.7/2075.8 |
| RAZ_loc | yes | 128.7 | 665.4 | 151.4 | 634.6 | 1166.0 | 60.6/17.1/48.3/364.7/5339.0 |
| AutoScale | yes | 97.3 | 571.2 | 123.9 | 515.5 | 871.0 | 42.3/18.8/46.1/301.7/3947.0 |
| TopoCount | yes | - | - | 107.8 | 438.5 | - | - |
| SCALNet | yes | 64.4 | 251.1 | 86.8 | 339.9 | 429.5 | 92.0/11.2/41.1/227.7/1775.3 |
| Ours | yes | 51.4 | 107.6 | 86.0 | 312.5 | 390.6 | 21.6/13.7/55.6/217.1/1645.4 |
Table 7: counting on JHU-Crowd++, UCF-QNRF, ShanghaiTech A and B, UCF_CC_50 tab. 7. Each cell is MAE / MSE.
| Method | Position | JHU | QNRF | Part A | Part B | UCF_CC_50 |
|---|---|---|---|---|---|---|
| CSRNet | no | 85.9 / 309.2 | - | 68.2 / 115.0 | 10.6 / 16.0 | 266.1 / 397.5 |
| SFCN | no | 77.5 / 297.6 | 102.0 / 171.4 | 64.8 / 107.5 | 7.6 / 13.0 | 214.2 / 318.2 |
| L2SM | no | - | 104.7 / 173.6 | 64.2 / 98.4 | 7.2 / 11.1 | 188.4 / 315.3 |
| CG-DRCN | no | 82.3 / 328.0 | 112.2 / 176.3 | 64.0 / 98.4 | 8.5 / 14.4 | - |
| MUD-iKNN | no | - | 104.0 / 172.0 | 68.0 / 117.7 | 13.4 / 21.4 | 237.7 / 305.7 |
| DSSI-Net | no | 133.5 / 416.5 | 99.1 / 159.2 | 60.6 / 96.0 | 6.9 / 10.3 | 216.9 / 302.4 |
| MBTTBF | no | 81.8 / 299.1 | 97.5 / 165.2 | 60.2 / 94.1 | 8.0 / 15.5 | 233.1 / 300.9 |
| BL | no | 75.0 / 299.9 | 88.7 / 154.8 | 62.8 / 101.8 | 7.7 / 12.7 | 229.3 / 308.2 |
| RPNet | no | - | - | 61.2 / 96.9 | 8.1 / 11.6 | - |
| ASNet | no | - | 91.6 / 159.7 | 57.8 / 90.1 | - | 174.8 / 251.6 |
| AMSNet | no | - | 101.8 / 163.2 | 56.7 / 93.4 | 6.7 / 10.2 | 208.6 / 296.3 |
| LibraNet | no | - | 88.1 / 143.7 | 55.9 / 97.1 | 7.3 / 11.3 | 181.2 / 262.2 |
| KDMG | no | 69.7 / 268.3 | 99.5 / 173.0 | 63.8 / 99.2 | 7.8 / 12.7 | - |
| NoisyCC | no | 67.7 / 258.5 | 85.8 / 150.6 | 61.9 / 99.6 | 7.4 / 11.3 | - |
| DM-Count | no | - | 85.6 / 148.3 | 59.7 / 95.7 | 7.4 / 11.8 | 211.0 / 291.5 |
| RAZ_loc+ | yes | - | 118.0 / 198.0 | 71.6 / 120.1 | 9.9 / 15.6 | - |
| PSDDN | yes | - | - | 65.9 / 112.3 | 9.1 / 14.2 | 359.4 / 514.8 |
| LSC-CNN | yes | 112.7 / 454.4 | 120.5 / 218.2 | 66.4 / 117.0 | 8.1 / 12.7 | 225.6 / 302.7 |
| Crowd-SDNet | yes | - | - | 65.1 / 104.4 | 7.8 / 12.6 | - |
| AutoScale | yes | 85.6 / 356.1 | 104.4 / 174.2 | 65.8 / 112.1 | 8.6 / 13.9 | 210.5 / 287.4 |
| TopoCount | yes | 60.9 / 267.4 | 89.0 / 159.0 | 61.2 / 104.6 | 7.8 / 13.7 | 184.1 / 258.3 |
| Ours | yes | 66.6 / 253.6 | 89.0 / 153.5 | 57.0 / 103.4 | 6.9 / 11.8 | 171.4 / 233.1 |
Table 8: TRANCOS vehicle counting, GAME(L) tab. 8. Lower is better. Dagger rows were trained by the authors.
| Method | GAME(0) | GAME(1) | GAME(2) | GAME(3) |
|---|---|---|---|---|
| PSDDN | 4.79 | 5.43 | 6.68 | 8.40 |
| LSC-CNN | 4.60 | 5.40 | 6.90 | 8.30 |
| AutoScale | 2.88 | 4.97 | 6.64 | 9.73 |
| Crowd-SDNet (dagger) | 3.82 | 5.27 | 7.72 | 10.11 |
| TopoCount (dagger) | 3.42 | 4.76 | 6.51 | 8.55 |
| Ours | 2.25 | 3.91 | 5.66 | 8.36 |
Table 9: alpha and beta on ShanghaiTech Part A, localization at sigma=8 tab. 9. The IDT row is alpha = 0, beta = 1.
| Method | alpha | beta | P (%) | R (%) | F (%) | MAE | MSE |
|---|---|---|---|---|---|---|---|
| IDT | 0.00 | 1.00 | 75.6 | 74.6 | 75.1 | 61.8 | 109.6 |
| FIDT | 0.01 | 0.65 | 76.6 | 76.0 | 76.3 | 60.5 | 107.4 |
| FIDT | 0.02 | 0.75 | 78.2 | 77.0 | 77.6 | 57.0 | 103.4 |
| FIDT | 0.03 | 0.85 | 77.0 | 76.8 | 76.9 | 58.3 | 106.6 |
Table 10: I-SSIM ablation, Part A, sigma=8 tab. 10.
| Loss | P (%) | R (%) | F (%) | MAE | MSE |
|---|---|---|---|---|---|
| L2 | 73.5 | 76.3 | 74.9 | 62.1 | 108.8 |
| L2 + SSIM | 76.8 | 76.6 | 76.7 | 59.3 | 106.5 |
| L2 + I-SSIM (ours) | 78.2 | 77.0 | 77.6 | 57.0 | 103.4 |
Table 11: I-SSIM region size, Part A, sigma=8 tab. 11.
| Region size | P (%) | R (%) | F (%) | MAE | MSE |
|---|---|---|---|---|---|
| 20 x 20 | 78.0 | 76.4 | 77.2 | 58.1 | 104.4 |
| 30 x 30 | 78.2 | 77.0 | 77.6 | 57.0 | 103.4 |
| 40 x 40 | 77.4 | 76.4 | 76.9 | 58.6 | 105.9 |
Table 12: threshold T_a ablation tab. 12. The dataset is not stated in the caption.
| Threshold | Adaptive | MAE | MSE |
|---|---|---|---|
| 50/255 | no | 95.6 | 169.9 |
| 70/255 | no | 92.1 | 167.0 |
| 90/255 | no | 80.6 | 152.3 |
| 100/255 | no | 115.3 | 206.4 |
| 110/255 | no | 122.6 | 233.5 |
| 90/255 x max(M) | yes | 60.4 | 105.3 |
| 100/255 x max(M) | yes | 57.0 | 103.4 |
| 110/255 x max(M) | yes | 58.1 | 107.1 |
Table 13: NWPU-Crowd test, negative (S0) and extremely dense (S4) scenes tab. 13.
| Method | S0 MAE | S0 MSE | S4 MAE | S4 MSE |
|---|---|---|---|---|
| KDMG | 77.3 | 303.0 | 2777.9 | 3521.8 |
| DM-Count | 146.7 | 736.1 | 2075.8 | 2895.2 |
| NoisyCC | 218.7 | 1415.6 | 2572.5 | 3414.9 |
| SCALNet | 92.0 | 479.3 | 1775.3 | 2676.4 |
| Ours | 21.6 | 129.3 | 1645.4 | 2288.2 |
Table 14: other regressors with FIDT maps, NWPU-Crowd validation tab. 14. Density-map columns count by integration; FIDT columns count by localization. The FIDT runs use only the L2 loss §5.4.
| Regressor | Density MAE | Density MSE | FIDT MAE | FIDT MSE | FIDT P (%) | FIDT R (%) | FIDT F (%) |
|---|---|---|---|---|---|---|---|
| CSRNet | 104.9 | 433.5 | 100.6 | 464.3 | 68.8 | 66.2 | 67.5 |
| CSRNet + FPN | 95.5 | 450.8 | 70.6 | 369.7 | 73.9 | 69.8 | 71.8 |
| BL | 93.6 | 470.4 | 89.7 | 446.6 | 69.9 | 68.9 | 69.4 |
| BL + FPN | 85.4 | 412.9 | 65.7 | 259.2 | 77.8 | 70.0 | 73.7 |
Table 15: complexity tab. 15. MACs at 768 x 1024, RTX 3090 §5.5.
| Method | MACs (G) | Inference speed | F-measure (NWPU test) |
|---|---|---|---|
| LSC-CNN | 1244.3 | 2.6 FPS | - |
| AutoScale | 1074.6 | 5.7 FPS | 62.0% |
| Crowd-SDNet | - | 0.8 FPS | 63.7% |
| GL | 324.6 | 20.3 FPS | 66.0% |
| TopoCount | 797.2 | 9.4 FPS | 69.1% |
| Ours | 426.7 | 7.1 FPS | 75.5% |
Qualitative results. Figures show FIDT versus density-map predictions in dense scenes fig. 6, box visualisations against LSC-CNN fig. 4 and fig. 5, and the maximum response per image used to pick T_f fig. 9.
Paper vs code
Official repository: github.com/dk-liang/FIDTM, owned by the first author
(Dingkang Liang), commit e9308bdd2292e0308b2e02a9c8fc21ec5530cd9e
(git rev-parse HEAD on a depth-1 clone). It is MIT-licensed. The paper's
abstract gives this link. Only what is needed for the card is read; no code is
quoted.
Discrepancies found:
- I-SSIM loss is not in the release. The training script uses only MSE with
size_average=Falsetrain_baseline.py and sums it in the loss train_baseline.py. The paper's objective eq. 8 adds I-SSIM, which is not implemented anywhere in the repository (nossimstring in the Python or Markdown files). The reported ablation tab. 10 cannot be checked from the code. - MSE reduction. The paper writes MSE with no reduction. The code sums over pixels and images train_baseline.py. Loss magnitudes, and so the Adam-normalised step size relative to the weight decay, depend on this choice.
- UCF-QNRF pooling in the training script. The training-time LMDS applies a 3x3 average pool to the prediction before max-pooling on UCF-QNRF train_baseline.py. The test script has that line commented out test.py. Algorithm 1 has no average pool alg. 1.
- Negative check. The code compares the global maximum of the map with T_f train_baseline.py train_baseline.py. The paper uses the maximum of the candidates M §3.2.2. The global maximum is always a candidate, so the two agree (inferred from the code).
- Adaptive threshold. The code uses 100/255 times the global maximum train_baseline.py, which matches the paper alg. 1.
- Box size. The paper's square size is min(f times the mean of k = 4 neighbour distances, 0.05 times the shorter side) eq. 4 §4. The code sums three neighbour distances and multiplies by 0.1 test.py test.py. The k-d tree query with k = 4 returns the point itself first, so the three terms are its three nearest other heads (inferred). The code then caps the value at 0.05 times the shorter side test.py, which matches. The drawn rectangle goes from the point minus sigma to the point plus sigma test.py, so its side is 2 sigma. The paper does not say whether s is a side or a half-side.
- Single-point images. The code uses a different size for an image with one head: the average image side over 4 test.py. The paper does not mention this.
- FIDT ground truth. The generator matches eq. 3 with C = 1 and alpha, beta as in the paper fidt_generate_sh.py. It also zeroes values below 1e-2 fidt_generate_sh.py, which the paper does not mention. It moves head coordinates of 0 to 1 fidt_generate_sh.py.
- Hyperparameters that match. Adam with lr 1e-4, weight decay 5e-4 and batch 16 config.py. The crop default is 256 config.py; the paper's 512 crop for the other datasets is not in any script shown.
- Regressor. HRNet-w48 with an ImageNet checkpoint config.py and a 1x1 convolution, then two transposed convolutions seg_hrnet.py. The output has no final activation seg_hrnet.py. The paper does not state the output activation.
- Training-time filter. Training images whose shorter side is under 256 are dropped train_baseline.py. The paper does not mention this.
- Training length and selection. The default is 3000 epochs config.py. Validation runs every 10 epochs from epoch 200 train_baseline.py. The best checkpoint is chosen by MAE on the test list train_baseline.py train_baseline.py. The paper does not describe selection.
- Evaluation files. The repository ships predicted coordinates and ground-truth
scripts under
local_eval/[README], and the NWPU sigmas come from box annotations in the benchmark eval.py. The fixed sigma of 4 and 8 for the other datasets is in gt_generate.py. - TRANCOS. The repository has FIDT generators for ShanghaiTech, JHU, UCF-QNRF and NWPU only [README]. The vehicle results cannot be reproduced from the release, and the paper does not say how its vehicle model was trained §5.3.
Pitfalls
- One loss term is absent from the release. The I-SSIM term, its region size and its region-centring rule are only in the paper, so a model trained with the released script is MSE-only. Its results may differ from tab. 1 and tab. 10.
- Region centring is not stated. For I-SSIM, the paper defines one 30x30 region per person §3.3 but does not say whether it is centred on the ground- truth head, on the prediction, or on a peak. A reimplementation has to choose.
- The negative threshold depends on output scale. T_f = 0.10 is set from the maxima of predicted maps on the NWPU validation set §5.4 fig. 9. A model trained with a different loss reduction or on a different scale needs its own threshold.
- Adaptive threshold ablation has no dataset. The T_a table tab. 12 gives no dataset in the caption. The text says the fixed thresholds lose to the adaptive one §5.4.
- FIDT depends on pixel distances. Eq. 1 and eq. 3 use distances in pixels, so a different resize changes the map. The paper resizes the three large datasets to a longer side below 2048 §4, and the release uses pre-resized folders make_npydata.py. The paper does not discuss how alpha and beta interact with resizing (the dependence is inferred from the formulas).
- Ties in the 3x3 maximum. Algorithm 1 keeps every pixel equal to its window maximum. A flat plateau of equal values can therefore produce several peaks for one head. The paper does not discuss ties (inferred from the algorithm).
- Label types differ across the comparison. TopoCount is trained with boxes on NWPU, while this method uses points only §5.1. The NWPU localization numbers come from the online benchmark, not from a local run §5.1.
- Inference cost. The method is slower than the real-time GL method, and the paper says it wants to move to real-time later §5.5. At 768 x 1024, it runs at 7.1 FPS on an RTX 3090 with 426.7 GMACs tab. 15.
- Small mismatches in the paper's tables. DM-Count's S0 MAE is 146.6 in tab. 6 but 146.7 in tab. 13. NoisyCC's S4 MAE is 2572.8 in tab. 6 and 2572.5 in tab. 13. The text gives the 27.4 MSE margin over SCALNet, which matches tab. 6.
- Citation key. The row labelled TopoCount in tab. 15 cites the DM-Count reference key §5.5 tab. 15. Treat the row as TopoCount, following its name and the other tables.
- Not stated. Training epochs, learning-rate schedule, ImageNet initialisation for the paper's own training, random seed, and the vehicle training protocol.
- Paper figures are described only. No figure is reproduced here. Read fig. 3 for the IDT and FIDT decay curves and fig. 9 for the peak-value distribution behind T_f.
Lineage
- Builds on: the iKNN map of Olmschenk et al. (IDT is its K = 1 case, not used for localization in that work) §3.1; the Euclidean distance transform §2.3.
- Loss ideas from: SSIM for density maps (Cao et al., DSSI-Net) §2.2 §3.3.
- Regressor: HRNet (Wang et al.) §3.2.1; the paper also tests CSRNet and BL §5.4 tab. 14.
- Compared against: TopoCount (Abousamra et al.), LSC-CNN (Sam et al.), AutoScale (Xu et al.), SCALNet, GL, Crowd-SDNet, RAZ_loc, PSDDN, VGG+GPR, TinyFaces and Faster R-CNN tab. 1. None of these have cards yet.
- Superseded by: not stated.
Source and license
Adapted from “Focal Inverse Distance Transform Maps for Crowd Localization” by Dingkang Liang, Wei Xu, Yingying Zhu, Yu Zhou (arXiv:2102.07925), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/dk-liang/FIDTM at commit e9308bdd2292 (MIT). Any quoted code is shown under that license.