使用浅色斑点进行斑点检测
Blob Detection with light-colored blobs
我在检测一组图像中的特定 "blobs" 时遇到一些问题。并非所有图像都相同,但我想无论如何都会使用相同的参数进行检测。
如果放大,您会看到叶子上有黄色的小蚜虫。我的目标是挑出这些并计算它们。我真的不需要对图像做太多,只需要计算它们的数量即可。
现在,我有这个:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.Features2D;
using Emgu.CV.Structure;
using Emgu.CV.Util;
namespace AphidCounter
{
class Program
{
static void Main(string[] args)
{
// Read image
Mat im_in = CvInvoke.Imread("myimage1.jpg", Emgu.CV.CvEnum.LoadImageType.Grayscale);
//Mat im_in = CvInvoke.Imread("myimage2.png", Emgu.CV.CvEnum.LoadImageType.Color);
Mat im = im_in;
CvInvoke.Threshold(im_in, im, 40, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv); // 60, 255, 1
//CvInvoke.NamedWindow("Blob Detector", Emgu.CV.CvEnum.NamedWindowType.AutoSize);
DetectBlobs(im, 0);
CvInvoke.WaitKey(0);
}
static void DetectBlobs(Mat im, int c)
{
int maxT = 50;
int minA = 125; // Minimum area in pixels
int maxA = 550; // Maximum area in pixels
SimpleBlobDetectorParams EMparams = new SimpleBlobDetectorParams();
SimpleBlobDetector detector;
EMparams.MinThreshold = 0;
EMparams.MaxThreshold = 100;
if (minA < 1) minA = 1;
EMparams.FilterByArea = true;
EMparams.MinArea = minA;
EMparams.MaxArea = maxA;
if (maxT < 1) maxT = 1;
EMparams.MinConvexity = (float)maxT / 1000.0F; // 0.67
EMparams.FilterByInertia = true;
EMparams.MinInertiaRatio = 0.01F;
EMparams.FilterByColor = true;
EMparams.blobColor = 0;
VectorOfKeyPoint keyPoints = new VectorOfKeyPoint();
detector = new SimpleBlobDetector(EMparams);
detector.DetectRaw(im, keyPoints);
Mat im_with_keypoints = new Mat();
Bgr color = new Bgr(0, 0, 255);
Features2DToolbox.DrawKeypoints(im, keyPoints, im_with_keypoints, color, Features2DToolbox.KeypointDrawType.DrawRichKeypoints);
// Show blobs
CvInvoke.Imwrite("keypoints1.jpg", im_with_keypoints);
CvInvoke.Imshow("Blob Detector " + keyPoints.Size, im_with_keypoints);
System.Console.WriteLine("Number of keypoints: " + keyPoints.Size);
}
}
}
然而,这是结果:
我是不是参数不对?还是我还缺少其他东西?
不是因为一些错误的参数。图像分割部分本身有其局限性
当斑点和背景之间的对比度非常低时,基于灰度的阈值可能不起作用。然而,在此示例中,大约 160 的阈值是可以接受的,但并不准确。
我建议采用基于颜色的阈值处理,因为存在不错的色差。
这是基于颜色的阈值处理的 C++ 实现。使用相同的 SimpleBlobDetector.
过滤 Blob
我已经将 RGB to ‘Lab’ 的图像转换为更好的分割。
由于提供的图片太大,处理时间较长。所以我裁剪了图像的关键部分,并为此调整了 blob 参数。所以我也提供了裁剪后的图像(755 x 494 像素)。
基于颜色的阈值和斑点过滤:
#include "opencv2\imgproc\imgproc.hpp";
#include "opencv2\highgui\highgui.hpp";
#include "opencv2\features2d\features2d.hpp";
using namespace cv;
using namespace std;
void main()
{
char image_path[] = "E:/Coding/media/images/leaf_small.jpg";
Mat img_color, img_lab, img_thresh, img_open, img_close, img_keypoints;
img_color = imread(image_path, IMREAD_ANYCOLOR);
//Convert image to CIE Lab colorspace for better colour based segmentation
cvtColor(img_color, img_lab, CV_BGR2Lab);
//create window before creating trackbar
namedWindow("win_thresh", WINDOW_NORMAL);
namedWindow("win_blob", WINDOW_NORMAL);
//Using trackbar calculate the range of L,a,b values to seperate blobs
int low_L = 150, low_A = 0, low_B = 155,
high_L = 255, high_A = 255, high_B = 255;
//*Use trackbars to caliberate colour thresholding
createTrackbar("low_L", "win_thresh", &low_L, 255);
createTrackbar("low_A", "win_thresh", &low_A, 255);
createTrackbar("low_B", "win_thresh", &low_B, 255);
createTrackbar("high_L", "win_thresh", &high_L, 255);
createTrackbar("high_A", "win_thresh", &high_A, 255);
createTrackbar("high_B", "win_thresh", &high_B, 255);
int minArea = 35, maxArea = 172, minCircularity = 58, minConvexity = 87, minInertiaRatio = 21;
//Use trackbar and set Blob detector parameters
createTrackbar("minArea", "win_blob", &minArea, 200);
createTrackbar("maxArea", "win_blob", &maxArea, 200);
createTrackbar("minCircular", "win_blob", &minCircularity, 99);
createTrackbar("minConvex", "win_blob", &minConvexity, 99);
createTrackbar("minInertia", "win_blob", &minInertiaRatio, 99);
SimpleBlobDetector::Params params;
vector<KeyPoint> keypoints;
while (waitKey(1) != 27) //press 'esc' to quit
{
//inRange thresholds basedon the Scalar boundaries provided
inRange(img_lab, Scalar(low_L, low_A, low_B), Scalar(high_L, high_A, high_B), img_thresh);
//Morphological filling
Mat strucElement = getStructuringElement(CV_SHAPE_ELLIPSE, Size(5, 5), Point(2, 2));
morphologyEx(img_thresh, img_close, MORPH_CLOSE, strucElement);
imshow("win_thresh", img_close);
//**SimpleBlobDetector works only in inverted binary images
//i.e.blobs should be in black and background in white.
bitwise_not(img_close, img_close); // inverts matrix
//Code crashes if minArea or any miin value is set to zero
//since trackbar starts from 0, it is adjusted here by adding 1
params.filterByArea = true;
params.minArea = minArea + 1;
params.maxArea = maxArea + 1;
params.filterByCircularity = true;
params.filterByConvexity = true;
params.filterByInertia = true;
params.minCircularity = (minCircularity + 1) / 100.0;
params.minConvexity = (minConvexity + 1) / 100.0;
params.minInertiaRatio = (minInertiaRatio + 1) / 100.0;
SimpleBlobDetector detector(params);
detector.detect(img_close, keypoints);
drawKeypoints(img_color, keypoints, img_keypoints, Scalar(0, 0, 255), DrawMatchesFlags::DEFAULT);
stringstream displayText;
displayText = stringstream();
displayText << "Blob_count: " << keypoints.size();
putText(img_keypoints, displayText.str(), Point(0, 50), CV_FONT_HERSHEY_PLAIN, 2, Scalar(0, 0, 255), 2);
imshow("win_blob", img_keypoints);
}
return;
}
输出截图
根据实际高清图像调整blob参数。
由于叶脉的颜色和强度几乎与蚜虫相同,因此当蚜虫靠近叶脉或恰好位于叶脉顶部时,此方法也可能完全失败。
这可能是临时修复,但不够稳健。
必须有一种简单而可靠的方法来获得结果,使用一些过滤器、变换或边缘检测。如果可用,请分享任何其他最佳解决方案。
编辑:选择灰度阈值作为先前的方法失败
的颜色阈值方法失败
基于颜色的阈值处理具有非常窄的带宽,如果图像落在带宽内,则精度会非常好,另一方面,颜色偏移会完全破坏精度。
由于您将处理 100 多张图像,因此颜色阈值可能不合适。
我尝试了带有一些形态侵蚀和填充的普通灰度阈值处理,并获得了不错的准确性。此外,灰度阈值对颜色偏移具有更好的免疫力。
此外,我们还有使用 OTSU 阈值的自动阈值选项,它根据图像选择阈值。
代码片段:
threshold(img_gray, img_thresh, 0, 255, THRESH_OTSU);
Mat strucElement = getStructuringElement(CV_SHAPE_ELLIPSE, Size(3, 3), Point(1, 1));
morphologyEx(img_thresh, img_open, MORPH_OPEN, strucElement);
其余代码保持不变。
参数值:
minArea = 75, maxArea = 1000, minCircularity = 50, minConvexity = 20, minInertiaRatio = 15
白蚂蚁很难与蚜虫区分开来,因为我们没有使用颜色信息。因此必须仔细调整 min_area
以排除它们。
调整形态学方法和 blob 参数以获得最佳平均计数。
我在检测一组图像中的特定 "blobs" 时遇到一些问题。并非所有图像都相同,但我想无论如何都会使用相同的参数进行检测。
如果放大,您会看到叶子上有黄色的小蚜虫。我的目标是挑出这些并计算它们。我真的不需要对图像做太多,只需要计算它们的数量即可。
现在,我有这个:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.Features2D;
using Emgu.CV.Structure;
using Emgu.CV.Util;
namespace AphidCounter
{
class Program
{
static void Main(string[] args)
{
// Read image
Mat im_in = CvInvoke.Imread("myimage1.jpg", Emgu.CV.CvEnum.LoadImageType.Grayscale);
//Mat im_in = CvInvoke.Imread("myimage2.png", Emgu.CV.CvEnum.LoadImageType.Color);
Mat im = im_in;
CvInvoke.Threshold(im_in, im, 40, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv); // 60, 255, 1
//CvInvoke.NamedWindow("Blob Detector", Emgu.CV.CvEnum.NamedWindowType.AutoSize);
DetectBlobs(im, 0);
CvInvoke.WaitKey(0);
}
static void DetectBlobs(Mat im, int c)
{
int maxT = 50;
int minA = 125; // Minimum area in pixels
int maxA = 550; // Maximum area in pixels
SimpleBlobDetectorParams EMparams = new SimpleBlobDetectorParams();
SimpleBlobDetector detector;
EMparams.MinThreshold = 0;
EMparams.MaxThreshold = 100;
if (minA < 1) minA = 1;
EMparams.FilterByArea = true;
EMparams.MinArea = minA;
EMparams.MaxArea = maxA;
if (maxT < 1) maxT = 1;
EMparams.MinConvexity = (float)maxT / 1000.0F; // 0.67
EMparams.FilterByInertia = true;
EMparams.MinInertiaRatio = 0.01F;
EMparams.FilterByColor = true;
EMparams.blobColor = 0;
VectorOfKeyPoint keyPoints = new VectorOfKeyPoint();
detector = new SimpleBlobDetector(EMparams);
detector.DetectRaw(im, keyPoints);
Mat im_with_keypoints = new Mat();
Bgr color = new Bgr(0, 0, 255);
Features2DToolbox.DrawKeypoints(im, keyPoints, im_with_keypoints, color, Features2DToolbox.KeypointDrawType.DrawRichKeypoints);
// Show blobs
CvInvoke.Imwrite("keypoints1.jpg", im_with_keypoints);
CvInvoke.Imshow("Blob Detector " + keyPoints.Size, im_with_keypoints);
System.Console.WriteLine("Number of keypoints: " + keyPoints.Size);
}
}
}
然而,这是结果:
我是不是参数不对?还是我还缺少其他东西?
不是因为一些错误的参数。图像分割部分本身有其局限性
当斑点和背景之间的对比度非常低时,基于灰度的阈值可能不起作用。然而,在此示例中,大约 160 的阈值是可以接受的,但并不准确。
我建议采用基于颜色的阈值处理,因为存在不错的色差。
这是基于颜色的阈值处理的 C++ 实现。使用相同的 SimpleBlobDetector.
过滤 Blob我已经将 RGB to ‘Lab’ 的图像转换为更好的分割。
由于提供的图片太大,处理时间较长。所以我裁剪了图像的关键部分,并为此调整了 blob 参数。所以我也提供了裁剪后的图像(755 x 494 像素)。
基于颜色的阈值和斑点过滤:
#include "opencv2\imgproc\imgproc.hpp";
#include "opencv2\highgui\highgui.hpp";
#include "opencv2\features2d\features2d.hpp";
using namespace cv;
using namespace std;
void main()
{
char image_path[] = "E:/Coding/media/images/leaf_small.jpg";
Mat img_color, img_lab, img_thresh, img_open, img_close, img_keypoints;
img_color = imread(image_path, IMREAD_ANYCOLOR);
//Convert image to CIE Lab colorspace for better colour based segmentation
cvtColor(img_color, img_lab, CV_BGR2Lab);
//create window before creating trackbar
namedWindow("win_thresh", WINDOW_NORMAL);
namedWindow("win_blob", WINDOW_NORMAL);
//Using trackbar calculate the range of L,a,b values to seperate blobs
int low_L = 150, low_A = 0, low_B = 155,
high_L = 255, high_A = 255, high_B = 255;
//*Use trackbars to caliberate colour thresholding
createTrackbar("low_L", "win_thresh", &low_L, 255);
createTrackbar("low_A", "win_thresh", &low_A, 255);
createTrackbar("low_B", "win_thresh", &low_B, 255);
createTrackbar("high_L", "win_thresh", &high_L, 255);
createTrackbar("high_A", "win_thresh", &high_A, 255);
createTrackbar("high_B", "win_thresh", &high_B, 255);
int minArea = 35, maxArea = 172, minCircularity = 58, minConvexity = 87, minInertiaRatio = 21;
//Use trackbar and set Blob detector parameters
createTrackbar("minArea", "win_blob", &minArea, 200);
createTrackbar("maxArea", "win_blob", &maxArea, 200);
createTrackbar("minCircular", "win_blob", &minCircularity, 99);
createTrackbar("minConvex", "win_blob", &minConvexity, 99);
createTrackbar("minInertia", "win_blob", &minInertiaRatio, 99);
SimpleBlobDetector::Params params;
vector<KeyPoint> keypoints;
while (waitKey(1) != 27) //press 'esc' to quit
{
//inRange thresholds basedon the Scalar boundaries provided
inRange(img_lab, Scalar(low_L, low_A, low_B), Scalar(high_L, high_A, high_B), img_thresh);
//Morphological filling
Mat strucElement = getStructuringElement(CV_SHAPE_ELLIPSE, Size(5, 5), Point(2, 2));
morphologyEx(img_thresh, img_close, MORPH_CLOSE, strucElement);
imshow("win_thresh", img_close);
//**SimpleBlobDetector works only in inverted binary images
//i.e.blobs should be in black and background in white.
bitwise_not(img_close, img_close); // inverts matrix
//Code crashes if minArea or any miin value is set to zero
//since trackbar starts from 0, it is adjusted here by adding 1
params.filterByArea = true;
params.minArea = minArea + 1;
params.maxArea = maxArea + 1;
params.filterByCircularity = true;
params.filterByConvexity = true;
params.filterByInertia = true;
params.minCircularity = (minCircularity + 1) / 100.0;
params.minConvexity = (minConvexity + 1) / 100.0;
params.minInertiaRatio = (minInertiaRatio + 1) / 100.0;
SimpleBlobDetector detector(params);
detector.detect(img_close, keypoints);
drawKeypoints(img_color, keypoints, img_keypoints, Scalar(0, 0, 255), DrawMatchesFlags::DEFAULT);
stringstream displayText;
displayText = stringstream();
displayText << "Blob_count: " << keypoints.size();
putText(img_keypoints, displayText.str(), Point(0, 50), CV_FONT_HERSHEY_PLAIN, 2, Scalar(0, 0, 255), 2);
imshow("win_blob", img_keypoints);
}
return;
}
输出截图
根据实际高清图像调整blob参数。
由于叶脉的颜色和强度几乎与蚜虫相同,因此当蚜虫靠近叶脉或恰好位于叶脉顶部时,此方法也可能完全失败。
这可能是临时修复,但不够稳健。 必须有一种简单而可靠的方法来获得结果,使用一些过滤器、变换或边缘检测。如果可用,请分享任何其他最佳解决方案。
编辑:选择灰度阈值作为先前的方法失败
的颜色阈值方法失败基于颜色的阈值处理具有非常窄的带宽,如果图像落在带宽内,则精度会非常好,另一方面,颜色偏移会完全破坏精度。 由于您将处理 100 多张图像,因此颜色阈值可能不合适。
我尝试了带有一些形态侵蚀和填充的普通灰度阈值处理,并获得了不错的准确性。此外,灰度阈值对颜色偏移具有更好的免疫力。
此外,我们还有使用 OTSU 阈值的自动阈值选项,它根据图像选择阈值。
代码片段:
threshold(img_gray, img_thresh, 0, 255, THRESH_OTSU);
Mat strucElement = getStructuringElement(CV_SHAPE_ELLIPSE, Size(3, 3), Point(1, 1));
morphologyEx(img_thresh, img_open, MORPH_OPEN, strucElement);
其余代码保持不变。
参数值:
minArea = 75, maxArea = 1000, minCircularity = 50, minConvexity = 20, minInertiaRatio = 15
白蚂蚁很难与蚜虫区分开来,因为我们没有使用颜色信息。因此必须仔细调整 min_area
以排除它们。
调整形态学方法和 blob 参数以获得最佳平均计数。