diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index 6d2c2bc0a0..60ece04036 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,35 +1,35 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag aa68beed) + set(revision_tag e44055a4) # ^^^^^^^^ these are just to check correct length of hash part ExternalProject_Add(${proj} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${ep_source_dir}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/Modules/OpenCVVideoSupport/CMakeLists.txt b/Modules/OpenCVVideoSupport/CMakeLists.txt index 8279580c0d..87c1edd38c 100644 --- a/Modules/OpenCVVideoSupport/CMakeLists.txt +++ b/Modules/OpenCVVideoSupport/CMakeLists.txt @@ -1,25 +1,24 @@ - if(MITK_USE_OpenCV) set(dependencies OpenCV) if(MITK_USE_videoInput) - set(dependencies ${dependencies} videoInput) + set(dependencies ${dependencies} videoInput) endif(MITK_USE_videoInput) MITK_CREATE_MODULE(mitkOpenCVVideoSupport + INCLUDE_DIRS Commands DEPENDS Mitk MitkExt PACKAGE_DEPENDS ${dependencies} ADDITIONAL_LIBS ${OPENCVVIDEOSUPPORT_ADDITIONAL_LIBS} EXPORT_DEFINE MITK_OPENCVVIDEOSUPPORT_EXPORT ) - + if(MITK_USE_QT) add_subdirectory(UI) - endif(MITK_USE_QT) - + endif(MITK_USE_QT) + if(BUILD_TESTING) add_subdirectory(Testing) endif(BUILD_TESTING) endif(MITK_USE_OpenCV) - diff --git a/Modules/OpenCVVideoSupport/Commands/mitkAbstractOpenCVImageFilter.cpp b/Modules/OpenCVVideoSupport/Commands/mitkAbstractOpenCVImageFilter.cpp new file mode 100644 index 0000000000..13d644b49f --- /dev/null +++ b/Modules/OpenCVVideoSupport/Commands/mitkAbstractOpenCVImageFilter.cpp @@ -0,0 +1,17 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkAbstractOpenCVImageFilter.h" diff --git a/Modules/OpenCVVideoSupport/Commands/mitkAbstractOpenCVImageFilter.h b/Modules/OpenCVVideoSupport/Commands/mitkAbstractOpenCVImageFilter.h new file mode 100644 index 0000000000..b709869360 --- /dev/null +++ b/Modules/OpenCVVideoSupport/Commands/mitkAbstractOpenCVImageFilter.h @@ -0,0 +1,57 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkCropOpenCVImageFilter_h +#define mitkCropOpenCVImageFilter_h + +#include "mitkOpenCVVideoSupportExports.h" + +#include + +//itk headers +#include + +namespace cv { +class Mat; +} + +namespace mitk { + +/** + * \brief Interface for image filters on OpenCV images. + * + * Every concrete filter has to implement the pure virual + * mitk::AbstractOpenCVImageFilter::filterImage() method. + * + */ +class MITK_OPENCVVIDEOSUPPORT_EXPORT AbstractOpenCVImageFilter : public itk::Object +{ + +public: + mitkClassMacro(AbstractOpenCVImageFilter, itk::Object); + + /** + * \brief Pure virtual method for filtering an image. + * + * \param image OpenCV image which is supposed to be manipulated. + * \return true if filtering was successfull, false otherwise + */ + virtual bool FilterImage( cv::Mat& image ) = 0; +}; + +} // namespace mitk + +#endif // mitkCropOpenCVImageFilter_h diff --git a/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.cpp b/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.cpp new file mode 100644 index 0000000000..3e73885fe1 --- /dev/null +++ b/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.cpp @@ -0,0 +1,36 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkConvertGrayscaleOpenCVImageFilter.h" + +#include "cv.h" + +namespace mitk { + +bool ConvertGrayscaleOpenCVImageFilter::FilterImage( cv::Mat& image ) +{ + cv::Mat buffer; + + cv::cvtColor(image, buffer, CV_RGB2GRAY, 1); + + // content of buffer should now be the conten of image + image.release(); + image = buffer; + + return true; +} + +} // namespace mitk diff --git a/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.h b/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.h new file mode 100644 index 0000000000..1311afc2bd --- /dev/null +++ b/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.h @@ -0,0 +1,43 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkConvertGrayscaleOpenCVImageFilter_h +#define mitkConvertGrayscaleOpenCVImageFilter_h + +#include "mitkAbstractOpenCVImageFilter.h" + +//itk headers +#include "itkObjectFactory.h" + +namespace mitk { + +class MITK_OPENCVVIDEOSUPPORT_EXPORT ConvertGrayscaleOpenCVImageFilter : public AbstractOpenCVImageFilter +{ + +public: + mitkClassMacro(ConvertGrayscaleOpenCVImageFilter, AbstractOpenCVImageFilter); + itkNewMacro(Self); + + /** + * \brief Converts given image to grayscale. + * \return always true + */ + bool FilterImage( cv::Mat& image ); +}; + +} // namespace mitk + +#endif // mitkConvertGrayscaleOpenCVImageFilter_h diff --git a/Modules/OpenCVVideoSupport/Commands/mitkCropOpenCVImageFilter.cpp b/Modules/OpenCVVideoSupport/Commands/mitkCropOpenCVImageFilter.cpp new file mode 100644 index 0000000000..eba3656c55 --- /dev/null +++ b/Modules/OpenCVVideoSupport/Commands/mitkCropOpenCVImageFilter.cpp @@ -0,0 +1,100 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkCropOpenCVImageFilter.h" + +#include "cv.h" + +namespace mitk { + +CropOpenCVImageFilter::CropOpenCVImageFilter( ) + : m_NewCropRegionSet(false) +{ + +} + +bool CropOpenCVImageFilter::FilterImage( cv::Mat& image ) +{ + if (m_CropRegion.width == 0) + { + MITK_ERROR("AbstractOpenCVImageFilter")("CropOpenCVImageFilter") + << "Cropping cannot be done without setting a non-empty crop region first."; + return false; + } + + // We can try and correct too large boundaries (do this only once + // after a new crop region was set. + if (m_NewCropRegionSet) + { + m_NewCropRegionSet = false; + + if ( m_CropRegion.x + m_CropRegion.width > image.size().width) + { + m_CropRegion.width = image.size().width - m_CropRegion.x; + MITK_WARN("AbstractOpenCVImageFilter")("CropOpenCVImageFilter") + << "Changed too large roi in x direction to fit the image size."; + } + if ( m_CropRegion.y + m_CropRegion.height > image.size().height) + { + m_CropRegion.height = image.size().height - m_CropRegion.y; + MITK_WARN("AbstractOpenCVImageFilter")("CropOpenCVImageFilter") + << "Changed too large roi in y direction to fit the image size."; + } + } + + cv::Mat buffer = image(m_CropRegion); + image.release(); + image = buffer; + + return true; +} + +void CropOpenCVImageFilter::SetCropRegion( cv::Rect cropRegion ) +{ + // First, let's do some basic checks to make sure rectangle is inside of actual image + if (cropRegion.x < 0) + { + MITK_WARN("AbstractOpenCVImageFilter")("CropOpenCVImageFilter") + << "Changed negative x value in roi to 0."; + cropRegion.x = 0; + } + if (cropRegion.y < 0) + { + cropRegion.y = 0; + MITK_WARN("AbstractOpenCVImageFilter")("CropOpenCVImageFilter") + << "Changed negative y value in roi to 0."; + } + + // Nothing to save, throw an exception + if ( cropRegion.height < 0 || cropRegion.width < 0 ) + { + mitkThrow() << "Invalid boundaries supplied to USImageVideoSource::SetRegionOfInterest()"; + } + + m_CropRegion = cropRegion; +} + +void CropOpenCVImageFilter::SetCropRegion( int topLeftX, int topLeftY, int bottomRightX, int bottomRightY ) +{ + this->SetCropRegion( cv::Rect(topLeftX, topLeftY, bottomRightX - topLeftX, bottomRightY - topLeftY) ); +} + +cv::Rect CropOpenCVImageFilter::GetCropRegion( ) +{ + return m_CropRegion; +} + +} // namespace mitk diff --git a/Modules/OpenCVVideoSupport/Commands/mitkCropOpenCVImageFilter.h b/Modules/OpenCVVideoSupport/Commands/mitkCropOpenCVImageFilter.h new file mode 100644 index 0000000000..8f96965c40 --- /dev/null +++ b/Modules/OpenCVVideoSupport/Commands/mitkCropOpenCVImageFilter.h @@ -0,0 +1,73 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkAbstractOpenCVImageFilter_h +#define mitkAbstractOpenCVImageFilter_h + +#include "mitkAbstractOpenCVImageFilter.h" + +#include "cv.h" + +//itk headers +#include + +namespace mitk { + +class MITK_OPENCVVIDEOSUPPORT_EXPORT CropOpenCVImageFilter : public AbstractOpenCVImageFilter +{ + +public: + mitkClassMacro(CropOpenCVImageFilter, AbstractOpenCVImageFilter); + itkNewMacro(Self); + + CropOpenCVImageFilter( ); + + /** + * \brief Crops image to rectangle given by mitk::CropOpenCVImageFilter::SetCropRegion. + * \return false if no crop region was set or the crop region width is zero, true otherwise. + */ + bool FilterImage( cv::Mat& image ); + + /** + * \brief Set region of interest for cropping. + */ + void SetCropRegion( cv::Rect cropRegion ); + + /** + * \brief Set region of interest for cropping. + */ + void SetCropRegion( int topLeftX, int topLeftY, int bottomRightX, int bottomRightY ); + + /** + * \brief Returns region, which was set by mitk::CropOpenCVImageFilter::SetCropRegion(). + */ + cv::Rect GetCropRegion( ); + +protected: + /** + * \brief Defines the region which will be cropped from the image. + */ + cv::Rect m_CropRegion; + + /** + * \brief True if no image was filtered since last set of a crop region. + */ + bool m_NewCropRegionSet; +}; + +} // namespace mitk + +#endif // mitkAbstractOpenCVImageFilter_h diff --git a/Modules/OpenCVVideoSupport/Testing/CMakeLists.txt b/Modules/OpenCVVideoSupport/Testing/CMakeLists.txt index 8d43ce4a4d..21826cc97f 100644 --- a/Modules/OpenCVVideoSupport/Testing/CMakeLists.txt +++ b/Modules/OpenCVVideoSupport/Testing/CMakeLists.txt @@ -1,10 +1,18 @@ MITK_CREATE_MODULE_TESTS() IF(BUILD_TESTING AND MODULE_IS_ENABLED) mitkAddCustomModuleTest("mitkOpenCVMitkConversionTest" "mitkOpenCVMitkConversionTest" "${MITK_DATA_DIR}/ToF-Data/Kinect_LiverPhantom_DistanceImage.nrrd" "${MITK_DATA_DIR}/ToF-Data/Kinect_LiverPhantom_RGBImage.nrrd" "${MITK_DATA_DIR}/Png2D-bw.png" "${MITK_DATA_DIR}/NrrdWritingTestImage.jpg" ) -ENDIF(BUILD_TESTING AND MODULE_IS_ENABLED) \ No newline at end of file + mitkAddCustomModuleTest("mitkCropOpenCVImageFilterTest" "mitkCropOpenCVImageFilterTest" + "${MITK_DATA_DIR}/OpenCV-Data/BaseImage.png" + "${MITK_DATA_DIR}/OpenCV-Data/CroppedImage.png" + ) + mitkAddCustomModuleTest("mitkConvertGrayscaleOpenCVImageFilterTest" "mitkConvertGrayscaleOpenCVImageFilterTest" + "${MITK_DATA_DIR}/OpenCV-Data/BaseImage.png" + "${MITK_DATA_DIR}/OpenCV-Data/GrayscaleImage.png" + ) +ENDIF(BUILD_TESTING AND MODULE_IS_ENABLED) diff --git a/Modules/OpenCVVideoSupport/Testing/files.cmake b/Modules/OpenCVVideoSupport/Testing/files.cmake index 396c39d368..397c0ad023 100644 --- a/Modules/OpenCVVideoSupport/Testing/files.cmake +++ b/Modules/OpenCVVideoSupport/Testing/files.cmake @@ -1,5 +1,8 @@ SET(MODULE_TESTS ) + SET(MODULE_CUSTOM_TESTS mitkOpenCVMitkConversionTest.cpp -) \ No newline at end of file + mitkConvertGrayscaleOpenCVImageFilterTest.cpp + mitkCropOpenCVImageFilterTest.cpp +) diff --git a/Modules/OpenCVVideoSupport/Testing/mitkConvertGrayscaleOpenCVImageFilterTest.cpp b/Modules/OpenCVVideoSupport/Testing/mitkConvertGrayscaleOpenCVImageFilterTest.cpp new file mode 100644 index 0000000000..bcea7a2908 --- /dev/null +++ b/Modules/OpenCVVideoSupport/Testing/mitkConvertGrayscaleOpenCVImageFilterTest.cpp @@ -0,0 +1,55 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkConvertGrayscaleOpenCVImageFilter.h" +#include + +#include +#include + +static void ConvertTestLoadedImage(std::string mitkImagePath, std::string mitkGrayscaleImagePath) +{ + cv::Mat image = cvLoadImage(mitkImagePath.c_str()); + cv::Mat compareImg = cvLoadImage(mitkGrayscaleImagePath.c_str()); + + // directly convert the image for comparison + cv::Mat comparisonImg; + cv::cvtColor(compareImg, comparisonImg, CV_RGB2GRAY, 1); + + mitk::ConvertGrayscaleOpenCVImageFilter::Pointer grayscaleFilter + = mitk::ConvertGrayscaleOpenCVImageFilter::New(); + + MITK_TEST_CONDITION(grayscaleFilter->FilterImage(image), "Filtering should return true for success."); + + MITK_TEST_CONDITION(image.channels() == 1, "Image must not have more than one channel after grayscale conversion."); + + MITK_TEST_CONDITION(cv::countNonZero(image != comparisonImg) == 0, "All pixel values must be the same between the two converted images."); +} + +/**Documentation + * test for the class "ConvertGrayscaleOpenCVImageFilter". + */ +int mitkConvertGrayscaleOpenCVImageFilterTest(int argc, char* argv[]) +{ + MITK_TEST_BEGIN("ConvertGrayscaleOpenCVImageFilter") + + MITK_TEST_CONDITION_REQUIRED(argc > 2, "At least three parameters needed for this test.") + + ConvertTestLoadedImage(argv[1], argv[2]); + + MITK_TEST_END(); // always end with this! + +} diff --git a/Modules/OpenCVVideoSupport/Testing/mitkCropOpenCVImageFilterTest.cpp b/Modules/OpenCVVideoSupport/Testing/mitkCropOpenCVImageFilterTest.cpp new file mode 100644 index 0000000000..54a5079e8b --- /dev/null +++ b/Modules/OpenCVVideoSupport/Testing/mitkCropOpenCVImageFilterTest.cpp @@ -0,0 +1,87 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkCropOpenCVImageFilter.h" +#include + +#include +#include + +static bool ImagesAreEqualInGray(const cv::Mat& img1, const cv::Mat& img2) +{ + cv::Mat grayImg1; + cv::Mat grayImg2; + + cv::cvtColor(img1, grayImg1, CV_RGB2GRAY, 1); + cv::cvtColor(img2, grayImg2, CV_RGB2GRAY, 1); + + return cv::countNonZero(grayImg1 != grayImg2) == 0; +} + +static void CropTestLoadedImage(std::string mitkImagePath, std::string mitkCroppedImagePath) +{ + cv::Mat image = cvLoadImage(mitkImagePath.c_str()); + cv::Mat croppedImage = cvLoadImage(mitkCroppedImagePath.c_str()); + + MITK_INFO << mitkImagePath.c_str(); + MITK_INFO << mitkCroppedImagePath.c_str(); + + mitk::CropOpenCVImageFilter::Pointer cropFilter = mitk::CropOpenCVImageFilter::New(); + + // try to crop without setting a region of interest + cv::Mat testImage = image.clone(); + MITK_TEST_CONDITION( ! cropFilter->FilterImage(testImage), "Filter function must return false if no region of interest is set."); + MITK_TEST_CONDITION(ImagesAreEqualInGray(testImage, image), "Image should not be changed yet."); + + // set region of interst now and then try to crop again + cv::Rect roi = cv::Rect(0,0, testImage.cols, testImage.rows); + cropFilter->SetCropRegion(roi); + MITK_TEST_CONDITION(cropFilter->FilterImage(testImage), "Filter function should return successfully."); + MITK_TEST_CONDITION(ImagesAreEqualInGray(testImage, image), "Image should not be changed if cropping with a roi of the whole image."); + + // test if filter corrects negative roi position + cv::Rect roiWrong = cv::Rect(-1,-1, 2, 2); + roi = cv::Rect(0,0,2,2); + cropFilter->SetCropRegion(roiWrong); + MITK_TEST_CONDITION(cropFilter->FilterImage(testImage), "Filter function should return successfully."); + MITK_TEST_CONDITION(ImagesAreEqualInGray(testImage, image(roi)), "Image should be equal to directly cropped image whith correct roi."); + + // test whith "normal" roi + testImage = image.clone(); + roi = cv::Rect( 150,100,100,100 ); + cropFilter->SetCropRegion(roi); + MITK_TEST_CONDITION(cropFilter->FilterImage(testImage), "Filter function should return successfully."); + MITK_TEST_CONDITION(ImagesAreEqualInGray(testImage, croppedImage), "Image should be equal to cropped image (loaded from data directory)."); + + // test with not correctable roi + roiWrong = cv::Rect( 5,5,-1,-1 ); + MITK_TEST_FOR_EXCEPTION(mitk::Exception, cropFilter->SetCropRegion(roiWrong)); +} + +/**Documentation + * test for the class "CropOpenCVImageFilter". + */ +int mitkCropOpenCVImageFilterTest(int argc, char* argv[]) +{ + MITK_TEST_BEGIN("CropOpenCVImageFilter") + + MITK_TEST_CONDITION_REQUIRED(argc > 2, "At least three parameters needed for this test."); + + CropTestLoadedImage(argv[1], argv[2]); + + MITK_TEST_END(); // always end with this! + +} diff --git a/Modules/OpenCVVideoSupport/files.cmake b/Modules/OpenCVVideoSupport/files.cmake index fd1990a304..11585fa4e6 100644 --- a/Modules/OpenCVVideoSupport/files.cmake +++ b/Modules/OpenCVVideoSupport/files.cmake @@ -1,14 +1,17 @@ set(CPP_FILES mitkMovieGeneratorOpenCV.cpp mitkUndistortCameraImage.cpp mitkOpenCVVideoSource.cpp mitkOpenCVToMitkImageFilter.cpp mitkImageToOpenCVImageFilter.cpp + Commands/mitkAbstractOpenCVImageFilter.cpp + Commands/mitkConvertGrayscaleOpenCVImageFilter.cpp + Commands/mitkCropOpenCVImageFilter.cpp ) if(MITK_USE_videoInput) set(CPP_FILES ${CPP_FILES} mitkVideoInputSource.cpp ) endif(MITK_USE_videoInput) \ No newline at end of file diff --git a/Modules/US/USFilters/mitkUSImageVideoSource.cpp b/Modules/US/USFilters/mitkUSImageVideoSource.cpp index cb197fbc71..7593c7c023 100644 --- a/Modules/US/USFilters/mitkUSImageVideoSource.cpp +++ b/Modules/US/USFilters/mitkUSImageVideoSource.cpp @@ -1,175 +1,161 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // MITK HEADER #include "mitkUSImageVideoSource.h" #include "mitkImage.h" +#include "mitkCropOpenCVImageFilter.h" +#include "mitkConvertGrayscaleOpenCVImageFilter.h" //OpenCV HEADER #include #include //Other #include mitk::USImageVideoSource::USImageVideoSource() : itk::Object(), m_VideoCapture(new cv::VideoCapture()), m_IsVideoReady(false), m_IsGreyscale(false), m_OpenCVToMitkFilter(mitk::OpenCVToMitkImageFilter::New()), m_ResolutionOverrideWidth(0), m_ResolutionOverrideHeight(0), -m_ResolutionOverride(false) +m_ResolutionOverride(false), +m_ImageFilter(0), +m_GrayscaleFilter(mitk::ConvertGrayscaleOpenCVImageFilter::New()), +m_CropFilter(mitk::CropOpenCVImageFilter::New()) { m_OpenCVToMitkFilter->SetCopyBuffer(false); } mitk::USImageVideoSource::~USImageVideoSource() { } void mitk::USImageVideoSource::SetVideoFileInput(std::string path) { m_VideoCapture->open(path.c_str()); if(!m_VideoCapture->isOpened()) // check if we succeeded m_IsVideoReady = false; else m_IsVideoReady = true; // If Override is enabled, use it if (m_ResolutionOverride) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, this->m_ResolutionOverrideWidth); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, this->m_ResolutionOverrideHeight); } } void mitk::USImageVideoSource::SetCameraInput(int deviceID) { m_VideoCapture->open(deviceID); if(!m_VideoCapture->isOpened()) // check if we succeeded m_IsVideoReady = false; else m_IsVideoReady = true; // If Override is enabled, use it if (m_ResolutionOverride) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, this->m_ResolutionOverrideWidth); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, this->m_ResolutionOverrideHeight); } } void mitk::USImageVideoSource::SetColorOutput(bool isColor){ m_IsGreyscale = !isColor; } int mitk::USImageVideoSource::GetImageHeight() { if (m_VideoCapture) return m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT); else return 0; } int mitk::USImageVideoSource::GetImageWidth() { if (m_VideoCapture) return m_VideoCapture->get(CV_CAP_PROP_FRAME_WIDTH); else return 0; } bool mitk::USImageVideoSource::GetIsReady() { if (!m_VideoCapture) return false; return m_VideoCapture->isOpened(); } void mitk::USImageVideoSource::SetRegionOfInterest(int topLeftX, int topLeftY, int bottomRightX, int bottomRightY) { - // First, let's do some basic checks to make sure rectangle is inside of actual image - if (topLeftX < 0) topLeftX = 0; - if (topLeftY < 0) topLeftY = 0; - - // We can try and correct too large boundaries - if (bottomRightX > m_VideoCapture->get(CV_CAP_PROP_FRAME_WIDTH)) bottomRightX = m_VideoCapture->get(CV_CAP_PROP_FRAME_WIDTH); - if (bottomRightY > m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT)) bottomRightY = m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT); - - // Nothing to save, throw an exception - if (topLeftX > bottomRightX) mitkThrow() << "Invalid boundaries supplied to USImageVideoSource::SetRegionOfInterest()"; - if (topLeftY > bottomRightY) mitkThrow() << "Invalid boundaries supplied to USImageVideoSource::SetRegionOfInterest()"; - - m_CropRegion = cv::Rect(topLeftX, topLeftY, bottomRightX - topLeftX, bottomRightY - topLeftY); + m_CropFilter->SetCropRegion(topLeftX, topLeftY, bottomRightX, bottomRightY); + m_IsCropped = true; } void mitk::USImageVideoSource::RemoveRegionOfInterest(){ - m_CropRegion.width = 0; - m_CropRegion.height = 0; + m_IsCropped = false; } mitk::USImage::Pointer mitk::USImageVideoSource::GetNextImage() { // Loop video if necessary if (m_VideoCapture->get(CV_CAP_PROP_POS_AVI_RATIO) >= 0.99 ) m_VideoCapture->set(CV_CAP_PROP_POS_AVI_RATIO, 0); // Setup pointers cv::Mat image; - cv::Mat buffer; // Retrieve image *m_VideoCapture >> image; // get a new frame from camera - // if Region of interest is set, crop image - if (m_CropRegion.width > 0){ - buffer = image(m_CropRegion); - image.release(); - image = buffer; - } + // If region of interest was set, crop image + if ( m_IsCropped ) { m_CropFilter->FilterImage(image); } + // If this source is set to deliver greyscale images, convert it - if (m_IsGreyscale) - { - cv::cvtColor(image, buffer, CV_RGB2GRAY, 1); - image.release(); - image = buffer; - } + if ( m_IsGreyscale ) { m_GrayscaleFilter->FilterImage(image); } + + // Execute filter, if an additional filter is specified + if ( m_ImageFilter.IsNotNull() ) { m_ImageFilter->FilterImage(image); } // Convert to MITK-Image IplImage ipl_img = image; this->m_OpenCVToMitkFilter->SetOpenCVImage(&ipl_img); this->m_OpenCVToMitkFilter->Update(); // OpenCVToMitkImageFilter returns a standard mitk::image. We then transform it into an USImage mitk::USImage::Pointer result = mitk::USImage::New(this->m_OpenCVToMitkFilter->GetOutput()); // Clean up - buffer.release(); image.release(); return result; } void mitk::USImageVideoSource::OverrideResolution(int width, int height){ this->m_ResolutionOverrideHeight = height; this->m_ResolutionOverrideWidth = width; if (m_VideoCapture != 0) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, width); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, height); } } diff --git a/Modules/US/USFilters/mitkUSImageVideoSource.h b/Modules/US/USFilters/mitkUSImageVideoSource.h index 9a1b9dcff9..89a36f96e9 100644 --- a/Modules/US/USFilters/mitkUSImageVideoSource.h +++ b/Modules/US/USFilters/mitkUSImageVideoSource.h @@ -1,153 +1,164 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKUSImageVideoSource_H_HEADER_INCLUDED_ #define MITKUSImageVideoSource_H_HEADER_INCLUDED_ // ITK #include // MITK #include "mitkUSImage.h" #include "mitkOpenCVToMitkImageFilter.h" +#include "Commands/mitkConvertGrayscaleOpenCVImageFilter.h" +#include "Commands/mitkCropOpenCVImageFilter.h" // OpenCV #include namespace mitk { /**Documentation * \brief This class can be pointed to a video file or a videodevice and delivers USImages. * * Images are in color by default, but can be set to greyscale via SetColorOutput(false), * which significantly improves performance. * * Images can also be cropped to a region of interest, further increasing performance. * * \ingroup US */ class MitkUS_EXPORT USImageVideoSource : public itk::Object { public: mitkClassMacro(USImageVideoSource, itk::ProcessObject); itkNewMacro(Self); /** * \brief Opens a video file for streaming. If nothing goes wrong, the * VideoSource is ready to deliver images after calling this function. */ void SetVideoFileInput(std::string path); /** * \brief Opens a video device for streaming. Takes the Device id. Try -1 for "grab the first you can get" * which works quite well if only one device is available. If nothing goes wrong, the * VideoSource is ready to deliver images after calling this function. */ void SetCameraInput(int deviceID); /** * \brief Sets the output image to rgb or grayscale. * Output is color by default * and can be set to color by passing true, or to grayscale again by passing false. */ void SetColorOutput(bool isColor); /** * /brief Defines the cropping area. The rectangle will be justified to the image borders * if the given rectangle is larger than the video source. If a correct rectangle is given, * The dimensions of the output image will be equal to those of the rectangle. */ void SetRegionOfInterest(int topLeftX, int topLeftY, int bottomRightX, int bottomRightY); /** * /brief Removes the region of interest. Produced images will be uncropped after call. */ void RemoveRegionOfInterest(); /** * \brief Retrieves the next frame. This will typically be the next frame in a file * or the last cached file in a device. */ mitk::USImage::Pointer GetNextImage(); /** * \brief This is a workaround for a problem that happens with some video device drivers. * * If you encounter OpenCV Warnings that buffer sizes do not match while calling getNextFrame, * then do the following: Using the drivers control panel to force a certain resolution, then call * this method with the same Dimensions after opening the device. * Before retrieving images one should call mitk::USImageVideoSource::isReady(). */ void OverrideResolution(int width, int height); // Getter & Setter itkGetMacro(IsVideoReady, bool); itkGetMacro(ResolutionOverride, bool); itkSetMacro(ResolutionOverride, bool); itkGetMacro(IsGreyscale,bool); itkGetMacro(ResolutionOverrideWidth,int); itkGetMacro(ResolutionOverrideHeight,int); int GetImageHeight(); int GetImageWidth(); + itkGetMacro(ImageFilter, mitk::AbstractOpenCVImageFilter::Pointer); + itkSetMacro(ImageFilter, mitk::AbstractOpenCVImageFilter::Pointer); /** * \brief Returns true if images can be delivered. * * Only if true is returned one can retrieve images via mitk::USImageVideoSource::GetNextImage(). * If false is returned, behaviour is undefined. */ bool GetIsReady(); protected: USImageVideoSource(); virtual ~USImageVideoSource(); /** * \brief The source of the video, managed internally */ cv::VideoCapture* m_VideoCapture; /** * \brief If true, a frame can be grabbed anytime. */ bool m_IsVideoReady; /** * \brief If true, image output will be greyscale. */ bool m_IsGreyscale; /** - * \brief If values inside are nonzero, this rectangle will be cropped from the stream and used as an output. - * Used to mark Region of Interest. + * \brief If true, image will be cropped according to settings of crop filter. */ - cv::Rect m_CropRegion; + bool m_IsCropped; /** * \brief Used to convert from OpenCV Images to MITK Images. */ mitk::OpenCVToMitkImageFilter::Pointer m_OpenCVToMitkFilter; /** * These Variables determined whether Resolution Override is on, what dimensions to use. */ int m_ResolutionOverrideWidth; int m_ResolutionOverrideHeight; bool m_ResolutionOverride; + /** + * \brief Filter is executed during mitk::USImageVideoSource::GetNextImage(). + */ + AbstractOpenCVImageFilter::Pointer m_ImageFilter; + + ConvertGrayscaleOpenCVImageFilter::Pointer m_GrayscaleFilter; + CropOpenCVImageFilter::Pointer m_CropFilter; + }; } // namespace mitk #endif /* MITKUSImageVideoSource_H_HEADER_INCLUDED_ */