Finding an Object
<module>/find-object searches one image, once, for a known object.
Inputs
| Node | Default | Meaning |
|---|---|---|
|
(empty) |
Address of the image node to search. |
|
(empty) |
Which object to look for. Required - an empty value is refused. |
|
|
Smallest acceptable score, 0 to 1. |
|
|
Minimum distance in pixels between two reported matches. |
|
|
Image pyramid levels the search runs at. Not a speed setting - see Speed. |
|
|
|
|
all |
Region to search; all zero searches the whole image. |
|
|
Search at a lower resolution: faster, less precise. See Bin size. |
|
off |
Optional blur - see Tuning the Search. |
Running it
Set the inputs, then write to <module>/find-object/execute:
module-1/find-object/input/input-image-address = hdvisionsystems/lumiscan-cam-driver/camera1/output/image module-1/find-object/input/object-id = screw-m6 module-1/find-object/input/confidence-threshold = 0.7 module-1/find-object/input/nms-min-dist = 40 write module-1/find-object/execute
Then read output/status-code and output/result.
Set nms-min-dist to roughly half the size of the part in pixels. Without it a single part is
often reported several times over, as a cluster of slightly shifted matches.
|
One object per search
input/object-id names one of the entries on system/objects and is required: an empty value is
refused with status code -2.
There is no "search for everything" run. A detector is built around one picture, so searching several
objects means several detectors, and each one re-processes the whole image - which is the expensive
part. Running find-object once per object makes that cost visible rather than hiding it behind an
empty input.
To sort mixed parts, run the method once per object and compare the scores.
The result
output/result is an object_find_result flatbuffer.
| Field | Meaning |
|---|---|
|
Top left corner of the matched template, in pixels. |
|
Size of the template that matched, so the match can be drawn. |
|
0.0 to 1.0 similarity. |
|
The object that was found; the same on every match of one run. |
|
The highest scoring match. |
|
The frame the coordinates are in. |
|
The threshold that was applied. |
|
Microseconds since epoch, stamped when the run finished. |
Matches are sorted by score, so matches[0] is the best one.
There is no rotation in the result: the reported rectangle is axis aligned. If you need to know which
orientation was found, give each orientation its own object - screw-m6-front, screw-m6-tilted -
and search for them in turn. The answer is then the object_id that matched.
Image and crop coordinates
input/result-coordinate chooses the frame positions are measured in:
-
IMAGE(default) - the full image atinput-image-address. This is what a robot pick needs. -
CROP- the searched region, whose top left corner becomes (0,0).
image_width and image_height follow the same choice, so normalising a coordinate by them is
correct either way.
The region is searched exactly as given
Any size works, and no part of input/crop is dropped. cv::linemod does need the image it is handed
to be a particular multiple, but the detector pads up to it internally rather than demanding a size
it likes, so nothing you configure has to satisfy a rule.
This used to trim instead, costing up to 7 pixels at the right and bottom edges - 31 at bin-size 4.
Trimming was worse than it looked: it threw away columns the camera really captured, and left
cv::linemod’s own dead border - it ignores the outer ring of whatever it is given - sitting on the
pixels that survived. Measured, an object at the last usable position scored 0.79 trimmed against
1.00 padded.
The padding replicates the edge pixels outward, so it introduces no gradients of its own and cannot be mistaken for a shape, and a match is never reported from inside it. It is added at the right and bottom only, so every reported position is still a position in the image you configured.
What an empty result means
An empty result with status-code 1 means the object was not in the image, and nothing else.
Every other reason a search could come back empty - the object has no picture, the image is
unusable, a pyramid level is invalid, bin-size left too little of the object to recognise - is
detected before the search runs and reported as a negative status code. See Execution Status.
Detection speed
The picture is compiled into a detector the first time it is used, and that detector is reused for as long as the settings and the object stay unchanged. Changing any input, or saving a new template, rebuilds it on the next run.
Compiling is by far the most expensive part of a run, so a production loop that executes repeatedly with unchanged settings pays that cost once. Changing a setting before every call pays it every time.
To make the search itself faster, narrow input/crop first and then raise
input/preprocess/bin-size. Raising input/pyramid does not help - see
Speed.
Searching every frame of a camera
find-object searches one image per call. To have a module search every frame a camera streams,
with the same inputs, see
Finding Objects on an Image Stream (Experimental).