Jump to content
Compvision.ru
KNCH

OpenCV в медицине

Recommended Posts

Здравствуйте!

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

Пробую вариировать параметры threshold(), inRange(), GaussianBlur(), но, к сожалению безуспешно.

Так же пробовал использовать HoughCircles(), но опять же безуспешно (либо много кругов, либо вообще нет, либо ошибочно).

Буду очень рад Вашей помощи.

post-1600-0-76823700-1295119105_thumb.pnpost-1600-0-24950900-1295119114_thumb.pn

Share this post


Link to post
Share on other sites

Здравствуйте!

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

Пробую вариировать параметры threshold(), inRange(), GaussianBlur(), но, к сожалению безуспешно.

Так же пробовал использовать HoughCircles(), но опять же безуспешно (либо много кругов, либо вообще нет, либо ошибочно).

Буду очень рад Вашей помощи.

post-1600-0-76823700-1295119105_thumb.pnpost-1600-0-24950900-1295119114_thumb.pn

Боюсь просто не отделаетесь.

Можно попробовать натренировать каскад Хаара на эти объекты.

Или активные модели применить, и то и другое потребует изрядных усилий.

Но более простого ничего в голову не приходит.

Share this post


Link to post
Share on other sites

Согласен, что выделение простым не будет.

Вообще говоря, перед началом решения подобной задачи нужно на естественном (русском) языке выделить отличительные признаки объекта, как его можно однозначно классифицировать, отделить от других. Если это удаётся (например круг от прямоугольника или изображение единицы от нуля), то можно пошагово реализовывать словесную классификацию в программе. Если не удаётся (а для многих сложных объектов это так), то создавай выборку изображений, выбирай классификатор и тренируй его.

Share this post


Link to post
Share on other sites

Боюсь просто не отделаетесь.

Можно попробовать натренировать каскад Хаара на эти объекты.

Или активные модели применить, и то и другое потребует изрядных усилий.

Но более простого ничего в голову не приходит.

СпасиБо за быстрый ответ.

Я тоже думал про каскад Хаара, точнее даже запустил его генерацию, но по истечении 36+ часов генерация практически не сдвинулась с места, это при том, что я (только для теста) сделал только 3 позитивных и три негативных изображения (или из-за такого маленького количества могут быть проблемы?), с параметрами всё в порядке вроде -- отталкивался от топиков на этом форуме и от других мануалов. Да и потом проблема то в том, что снимков с такими вот объектами в сети практически нет, а следовательно нет в принципе смысла создавать коллекцию из сгенерированных изображений. Вобщем Хаар, я думаю, отпадает. Я больше думаю в сторону отделения приближённых к окружности объектов и потом через сравнение площади определять искомый ли это объект или нет.

За ссылку спасиБо!

Share this post


Link to post
Share on other sites

Согласен, что выделение простым не будет.

Вообще говоря, перед началом решения подобной задачи нужно на естественном (русском) языке выделить отличительные признаки объекта, как его можно однозначно классифицировать, отделить от других. Если это удаётся (например круг от прямоугольника или изображение единицы от нуля), то можно пошагово реализовывать словесную классификацию в программе. Если не удаётся (а для многих сложных объектов это так), то создавай выборку изображений, выбирай классификатор и тренируй его.

Единственное отличие - это округлая форма, и возможно более яркий цвет. Но на данном снимке этот объект - не единственное яркое "пятно". С созданием классификации тоже проблема, как я уже писал выше, так как нет такой базы данных.

В любом случае, спасиБо за советы!

Share this post


Link to post
Share on other sites

Если принять гипотезу, что наш объект внутри тёмный, а снаружи светлый, то можно воспользоваться операциями математической морфологии: CV_MOP_TOPHAT - поиск светлых областей и CV_MOP_BLACKHAT - поиск тёмных областей. После построить гистограмму для каждого результата, найти по ней порог, бинаризовать, отсеять мелкие объекты эрозией, результат нарастить, найти на нём контуры. Если в результате получатся вложенные контуры, то искомый объект найден. Как тебе идея?

Сразу предупреждаю, что код довольно корявый - писал его быстро, только ради иллюстрации:

#include "stdafx.h"


#include <cv.h>

#include <highgui.h>


int main(int argc, char* argv[])

{

	IplImage* image = cvLoadImage("d:\\resultFrame4.png", 0);

	IplImage* tophat = cvCloneImage(image);

	IplImage* blackhat = cvCloneImage(image);


	IplImage *result = cvCreateImage(cvSize(image->width, image->height), IPL_DEPTH_8U, 1);


	cvShowImage("original",image);


	int radius = 2;

	IplConvKernel* Kern = cvCreateStructuringElementEx(radius * 2 + 1, radius * 2 + 1, radius, radius, CV_SHAPE_ELLIPSE);


	IplImage* Temp = cvCreateImage(cvSize(image->width, image->height), IPL_DEPTH_8U, 1);

	int iterations = 7;

	cvMorphologyEx(image, tophat, Temp, Kern, CV_MOP_TOPHAT, iterations);

	cvMorphologyEx(image, blackhat, Temp, Kern, CV_MOP_BLACKHAT, iterations);



	cvShowImage("CV_MOP_TOPHAT", tophat);

	cvShowImage("CV_MOP_BLACKHAT", blackhat);


	{

		int hist[256] = {0};

		for (unsigned char *ib = (unsigned char *)tophat->imageData, *stopb = (unsigned char *)(tophat->imageData + tophat->imageSize); ib != stopb; ++ib)

		{

			++hist[*ib];

		}

		int threshold = 255;

		int sum = 0;

		for (int i = 255; i != 0; --i)

		{

			sum += hist[i];

			if (sum > tophat->imageSize / 100)

			{

				threshold = i;

				break;

			}

		}

		cvThreshold(tophat, tophat, threshold, 255, CV_THRESH_BINARY);

		cvErode(tophat, tophat, NULL, 1);

		cvDilate(tophat, tophat, NULL, 7);

		cvShowImage("binary_tophat", tophat);

	}


	{

		int hist[256] = {0};

		for (unsigned char *ib = (unsigned char *)blackhat->imageData, *stopb = (unsigned char *)(blackhat->imageData + blackhat->imageSize); ib != stopb; ++ib)

		{

			if (*ib > 100)

				*ib = 0;

			++hist[*ib];

		}

		int threshold = 255;

		int sum = 0;

		for (int i = 255; i != 0; --i)

		{

			sum += hist[i];

			if (sum > blackhat->imageSize / 100)

			{

				threshold = i;

				break;

			}

		}

		cvThreshold(blackhat, blackhat, threshold, 255, CV_THRESH_BINARY);

		cvErode(blackhat, blackhat, NULL, 1);

		cvDilate(blackhat, blackhat, NULL, 7);

		cvShowImage("binary_blackhat", blackhat);

	}


#if 1

	cvSet(result, cvScalar(0));

#else

	cvOr(tophat, blackhat, result);

#endif


	{

		CvMemStorage *storage = cvCreateMemStorage(0);

		CvContourScanner cs = cvStartFindContours(tophat, storage, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE);


		CvSeq *mContour = 0;

		for (CvSeq *contour = cvFindNextContour(cs); contour; contour = cvFindNextContour(cs))

		{

			if (contour->total >= 6)

			{

				CvBox2D box = cvFitEllipse2(contour);

				CvPoint center = cvPointFrom32f(box.center);

				CvSize size = cvSize(cvRound(box.size.width * 0.5), cvRound(box.size.height * 0.5));

				cvEllipse(result, center, size, -box.angle, 0, 360, CV_RGB(0, 0, 255), 1, CV_AA, 0);

			}

		}


		cvEndFindContours(&cs);

		cvReleaseMemStorage(&storage);

	}


	{

		CvMemStorage *storage = cvCreateMemStorage(0);

		CvContourScanner cs = cvStartFindContours(blackhat, storage, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE);


		CvSeq *mContour = 0;

		for (CvSeq *contour = cvFindNextContour(cs); contour; contour = cvFindNextContour(cs))

		{

			if (contour->total >= 6)

			{

				CvBox2D box = cvFitEllipse2(contour);

				CvPoint center = cvPointFrom32f(box.center);

				CvSize size = cvSize(cvRound(box.size.width * 0.5), cvRound(box.size.height * 0.5));

				cvEllipse(result, center, size, -box.angle, 0, 360, CV_RGB(0, 0, 255), 1, CV_AA, 0);

			}

		}


		cvEndFindContours(&cs);

		cvReleaseMemStorage(&storage);

	}


	cvShowImage("result", result);


	cvReleaseStructuringElement(&Kern);

	cvReleaseImage(&Temp);


	while(1)

	{

		if (cvWaitKey(33) > 0)

			break;

	}


	cvReleaseImage(&result);

	cvReleaseImage(&image);

	cvReleaseImage(&tophat);

	cvReleaseImage(&blackhat);


	cvDestroyAllWindows();

	return 0;

}

post-391-0-49827300-1295167993_thumb.png

  • Like 1

Share this post


Link to post
Share on other sites

