    001package visrec.ri.ml.detection;
    002
    003import javax.visrec.AbstractImageClassifier;
    004import javax.visrec.ml.detection.ObjectDetector;
    005import javax.visrec.util.BoundingBox;
    006import java.io.File;
    007import java.io.IOException;
    008import java.io.InputStream;
    009import java.util.List;
    010import java.util.Map;
    011import java.util.Objects;
    012
    013/**
    014 * Abstract object detector which implements {@link ObjectDetector} to return the positions
    015 * of an object within the given image.
    016 *
    017 * @author Zoran Sevarac
    018 */
    019public abstract class AbstractObjectDetector<IMAGE_CLASS> implements ObjectDetector<IMAGE_CLASS> {
    020
    021    private AbstractImageClassifier<IMAGE_CLASS, Boolean> imageClassifier; // This should be binary classifier, that can detectObject some object / image
    022
    023    /**
    024     * Creates an instance of the object detector
    025     * @param imageClassifier A {@link AbstractImageClassifier} which may not be null
    026     */
    027    public AbstractObjectDetector(AbstractImageClassifier<IMAGE_CLASS, Boolean> imageClassifier) {
    028        Objects.requireNonNull(imageClassifier, "A classifier is required for the object detector.");
    029        this.imageClassifier = imageClassifier;
    030    }
    031
    032    /**
    033     * Scan entire image and return positions where object is detected
    034     *
    035     * @param image {@code IMAGE_CLASS} image
    036     * @return {@code Map} of {@link BoundingBox} of where the object
    037     * has been detected.
    038     */
    039    @Override
    040    public abstract Map<String, List<BoundingBox>> detectObject(IMAGE_CLASS image);
    041
    042    /**
    043     * Detect the object based on the given {@code File}.
    044     * @param file Image file.
    045     * @return {@code Map} of {@link BoundingBox} of where the object
    046     * has been detected.
    047     * @throws IOException if the image couldn't be retrieved from storage.
    048     */
    049    public Map<String, List<BoundingBox>> detect(File file) throws IOException {
    050        IMAGE_CLASS image = imageClassifier.getImageFactory().getImage(file);
    051        return detectObject(image);
    052    }
    053
    054    /**
    055     * Detect the object based on the given {@code InputStream}.
    056     * @param inStream {@code InputStream} of the image
    057     * @return {@code Map} of {@link BoundingBox} of where the object
    058     * has been detected.
    059     * @throws IOException if the image couldn't be retrieved from storage.
    060     */
    061    public Map<String, List<BoundingBox>> detect(InputStream inStream) throws IOException {
    062        IMAGE_CLASS image = imageClassifier.getImageFactory().getImage(inStream);
    063        return detectObject(image);
    064    }
    065
    066    /**
    067     * Subclasses should use ths method to use the underlying image classifier
    068     *
    069     * @return configured {@link AbstractImageClassifier} of the {@link AbstractObjectDetector}
    070     */
    071    public AbstractImageClassifier<IMAGE_CLASS, Boolean> getImageClassifier() {
    072        return imageClassifier;
    073    }
    074
    075}