Object Counting via Camera: From Detection to Tracking
Real-time object counting via camera is a tricky task. Overlapping objects, varying scale, and the main pitfall — double counting when the camera moves. An industrial warehouse, a herd of animals, coins on a table — each scenario demands its own strategy. We have been doing mobile AI computer vision for over 5 years and have delivered 30+ projects. We offer turnkey solutions for iOS and Android using the latest versions of frameworks.
When is Automatic Object Counting Needed?
Typical use cases: inventory in a warehouse (warehouse logistics), livestock monitoring in agriculture, visitor counting in a store. Anywhere you need quick and accurate counts without manual recounting. Automation reduces costs by up to 15% and eliminates human error.
Two Approaches: Detection vs. Density Map
Detection-based counting — YOLOv8 mobile or RT-DETR detects each object; count = number of detections. Works well at low density (up to 50–100 objects per frame) with minimal overlap.
Density map estimation — A CNN predicts a density map; integrating the map gives the count. Used for high density: crowds, grain in a bin, cells under a microscope. CSRNet, DMCount, BL-model are current architectures.
| Criteria | Detection-based | Density map |
|---|---|---|
| Max density | up to 100 objects | unlimited |
| Accuracy under occlusion | low | high |
| Speed (FPS) | 30+ (iPhone 15) | 15-20 |
| Tracking required | yes (when moving) | no (integral stable) |
| Counting accuracy comparison | Detection-based (YOLOv8) | Density map (CSRNet) |
|---|---|---|
| Low density (<50 objects) | 95-99% | 97-99% |
| Medium density (50-200) | 80-90% | 95-98% |
| High density (200+) | 50-70% | 90-95% |
// iOS: choose method based on expected density
enum CountingStrategy {
case detection(model: VNCoreMLModel) // < 100 objects
case densityMap(model: VNCoreMLModel) // > 100 objects per frame
case hybrid // mixed, determined adaptively
}
class AdaptiveObjectCounter {
func selectStrategy(for objectClass: CountableObject) -> CountingStrategy {
switch objectClass {
case .vehicle, .person_sparse:
return .detection(model: vehicleDetector)
case .crowd, .grain, .cell:
return .densityMap(model: densityEstimator)
case .product_shelf:
return .hybrid
}
}
}
How to Avoid Double Counting When the Camera Moves?
If the user pans the camera smoothly (warehouse, auditorium), tracking is needed to avoid counting the same object twice. ByteTracker is one of the best algorithms for this task, robust to occlusions. We have implemented integration on iOS and Android using non-maximum suppression to filter duplicates.
class TrackingObjectCounter {
private var tracker = ByteTracker() // BYTE tracking algorithm
private var countedIds: Set<Int> = [] // unique IDs per session
func processFrame(_ detections: [Detection]) -> TrackingCountResult {
let tracks = tracker.update(detections: detections)
// New IDs — new objects that entered the frame
let newIds = tracks.map { $0.trackId }.filter { !countedIds.contains($0) }
countedIds.formUnion(newIds)
return TrackingCountResult(
currentFrameCount: tracks.count, // currently in frame
totalUniqueCount: countedIds.count // total this session
)
}
}
Why Density Map is More Accurate than Detection at High Density?
Detection-based methods fail when objects overlap: one bounding box covers multiple objects, or one object is split into parts. Density map solves this — the neural network predicts a distribution map, and the sum gives the exact count. For example, when counting grains in a bin (1000+ objects), density map is off by 2-5%, while detection has an error of 20-30%. Density map estimation is 4-10 times more accurate than detection under heavy occlusion.
// Android: density map estimation via TFLite
class DensityMapCounter(context: Context) {
private val interpreter: Interpreter by lazy {
val model = FileUtil.loadMappedFile(context, "csrnet_lite.tflite")
Interpreter(model, Interpreter.Options().apply {
addDelegate(GpuDelegate())
numThreads = 4
})
}
fun estimate(bitmap: Bitmap): Int {
// Model input size — typically 512×512 or multiple of 16
val resized = Bitmap.createScaledBitmap(bitmap, 512, 512, true)
val inputBuffer = TensorImage.fromBitmap(resized).buffer
// Output tensor — density map of same resolution
val outputBuffer = TensorBuffer.createFixedSize(
intArrayOf(1, 512, 512, 1), DataType.FLOAT32
)
interpreter.run(inputBuffer, outputBuffer.buffer)
// Sum over all density map pixels = estimated count
val densitySum = outputBuffer.floatArray.sum()
// Scaling: sum corresponds to number of objects
return densitySum.roundToInt()
}
}
What’s Included in Object Counting Implementation
- Scenario analysis — evaluate density, object types, shooting conditions (lighting, static/moving).
- Model selection — train/fine-tune YOLOv8, CSRNet, or a custom architecture.
- Integration — connect Vision (iOS) / TFLite (Android), implement pipeline: detection → NMS → tracking.
- Counter UI — display current and total count, animations, sound alerts.
- Optimization — quantization, GPU delegate, descriptor caching.
- Documentation and support — deliver source code, API description, team training.
We guarantee counting accuracy of 90-97% depending on conditions (verified on 10+ projects for warehouses and agricultural monitoring). Contact us to assess your scenario — we’ll determine the strategy and timeline within 1-2 days.
Process for Implementing Object Counting
- Analysis — you send video or description of the task. We select the architecture.
- Prototype — in 3-5 days we build a working demo build for iOS and Android.
- Integration — embed the module into your app, configure the pipeline.
- Test — measure accuracy on your data, fine-tune the model if needed.
- Deploy — publish to App Store / Google Play, monitor in production.
Timeline: from 5 days to 2 weeks depending on complexity. Exact cost calculated individually after task analysis. Request a consultation — we’ll analyze your task and propose the optimal strategy.
Common Mistakes When Implementing AI Counting
- Using detection-based methods at high density without adaptation — accuracy drops to 50%.
- Ignoring tracking when the camera moves — double counting up to 40% excess.
- Not accounting for lighting: models trained on uniform light fail with highlights and shadows.
- Missing model quantization — FPS below 5 on devices without GPU.







