Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "opencv2/video/tracking.hpp"
- #include "opencv2/imgproc/imgproc.hpp"
- #include "opencv2/videoio/videoio.hpp"
- #include "opencv2/highgui/highgui.hpp"
- #include "opencv2/imgcodecs.hpp"
- #include "opencv2/highgui.hpp"
- #include "opencv2/stitching.hpp"
- #include <iostream>
- #include <fstream>
- #include <ctype.h>
- using namespace cv;
- using namespace std;
- //! type of the kernel
- enum
- {
- KERNEL_GENERAL = 0, // the kernel is generic. No any type of symmetry or other properties.
- KERNEL_SYMMETRICAL = 1, // kernel[i] == kernel[ksize-i-1] , and the anchor is at the center
- KERNEL_ASYMMETRICAL = 2, // kernel[i] == -kernel[ksize-i-1] , and the anchor is at the center
- KERNEL_SMOOTH = 4, // all the kernel elements are non-negative and summed to 1
- KERNEL_INTEGER = 8 // all the kernel coefficients are integer numbers
- };
- /*!
- The Base Class for 1D or Row-wise Filters
- This is the base class for linear or non-linear filters that process 1D data.
- In particular, such filters are used for the "horizontal" filtering parts in separable filters.
- Several functions in OpenCV return Ptr<BaseRowFilter> for the specific types of filters,
- and those pointers can be used directly or within cv::FilterEngine.
- */
- class BaseRowFilter
- {
- public:
- //! the default constructor
- BaseRowFilter();
- //! the destructor
- virtual ~BaseRowFilter();
- //! the filtering operator. Must be overridden in the derived classes. The horizontal border interpolation is done outside of the class.
- virtual void operator()(const uchar* src, uchar* dst, int width, int cn) = 0;
- int ksize;
- int anchor;
- };
- /*!
- The Base Class for Column-wise Filters
- This is the base class for linear or non-linear filters that process columns of 2D arrays.
- Such filters are used for the "vertical" filtering parts in separable filters.
- Several functions in OpenCV return Ptr<BaseColumnFilter> for the specific types of filters,
- and those pointers can be used directly or within cv::FilterEngine.
- Unlike cv::BaseRowFilter, cv::BaseColumnFilter may have some context information,
- i.e. box filter keeps the sliding sum of elements. To reset the state BaseColumnFilter::reset()
- must be called (e.g. the method is called by cv::FilterEngine)
- */
- class BaseColumnFilter
- {
- public:
- //! the default constructor
- BaseColumnFilter();
- //! the destructor
- virtual ~BaseColumnFilter();
- //! the filtering operator. Must be overridden in the derived classes. The vertical border interpolation is done outside of the class.
- virtual void operator()(const uchar** src, uchar* dst, int dststep, int dstcount, int width) = 0;
- //! resets the internal buffers, if any
- virtual void reset();
- int ksize;
- int anchor;
- };
- /*!
- The Base Class for Non-Separable 2D Filters.
- This is the base class for linear or non-linear 2D filters.
- Several functions in OpenCV return Ptr<BaseFilter> for the specific types of filters,
- and those pointers can be used directly or within cv::FilterEngine.
- Similar to cv::BaseColumnFilter, the class may have some context information,
- that should be reset using BaseFilter::reset() method before processing the new array.
- */
- class BaseFilter
- {
- public:
- //! the default constructor
- BaseFilter();
- //! the destructor
- virtual ~BaseFilter();
- //! the filtering operator. The horizontal and the vertical border interpolation is done outside of the class.
- virtual void operator()(const uchar** src, uchar* dst, int dststep, int dstcount, int width, int cn) = 0;
- //! resets the internal buffers, if any
- virtual void reset();
- Size ksize;
- Point anchor;
- };
- /*!
- The Main Class for Image Filtering.
- The class can be used to apply an arbitrary filtering operation to an image.
- It contains all the necessary intermediate buffers, it computes extrapolated values
- of the "virtual" pixels outside of the image etc.
- Pointers to the initialized cv::FilterEngine instances
- are returned by various OpenCV functions, such as cv::createSeparableLinearFilter(),
- cv::createLinearFilter(), cv::createGaussianFilter(), cv::createDerivFilter(),
- cv::createBoxFilter() and cv::createMorphologyFilter().
- Using the class you can process large images by parts and build complex pipelines
- that include filtering as some of the stages. If all you need is to apply some pre-defined
- filtering operation, you may use cv::filter2D(), cv::erode(), cv::dilate() etc.
- functions that create FilterEngine internally.
- Here is the example on how to use the class to implement Laplacian operator, which is the sum of
- second-order derivatives. More complex variant for different types is implemented in cv::Laplacian().
- \code
- void laplace_f(const Mat& src, Mat& dst)
- {
- CV_Assert( src.type() == CV_32F );
- // make sure the destination array has the proper size and type
- dst.create(src.size(), src.type());
- // get the derivative and smooth kernels for d2I/dx2.
- // for d2I/dy2 we could use the same kernels, just swapped
- Mat kd, ks;
- getSobelKernels( kd, ks, 2, 0, ksize, false, ktype );
- // let's process 10 source rows at once
- int DELTA = std::min(10, src.rows);
- Ptr<FilterEngine> Fxx = createSeparableLinearFilter(src.type(),
- dst.type(), kd, ks, Point(-1,-1), 0, borderType, borderType, Scalar() );
- Ptr<FilterEngine> Fyy = createSeparableLinearFilter(src.type(),
- dst.type(), ks, kd, Point(-1,-1), 0, borderType, borderType, Scalar() );
- int y = Fxx->start(src), dsty = 0, dy = 0;
- Fyy->start(src);
- const uchar* sptr = src.data + y*src.step;
- // allocate the buffers for the spatial image derivatives;
- // the buffers need to have more than DELTA rows, because at the
- // last iteration the output may take max(kd.rows-1,ks.rows-1)
- // rows more than the input.
- Mat Ixx( DELTA + kd.rows - 1, src.cols, dst.type() );
- Mat Iyy( DELTA + kd.rows - 1, src.cols, dst.type() );
- // inside the loop we always pass DELTA rows to the filter
- // (note that the "proceed" method takes care of possibe overflow, since
- // it was given the actual image height in the "start" method)
- // on output we can get:
- // * < DELTA rows (the initial buffer accumulation stage)
- // * = DELTA rows (settled state in the middle)
- // * > DELTA rows (then the input image is over, but we generate
- // "virtual" rows using the border mode and filter them)
- // this variable number of output rows is dy.
- // dsty is the current output row.
- // sptr is the pointer to the first input row in the portion to process
- for( ; dsty < dst.rows; sptr += DELTA*src.step, dsty += dy )
- {
- Fxx->proceed( sptr, (int)src.step, DELTA, Ixx.data, (int)Ixx.step );
- dy = Fyy->proceed( sptr, (int)src.step, DELTA, d2y.data, (int)Iyy.step );
- if( dy > 0 )
- {
- Mat dstripe = dst.rowRange(dsty, dsty + dy);
- add(Ixx.rowRange(0, dy), Iyy.rowRange(0, dy), dstripe);
- }
- }
- }
- \endcode
- */
- class FilterEngine
- {
- public:
- //! the default constructor
- FilterEngine();
- //! the full constructor. Either _filter2D or both _rowFilter and _columnFilter must be non-empty.
- FilterEngine(const Ptr<BaseFilter>& _filter2D,
- const Ptr<BaseRowFilter>& _rowFilter,
- const Ptr<BaseColumnFilter>& _columnFilter,
- int srcType, int dstType, int bufType,
- int _rowBorderType = BORDER_REPLICATE,
- int _columnBorderType = -1,
- const Scalar& _borderValue = Scalar());
- //! the destructor
- virtual ~FilterEngine();
- //! reinitializes the engine. The previously assigned filters are released.
- void init(const Ptr<BaseFilter>& _filter2D,
- const Ptr<BaseRowFilter>& _rowFilter,
- const Ptr<BaseColumnFilter>& _columnFilter,
- int srcType, int dstType, int bufType,
- int _rowBorderType = BORDER_REPLICATE,
- int _columnBorderType = -1,
- const Scalar& _borderValue = Scalar());
- //! starts filtering of the specified ROI of an image of size wholeSize.
- virtual int start(Size wholeSize, Rect roi, int maxBufRows = -1);
- //! starts filtering of the specified ROI of the specified image.
- virtual int start(const Mat& src, const Rect& srcRoi = Rect(0,0,-1,-1),
- bool isolated = false, int maxBufRows = -1);
- //! processes the next srcCount rows of the image.
- virtual int proceed(const uchar* src, int srcStep, int srcCount,
- uchar* dst, int dstStep);
- //! applies filter to the specified ROI of the image. if srcRoi=(0,0,-1,-1), the whole image is filtered.
- virtual void apply( const Mat& src, Mat& dst,
- const Rect& srcRoi = Rect(0,0,-1,-1),
- Point dstOfs = Point(0,0),
- bool isolated = false);
- //! returns true if the filter is separable
- bool isSeparable() const { return !filter2D; }
- //! returns the number
- int remainingInputRows() const;
- int remainingOutputRows() const;
- int srcType;
- int dstType;
- int bufType;
- Size ksize;
- Point anchor;
- int maxWidth;
- Size wholeSize;
- Rect roi;
- int dx1;
- int dx2;
- int rowBorderType;
- int columnBorderType;
- std::vector<int> borderTab;
- int borderElemSize;
- std::vector<uchar> ringBuf;
- std::vector<uchar> srcRow;
- std::vector<uchar> constBorderValue;
- std::vector<uchar> constBorderRow;
- int bufStep;
- int startY;
- int startY0;
- int endY;
- int rowCount;
- int dstY;
- std::vector<uchar*> rows;
- Ptr<BaseFilter> filter2D;
- Ptr<BaseRowFilter> rowFilter;
- Ptr<BaseColumnFilter> columnFilter;
- };
- //! returns type (one of KERNEL_*) of 1D or 2D kernel specified by its coefficients.
- int getKernelType(InputArray kernel, Point anchor);
- //! returns the primitive row filter with the specified kernel
- Ptr<BaseRowFilter> getLinearRowFilter(int srcType, int bufType,
- InputArray kernel, int anchor,
- int symmetryType);
- //! returns the primitive column filter with the specified kernel
- Ptr<BaseColumnFilter> getLinearColumnFilter(int bufType, int dstType,
- InputArray kernel, int anchor,
- int symmetryType, double delta = 0,
- int bits = 0);
- //! returns 2D filter with the specified kernel
- Ptr<BaseFilter> getLinearFilter(int srcType, int dstType,
- InputArray kernel,
- Point anchor = Point(-1,-1),
- double delta = 0, int bits = 0);
- //! returns the separable linear filter engine
- Ptr<FilterEngine> createSeparableLinearFilter(int srcType, int dstType,
- InputArray rowKernel, InputArray columnKernel,
- Point anchor = Point(-1,-1), double delta = 0,
- int rowBorderType = BORDER_DEFAULT,
- int columnBorderType = -1,
- const Scalar& borderValue = Scalar());
- //! returns the non-separable linear filter engine
- Ptr<FilterEngine> createLinearFilter(int srcType, int dstType,
- InputArray kernel, Point _anchor = Point(-1,-1),
- double delta = 0, int rowBorderType = BORDER_DEFAULT,
- int columnBorderType = -1, const Scalar& borderValue = Scalar());
- //! returns the Gaussian filter engine
- Ptr<FilterEngine> createGaussianFilter( int type, Size ksize,
- double sigma1, double sigma2 = 0,
- int borderType = BORDER_DEFAULT);
- //! returns filter engine for the generalized Sobel operator
- Ptr<FilterEngine> createDerivFilter( int srcType, int dstType,
- int dx, int dy, int ksize,
- int borderType = BORDER_DEFAULT );
- //! returns horizontal 1D box filter
- Ptr<BaseRowFilter> getRowSumFilter(int srcType, int sumType,
- int ksize, int anchor = -1);
- //! returns vertical 1D box filter
- Ptr<BaseColumnFilter> getColumnSumFilter( int sumType, int dstType,
- int ksize, int anchor = -1,
- double scale = 1);
- //! returns box filter engine
- Ptr<FilterEngine> createBoxFilter( int srcType, int dstType, Size ksize,
- Point anchor = Point(-1,-1),
- bool normalize = true,
- int borderType = BORDER_DEFAULT);
- //! returns horizontal 1D morphological filter
- Ptr<BaseRowFilter> getMorphologyRowFilter(int op, int type, int ksize, int anchor = -1);
- //! returns vertical 1D morphological filter
- Ptr<BaseColumnFilter> getMorphologyColumnFilter(int op, int type, int ksize, int anchor = -1);
- //! returns 2D morphological filter
- Ptr<BaseFilter> getMorphologyFilter(int op, int type, InputArray kernel,
- Point anchor = Point(-1,-1));
- //! returns morphological filter engine. Only MORPH_ERODE and MORPH_DILATE are supported.
- CV_EXPORTS Ptr<FilterEngine> createMorphologyFilter(int op, int type, InputArray kernel,
- Point anchor = Point(-1,-1), int rowBorderType = BORDER_CONSTANT,
- int columnBorderType = -1,
- const Scalar& borderValue = morphologyDefaultBorderValue());
- static inline Point normalizeAnchor( Point anchor, Size ksize )
- {
- if( anchor.x == -1 )
- anchor.x = ksize.width/2;
- if( anchor.y == -1 )
- anchor.y = ksize.height/2;
- CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) );
- return anchor;
- }
- void preprocess2DKernel( const Mat& kernel, std::vector<Point>& coords, std::vector<uchar>& coeffs );
- void crossCorr( const Mat& src, const Mat& templ, Mat& dst,
- Size corrsize, int ctype,
- Point anchor=Point(0,0), double delta=0,
- int borderType=BORDER_REFLECT_101 );
- template<typename T, typename ST> struct RowSum : public BaseRowFilter
- {
- RowSum( int _ksize, int _anchor )
- {
- ksize = _ksize;
- anchor = _anchor;
- }
- void operator()(const uchar* src, uchar* dst, int width, int cn)
- {
- const T* S = (const T*)src;
- ST* D = (ST*)dst;
- int i = 0, k, ksz_cn = ksize*cn;
- width = (width - 1)*cn;
- for( k = 0; k < cn; k++, S++, D++ )
- {
- ST s = 0;
- for( i = 0; i < ksz_cn; i += cn )
- s += S[i];
- D[0] = s;
- for( i = 0; i < width; i += cn )
- {
- s += S[i + ksz_cn] - S[i];
- D[i+cn] = s;
- }
- }
- }
- };
- template<typename ST, typename T> struct ColumnSum : public BaseColumnFilter
- {
- ColumnSum( int _ksize, int _anchor, double _scale )
- {
- ksize = _ksize;
- anchor = _anchor;
- scale = _scale;
- sumCount = 0;
- }
- void reset() { sumCount = 0; }
- void operator()(const uchar** src, uchar* dst, int dststep, int count, int width)
- {
- int i;
- ST* SUM;
- bool haveScale = scale != 1;
- double _scale = scale;
- if( width != (int)sum.size() )
- {
- sum.resize(width);
- sumCount = 0;
- }
- SUM = &sum[0];
- if( sumCount == 0 )
- {
- for( i = 0; i < width; i++ )
- SUM[i] = 0;
- for( ; sumCount < ksize - 1; sumCount++, src++ )
- {
- const ST* Sp = (const ST*)src[0];
- for( i = 0; i <= width - 2; i += 2 )
- {
- ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1];
- SUM[i] = s0; SUM[i+1] = s1;
- }
- for( ; i < width; i++ )
- SUM[i] += Sp[i];
- }
- }
- else
- {
- CV_Assert( sumCount == ksize-1 );
- src += ksize-1;
- }
- for( ; count--; src++ )
- {
- const ST* Sp = (const ST*)src[0];
- const ST* Sm = (const ST*)src[1-ksize];
- T* D = (T*)dst;
- if( haveScale )
- {
- for( i = 0; i <= width - 2; i += 2 )
- {
- ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1];
- D[i] = saturate_cast<T>(s0*_scale);
- D[i+1] = saturate_cast<T>(s1*_scale);
- s0 -= Sm[i]; s1 -= Sm[i+1];
- SUM[i] = s0; SUM[i+1] = s1;
- }
- for( ; i < width; i++ )
- {
- ST s0 = SUM[i] + Sp[i];
- D[i] = saturate_cast<T>(s0*_scale);
- SUM[i] = s0 - Sm[i];
- }
- }
- else
- {
- for( i = 0; i <= width - 2; i += 2 )
- {
- ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1];
- D[i] = saturate_cast<T>(s0);
- D[i+1] = saturate_cast<T>(s1);
- s0 -= Sm[i]; s1 -= Sm[i+1];
- SUM[i] = s0; SUM[i+1] = s1;
- }
- for( ; i < width; i++ )
- {
- ST s0 = SUM[i] + Sp[i];
- D[i] = saturate_cast<T>(s0);
- SUM[i] = s0 - Sm[i];
- }
- }
- dst += dststep;
- }
- }
- double scale;
- int sumCount;
- vector<ST> sum;
- };
- template<> struct ColumnSum<float, float> : public BaseColumnFilter
- {
- ColumnSum( int _ksize, int _anchor, double _scale )
- {
- ksize = _ksize;
- anchor = _anchor;
- scale = _scale;
- sumCount = 0;
- }
- void reset() { sumCount = 0; }
- void operator()(const uchar** src, uchar* dst, int dststep, int count, int width)
- {
- int i;
- float* SUM;
- bool haveScale = scale != 1;
- double _scale = scale;
- #if CV_SSE2
- bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
- #endif
- if( width != (int)sum.size() )
- {
- sum.resize(width);
- sumCount = 0;
- }
- SUM = &sum[0];
- if( sumCount == 0 )
- {
- memset((void*)SUM, 0, width*sizeof(float));
- for( ; sumCount < ksize - 1; sumCount++, src++ )
- {
- const float* Sp = (const float*)src[0];
- i = 0;
- #if CV_SSE2
- if(haveSSE2)
- {
- for( ; i < width-4; i+=4 )
- {
- __m128 _sum = _mm_loadu_ps((SUM+i));
- __m128 _sp = _mm_loadu_ps((Sp+i));
- _mm_storeu_ps((SUM+i),_mm_add_ps(_sum, _sp));
- }
- }
- #endif
- for( ; i < width; i++ )
- SUM[i] += Sp[i];
- }
- }
- else
- {
- CV_Assert( sumCount == ksize-1 );
- src += ksize-1;
- }
- for( ; count--; src++ )
- {
- const float* Sp = (const float*)src[0];
- const float* Sm = (const float*)src[1-ksize];
- float* D = (float*)dst;
- if( haveScale )
- {
- i = 0;
- #if CV_SSE2
- if(haveSSE2)
- {
- const __m128 scale4 = _mm_set1_ps((float)_scale);
- for( ; i < width-4; i+=4 )
- {
- __m128 _sm = _mm_loadu_ps((Sm+i));
- __m128 _s0 = _mm_add_ps(_mm_loadu_ps((SUM+i)),
- _mm_loadu_ps((Sp+i)));
- _mm_storeu_ps(D+i, _mm_mul_ps(scale4,_s0));
- _mm_storeu_ps(SUM+i,_mm_sub_ps(_s0,_sm));
- }
- }
- #endif
- for( ; i < width; i++ )
- {
- float s0 = SUM[i] + Sp[i];
- D[i] = saturate_cast<float>(s0*_scale);
- SUM[i] = s0 - Sm[i];
- }
- }
- else
- {
- i = 0;
- #if CV_SSE2
- if(haveSSE2)
- {
- for( ; i < width-4; i+=4 )
- {
- __m128 _sm = _mm_loadu_ps((Sm+i));
- __m128 _s0 = _mm_add_ps(_mm_loadu_ps((SUM+i)),
- _mm_loadu_ps((Sp+i)));
- _mm_storeu_ps(D+i,_s0);
- _mm_storeu_ps(SUM+i,_mm_sub_ps(_s0,_sm));
- }
- }
- #endif
- for( ; i < width; i++ )
- {
- float s0 = SUM[i] + Sp[i];
- D[i] = saturate_cast<uchar>(s0);
- SUM[i] = s0 - Sm[i];
- }
- }
- dst += dststep;
- }
- }
- double scale;
- int sumCount;
- vector<float> sum;
- };
- cv::Ptr<FilterEngine> createBoxFilterFFF(int cn, Size ksize,
- Point anchor, bool normalize, int borderType )
- {
- Ptr<BaseRowFilter> rowFilter = Ptr<BaseRowFilter>(new RowSum<float, float>(ksize.width, anchor.x < 0 ? ksize.width/2 : anchor.x));
- Ptr<BaseColumnFilter> columnFilter = Ptr<BaseColumnFilter>(new ColumnSum<float, float>(ksize.height, anchor.y < 0 ? ksize.height/2 : anchor.y, normalize ? 1./(ksize.width*ksize.height) : 1));
- return Ptr<FilterEngine>(new FilterEngine(Ptr<BaseFilter>(/*0*/), rowFilter, columnFilter,
- CV_32F, CV_32F, CV_32F, borderType ));
- }
- int main(int argc, char* argv[])
- {
- Mat planes=imread("f:/lib/opencv/samples/data/graf1.png");
- Ptr<BaseRowFilter> f;
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment