检测图像中的峰值

时间:2017-09-01 13:01:13

标签: c# image-processing unsafe

我收到了一大堆种子的红外图像,它们的大小略有不同。 我想找到它们(以最快的方式)。 下面我展示了我处理的图像的放大细节。 在第一次去除噪声和blob滤波器后,这就是我所拥有的: enter image description here

明亮的白色只是红外灯的直接反射,白色像素永远不会在多个种子上结合(伸展)。

为了更清楚,我在一些个别种子上写了一封信。 enter image description here

我遇到的问题:

  • A是单个种子(种子上的污垢)会产生轻微的暗线。
  • B靠近它的附近的X是在它最暗的交叉点,它仍然比其他一些种子更亮(如果灰度值低于某个值,则无法改变亮度或移除。
  • C这些是3粒种子彼此靠近。
  • 上面最小的可见种子不应该更小。

我没有使用mathlab或openCV,因为我直接使用锁定的图像和内存数据。我可以通过数组或简单的getpixel / putpixel命令访问像素数据。我编写了自己的图形库,它对于实时摄像机数据足够快,处理速度目前在13ms左右,大约25ms我输入流处理滞后

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

好吧我做了不同的斜率检测代码,现在我不寻找某种程度,但只是在一个小范围内的倾斜点,它在X轴上工作得很好..但基本上我认为它应该适用于X和Y 这是新结果: enter image description here 它可以解决问题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); }
     }

2 个答案:

答案 0 :(得分:0)

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

管道概述:removeSaturation&gt;&gt;高斯模糊&gt;&gt;二进制化&gt;&gt; padd&gt;&gt; distanceTransform&gt;&gt; peak&gt;&gt; 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;
}

速度: enter image description here

调试图片: enter image description here

结果: enter image description here

希望这有帮助!干杯!

答案 1 :(得分:0)

SO answer的类似问题中,我应用持久同源性来查找图像中的峰值。我拿了your image,将其缩小到50%,应用了半径为20的Guassian模糊(在Gimp中),并应用了另一篇文章中描述的方法(点击放大):

Result

我只显示持久性峰值(参见另一个SO答案)至少为20.持久性图表如下所示:

Persistence diagram

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

可以找到Python代码here