Beispiel #1
1
//general processing function of UVDisparity based function
cv::Mat UVDisparity::Process(cv::Mat& img_L, cv::Mat& disp_sgbm,
                             VisualOdometryStereo& vo, cv::Mat& xyz,
                             cv::Mat& roi_mask, cv::Mat& ground_mask,
                             double& pitch1, double& pitch2)
{
    cv::Mat mask_moving;
    calVDisparity(disp_sgbm,xyz);

    //sequentially estimate pitch angles by Kalman Filter
    vector<cv::Mat> pitch_measures;

    pitch_measures = Pitch_Classify(xyz,ground_mask);
    pitch1_KF->predict();
    pitch1_KF->correct(pitch_measures[0]);

    pitch2_KF->predict();
    pitch2_KF->correct(pitch_measures[1]);

    pitch1 = pitch_measures[0].at<float>(0);
    pitch2 = pitch_measures[1].at<float>(0);


    //Improve 3D reconstruction results by pitch angles
    correct3DPoints(xyz,roi_,pitch1_KF->statePost.at<float>(0),pitch2_KF->statePost.at<float>(0));

    //set image ROI according to ROI3D (ROI within a 3D space)
    setImageROI(xyz, roi_mask);

    //filter inliers and outliers
    filterInOut(img_L,roi_mask,disp_sgbm,vo,pitch1);

    //calculate Udisparity image
    calUDisparity(disp_sgbm,xyz,roi_mask,ground_mask);

    //using sigmoid function to adjust Udisparity image for segmentation
    double scale = 0.02, range = 32;
    adjustUdisIntense(scale,range);

     //Find all possible segmentation
     findAllMasks(vo,img_L,xyz,roi_mask);

    if(masks_.size()>0)
    {
       //merge overlapped masks
       mergeMasks();

       //improve the segments by inliers
       verifyByInliers(vo,img_L);
     }

   //perform segmentation in disparity image
   segmentation(disp_sgbm,img_L,roi_mask,mask_moving);

   //demonstration
   cv::Mat img_show;
   img_L.copyTo(img_show,mask_moving);
   cv::imshow("moving",img_show);
   cv::waitKey(1);

   masks_.clear();
   return mask_moving;
}
PowertfDialog::PowertfDialog(cv::Mat& img, QWidget *parent)
    : QDialog(parent)
{
    r = 1;
    c = 1;
    b = 0;
    img.copyTo(image);
    pimage = &img;

    rSlider = new QSlider(Qt::Horizontal);
    rSlider->setRange(0,10);
    rSlider->setValue(r);
    cSlider = new QSlider(Qt::Horizontal);
    cSlider->setRange(0,10);
    cSlider->setValue(c);
    bSlider = new QSlider(Qt::Horizontal);
    bSlider->setRange(0,10);
    bSlider->setValue(b);

    rSBx = new QSpinBox();
    rSBx->setRange(0,10);
    rSBx->setValue(r);
    cSBx = new QSpinBox();
    cSBx->setRange(0,10);
    cSBx->setValue(c);
    bSBx = new QSpinBox();
    bSBx->setRange(0,10);
    bSBx->setValue(b);

    connect(rSlider,SIGNAL(valueChanged(int)),this,SLOT(rChanged(int)));
    connect(cSlider,SIGNAL(valueChanged(int)),this,SLOT(cChanged(int)));
    connect(bSlider,SIGNAL(valueChanged(int)),this,SLOT(bChanged(int)));
    connect(rSlider,SIGNAL(valueChanged(int)),rSBx,SLOT(setValue(int)));
    connect(cSlider,SIGNAL(valueChanged(int)),cSBx,SLOT(setValue(int)));
    connect(bSlider,SIGNAL(valueChanged(int)),bSBx,SLOT(setValue(int)));

    connect(rSBx,SIGNAL(valueChanged(int)),this,SLOT(rChanged(int)));
    connect(cSBx,SIGNAL(valueChanged(int)),this,SLOT(cChanged(int)));
    connect(bSBx,SIGNAL(valueChanged(int)),this,SLOT(bChanged(int)));
    connect(rSBx,SIGNAL(valueChanged(int)),rSlider,SLOT(setValue(int)));
    connect(cSBx,SIGNAL(valueChanged(int)),cSlider,SLOT(setValue(int)));
    connect(bSBx,SIGNAL(valueChanged(int)),bSlider,SLOT(setValue(int)));

    rLabel = new QLabel(tr("r"));
    cLabel = new QLabel(tr("c"));
    bLabel = new QLabel(tr("b"));

    okButton = new QPushButton(tr("&OK"));
    okButton->setDefault(true);
    okButton->setEnabled(true);
    connect(okButton, SIGNAL(clicked()), this, SLOT(okClicked()));

    closeButton = new QPushButton(tr("&Close"));
    connect(closeButton, SIGNAL(clicked()), this, SLOT(closePowertf()));

    QHBoxLayout *rLayout = new QHBoxLayout;
    rLayout->addWidget(rLabel);
    rLayout->addWidget(rSlider);
    rLayout->addWidget(rSBx);
    QHBoxLayout *cLayout = new QHBoxLayout;
    cLayout->addWidget(cLabel);
    cLayout->addWidget(cSlider);
    cLayout->addWidget(cSBx);
    QHBoxLayout *bLayout = new QHBoxLayout;
    bLayout->addWidget(bLabel);
    bLayout->addWidget(bSlider);
    bLayout->addWidget(bSBx);

    QVBoxLayout *leftLayout = new QVBoxLayout;
    leftLayout->addLayout(rLayout);
    leftLayout->addLayout(cLayout);
    leftLayout->addLayout(bLayout);
    
    QVBoxLayout *rightLayout = new QVBoxLayout;
    rightLayout->addWidget(okButton);
    rightLayout->addWidget(closeButton);
    rightLayout->addStretch();

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addLayout(leftLayout);
    mainLayout->addLayout(rightLayout);
    setLayout(mainLayout);

    setWindowTitle(tr("Power Tranform"));
    setFixedHeight(sizeHint().height());
}
Beispiel #3
0
cv::Mat makeFrame(cv::Mat control,
                  cv::Mat interaction,
                  cv::Mat fill,
                  unsigned char threshold,
                  int blurkernelsize,
                  int offsetx,
                  int offsety
                 )
{
    //take the absolute difference between the interaction and the 
    //control images and store it in diff
    cv::Mat diff; 
    cv::absdiff(control, interaction, diff);
    
    //initialize an image to store the final result
    cv::Mat result = cv::Mat::zeros( fill.rows, fill.cols, fill.type() );
    
    //initialize a blank mask
    cv::Mat mask = cv::Mat::zeros(control.rows, control.cols, CV_8UC1);
    
    
    //for every pixel in diff...
    for(int i = 0; i < diff.rows; i++)
    {
        for(int j = 0; j < diff.cols; j++)
        {
            cv::Vec3b pixel = diff.at<cv::Vec3b>(i, j);
            
            //...if the absolute value of the pixel exceeds the threshold,
            //set corresponding mask's pixel to white.
            //Otherwise, leave it black.
            /*
            if(sqrt(pixel[0] * pixel[0] +
                    pixel[1] * pixel[1] +
                    pixel[2] * pixel[2]
                   ) >= threshold
              )
            /*/
            if(cv::max( cv::max(pixel[0], pixel[1]),
                        pixel[2]
                      ) >= threshold
              )
            //*/
            {
               mask.at<unsigned char>(i, j) = 255;
            }
        }
    }
    
    //apply median-blur to mask with kernel size of blurkernelsize
    cv::Mat blurredmask;
    cv::medianBlur(mask, blurredmask, blurkernelsize);
    
    //resize mask's resolution to math fill's
    cv::resize( blurredmask, blurredmask, cv::Size(fill.cols, fill.rows) );
    
    cv::Mat roit;
    cv::Mat finalmask = cv::Mat::zeros(fill.rows,
                                       fill.cols,
                                       blurredmask.type()
                                      );
    if(offsetx >= 0)
    {
        if(offsety >= 0)
        {
            roit = cv::Mat(blurredmask,
                       cv::Range(0, blurredmask.rows - offsety),
                       cv::Range(0, blurredmask.cols - offsetx)
                      );
        
            roit.copyTo(finalmask(cv::Rect(offsetx,
                                           offsety,
                                           roit.cols,
                                           roit.rows
                                          )
                                 )
                       );
        }
        else
        {
            roit = cv::Mat(blurredmask,
                       cv::Range(-offsety, blurredmask.rows),
                       cv::Range(0, blurredmask.cols - offsetx)
                      );
        
            roit.copyTo( finalmask(cv::Rect(offsetx, 0, roit.cols, roit.rows)) );
        }
    }
    else
    {
        if(offsety >= 0)
        {
            roit = cv::Mat(blurredmask,
                       cv::Range(0, blurredmask.rows - offsety),
                       cv::Range(-offsetx, blurredmask.cols)
                      );
            roit.copyTo( finalmask(cv::Rect(0, offsety, roit.cols, roit.rows)) );
        }
        else
        {
            roit = cv::Mat(blurredmask,
                       cv::Range(-offsety, blurredmask.rows),
                       cv::Range(-offsetx, blurredmask.cols)
                      );
            roit.copyTo( finalmask(cv::Rect(0, 0, roit.cols, roit.rows)) );
        }
        
    }
    
    //apply mask to fill image and return it
    fill.copyTo(result, finalmask);
    return result;
}
//! Processes a frame and returns output image
bool VideoTrackingSample::processFrame(const cv::Mat& inputFrame, cv::Mat& outputFrame)
{
    inputFrame.copyTo(outputFrame);
    
    getGray(inputFrame, m_nextImg);
    
    if (m_activeTrackingAlgorithm == TrackingAlgorithmKLT)
    {
        
        if (m_mask.rows != inputFrame.rows || m_mask.cols != inputFrame.cols)
            m_mask.create(inputFrame.rows, inputFrame.cols, CV_8UC1);
        
        if (m_prevPts.size() > 0)
        {
            cv::calcOpticalFlowPyrLK(m_prevImg, m_nextImg, m_prevPts, m_nextPts, m_status, m_error);
        }
        
        m_mask = cv::Scalar(255);
        
        std::vector<cv::Point2f> trackedPts;
        
        for (size_t i=0; i<m_status.size(); i++)
        {
            if (m_status[i])
            {
                trackedPts.push_back(m_nextPts[i]);
                
                cv::circle(m_mask, m_prevPts[i], 15, cv::Scalar(0), -1);
                cv::line(outputFrame, m_prevPts[i], m_nextPts[i], cv::Scalar(0,250,0));
                cv::circle(outputFrame, m_nextPts[i], 3, cv::Scalar(0,250,0), -1);
            }
        }
        
        bool needDetectAdditionalPoints = trackedPts.size() < m_maxNumberOfPoints;
        if (needDetectAdditionalPoints)
        {
            m_detector->detect(m_nextImg, m_nextKeypoints, m_mask);
            int pointsToDetect = m_maxNumberOfPoints -  trackedPts.size();
            
            if (m_nextKeypoints.size() > pointsToDetect)
            {
                std::random_shuffle(m_nextKeypoints.begin(), m_nextKeypoints.end());
                m_nextKeypoints.resize(pointsToDetect);
            }
            
            std::cout << "Detected additional " << m_nextKeypoints.size() << " points" << std::endl;
            
            for (size_t i=0; i<m_nextKeypoints.size(); i++)
            {
                trackedPts.push_back(m_nextKeypoints[i].pt);
                cv::circle(outputFrame, m_nextKeypoints[i].pt, 5, cv::Scalar(255,0,255), -1);
            }
        }
        
        m_prevPts = trackedPts;
        m_nextImg.copyTo(m_prevImg);
    }
    if (m_activeTrackingAlgorithm == TrackingAlgorithmORB)
    {
        m_orbFeatureEngine(m_nextImg, cv::Mat(), m_nextKeypoints, m_nextDescriptors);
        
        if (m_prevKeypoints.size() > 0)
        {
            std::vector< std::vector<cv::DMatch> > matches;
            m_orbMatcher.radiusMatch(m_nextDescriptors, m_prevDescriptors, matches, 10);
            
            for (size_t i=0; i<matches.size(); i++)
            {
                cv::Point prevPt = m_prevKeypoints[matches[i][0].trainIdx].pt;
                cv::Point nextPt = m_nextKeypoints[matches[i][0].queryIdx].pt;
                
                cv::circle(outputFrame, prevPt, 5, cv::Scalar(250,0,250), -1);
                cv::line(outputFrame, prevPt, nextPt, cv::Scalar(0,250,0));
                cv::circle(outputFrame, nextPt, 3, cv::Scalar(0,250,0), -1);
            }
        }
        
        m_prevKeypoints.swap(m_nextKeypoints);
        m_nextDescriptors.copyTo(m_prevDescriptors);
    }
    else if(m_activeTrackingAlgorithm == TrackingAlgorithmBRIEF)
    {
        m_fastDetector->detect(m_nextImg, m_nextKeypoints);
        m_briefExtractor->compute(m_nextImg, m_nextKeypoints, m_nextDescriptors);
        
        if (m_prevKeypoints.size() > 0)
        {
            std::vector< std::vector<cv::DMatch> > matches;
            m_orbMatcher.radiusMatch(m_nextDescriptors, m_prevDescriptors, matches, 10);
            
            for (size_t i=0; i<matches.size(); i++)
            {
                cv::Point prevPt = m_prevKeypoints[matches[i][0].trainIdx].pt;
                cv::Point nextPt = m_nextKeypoints[matches[i][0].queryIdx].pt;
                
                cv::circle(outputFrame, prevPt, 5, cv::Scalar(250,0,250), -1);
                cv::line(outputFrame, prevPt, nextPt, cv::Scalar(0,250,0));
                cv::circle(outputFrame, nextPt, 3, cv::Scalar(0,250,0), -1);
            }
        }
        
        m_prevKeypoints.swap(m_nextKeypoints);
        m_nextDescriptors.copyTo(m_prevDescriptors);
    }
    
    return true;
}
Beispiel #5
0
// Contructor
reconstructor::reconstructor(cv::Mat &img)
{
    cont = 0;
    img.copyTo(inImg);
    img.copyTo(outImg);
}
Beispiel #6
0
PERF_TEST_P(Sz, DISABLED_GeneralizedHoughGuil, CUDA_TYPICAL_MAT_SIZES)
{
    declare.time(10);

    const cv::Size imageSize = GetParam();

    const cv::Mat templ = readImage("cv/shared/templ.png", cv::IMREAD_GRAYSCALE);
    ASSERT_FALSE(templ.empty());

    cv::Mat image(imageSize, CV_8UC1, cv::Scalar::all(0));
    templ.copyTo(image(cv::Rect(50, 50, templ.cols, templ.rows)));

    cv::RNG rng(123456789);
    const int objCount = rng.uniform(5, 15);
    for (int i = 0; i < objCount; ++i)
    {
        double scale = rng.uniform(0.7, 1.3);
        bool rotate = 1 == rng.uniform(0, 2);

        cv::Mat obj;
        cv::resize(templ, obj, cv::Size(), scale, scale);
        if (rotate)
            obj = obj.t();

        cv::Point pos;

        pos.x = rng.uniform(0, image.cols - obj.cols);
        pos.y = rng.uniform(0, image.rows - obj.rows);

        cv::Mat roi = image(cv::Rect(pos, obj.size()));
        cv::add(roi, obj, roi);
    }

    cv::Mat edges;
    cv::Canny(image, edges, 50, 100);

    cv::Mat dx, dy;
    cv::Sobel(image, dx, CV_32F, 1, 0);
    cv::Sobel(image, dy, CV_32F, 0, 1);

    if (PERF_RUN_CUDA())
    {
        cv::Ptr<cv::GeneralizedHoughGuil> alg = cv::cuda::createGeneralizedHoughGuil();
        alg->setMaxAngle(90.0);
        alg->setAngleStep(2.0);

        const cv::cuda::GpuMat d_edges(edges);
        const cv::cuda::GpuMat d_dx(dx);
        const cv::cuda::GpuMat d_dy(dy);
        cv::cuda::GpuMat positions;

        alg->setTemplate(cv::cuda::GpuMat(templ));

        TEST_CYCLE() alg->detect(d_edges, d_dx, d_dy, positions);
    }
    else
    {
        cv::Ptr<cv::GeneralizedHoughGuil> alg = cv::createGeneralizedHoughGuil();
        alg->setMaxAngle(90.0);
        alg->setAngleStep(2.0);

        cv::Mat positions;

        alg->setTemplate(templ);

        TEST_CYCLE() alg->detect(edges, dx, dy, positions);
    }

    // The algorithm is not stable yet.
    SANITY_CHECK_NOTHING();
}
bool ImageGenerator::InitMat(cv::Mat &frame)	// for video interface
{
	// image_.release();	// ??
	frame.copyTo(image_);
	return true;
}
void Image::operator()(const cv::Mat& frame) {
    frame.copyTo(img);
}
Image::Image(const cv::Mat& frame) {
    frame.copyTo(img);
}
// corners (z_all_l, z_all_r) and status are output variables
void trackFeatures(const cv::Mat &img_l, const cv::Mat &img_r, std::vector<cv::Point2f> &features_l, std::vector<cv::Point2f> &features_r, std::vector<int> &status,
        int stereo, int camNumber) {
    if (!img_l.data)
        throw "Left image is invalid";
    if (stereo && !img_r.data)
        throw "Right image is invalid";

    unsigned int numPoints = status.size();
    features_l.resize(numPoints);
    std::fill(features_l.begin(), features_l.end(), cv::Point2f(-100, -100));

    features_r.resize(numPoints);
    std::fill(features_r.begin(), features_r.end(), cv::Point2f(-100, -100));

    for (size_t i = 0; i < status.size() && i < numPoints; ++i) {
        if (status[i] == 1) {
            prev_status[i] = 1;
        } else {
            prev_status[i] = 0;  // if updateVect[i] == 0 feature is inactive, == 2 request new feature
        }
    }

    std::vector<unsigned char> status_left, status_right;
    std::vector<cv::Point2f> cur_corners, right_corners;
    std::vector<float> error;

    if (!prev_img[camNumber].empty()) {
        if (!prev_corners[camNumber].empty()) {
            cv::calcOpticalFlowPyrLK(prev_img[camNumber], img_l, prev_corners[camNumber], cur_corners, status_left, error, cv::Size(9, 9), 3);
            prev_corners[camNumber] = cur_corners;
            if (stereo == 2)
                cv::calcOpticalFlowPyrLK(img_l, img_r, prev_corners[camNumber], right_corners, status_right, error, cv::Size(9, 9), 3);

            for (size_t i = 0; i < prev_corners[camNumber].size() && i < numPoints; ++i) {
                if (!(prev_status[i] && status_left[i] && (stereo != 2 || status_right[i])))
                    prev_status[i] = 0;

                if (prev_status[i] == 1) {
                    if (prev_corners[camNumber][i].x < 0 || prev_corners[camNumber][i].x > img_l.cols || prev_corners[camNumber][i].y < 0 || prev_corners[camNumber][i].y > img_l.rows
                            || ((stereo == 2)
                                    && (right_corners[i].x < 0 || right_corners[i].x > img_l.cols || right_corners[i].y < 0 || right_corners[i].y > img_l.rows))) {
                        status[i] = 0;
                    } else {
                        features_l[i] = prev_corners[camNumber][i];

                        if (stereo == 2) {
                            features_r[i] = right_corners[i];
                        }
                        status[i] = 1;
                    }
                } else {
                    if (status[i] == 1)  // be careful not to overwrite 2s in updateVect
                        status[i] = 0;
                }
            }
        }
    }

    img_l.copyTo(prev_img[camNumber]);

    // initialize new points if needed
    initMorePoints(img_l, img_r, status, features_l, features_r, stereo, camNumber);
}
Beispiel #11
0
bool task3_5(const cv::Mat& image, const cv::Mat& orig) {
    cv::Mat grey, tmp, res;
    image.copyTo(grey);
    grey.convertTo(grey, CV_32F);

    grey.copyTo(res);
    res.convertTo(res, CV_8U);
    std::vector<cv::Mat> planes(2, cv::Mat());
    std::vector<cv::Mat> polar(2, cv::Mat());

    cv::dft(grey, tmp, cv::DFT_COMPLEX_OUTPUT);
    cv::split(tmp, planes);
    cv::cartToPolar(planes[0], planes[1], polar[0], polar[1]);

    int cx = polar[0].cols / 2;
    int cy = polar[0].rows / 2;
    cv::Point max;

    cv::Mat top = polar[0].rowRange(0, cx);
    cv::Mat bot = polar[0].rowRange(cx, polar[0].rows);

    int row = 0;
    do {
        cv::minMaxLoc(top.rowRange(row++, top.rows), 0, 0, 0, &max);
    } while (max.x == 0);


    int r = 3;

    cv::Mat noizeCol = polar[0].colRange(max.x - r, max.x + r);
    cv::Mat noizeRow = polar[0].rowRange(max.y - r, max.y + r);
    cv::Mat blurCol = polar[0].colRange(max.x - 12, max.x - 12 + 2 * r);
    cv::Mat blurRow = polar[0].rowRange(max.y - 3 * r, max.y - r);

    blurCol.copyTo(noizeCol);
    blurRow.copyTo(noizeRow);


    cv::Mat noizeColB = polar[0].colRange(polar[0].cols - max.x - r, polar[0].cols - max.x + r);
    cv::Mat noizeRowB = polar[0].rowRange(polar[0].rows - max.y - r, polar[0].rows - max.y + r);

    blurCol.copyTo(noizeColB);
    blurRow.copyTo(noizeRowB);

    cv::Mat roi = polar[0];
    cv::Mat mean, stddev, tmp1;
    roi = roi.colRange(max.x + 20, roi.cols - max.x - 20).rowRange(max.y + 20, roi.cols - max.y - 20);
    for (int i = 0; i < roi.rows; ++i) {
        cv::Mat row = roi.row(i);
        cv::meanStdDev(row, mean, stddev);
        float m = mean.at<double>(0, 0);
        float st = stddev.at<double>(0, 0);
        for (Mfit mfit = row.begin<float>(); mfit != row.end<float>(); ++mfit) {
            if (*mfit > m + 1.5 * st) {
                *mfit = 0.5 * m;
            }
        }
    }
    visualization(polar[0], tmp);

    //    
    //    
    //    cv::namedWindow("Lesson 2", CV_WINDOW_NORMAL);
    //    cv::imshow("Lesson 2", tmp);
    //    cv::waitKey(0);


    cv::polarToCart(polar[0], polar[1], planes[0], planes[1]);
    cv::merge(planes, tmp);
    cv::dft(tmp, tmp, cv::DFT_SCALE | cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT);



    tmp.convertTo(tmp, CV_8U);



    cv::Mat lut(1, 256, CV_32F, cv::Scalar(0));
    for (int i = 0; i < 256; ++i) {
        lut.at<float>(0, i) = i;
    }

    for (int i = 65; i < 200; ++i) {
        lut.at<float>(0, i) = i - 30;
    }
    
    for (int i = 200; i < 220; ++i) {
        lut.at<float>(0, i) = i - 20;
    }
    
    lut.convertTo(lut, CV_8U);

    tmp.convertTo(tmp, CV_8U);

    cv::normalize(tmp, tmp, 0, 255, cv::NORM_MINMAX);
    
    cv::LUT(tmp, lut, tmp);


    cv::GaussianBlur(tmp, tmp, cv::Size(3, 3), 1);
    cv::medianBlur(tmp, tmp, 3);
    cv::Mat result;
    cv::matchTemplate(orig, tmp, result, CV_TM_SQDIFF);
    std::cout << "RMSE Task 3.5: " << result / (orig.cols * orig.rows) << std::endl;

    concatImages(res, tmp, res);
    cv::absdiff(tmp, orig, tmp);
    concatImages(res, tmp, res);

    cv::absdiff(image, orig, tmp);
    concatImages(res, tmp, res);
    concatImages(res, orig, res);

//    cv::namedWindow("Lesson 2", CV_WINDOW_NORMAL);
//    cv::imshow("Lesson 2", res);
//    cv::waitKey(0);

    return cv::imwrite(PATH + "Task3_5.jpg", res);
}
cv::Mat DarkPixelFilter2Plugin::filter(const cv::Mat &data) const
{
    cv::Mat out;
    if (data.channels() > 1)
    {
        // create gray image
        std::vector<cv::Mat> iChannels(data.channels());
        cv::split(data, &iChannels[0]);

        double a = 1.0/iChannels.size();
        iChannels[0].convertTo(out, CV_32F, a);
        for (int i=1; i<iChannels.size();i++)
        {
            out += a*iChannels[i];
        }
    }
    else
    {
        if (data.depth() == CV_32F)
        {
            data.copyTo(out);
        }
        else
        {
            data.convertTo(out, CV_32F);
        }
    }

    // -) Compute mask from specified value:
    cv::Mat datamask;
    if (_maskByValue > -12345)
    {
        datamask = out != _maskByValue;
    }


    // -) Image -> 1/Image
    cv::divide(1.0,out,out,CV_32F);

    if (_verbose) { verboseDisplayImage("Image -> 1/Image", out); }
    emit progressValue(15);


    // -) Gaussian blur
    cv::GaussianBlur(out, out, cv::Size(_gbWinSize, _gbWinSize), _gbWinSize/1.5);
    if (_verbose) { verboseDisplayImage("Gaussian blur", out); }


    // -) Resize image
    int initW=out.cols, initH=out.rows;
    double rf = _resizeFactor;
    int newW = initW*rf;
    int newH = initH*rf;
    if (newW < 256 || newH < 256)
    {
        rf = qMax(256.0 / initW, 256.0 / initH);
        SD_TRACE1("New resize factor : %1", rf);
    }

    cv::resize(out, out, cv::Size(0, 0), rf, rf, cv::INTER_NEAREST);
    if (!datamask.empty())
    {
        cv::resize(datamask, datamask, cv::Size(0, 0), rf, rf, cv::INTER_NEAREST);
    }

    emit progressValue(25);

    // -) Convert to 8U
    {
        double minVal, maxVal;
        cv::minMaxLoc(out, &minVal, &maxVal, 0, 0,datamask);
        cv::Scalar mean, std;
        cv::meanStdDev(out, mean, std, datamask);
        double nmin = mean.val[0] - 3.0*std.val[0];
        minVal = (nmin < minVal) ? minVal : nmin;
        double nmax = mean.val[0] + 3.0*std.val[0];
        maxVal = (nmax > maxVal) ? maxVal : nmax;
        cv::Mat out8U;
        out.convertTo(out8U, CV_8U, 255.0/(maxVal-minVal), -255.0*minVal/(maxVal-minVal));
        out = out8U;
        emit progressValue(30);
    }

    // -) Median blur
    cv::medianBlur(out, out, 3);

    // -) Only bright objects
    {
        cv::Scalar mean = cv::mean(out, datamask);
        cv::threshold(out, out, mean[0], 255, cv::THRESH_TOZERO);
        cv::Mat mask, m = out == 0;
        m.convertTo(mask, out.type(), mean[0]/255.0);
        out = out + mask;
    }
    if (_verbose) { verboseDisplayImage("Only bright objects", out); }

    // -) Adaptive thresholding

    // Y = (Ymax - Ymin) * (X - Xmin)/(Xmax - Xmin) + Ymin
    // Y = (Ymin - Ymax) * (X - Xmin)/(Xmax - Xmin) + Ymax
    // transform sensivity [0.0 -> 1.0] into coeff [1.0 -> 0.3]
    double v = 1.0 - (0.7)*_sensivity;
    cv::Scalar mean = cv::mean(out, datamask);
    double c = -v*mean[0];
    cv::adaptiveThreshold(out, out, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, _atWinSize, c);

    if (_verbose) { verboseDisplayImage("Adaptive thresholding", out); }
    emit progressValue(40);

    // -) Morpho close
    out = blurThreshClose(out, 3, 100, _mcWinSize, 2);
    if (_verbose) { verboseDisplayImage("Blur + Theshold + Morpho", out); }
    emit progressValue(50);

    // -) Resize to initial
    cv::resize(out, out, cv::Size(initW, initH), 0, 0, cv::INTER_LINEAR);
    emit progressValue(60);

    // -) Make contours smoother
    {
        int s = 7;
        cv::blur(out, out, cv::Size(s, s));
        cv::Mat k1 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(s, s));
        cv::morphologyEx(out, out, cv::MORPH_ERODE, k1);
    }

    // -) Find contours
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(out, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);

    cv::Mat res(out.size(), CV_32F);
    res.setTo(_noDataValue);
    emit progressValue(80);

    if (contours.size() > 0)
    {
        double minArea = _minSize*_minSize;
        for (int i=0;i<contours.size();i++)
        {
            std::vector<cv::Point> contour = contours[i];
            // remove line and points
            if (contour.size() < 3)
                continue;
            double s = cv::contourArea(contour);
            if (s > minArea)
            {
                cv::drawContours(res, contours, i, cv::Scalar::all(1.0), CV_FILLED);
            }
        }
        out = res;
    }
    else
    {
        _errorMessage = tr("No dark pixel zones found of size larger than %1").arg(_minSize);
        return cv::Mat();
    }

    return out;
}