2016-02-24 3 views
3

У меня возникли проблемы с обнаружением определенных «капель» в наборе изображений. Не все изображения одинаковы, но я предполагаю, что одинаковые параметры будут использоваться для обнаружения в любом случае. Image1Обнаружение BLOB с светлыми пятнами

Если вы увеличите масштаб, вы увидите небольшую желтую тлю на листе. Моя цель - выделить их и подсчитать. Мне не нужно много делать с изображением, просто получайте их.

Прямо сейчас, у меня есть это:

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); 

     } 
    } 
} 

Однако это результат: Image2

я не получаю параметры правильно? Или есть что-то еще, что мне не хватает?

+0

Просьба предоставить промежуточные изображения, например, ваше двоичное изображение. – Piglet

ответ

3

Это не из-за неправильных параметров. Ограничивается сама часть сегментации изображения.

Пороговое значение на основе серого не может работать, если контраст между блобом и фоном очень низок. Однако пороговое значение около 160 вполне допустимо в этом примере, но не является точным.

Я предлагаю пойти для определения цвета на основе порога, так как есть приличный цветовой разрыв.

Ниже приведена реализация пороговых значений на основе цвета на C++. Блоки отфильтровываются с использованием того же SimpleBlobDetector.

Я преобразовал изображение с RGB to ‘Lab’ для лучшей сегментации.

Поскольку изображение предоставлено слишком велико, потребовалось больше времени для обработки. Поэтому я обрезал ключевую часть изображения и настраивал параметры blob для того же самого. Поэтому я также предоставляю обрезанное изображение (755 x 494px).

leaf_cropped

Цвет на основе порогового значения и блоб фильтрации:

#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; 
} 

Выход Скриншот

output screenshot

Настройте параметры blob в соответствии с фактическим HD-изображением.

Поскольку жилы листа имеют почти одинаковый цвет и интенсивность тли, этот метод также может полностью потерпеть неудачу, когда тля находится близко или точно на вершине вены.

Это может быть специальным исправлением, но недостаточно надежным. Должен быть простой и надежный способ достижения результата, используя некоторые фильтры, преобразование или обнаружение краев. Пожалуйста, поделитесь любым другим оптимальным решением, если оно доступно.

EDIT: Opting Grayscale порогового, как предыдущий подход не удался

Цвета порогового подхода потерпел неудачу для this_image

Цвета основы порогового имеет очень узкую полосу пропускания, если изображение находится в пределах полосы пропускания, точность будет быть действительно хорошими, с другой стороны, изменения цвета полностью разрушают точность. Поскольку вы будете обрабатывать 100 изображений, цветовое ограничение может оказаться непригодным.

Я пробовал нормальное градиентное пороговое значение с некоторой морфологической эрозией и наполнением и получал приличную точность. Также пороговое значение шкалы серого имеет лучшую устойчивость к цветовым сдвигам.

Кроме того, у нас есть опция auto thrsholding с использованием OTSU Thresholding, которая выбирает пороговое значение на основе изображения.

Фрагмент кода:

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, чтобы исключить их.

Обработанные изображения можно найти здесь img_1, img_2.

Измените методы морфологии и параметры blob для получения оптимального среднего значения.

+0

Какое время обработки у вас получилось и без обрезанного изображения? Моя цель - делать подобные вещи на лету (20-45 секунд на изображение). Существует допустимый уровень ошибок, который, как я предполагаю, произойдет. Я просто хочу в среднем, уровень должен быть не более 5% -10% по набору из 100 изображений. – Jerry

+0

Вот несколько фотографий, которые я получил от этого. Как вы можете видеть, чем больше тлей, тем больше она промахивается. Возможно, это проблема цветовой дисперсии? http://i.imgur.com/zPizCnL.jpg http://i.imgur.com/uD8XK29.jpg – Jerry

+0

Я отредактировал ответ, чтобы изменить метод порогового значения. Это занимает около 15-30 секунд на HD-изображение. Мои знания по обработке изображений ограничены, иначе я бы попробовал передовые методы, такие как маскирование шаблонов или маскирование переднего плана и т. Д. – Shan

Смежные вопросы