Если принять гипотезу, что наш объект внутри тёмный, а снаружи светлый, то можно воспользоваться операциями математической морфологии: CV_MOP_TOPHAT - поиск светлых областей и CV_MOP_BLACKHAT - поиск тёмных областей. После построить гистограмму для каждого результата, найти по ней порог, бинаризовать, отсеять мелкие объекты эрозией, результат нарастить, найти на нём контуры. Если в результате получатся вложенные контуры, то искомый объект найден. Как тебе идея?

Сразу предупреждаю, что код довольно корявый - писал его быстро, только ради иллюстрации:

...

Огромное-огромное спасиБо!!

Видать, я слишком быстро "прощёлкал" tophat и blackhat. Буду пробовать, потом отпишусь.

Share this post


Link to post
Share on other sites

Здравствуйте всем!

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

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

Вот ролик test.rar

и код CircleDetection.rar.

Share this post


Link to post
Share on other sites

при вызове cvHoughCircles задайте минимальный и максимальный радиус окружности, тогда правильно выделится процентов 60, я поставил 5 и 40. Также можно попробовать отделить клетки от фона и потом применять преобразование Хафа, короче надо экспериментировать...

Share this post


Link to post
Share on other sites

Сохрани изображение одной клетки, а после используй его как шаблон для функции cvMatchTemplate. Порог выбирай небольшой, в районе 0.1

Share this post


Link to post
Share on other sites

Да, ещё можно, как советовал Romiks, отделить клетки от фона. И искать уже по бинарному изображению Это можно сделать, например, так:

cvSmooth(gray, gray, CV_GAUSSIAN, 5, 5);

cvCanny(gray, gray, 50, 150);

cvDilate(gray, gray, NULL, 2);

cvErode(gray, gray, NULL, 2);

Share this post


Link to post
Share on other sites

Пока я решил остановиться только на применении TopHat и вычислении площади контуров, этого вполне достаточно. По логике ведь, выпуклые объекты всегда будут светлее при освещении эндоскопической камеры (да и не только её). Ну края тоже бывают светлыми, т.к. они ближе, но я накладываю круглую маску на изображение и края обрезаются (http://nashruddin.com/OpenCV_Circular_ROI).

Огромное спасиБо ещё раз за идею, Вы меня спасли! =)

Share this post


Link to post
Share on other sites

Спасибо всем за предложения, попробую похимичить.

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

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

Может что-то похожее есть в примерах к OpenCV?

Share this post


Link to post
Share on other sites

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

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

Может что-то похожее есть в примерах к OpenCV?

а разве клетки на видео чем-то друг от друга отличаются?, если да это это сложновато будет сделать, а если нет то попробовать можно

Share this post


Link to post
Share on other sites
Может что-то похожее есть в примерах к OpenCV?
Есть выделение мышью в стандартном примере camshiftdemo.

Вот программа с иллюстрацией работы cvMatchTemplate:

#include "stdafx.h"

#include <cv.h>  

#include <highgui.h>


#define USE_BINARY_TEMPL

////////////////////////////////////////////////////////////////////////////


int _tmain(int argc, _TCHAR* argv[])

{

	CvCapture* capture = cvCaptureFromAVI("d:\\test.avi");

	if (!capture)

		return 1;


#ifdef USE_BINARY_TEMPL

	IplImage *tpl = cvLoadImage("d:\\cell.png", 0);

#else

	IplImage *tpl = cvLoadImage("d:\\cell_cl.png", 1);

#endif

	IplImage *gray = NULL;

	IplImage *res = NULL;


	for (IplImage *frame = cvQueryFrame(capture); frame; frame = cvQueryFrame(capture))

	{

		if (!gray)

			gray = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1);


		int w = frame->width - tpl->width + 1;

		int h = frame->height - tpl->height + 1;

		if (!res)

			res = cvCreateImage(cvSize(w, h), IPL_DEPTH_32F, 1);



#ifdef USE_BINARY_TEMPL

		cvCvtColor(frame, gray, CV_BGR2GRAY);

		cvSmooth(gray, gray, CV_GAUSSIAN, 5, 5);

		cvCanny(gray, gray, 50, 150);

		cvDilate(gray, gray, NULL, 2);

		cvErode(gray, gray, NULL, 2);


		cvMatchTemplate(gray, tpl, res, CV_TM_SQDIFF_NORMED);

#else

		cvMatchTemplate(frame, tpl, res, CV_TM_SQDIFF_NORMED);

#endif


		cvShowImage("gray", gray);

		cvSet(gray, cvScalar(0));


#ifdef USE_BINARY_TEMPL

		float threshold = 0.8f;

#else

		float threshold = 0.08f;

#endif

		for (int y = 0 ; y < res->height; ++y)

		{

			for (int x = 0 ; x < res->width ; ++x)

			{

				CvScalar s = cvGet2D(res, y, x);

				if (s.val[0] < threshold)

					cvSet2D(gray, y, x, cvScalar(255));

			}

		}


		CvMemStorage *storage = cvCreateMemStorage(0);

		CvContourScanner cs = cvStartFindContours(gray, storage, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE);


		for (CvSeq *contour = cvFindNextContour(cs); contour; contour = cvFindNextContour(cs))

		{

			if (contour->total >= 6)

			{

				CvBox2D box = cvFitEllipse2(contour);

				CvPoint center = cvPointFrom32f(box.center);

				cvCircle(frame, cvPoint(center.x + tpl->width / 2, center.y + tpl->height / 2), tpl->width / 2, CV_RGB(0, 255, 255));

			}

		}


		cvEndFindContours(&cs);

		cvReleaseMemStorage(&storage);



		cvShowImage("color", frame);


		if (cvWaitKey(30) == 27)   

			break;

	}


	cvReleaseImage(&res);

	cvReleaseImage(&tpl);

	cvReleaseImage(&gray);

	cvReleaseCapture(&capture);

	cvDestroyAllWindows();

	return 0;

}

