#include "BlobDetector.h"

BlobDetector::BlobDetector()
{

}

/**
- FUNCTION: Blob
- FUNCTIONALITY: Constructor from an image. Fills an object with all the blobs in
    the image
- PARAMETERS:
    - source: image to extract the blobs from
    - mask: optional mask to apply. The blobs will be extracted where the mask is not 0.
    - numThreads: number of labelling threads.
- RESULT:
    - object with all the blobs in the image.
- RESTRICTIONS:
- AUTHOR: Ricard Borràs
- CREATION DATE: 25-05-2005.
- MODIFICATION: Oct-2013. Luca Nardelli and Saverio Murgia. Changed to comply with reimplemented labelling algorithm
*/
BlobDetector::BlobDetector(IplImage* source, IplImage* mask, int numThreads)
{
    if (mask != NULL) {
        cv::Mat temp = cv::Mat::zeros(cv::Size(source->width, source->height), CV_8UC1);
        cv::cvarrToMat(source).copyTo(temp, cv::cvarrToMat(mask));
        m_compLabeler.set(numThreads, temp);
        m_compLabeler.doLabeling(m_blobGroup.m_blobs);
    }
    else {
        m_compLabeler.set(numThreads, cv::cvarrToMat(source));
        m_compLabeler.doLabeling(m_blobGroup.m_blobs);
    }
}

/**
- FUNCTION: BlobDetector
- FUNCTIONALITY: Copy constructor
- PARAMETERS:
    - source: object to copy
- RESULT:
- RESTRICTIONS:
- AUTHOR: Ricard Borràs
- CREATION DATE: 25-05-2005.
- MODIFICATION: Date. Author. Description.
*/
BlobDetector::BlobDetector(const BlobDetector& source)
{
    // create the new from the past as a parameter
    //m_blobs = BlobVector(source.getNumBlobs());
    m_blobGroup.m_blobs.reserve(source.m_blobGroup.getNumBlobs());
    // copy the blobs from the origin to the current one
    BlobVector::const_iterator pBlobsSrc = source.m_blobGroup.m_blobs.begin();
    //BlobVector::iterator pBlobsDst = m_blobs.begin();
    while (pBlobsSrc != source.m_blobGroup.m_blobs.end()) {
        // can't call the operator = since BlobVector is a
        // Blob vector *. So create a new blob from the
        // original blob
        m_blobGroup.m_blobs.push_back(new Blob(**pBlobsSrc));
        pBlobsSrc++;
    }
}

BlobDetector& BlobDetector::operator=(const BlobDetector& source)
{
    if (this != &source) {
        m_blobGroup.m_blobs.reserve(source.m_blobGroup.getNumBlobs());
        BlobVector::const_iterator pBlobsSrc = source.m_blobGroup.m_blobs.begin();
        while (pBlobsSrc != source.m_blobGroup.m_blobs.end()) {
            m_blobGroup.m_blobs.push_back(new Blob(**pBlobsSrc));
            pBlobsSrc++;
        }
    }
    return *this;
}

BlobDetector::BlobDetector(BlobDetector&& source) noexcept
{
    std::exchange(m_blobGroup, std::move(source.m_blobGroup));
}

BlobDetector& BlobDetector::operator=(BlobDetector&& source) noexcept
{
    if (this != &source) {
        std::exchange(m_blobGroup, std::move(source.m_blobGroup));
    }
    return *this;
}

/**
- FUNCTION: ~BlobDetector
- FUNCTIONALITY: Destructor
- PARAMETERS:
- RESULT:
- RESTRICTIONS:
- AUTHOR: Ricard Borràs
- CREATION DATE: 25-05-2005.
- MODIFICATION: Date. Author. Description.
*/
BlobDetector::~BlobDetector()
{
    m_blobGroup.clearBlobs();
}

/**
- FUNCTION: BlobDetector
- FUNCTIONALITY: Constructor from an image. Fills an object with all the blobs in
    the image, OPENCV 2 interface
- PARAMETERS:
    - source: Mat to extract the blobs from, CV_8UC1
    - mask: optional mask to apply. The blobs will be extracted where the mask is
            not 0. All the neighbouring blobs where the mask is 0 will be external blobs
    - numThreads: number of labelling threads.
- RESULT:
    - object with all the blobs in the image.
- RESTRICTIONS:
- AUTHOR: Saverio Murgia & Luca Nardelli
- CREATION DATE: 06-04-2013.
- MODIFICATION: Date. Author. Description.
*/
BlobDetector::BlobDetector(cv::Mat& source, const cv::Mat& mask, int numThreads) {
    if (mask.data) {
        cv::Mat temp = cv::Mat::zeros(source.size(), source.type());
        source.copyTo(temp, mask);
        m_compLabeler.set(numThreads, temp);
        m_compLabeler.doLabeling(m_blobGroup.m_blobs);
    }
    else {
        m_compLabeler.set(numThreads, source);
        m_compLabeler.doLabeling(m_blobGroup.m_blobs);
    }
}

/**
- FUNCTION: detect
- FUNCTIONALITY: detects blob in the image
- PARAMETERS:
    - source: Mat to extract the blobs from, CV_8UC1
    - mask: optional mask to apply. The blobs will be extracted where the mask is
            not 0. All the neighbouring blobs where the mask is 0 will be external blobs
    - numThreads: number of labelling threads.
- RESULT:
    - the object will contain the detected blobs.
- RESTRICTIONS:
- AUTHOR: Saverio Murgia & Luca Nardelli
- CREATION DATE: 10-04-2014.
- MODIFICATION: Date. Author. Description.
*/
const BlobGroup& BlobDetector::detect(cv::Mat& source, const cv::Mat& mask /*= cv::Mat()*/, int numThreads/*=1*/)
{
    m_blobGroup.clearBlobs();
    if (mask.data) {
        cv::Mat temp = cv::Mat::zeros(source.size(), source.type());
        source.copyTo(temp, mask);
        m_compLabeler.set(numThreads, temp);
        m_compLabeler.doLabeling(m_blobGroup.m_blobs);
    }
    else {
        m_compLabeler.set(numThreads, source);
        m_compLabeler.doLabeling(m_blobGroup.m_blobs);
    }

    return m_blobGroup;
}

const BlobGroup& BlobDetector::getBlobGroup()
{
    return m_blobGroup;
}