Распознавание топологического графа на зашумленном изображении

Я совсем не разбираюсь в машинном обучении или обработке изображений, поэтому я надеюсь, что кто-то может дать несколько советов по поводу этой проблемы:

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

введите здесь описание изображения

Итак, мой вопрос: какие типы фильтров/классификаторов сразу приходят на ум? Есть ли что-нибудь, что вы порекомендуете мне прочитать или посмотреть?

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

Спасибо за любую помощь!


person gmoss    schedule 16.04.2014    source источник
comment
Эта проблема выглядит интересной, дайте мне знать, если вам нужна помощь с прототипированием/реализацией решения.   -  person voidengine    schedule 17.04.2014


Ответы (2)


Сразу приходят на ум два способа

  1. классификатор нейронной сети со скользящим окном
  2. определение порога, который разделяет темные/светлые пиксели на изображении (это можно сделать с помощью машинного обучения или, возможно, простого вычисления), а затем выполнение заливки для определения областей на изображении.

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

В любом случае, моя интуиция подсказывает, что будет проще решить двойную задачу — не пытаться найти ребра и узлы графа, а найти его грани. Отсюда вы легко получите сам график.

person voidengine    schedule 17.04.2014
comment
Спасибо, что указали на то, что двойная проблема будет проще — удаление точек и сглаживание шума гораздо проще, чем поиск самих краев! - person gmoss; 17.04.2014

Я сделал эту очень простую программу для фильтрации областей вен с помощью opencv. Я добавил комментарии для объяснения операций. Результирующие изображения для промежуточных шагов сохраняются. Надеюсь, поможет.

#include "stdafx.h"

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;

#define INPUT_FILE              "wMTjH3L.png"
#define OUTPUT_FOLDER_PATH      string("")
#define CONTOUR_AREA_THRESHOLD  30.0

int _tmain(int argc, _TCHAR* argv[])
{
    // read image as grayscale
    Mat im = imread(INPUT_FILE, CV_LOAD_IMAGE_GRAYSCALE);
    imwrite(OUTPUT_FOLDER_PATH + string("gray.jpg"), im);
    // smooth the image with a gaussian filter
    Mat blurred;
    GaussianBlur(im, blurred, Size(3, 3), 1.5);
    imwrite(OUTPUT_FOLDER_PATH + string("blurred.jpg"), blurred);
    // flatten lighter regions while retaining the darker vein regions using morphological opening
    Mat morph;
    Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
    morphologyEx(blurred, morph, MORPH_OPEN, morphKernel);
    imwrite(OUTPUT_FOLDER_PATH + string("morph.jpg"), morph);
    // apply adaptive thresholding
    Mat adaptTh;
    adaptiveThreshold(morph, adaptTh, 255.0, ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, 7, 2.0);
    imwrite(OUTPUT_FOLDER_PATH + string("adaptth.jpg"), adaptTh);
    // morphological closing to merge disjoint regions
    Mat morphBin;
    Mat morphKernelBin = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
    morphologyEx(adaptTh, morphBin, MORPH_CLOSE, morphKernelBin);
    imwrite(OUTPUT_FOLDER_PATH + string("adptmorph.jpg"), morphBin);
    // find contours
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(morphBin, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
    // filter contours by region areas and draw
    RNG rng(12345);
    Mat drawing = Mat::zeros(morphBin.size(), CV_8UC3);
    for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
    {
         if (contourArea(contours[idx]) > CONTOUR_AREA_THRESHOLD)
         {
             Scalar color( rand()&255, rand()&255, rand()&255 );
             drawContours( drawing, contours, idx, color, CV_FILLED, 8, hierarchy );
         }
    }
    imwrite(OUTPUT_FOLDER_PATH + string("cont.jpg"), drawing);
    return 0;
}

Вывод для предоставленного образца изображения выглядит следующим образом:

введите здесь описание изображения

person dhanushka    schedule 20.04.2014
comment
Привет, Спасибо за это! Это выглядит очень многообещающе, с некоторыми настройками параметров. Это действительно простое решение, и я обязательно буду держать вас в курсе проекта, особенно если мы будем сильно полагаться на этот метод. - person gmoss; 21.04.2014