////////////////////////////////////////////////////////////////////////////

Если закомментируешь строку #define USE_BINARY_TEMPL, то сравнение будет идти с цветной клеткой (cell_cl.png), иначе с чёрно-белой бинаризованной (cell.png). Примеры клеток шаблонов:

post-391-0-00771400-1295463429_thumb.png

post-391-0-46393200-1295463439_thumb.png

Share this post


Link to post
Share on other sites

Есть задачка:

Есть изображения с органами человека. На картинке нужно распознавать органы. То есть если там сердце, программа должна выделить и подписать "сердце".

Не подскажешь каким методом лучше реализовать?

1 Думаю использовать обучение каскадов Хаара

2 Или как-нибудь задать шаблоны контуров и делать поиск по контурам.

Есть какие-нибудь идеи?

То есть суть задачи пользователь задает какой-то шаблон и дает название. На изображении по шаблону ищутся объекты. Сложность в том объект может отображаться по-разному.

Share this post


Link to post
Share on other sites

Спасибо!

1 SURF мне точно не подойдет.

2 каскадов Хаара - если только самому обучить все органы и ищет он все равно слабо. А так если сделать какой-то конструктор, что бы пользователь сам мог обучать, но обучение долго идет.

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

Есть ли какие-нибудь решения, которые более менее ищут объекты? Что бы можно было ввести либо параметры или шаблоны какие-то, а по ним уже поиск делать.

PS: Много битых ссылок на страницах.

Share this post


Link to post
Share on other sites

Ссылки посмотрю. Форум падал как то, до сих пор разгребаю.

По поводу SURF , я бы подумал. На счет Хаара это Вы правильно решили.

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

Часто для выделения органов на медицинских изображениях используют Active Appeareance Models (AAM), Active Shape Models (ASM), и змеиные алгоритмы.

Вот ссылки:

http://www.scs.ryerson.ca/tmcinern/mypapers/papers.html

http://www.lumc.nl/con/1010/83058/87377/87386/904011158482222/

Можно подгонять еще и трехмерные модели (параметрические), но для этого надо их создать.

Share this post


Link to post
Share on other sites

непонятно как у вас выглядят эти органы, как они могут варьироваться и т.д.

Share this post


Link to post
Share on other sites

рентгеновские снимки. К примеру сердце. Вид сердца на картинке может быть разный.

Хотелось сделать, что-то универсальное. Что бы можно было через какой-то конструктор задавать шаблон и по нему был бы поиск.

Я понял уже что так сделать не просто. Скорее всего придется для каждого органа писать свой алгоритм распознавания.

Share this post


Link to post
Share on other sites

если они имеют non-rigid форму, то да будет сложно, то что выше обозначено

Часто для выделения органов на медицинских изображениях используют Active Appeareance Models (AAM), Active Shape Models (ASM), и змеиные алгоритмы.

наверно может помочь.

Share this post


Link to post
Share on other sites

Вот тут посмотрите, может пригодится:

http://www.compvision.ru/forum/index.php?showtopic=443

это не то, так как мне поиск надо делать. То есть будет поиск либо по алгоритму или по шаблону для нужного органа.

Сейчас вот смотрю Active Appeareance Models, Active Shape Models (ASM).

Или думаю использовать SURF, только сравнивать не с одной картинкой, а с несколькими в разных положениях.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×