检测图像中的峰值
我得到了一大组种子的红外图像,它们的大小略有不同。 我想找到它们(以最快的方式)。 下面我显示放大我处理的图像的细节。 第一个噪音去除和blob过滤器后,这是我有:
明亮的白色只是红外灯的直接反射,白色像素从未结合(伸出)多个种子。
为了更清楚地说明我给某些种子写了一封信。
我有这些问题:
我没有使用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