# Macbeth Chart Detector Detects a Macbeth / ColorChecker Classic colour chart in a photograph and returns its bounding box. This is the detection model used by OpenCV's `mcc` colour-correction code (`objdetect`, `checker_detector.cpp`) to locate a chart before reading its patches. The model is a Faster R-CNN with an Inception V2 backbone, trained as a single-class detector with the TensorFlow Object Detection API. It was originally distributed as a frozen TensorFlow graph (`frozen_inference_graph.pb`) and converted to ONNX for use with OpenCV's DNN module. ## Model Details - **Architecture**: Faster R-CNN, Inception V2 backbone, one class (the chart) - **Input**: `image_tensor:0`, **NHWC** `[1, H, W, 3]`, **raw uint8 RGB** (0-255, no scaling and no mean subtraction). `H`/`W` are dynamic — feed the image at its own resolution. The graph resizes internally (keep aspect ratio, min side 768, max side 1024), so do not pre-resize, and do not use `blobFromImage`: that produces NCHW. - **Outputs** (all four must be requested together): - `detection_boxes:0` — `[1, 300, 4]`, normalized, **`[ymin, xmin, ymax, xmax]`** (y first) - `detection_scores:0` — `[1, 300]`, descending - `detection_classes:0` — `[1, 300]`, always `1.0` (single class, so it carries no information) - `num_detections:0` — `[1]` - **Framework**: ONNX (converted from the TensorFlow frozen graph via tf2onnx, opset 18) - **Original weights**: [gursimarsingh/opencv_zoo @ `mcc_model`](https://github.com/gursimarsingh/opencv_zoo/tree/mcc_model/models/macbeth_chart_detector) — `frozen_inference_graph.pb`, sha1 `fae7dbef14c4ae1fca76f3662220fbd460ed5ed6` > **`num_detections` is not a detection count.** It reports the post-NMS slot count — 100 on the > example image, where exactly one chart is present. Threshold on `detection_scores` instead; > iterating `num_detections` yields 99 phantom boxes. ## Usage ### Python ```bash python demo.py --model macbeth_chart_detector_2026sep.onnx --image example_outputs/input_image.png --output example_outputs/output_image.png --conf 0.3 ``` On the provided `example_outputs/input_image.png` (900x463) it reports one detection: ``` macbeth_chart_detector 1 detections 0.582 x1=237 y1=79 x2=650 y2=368 ``` `demo.py` requires OpenCV 5.1 or newer, for `cv.dnn.ENGINE_OPENCV`. On OpenCV 5.0 that constant does not exist (it has `ENGINE_CLASSIC` / `ENGINE_NEW`); drop the second argument to `readNetFromONNX` to use the default engine instead. ## Conversion Exported from the frozen TensorFlow graph with tf2onnx (opset 18) via [convert_to_onnx.py](./convert_to_onnx.py) — input `image_tensor:0`, outputs `detection_boxes:0`, `detection_scores:0`, `detection_classes:0`, `num_detections:0`. Requires `tensorflow`, `tf2onnx` and `onnx`. ```bash python convert_to_onnx.py --pb frozen_inference_graph.pb ``` The graph needs no special handling: its weights are plain float32 (no `quantize_weights` / `Dequantize` nodes) and all four detection heads are present in the frozen graph. ### Conversion accuracy Verified against the original `.pb` under TensorFlow 2.15.1, feeding both the identical uint8 buffer: | | top score | box | |---|---|---| | TensorFlow `.pb` | 0.582205 | `0.171078 0.263475 0.794357 0.721806` | | ONNX (onnxruntime) | 0.582205 | `0.171078 0.263475 0.794356 0.721806` | The conversion is faithful to within one float32 ULP. ## Known issue: OpenCV's DNN engine The conversion is correct, but **OpenCV's built-in DNN engine cannot currently run this model.** On OpenCV 5.0.0 it aborts before producing output: ``` net_impl2.cpp: (-215:Assertion failed) buf.shape() == m.shape() in function 'forwardGraph' ``` The same failure affects the other converted Faster R-CNN / Mask R-CNN models in this repository, so it is a limitation of the engine's handling of these graphs rather than something specific to this model. On builds where the graph does run, the score comes out around 0.02 instead of 0.582, because `Resize` with `coordinate_transformation_mode="tf_crop_and_resize"` and a dynamic ROI — the ROI-pooling step of the second stage — is not evaluated correctly, so every region proposal is classified from the wrong features. Until that is fixed in `modules/dnn`, treat the ONNX file as correct (onnxruntime and TensorFlow agree exactly) and the OpenCV-engine results as unreliable. ## License See [LICENSE](./LICENSE) — Apache License 2.0, taken from the upstream [opencv_zoo](https://github.com/gursimarsingh/opencv_zoo) repository that distributes the original frozen graph.