# Object Detection — what is on the picture, and where (`praestat/object-detection`) Actor

Detect the 80 everyday COCO object classes (person, car, dog, bottle, chair, laptop ...) in images with a license-clean YOLOX model on onnxruntime. Returns label, confidence and bounding box per object, or crops every hit into its own image. One dataset item per image, per-image pricing.

- **URL**: https://apify.com/praestat/object-detection.md
- **Developed by:** [praestat media](https://apify.com/praestat) (community)
- **Categories:** AI, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 item processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Object Detection

Detect the 80 COCO object classes in images and get label, confidence and bounding box per
object. `detect` answers "what is on this picture, and where"; `crop` additionally cuts every
hit into its own JPEG.

### Why YOLOX and not YOLOv8

YOLOX (Megvii) is **Apache-2.0**. That matters for you, the user, not for a licence fee:
you get the exact model weights, the code that runs them and the freedom to use the output
commercially, with no second licence, no attribution burden on your own product and no
restriction on the images you process with it.

YOLOv8 models are AGPL-3.0 instead. Pairing those weights with a hosted service would put the
AGPL's source-disclosure requirement on the service around them — a restriction this Actor
simply does not carry. Same 80 COCO classes, same kind of output, plain ONNX without torch.
All model files ship inside the image (`/opt/models`), so no download happens at runtime.

### Model size: tiny, s or m

All three are the same YOLOX release (Apache-2.0), the same 80 COCO classes and the same output —
they differ in resolution and depth. `tiny` is the default because it keeps runs cheap.

| `modelName` | Input | File | Measured per image (warm) | On `dog.jpg`: dog score |
| --- | --- | --- | --- | --- |
| `yolox-tiny` (default) | 416 px | 20 MB | 225 ms | 0.58 |
| `yolox-s` | 640 px | 35 MB | 689 ms | 0.90 |
| `yolox-m` | 640 px | 97 MB | 1510 ms | 0.94 |

Measured on a 4-core i5-3570 without GPU, 768×576 image, median of three runs after warm-up;
cold start (first image loads the model) is 383 / 800 / 1966 ms. On Apify's default hardware it
will be faster, but the ratio stays: s is about 3× and m about 7× the work of tiny.

The larger models help with small, distant or partly hidden objects — that is where the dog score
moves from 0.58 to 0.90. For "is there a person in this photo" tiny is enough; for crowded scenes,
small products or surveillance-frame use cases pick `yolox-s`. `yolox-m` costs another 2× time for
a few points of confidence and is rarely worth it for a per-image price.

### Operations

| Operation | Does | Output |
| --- | --- | --- |
| `detect` | Analyses every image | one dataset item per image with `detections` |
| `crop` | Same, plus cuts out each hit | dataset item plus the crops in the key-value store |

Every detection carries `label`, `classId`, `confidence` and `box` (`[x, y, width, height]` in
pixels of the original image). The list is sorted by confidence, duplicates are removed by NMS.

### Input

| Field | Default | Meaning |
| --- | --- | --- |
| `operation` | `detect` | `detect` or `crop` |
| `imageUrls` | — | direct links or local paths |
| `confidenceThreshold` | `0.25` | drop hits below this model score |
| `iouThreshold` | `0.45` | boxes overlapping more are merged |
| `modelName` | `yolox-tiny` | `yolox-tiny`, `yolox-s` or `yolox-m` — see the table above |
| `classes` | all | filter by COCO name (`person`, `dog`, …) or id 0–79 |

### Output

```json
{
  "operation": "detect",
  "source": "dog.jpg",
  "status": "ok",
  "width": 768,
  "height": 576,
  "count": 3,
  "detections": [
    {"label": "bicycle", "classId": 1, "confidence": 0.8408, "box": [125.2, 124.2, 438.9, 295.8]},
    {"label": "car", "classId": 2, "confidence": 0.7275, "box": [462.2, 82.5, 230.1, 89.4]},
    {"label": "dog", "classId": 16, "confidence": 0.5833, "box": [130.1, 141.4, 249.7, 251.2]}
  ],
  "model": "yolox_tiny.onnx",
  "modelName": "yolox-tiny",
  "inputSize": 416,
  "license": "YOLOX (Megvii), Apache-2.0"
}
```

### What this does NOT do

- **No authenticity check.** It finds objects, not forgeries. A confidence value is a model
  score, not evidence that the photo is real or synthetic.
- **No fine-grained classes.** The 80 COCO classes are what the model knows: "bottle", not
  "Austrian wine bottle"; "dog", not "dachshund".
- **No text, no faces, no emotions.** Use OCR for text and a face model for faces — both are
  different products with their own licence questions.
- **No custom classes.** You cannot teach these models your own labels. A filter narrows the
  output to the 80 COCO classes; a new class means training a new model.
- **No video.** One image per request. For video, extract frames first (ffmpeg) and send them as
  a batch — every analysed frame is one `image-analyzed` event.

### Pricing (pay per event)

| Event | When | Price |
| --- | --- | --- |
| `apify-actor-start` | once per run | $0.005 |
| `image-analyzed` | per image with `status: "ok"` | $0.002 |

A 100-image batch with the default model is roughly $0.20 plus the start event; with `yolox-s`
count the 689 ms per image instead of 225 ms. Measured on this host (4-core i5-3570, no GPU):
225 / 689 / 1510 ms per 768×576 image for tiny / s / m after warm-up, model load 0.38 / 0.80 /
1.97 s. That is CPU inference on a weak CPU — on Apify's default hardware it will be faster.

### Local run

```bash
python -m src --input input.json --outdir out --push
```

# Actor input Schema

## `operation` (type: `string`):

detect = list what is on each image. crop = additionally cut every hit into its own JPEG.

## `imageUrls` (type: `array`):

Direct links to JPEG/PNG/WebP images, or local paths when running the Actor locally.

## `confidenceThreshold` (type: `number`):

Hits below this model score are dropped. 0.25 is a good default; 0.5 for strict results, 0.1 to see almost everything.

## `iouThreshold` (type: `number`):

Boxes overlapping more than this are treated as the same object. Lower = fewer duplicates, higher = more boxes.

## `classes` (type: `array`):

Optional filter by COCO class name (e.g. person, dog, car) or class id 0-79. Empty = all 80 classes.

## `modelName` (type: `string`):

yolox-tiny (default, 20 MB, 416 px) is the fastest. yolox-s and yolox-m look at 640 px and find small or partly hidden objects better, but take longer per image and make the image bigger. Same 80 COCO classes in all three.

## Actor input object example

```json
{
  "operation": "detect",
  "imageUrls": [
    "https://raw.githubusercontent.com/Megvii-BaseDetection/YOLOX/main/assets/dog.jpg"
  ],
  "confidenceThreshold": 0.25,
  "iouThreshold": 0.45,
  "modelName": "yolox-tiny"
}
```

# Actor output Schema

## `results` (type: `string`):

One item per image: status, image size, number of hits and the list of detections with label, class id, confidence and box.

## `crops` (type: `string`):

For the crop operation: every detected object as its own JPEG in the default key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "imageUrls": [
        "https://raw.githubusercontent.com/Megvii-BaseDetection/YOLOX/main/assets/dog.jpg"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("praestat/object-detection").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "imageUrls": ["https://raw.githubusercontent.com/Megvii-BaseDetection/YOLOX/main/assets/dog.jpg"] }

# Run the Actor and wait for it to finish
run = client.actor("praestat/object-detection").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "imageUrls": [
    "https://raw.githubusercontent.com/Megvii-BaseDetection/YOLOX/main/assets/dog.jpg"
  ]
}' |
apify call praestat/object-detection --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,praestat/object-detection"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/X9gF2VU8GDIHkof2I/builds/QLRHtSFJ1IyvFaKcJ/openapi.json
