18 #include "itkMultiThreader.h" 19 #include "itkFastMutexLock.h" 20 #include "itkConditionVariable.h" 22 #include <opencv2/imgproc.hpp> 28 #define GMM_COMPONENTS_COUNT 5 31 : m_ModelPointsDilationSize(0),
32 m_UseOnlyRegionAroundModelPoints(false),
33 m_CurrentProcessImageNum(0),
36 m_ThreadId(-1), m_StopThread(false),
37 m_MultiThreader(
itk::MultiThreader::New()),
38 m_WorkerBarrier(
itk::ConditionVariable::New()),
39 m_ImageMutex(
itk::FastMutexLock::New()),
40 m_ResultMutex(
itk::FastMutexLock::New()),
41 m_PointSetsMutex(
itk::FastMutexLock::New())
43 m_ThreadId = m_MultiThreader->SpawnThread(this->SegmentationWorker,
this);
50 m_WorkerBarrier->Broadcast();
51 if ( m_ThreadId >= 0) { m_MultiThreader->TerminateThread(m_ThreadId); }
64 if (image.type() != CV_8UC3)
66 cv::Mat tmp = image.clone();
67 cv::cvtColor(tmp, image, CV_GRAY2RGB);
75 m_ImageMutex->Unlock();
86 m_PointSetsMutex->Lock();
88 m_PointSetsMutex->Unlock();
93 m_PointSetsMutex->Lock();
96 m_PointSetsMutex->Unlock();
101 m_PointSetsMutex->Lock();
103 m_PointSetsMutex->Unlock();
108 m_PointSetsMutex->Lock();
111 m_PointSetsMutex->Unlock();
116 if ( modelPointsDilationSize < 0 )
118 MITK_ERROR(
"AbstractOpenCVImageFilter")(
"GrabCutOpenCVImageFilter")
119 <<
"Model points dilation size must not be smaller then zero.";
120 mitkThrow() <<
"Model points dilation size must not be smaller then zero.";
151 m_ResultMutex->Lock();
153 m_ResultMutex->Unlock();
160 std::vector<std::vector<cv::Point> > cvContours;
161 std::vector<cv::Vec4i> hierarchy;
162 std::vector<mitk::GrabCutOpenCVImageFilter::ModelPointsList> contourPoints;
165 if (resultMask.empty()) {
return contourPoints; }
167 cv::findContours(resultMask, cvContours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
170 for (
unsigned int i = 0; i < cvContours.size(); ++i )
174 for (
auto it = cvContours[i].begin();
175 it != cvContours[i].end(); ++it)
178 index.SetElement(0, it->x);
179 index.SetElement(1, it->y);
180 curContourPoints.push_back(index);
183 contourPoints.push_back(curContourPoints);
186 return contourPoints;
195 if (pixelIndex.GetElement(0) < 0 || pixelIndex.GetElement(0) >= mask.size().height
196 || pixelIndex.GetElement(1) < 0 || pixelIndex.GetElement(1) >= mask.size().width)
198 MITK_WARN(
"AbstractOpenCVImageFilter")(
"GrabCutOpenCVImageFilter")
199 <<
"Given pixel index ("<< pixelIndex.GetElement(0) <<
", " << pixelIndex.GetElement(1)
200 <<
") is outside the image (" << mask.size().height <<
", " << mask.size().width <<
").";
207 cv::floodFill(mask, cv::Point(pixelIndex.GetElement(0), pixelIndex.GetElement(1)), 5);
209 cv::Mat foregroundMask;
213 std::vector<std::vector<cv::Point> > cvContours;
214 std::vector<cv::Vec4i> hierarchy;
215 cv::findContours(foregroundMask, cvContours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
220 for (
auto it = cvContours[0].begin();
221 it != cvContours[0].end(); ++it)
224 index.SetElement(0, it->x);
225 index.SetElement(1, it->y);
226 contourPoints.push_back(index);
229 return contourPoints;
238 m_PointSetsMutex->Lock();
240 m_PointSetsMutex->Unlock();
243 unsigned int pixelValues[2] = {cv::GC_FGD, cv::GC_BGD};
245 for (
unsigned int n = 0; n < 2; ++n)
247 for (
auto it = pointsLists[n].begin();
248 it != pointsLists[n].end(); ++it)
256 int x = it->GetElement(1) + i;
int y = it->GetElement(0) + j;
257 if ( x >= 0 && y >= 0 && x <
mask.cols && y <
mask.rows)
259 mask.at<
unsigned char>(x, y) = pixelValues[n];
271 cv::Mat nonPropablyBackgroundMask, modelPoints;
272 cv::compare(mask, cv::GC_PR_BGD, nonPropablyBackgroundMask, cv::CMP_NE);
273 cv::findNonZero(nonPropablyBackgroundMask, modelPoints);
275 if (modelPoints.empty())
277 MITK_WARN(
"AbstractOpenCVImageFilter")(
"GrabCutOpenCVImageFilter")
278 <<
"Cannot find any foreground points. Returning full image size as bounding rectangle.";
279 return cv::Rect(0, 0, mask.rows, mask.cols);
283 cv::Rect boundingRect = cv::boundingRect(modelPoints);
291 if ( static_cast<unsigned int>(boundingRect.x + boundingRect.width)
292 + 2 * m_AdditionalWidth < static_cast<unsigned int>(mask.size().width) )
298 boundingRect.width = mask.size().width - boundingRect.x - 1;
303 if ( static_cast<unsigned int>(boundingRect.y + boundingRect.height)
310 boundingRect.height = mask.size().height - boundingRect.y - 1;
313 assert(boundingRect.x + boundingRect.width < mask.size().width);
314 assert(boundingRect.y + boundingRect.height < mask.size().height);
322 cv::Mat compareFgResult, compareBgResult;
323 cv::compare(mask, cv::GC_FGD, compareFgResult, cv::CMP_EQ);
324 cv::compare(mask, cv::GC_PR_BGD, compareBgResult, cv::CMP_EQ);
329 return cv::Mat::zeros(mask.size(), mask.type());
333 cv::Mat bgdModel, fgdModel;
334 cv::grabCut(input, mask, cv::Rect(), bgdModel, fgdModel, 1, cv::GC_INIT_WITH_MASK);
338 cv::compare(mask, cv::GC_PR_FGD, result, cv::CMP_EQ);
341 cv::Mat foregroundMat;
342 cv::compare(mask, cv::GC_FGD, foregroundMat, cv::CMP_EQ);
343 foregroundMat.copyTo(result, foregroundMat);
351 cv::findNonZero(mask, points);
355 for (
size_t n = 0; n < points.total(); ++n)
358 index.SetElement(0, points.at<cv::Point>(n).x);
359 index.SetElement(1, points.at<cv::Point>(n).y);
360 pointsVector.push_back(index);
366 ITK_THREAD_RETURN_TYPE mitk::GrabCutOpenCVImageFilter::SegmentationWorker(
void* pInfoStruct)
369 struct itk::MultiThreader::ThreadInfoStruct * pInfo = (
struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
372 itk::SimpleMutexLock mutex;
377 if (thisObject->m_StopThread) {
break; }
379 thisObject->m_WorkerBarrier->Wait(&mutex);
381 if (thisObject->m_StopThread) {
break; }
383 thisObject->m_ImageMutex->Lock();
386 thisObject->m_ImageMutex->Unlock();
393 result = cv::Mat(mask.rows, mask.cols, mask.type(), 0.0);
403 thisObject->m_ResultMutex->Lock();
406 thisObject->m_ResultMutex->Unlock();
411 return ITK_THREAD_RETURN_VALUE;
std::vector< itk::Index< 2 > > ModelPointsList
List holding image indices of the model points.
unsigned int m_AdditionalWidth
cv::Mat RunSegmentation(cv::Mat input, cv::Mat mask)
Performs a GrabCut segmentation of the given input image.
ModelPointsList ConvertMaskToModelPointsList(cv::Mat mask)
Creates a list of points from every non-zero pixel of the given mask.
int m_ResultImageId
id of the image which segmentation result is currently present in m_ResultMask
std::vector< ModelPointsList > GetResultContours()
Getter for the contours of the current segmentation.
cv::Rect GetBoundingRectFromMask(cv::Mat mask)
Creates a bounding box around all pixels which aren't propably background. The bounding box is widene...
ModelPointsList m_ForegroundPoints
bool m_UseOnlyRegionAroundModelPoints
bool OnFilterImage(cv::Mat &image) override
Implementation of the virtual image filtering method. The input image is copied to a member attribute...
ModelPointsList GetResultContourWithPixel(itk::Index< 2 > pixelIndex)
Getter for one specific contour of the current segmentation.
void SetUseFullImage()
The full image is used as input for the segmentation. This method sets the behaviour back to the defa...
cv::Mat GetMaskFromPointSets()
Creates an image mask for GrabCut algorithm by using the foreground and background point sets...
GrabCutOpenCVImageFilter()
void SetModelPoints(ModelPointsList foregroundPoints)
Sets a list of image indices as foreground model points.
ModelPointsList m_BackgroundPoints
Makes the OpenCV GrabCut filter available as OpenCVImageFilter.
bool compare(std::pair< double, int > i, std::pair< double, int > j)
#define GMM_COMPONENTS_COUNT
cv::Rect GetRegionAroundModelPoints()
Getter for the rectangle used for the area of segmentation. See mitk::GrabCutOpenCVImageFilter::SetUs...
void SetModelPointsDilationSize(int modelPointsDilationSize)
Set a size of which each model point is dilated before image filtering. The more color information of...
mitk::Image::Pointer image
Interface for image filters on OpenCV images.
void SetUseOnlyRegionAroundModelPoints(unsigned int additionalBorder)
Use only the region around the foreground model points for the segmentation.
~GrabCutOpenCVImageFilter() override
cv::Mat GetResultMask()
Getter for the result mask of the current segmentation. The result of this method is not necessarily ...
mitk::Image::Pointer mask
int m_InputImageId
id of the image currently set as m_InputImage
int GetResultImageId()
Getter for an ascending id of the current result image. The id will be increased for every segmentati...
int m_ModelPointsDilationSize