检测图像中的峰值

我得到了一大组种子的红外图像,它们的大小略有不同。 我想找到它们(以最快的方式)。 下面我显示放大我处理的图像的细节。 第一个噪音去除和blob过滤器后,这是我有: 在这里输入图像描述

明亮的白色只是红外灯的直接反射,白色像素从未结合(伸出)多个种子。

为了更清楚地说明我给某些种子写了一封信。 在这里输入图像描述

我有这些问题:

  • A是单粒种子(种子上的污垢)会产生一个微弱的黑线。
  • B附近的X在它最黑暗的交叉点,它的光线仍然比其他种子更亮(如果灰度值低于某个值,则不能改变亮度或去除。
  • C是那些接近彼此的3颗种子。
  • 上面最小的可见种子不应小得多。
  • 我没有使用mathlab或openCV,因为我直接处理锁定的图像和内存数据。 我可以通过数组或简单的getpixel / putpixel命令来访问像素数据。 我写了自己的图形库,对于实时相机数据足够快,在25ms左右处理速度约为13ms,进入流处理滞后

    我想知道如何更好地分离那些'阴天'的斑点。 我想在特定像素范围内找到局部最大值..但是应该看到A是一个种子,而在B上发现B和X没有连接。 所以我不确定在这里,这样的本地窥视功能或其他功能应该如何。 虽然我在C#中的代码,我看着其他的C ++函数以及像扩张等,但那不是它。 我还写了一个函数来检查斜度(如果它是一个山高度图像),但不能区分B和C.

    好吧,我做了不同的斜率检测代码,现在我不寻找一定的程度,但只是在一个小范围内的倾斜点,它在X轴上工作很好..但基本上我认为它应该在X和Y上都有效,这里是新的结果: 在这里输入图像描述 它可以解决问题A和B!

    然而,它不能区分在垂直行中排列的种子,并且会导致小的白噪声(未连接的线)。 在几乎没有任何可检测到的地方。 我还不确定如何在Y轴上执行相同的(组合)以使顶部从顶部的某个距离擦除东西..(分离)。

    使用这个代码只是显示它的像素操作。

     for (int y =  raw.Height;y>5; y--)
            {slopeUP = false;
                int[] peek = new int[raw.Width];
                for (int x = raw.Width; x> 7; x--)
                {
                    int a = raw.GetPixelBleu(x, y);
                    int b = raw.GetPixelBleu(x - 1, y);
                    int c = raw.GetPixelBleu(x - 2, y);
                    int d = raw.GetPixelBleu(x - 11, y);
                    int f = raw.GetPixelBleu(x - 12, y);
    
                    if ((f + d) > (a + b))slopeUP  = true;
    
                    if ((f + d) < (a + b))
                    {
                        if (slopeUP)
                        {
                            slopeUP = false;
                            peek[x - 6] = 10;
                            //raw.SetPixel(x, y, Color.GreenYellow);
                        }
                        else peek[x - 6] = 0;
                    }
    
                }
                for (int x = raw.Width; x > 7; x--) 
                { if (peek[x-1] > 5) raw.SetPixel(x, y, Color.Lavender); }
         }
    

    所以,就速度而言,我只是从你张贴在这里的图像上开始......因为它很小,所有的东西都快速地运行着。 请注意,我在二值化之后填充了图像并且从未取消填充,因此您需要取消填充或相应地移动结果。 你甚至可能不想垫,但它可以检测到切断的种子。

    管道概述:removeSaturation >>高斯模糊>> binarize >> padd >> distanceTransform >> peaks >> clustering

    这里说的是我的代码和结果:

    void drawText(Mat & image);
    void onMouse(int event, int x, int y, int, void*);
    Mat bruteForceLocalMax(Mat srcImage, int searchRad);
    void zoomPixelImage(Mat sourceImage, int multFactor, string name, bool mouseCallback);
    Mat mergeLocalPeaks(Mat srcImage, int mergeRadius);
    Mat image;
    bool debugDisplays = false;
    
    
    int main()
    {
        cout << "Built with OpenCV " << CV_VERSION << endl;
        TimeStamp precisionClock = TimeStamp();
    
        image = imread("../Raw_Images/Seeds1.png",0);
    
    
        if (image.empty()) { cout << "failed to load image"<<endl; }
        else
        {
            zoomPixelImage(image, 5, "raw data", false);
            precisionClock.labeledlapStamp("image read", true);
    
            //find max value in image that is not oversaturated
            int maxVal = 0;
            for (int x = 0; x < image.rows; x++)
            {
                for (int y = 0; y < image.cols; y++)
                {
                    int val = image.at<uchar>(x, y);
                    if (val >maxVal && val !=255)
                    {
                        maxVal = val;
                    }
                }
            }
    
            //get rid of oversaturation regions (as they throw off processing)
            image.setTo(maxVal, image == 255);
    
            if (debugDisplays)
            {zoomPixelImage(image, 5, "unsaturated data", false);}
            precisionClock.labeledlapStamp("Unsaturate Data", true);
    
            Mat gaussianBlurred = Mat();
            GaussianBlur(image, gaussianBlurred, Size(9, 9), 10, 0);
            if (debugDisplays)
            {zoomPixelImage(gaussianBlurred, 5, "blurred data", false);}
            precisionClock.labeledlapStamp("Gaussian", true);
    
            Mat binarized = Mat();
            threshold(gaussianBlurred, binarized, 50, 255, THRESH_BINARY);
            if (debugDisplays)
            {zoomPixelImage(binarized, 5, "binarized data", false);}
            precisionClock.labeledlapStamp("binarized", true);
    
            //pad edges (may or may not be neccesary depending on setup)
            Mat paddedImage = Mat();
            copyMakeBorder(binarized, paddedImage, 1, 1, 1, 1, BORDER_CONSTANT, 0);
            if (debugDisplays)
            {zoomPixelImage(paddedImage, 5, "padded data", false);}
            precisionClock.labeledlapStamp("add padding", true);
    
            Mat distTrans =  Mat();
            distanceTransform(paddedImage, distTrans, CV_DIST_L1,3,CV_8U);
            if (debugDisplays)
            {zoomPixelImage(distTrans, 5, "distanceTransform", true);}
            precisionClock.labeledlapStamp("distTransform", true);
    
            Mat peaks = Mat();
            peaks = bruteForceLocalMax(distTrans,10);
            if (debugDisplays)
            {zoomPixelImage(peaks, 5, "peaks", false);}
            precisionClock.labeledlapStamp("peaks", true);
    
            //attempt to cluster any colocated peaks and find the best clustering count
            Mat mergedPeaks = Mat();
            mergedPeaks = mergeLocalPeaks(peaks, 5);
            if (debugDisplays)
            {zoomPixelImage(mergedPeaks, 5, "peaks final", false);}
            precisionClock.labeledlapStamp("final peaks", true);
    
            precisionClock.fullStamp(false);
            waitKey(0);
        }
    }
    
    void drawText(Mat & image)
    {
        putText(image, "Hello OpenCV",
                Point(20, 50),
                FONT_HERSHEY_COMPLEX, 1, // font face and scale
                Scalar(255, 255, 255), // white
                1, LINE_AA); // line thickness and type
    }
    
    void onMouse(int event, int x, int y, int, void*)
    {
        if (event != CV_EVENT_LBUTTONDOWN)
            return;
    
        Point pt = Point(x, y);
        std::cout << "x=" << pt.x << "t y=" << pt.y << "t value=" << int(image.at<uchar>(y,x)) << "n";
    
    }
    
    void zoomPixelImage(Mat sourceImage, int multFactor, string name, bool normalized)
    {
        Mat zoomed;// = Mat::zeros(sourceImage.rows*multFactor, sourceImage.cols*multFactor, CV_8U);
        resize(sourceImage, zoomed, Size(sourceImage.cols*multFactor, sourceImage.rows*multFactor), sourceImage.cols*multFactor, sourceImage.rows*multFactor, INTER_NEAREST);
        if (normalized) { normalize(zoomed, zoomed, 0, 255, NORM_MINMAX); }
        namedWindow(name);
        imshow(name, zoomed);
    }
    
    Mat bruteForceLocalMax(Mat srcImage, int searchRad)
    {
        Mat outputArray = Mat::zeros(srcImage.rows, srcImage.cols, CV_8U);
        //global search top
        for (int x = 0; x < srcImage.rows - 1; x++)
        {
            for (int y = 0; y < srcImage.cols - 1; y++)
            {
                bool peak = true;
                float centerVal = srcImage.at<uchar>(x, y);
                if (centerVal == 0) { continue; }
                //local search top
                for (int a = -searchRad; a <= searchRad; a++)
                {
                    for (int b = -searchRad; b <= searchRad; b++)
                    {
                        if (x + a<0 || x + a>srcImage.rows - 1 || y + b < 0 || y + b>srcImage.cols - 1) { continue; }
                        if (srcImage.at<uchar>(x + a, y + b) > centerVal)
                        {
                            peak = false;
                        }
                        if (peak == false) { break; }
                    }
                    if (peak == false) { break; }
                }
                if (peak)
                {
                    outputArray.at<uchar>(x, y) = 255;
                }
    
            }
        }
        return outputArray;
    }
    
    Mat mergeLocalPeaks(Mat srcImage, int mergeRadius)
    {
        Mat outputArray = Mat::zeros(srcImage.rows, srcImage.cols, CV_8U);
        //global search top
        for (int x = 0; x < srcImage.rows - 1; x++)
        {
            for (int y = 0; y < srcImage.cols - 1; y++)
            {
                float centerVal = srcImage.at<uchar>(x, y);
                if (centerVal == 0) { continue; }
    
                int aveX = x;
                int aveY = y;
    
                int xCenter = -1;
                int yCenter = -1;
    
                while (aveX != xCenter || aveY != yCenter)
                {
                    xCenter = aveX;
                    yCenter = aveY;
                    aveX = 0;
                    aveY = 0;
                    int peakCount = 0;
                    //local search top
                    for (int a = -mergeRadius; a <= mergeRadius; a++)
                    {
                        for (int b = -mergeRadius; b <= mergeRadius; b++)
                        {
                            if (xCenter + a<0 || xCenter + a>srcImage.rows - 1 || yCenter + b < 0 || yCenter + b>srcImage.cols - 1) { continue; }
                            if (srcImage.at<uchar>(xCenter + a, yCenter + b) > 0)
                            {
                                aveX += (xCenter + a);
                                aveY += (yCenter + b);
                                peakCount += 1;
                            }
                        }
                    }
                    double dCentX = ((double)aveX / (double)peakCount);
                    double dCentY = ((double)aveY / (double)peakCount);
                    aveX = floor(dCentX);
                    aveY = floor(dCentY);
                }
                outputArray.at<uchar>(xCenter, yCenter) = 255;
            }
        }
        return outputArray;
    }
    

    速度: 在这里输入图像描述

    调试图像: 在这里输入图像描述

    结果: 在这里输入图像描述

    希望这可以帮助! 干杯!


    在这个SO回答一个类似的问题,我应用持久性同源性来找到图像中的峰值。 我把你的形象,缩小到50%,应用半径20(在Gimp)的高斯模糊,并应用其他文章中描述的方法(点击放大):

    结果

    我只显示至少20个具有持久性的峰值(请参阅另一个SO答案)。持久性图如下所示:

    第20个峰值将是左上角的小峰值,持续时间约为9.通过使用更强的高斯滤波器,图像会变得更加分散,峰值将更加突出。

    链接地址: http://www.djcxy.com/p/26805.html

    上一篇: Detecting peaks in images

    下一篇: How to detect a Christmas Tree?