I took a public Oriented R-CNN, trained on aerial photos, and pointed it at one Copernicus Sentinel-2 tile. No new labels.
The boxes came out with plausible headings. What found more ships was zooming the tile, so each vessel looked the size the detector expects. The pictures and the command are below.

The scene Link to heading
The input image is T30NZM_20260616T101021_TCI_10m_2976_7936.png, a 1024×1024 RGB crop at 10 m ground sampling distance.
Ships appear as small elongated blobs: white hulls, orange decks, dark wakes, and many arbitrary headings. That is exactly the kind of geometry where horizontal boxes are a poor fit. A rotated bounding box can follow the vessel footprint instead of enclosing a large patch of water around it.

DOTA’s ship class is a reasonable semantic match, but the domain gap is large. DOTA training images are mostly aerial imagery with different resolution, colour response, viewing conditions, and object scale. Ships on Sentinel-2 images are often only a handful of pixels wide.
Baseline: one forward pass Link to heading
The Oriented R-CNN DOTA recipe uses a 1024×1024 model canvas. Since the tile is already 1024×1024, the first baseline is a single forward pass: no tiling, no resize stretch.
We used the published oriented_rcnn_dota_le90_1x checkpoint, which reaches 76.73% official DOTA v1.0 Task 1. The sidecar config resolves class names correctly, so the output says ship rather than Class 10.
At a permissive score threshold of 0.05 and merge NMS IoU of 0.2, the model produced roughly 20 detections. Some were genuine ships with boxes aligned to vessel heading. Many visible ships were missed. A few false positives appeared as swimming pool or other DOTA classes, which is understandable around bright linear structures and pier-like features on water.
The takeaway is simple: the model knows the category in principle, but native 10 m resolution leaves many targets near or below the effective scale it saw during training.
Synthetic zoom Link to heading
If the ships are too small, a cheap diagnostic is to upscale the image before inference.
LANCZOS interpolation does not create new information. It cannot recover detail that Sentinel-2 did not capture. But it does present each vessel as a larger footprint to the detector, which can help a DOTA-trained model operate closer to its familiar pixel scale.
odet image-demo --zoom does this in memory, runs inference on the zoomed image, then maps boxes back to the original image before visualization.
| Variant | Image size | Inference mode | Windows | Typical detections |
|---|---|---|---|---|
| 1× | 1024×1024 | Single forward | 1 | ~21 at score ≥ 0.05 |
| 2× | 2048×2048 | Sliding window | 9 | 21 ships at score ≥ 0.15 |
| 4× | 4096×4096 | Sliding window | 49 | 28 ships at score ≥ 0.15 |
Recall improved with zoom. Several high-confidence boxes, around 0.8 to 0.97, appeared in the 2× and 4× runs where the 1× baseline had missed the same vessels entirely.
Runtime grows with the number of windows. On CPU, the 4× tile took about two minutes because it requires 49 model windows.


Sliding-window settings Link to heading
Once the image exceeds the model canvas, oriented-det switches to padded sliding-window inference: 1024×1024 crops, zero padding at the edges, detections merged back into full-image coordinates, then NMS.
The final demo does not need a Copernicus-specific config file. We pass the registered pretrained checkpoint, let odet image-demo resolve its sidecar config automatically, and keep the tiling settings explicit in the command.
| CLI setting | Value | Role |
|---|---|---|
--zoom | 4 | Upscale before inference, then map boxes back |
--overlap-pixels | 512 | Keep overlap larger than the expected target footprint |
--ignore-margin-pixels | 256 | Drop duplicate boxes emitted in overlap bands |
--score-thr | 0.15 | Balance recall and clutter |
--nms-thr | 0.2 | Merge duplicate cross-window detections |
--classes | ship | Keep the maritime class only |
The overlap is not just a throughput knob. It should be tied to the physical footprint of the objects we want to detect. If the overlap is smaller than the largest target, a ship can be split across adjacent windows with neither crop seeing the whole object.
For these Sentinel-2 ships, 512 px overlap is conservative. The point is to make the experiment robust and reproducible, especially for larger objects or future scenes.
Thresholds and NMS Link to heading
Three different thresholds matter in this workflow:
- Model decode score threshold controls how many raw proposals survive inside the network before NMS. We keep it permissive so small ships are not discarded too early.
--score-thrcontrols the minimum confidence for a box to appear in the final output. For the 4× ship-only visualization,0.15was a useful balance.--nms-thrcontrols merge NMS after inference. Lower values suppress overlapping duplicates more aggressively, which matters when sliding windows overlap.
These settings are not universal. They are a compact record of what worked on this tile with this checkpoint.
Reproduce it Link to heading
From the oriented-det repository root:
odet pretrained download oriented_rcnn_dota_le90_1x
odet image-demo \
demo/copernicus/T30NZM_20260616T101021_TCI_10m_2976_7936.png \
hf://oriented_rcnn_dota_le90_1x \
--out-file demo/copernicus/T30NZM_20260616T101021_TCI_10m_2976_7936_4x_detections.png \
--score-thr 0.15 \
--nms-thr 0.2 \
--classes ship \
--zoom 4 \
--overlap-pixels 512 \
--ignore-margin-pixels 256 \
--device cpu
The output is written at the original image size, even though inference runs on the zoomed image internally.
References Link to heading
- oriented-det on GitHub
- Pretrained weights on Hugging Face
- DOTA dataset
- Copernicus Sentinel-2
- Previous post: Oriented object detection on macOS, in pure Python
- Next: Sliding-window inference