bool IPLMorphologyHitMiss::processInputData(IPLImage* image, int, bool)
{
    // delete previous result
    delete _result;
    _result = NULL;

    int width = image->width();
    int height = image->height();

    // copy constructor doesnt work:
    // _result = new IPLImage(*image);

    _result = new IPLImage( IPL_IMAGE_BW, width, height);

    // get properties
//    _propertyMutex.lock();
    _kernel     = getProcessPropertyVectorInt("kernel");
//    _propertyMutex.unlock();

    IPLImagePlane* inputPlane = image->plane( 0 );
    IPLImagePlane* resultPlane = _result->plane( 0 );

    IPLImagePlane* workingPlane = new IPLImagePlane(width, height);

    // the algorithm needs a working plane
    for(int x=0; x<width; x++)
    {
        for(int y=0; y<height; y++)
        {
            workingPlane->p(x,y) = inputPlane->p(x,y);
        }
    }


    _progress = 0;
    _maxProgress = image->height() * image->getNumberOfPlanes();

    hitmiss(workingPlane, resultPlane);

    return true;
}
Пример #2
0
bool IPLMorphologyBinary::processInputData(IPLImage* image, int, bool useOpenCV)
{
    // delete previous result
    delete _result;
    _result = NULL;

    int width = image->width();
    int height = image->height();

    // get properties
    _kernel     = getProcessPropertyVectorInt("kernel");
    _iterations = getProcessPropertyInt("iterations");
    _operation  = getProcessPropertyInt("operation");

    if (std::accumulate(_kernel.begin(),_kernel.end(),0) == 0)
    {
        //Add an empty image - The image viewer currently may trigger
        //a segfault if we return NULL.
        _result = new IPLImage( IPLImage::IMAGE_BW, width, height);
        addError("Empty kernel.");
        return false;
    }

    // TODO: implement manhattan distance threshold instead of stupid iterations...
    // TODO: implement border interpolation properties

    enum Operation
    {
        DILATE = 0,
        ERODE,
        OPEN,
        CLOSE
    };

    if (!useOpenCV)
    {
        _result = new IPLImage( IPLImage::IMAGE_BW, width, height);

        //std::vector<bool> packs its elements bitwise into a vector of
        //bytes. The kernel therefore uses much less cpu cache this way.
        std::vector<bool> kernel;
        kernel.reserve(_kernel.size());
        for (auto &i: _kernel) kernel.push_back(i > 0);

        std::atomic<int> progress(0);
        int totalLines = image->height()*_iterations;
        auto updateProgress = [&]() {
            notifyProgressEventHandler(100*((float)++progress)/totalLines);
        };

        switch(_operation)
        {
        case DILATE:
            dilate(*image->plane(0),*_result->plane(0),_iterations,kernel,updateProgress);
            break;
        case ERODE:
            erode (*image->plane(0),*_result->plane(0),_iterations,kernel,updateProgress);
            break;
        case OPEN:
            totalLines *= 2;
            open  (*image->plane(0),*_result->plane(0),_iterations,kernel,updateProgress);
            break;
        case CLOSE:
            totalLines *= 2;
            close (*image->plane(0),*_result->plane(0),_iterations,kernel,updateProgress);
            break;
        }
    }
    else
    {
        notifyProgressEventHandler(-1);

        int kernelSize = (int)sqrt((float)_kernel.size());
        cv::Mat src = image->toCvMat();
        cv::Mat dst;

        cv::Mat kernel(kernelSize,kernelSize,CV_8UC1);
        int i = 0;
        for (auto pixel: _kernel)
            kernel.at<unsigned char>(i++) = pixel;

        static const int OPERATIONS[4] = {
            cv::MORPH_DILATE,
            cv::MORPH_ERODE,
            cv::MORPH_OPEN,
            cv::MORPH_CLOSE
        };

        cv::morphologyEx(src,dst,OPERATIONS[_operation],kernel,cv::Point(-1,-1),_iterations);
        _result = new IPLImage(dst);
    }

    return true;
}
bool IPLConvolutionFilter::processInputData(IPLImage* image , int, bool useOpenCV)
{
    // delete previous result
    delete _result;
    _result = NULL;

    int width = image->width();
    int height = image->height();

    // get properties
    _kernel     = getProcessPropertyVectorInt("kernel");
    _divisor    = getProcessPropertyInt("divisor");
    _offset     = getProcessPropertyDouble("offset");
    _normalize  = getProcessPropertyBool("normalize");
    _borders    = getProcessPropertyInt("borders");

    if(_normalize)
    {
        int sum = 0;
        for(size_t i=0; i<_kernel.size(); i++)
        {
            sum += _kernel[i];
        }
        _divisor = (sum != 0 ? sum : 1);
    }

    if (_divisor == 0)
    {
        addError("Invalid divisor: 0");
        return false;
    }

    float divFactor = 1.0f/_divisor;

    int kernelWidth = (int)sqrt((float)_kernel.size());
    int kernelOffset = kernelWidth / 2;

    int progress = 0;
    int maxProgress = image->height() * image->getNumberOfPlanes();

    if (!useOpenCV)
    {
        _result = new IPLImage( image->type(), width, height );
        #pragma omp parallel for default(shared)
        for( int planeNr=0; planeNr < image->getNumberOfPlanes(); planeNr++ )
        {
            IPLImagePlane* plane = image->plane( planeNr );
            IPLImagePlane* newplane = _result->plane( planeNr );

            for(int y=0; y<plane->height(); y++)
            {
                // progress
                notifyProgressEventHandler(100*progress++/maxProgress);

                for(int x=0; x<plane->width(); x++)
                {
                    float sum = 0;
                    int i = 0;
                    for( int ky=-kernelOffset; ky<=kernelOffset; ky++ )
                    {
                        for( int kx=-kernelOffset; kx<=kernelOffset; kx++ )
                        {
                            int h = _kernel[i++];
                            if( h )
                            {
                                if(_borders == 0)
                                {
                                    // Crop borders
                                    sum += plane->cp(x+kx, y+ky) * h;
                                }
                                else if(_borders == 1)
                                {
                                    // Extend borders
                                    sum += plane->bp(x+kx, y+ky) * h;
                                } else {
                                    // Wrap borders
                                    sum += plane->wp(x+kx, y+ky) * h;
                                }
                            }
                        }
                    }
                    sum = sum * divFactor + _offset;
                    sum = (sum>1.0) ? 1.0 : (sum<0) ? 0.0 : sum; // clamp to 0.0 - 1.0
                    newplane->p(x,y) = sum;
                }
            }
        }
    }
    else
    {
        notifyProgressEventHandler(-1);

        cv::Mat src = image->toCvMat();
        cv::Mat dst;
        cv::Mat kernel(kernelWidth, kernelWidth, CV_32FC1 );

        int i = 0;
        for( int y=0; y < kernelWidth; y++ )
            for( int x=0; x < kernelWidth; x++ )
                kernel.at<float>(cv::Point(x,y)) = _kernel[i++];

        kernel *= divFactor;

        static const int BORDER_TYPES[3] = {
          cv::BORDER_CONSTANT,
          cv::BORDER_REPLICATE,
          cv::BORDER_WRAP
        };

        cv::filter2D(src, dst, -1, kernel, cv::Point(-1,-1), _offset, BORDER_TYPES[_borders]);
        _result = new IPLImage(dst);
    }

    return true;
}