vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e

This commit is contained in:
Gitea Mirror Bot
2026-08-22 00:11:13 +08:00
commit 12022378a3
3872 changed files with 2513409 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
if(IOS OR WINRT OR (NOT HAVE_CUDA AND NOT BUILD_CUDA_STUBS))
ocv_module_disable(cudaimgproc)
endif()
set(the_description "CUDA-accelerated Image Processing")
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4127 /wd4100 /wd4324 /wd4512 /wd4515 -Wundef -Wmissing-declarations -Wshadow -Wunused-parameter)
ocv_define_module(cudaimgproc opencv_imgproc OPTIONAL opencv_cudev opencv_cudaarithm opencv_cudafilters opencv_geometry WRAP python)
if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE)
ocv_target_link_libraries(${the_module} PRIVATE CUDA::cudart${CUDA_LIB_EXT} CUDA::nppial${CUDA_LIB_EXT} CUDA::nppist${CUDA_LIB_EXT} CUDA::nppicc${CUDA_LIB_EXT} CUDA::nppidei${CUDA_LIB_EXT})
endif()
+19
View File
@@ -0,0 +1,19 @@
@article{Allegretti2019,
title={Optimized block-based algorithms to label connected components on GPUs},
author={Allegretti, Stefano and Bolelli, Federico and Grana, Costantino},
journal={IEEE Transactions on Parallel and Distributed Systems},
volume={31},
number={2},
pages={423--438},
year={2019},
publisher={IEEE}
}
@article{BT.709,
title={Recommendation ITU-R BT.709-6},
author={ITU},
pages={3},
year={2015},
publisher={ITU}
url={https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-6-201506-I!!PDF-E.pdf}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

@@ -0,0 +1,798 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef OPENCV_CUDAIMGPROC_HPP
#define OPENCV_CUDAIMGPROC_HPP
#ifndef __cplusplus
# error cudaimgproc.hpp header must be compiled as C++
#endif
#include "opencv2/core/cuda.hpp"
#include "opencv2/imgproc.hpp"
/**
@addtogroup cuda
@{
@defgroup cudaimgproc Image Processing
@{
@defgroup cudaimgproc_color Color space processing
@defgroup cudaimgproc_hist Histogram Calculation
@defgroup cudaimgproc_shape Structural Analysis and Shape Descriptors
@defgroup cudaimgproc_hough Hough Transform
@defgroup cudaimgproc_feature Feature Detection
@}
@}
*/
namespace cv { namespace cuda {
//! @addtogroup cudaimgproc
//! @{
/////////////////////////// Color Processing ///////////////////////////
//! @addtogroup cudaimgproc_color
//! @{
/** @brief Converts an image from one color space to another.
@param src Source image with CV_8U , CV_16U , or CV_32F depth and 1, 3, or 4 channels.
@param dst Destination image.
@param code Color space conversion code. For details, see cvtColor .
@param dcn Number of channels in the destination image. If the parameter is 0, the number of the
channels is derived automatically from src and the code .
@param stream Stream for the asynchronous version.
3-channel color spaces (like HSV, XYZ, and so on) can be stored in a 4-channel image for better
performance.
@sa cvtColor
*/
CV_EXPORTS_W void cvtColor(InputArray src, OutputArray dst, int code, int dcn = 0, Stream& stream = Stream::Null());
enum DemosaicTypes
{
//! Bayer Demosaicing (Malvar, He, and Cutler)
COLOR_BayerBG2BGR_MHT = 256,
COLOR_BayerGB2BGR_MHT = 257,
COLOR_BayerRG2BGR_MHT = 258,
COLOR_BayerGR2BGR_MHT = 259,
COLOR_BayerBG2RGB_MHT = COLOR_BayerRG2BGR_MHT,
COLOR_BayerGB2RGB_MHT = COLOR_BayerGR2BGR_MHT,
COLOR_BayerRG2RGB_MHT = COLOR_BayerBG2BGR_MHT,
COLOR_BayerGR2RGB_MHT = COLOR_BayerGB2BGR_MHT,
COLOR_BayerBG2GRAY_MHT = 260,
COLOR_BayerGB2GRAY_MHT = 261,
COLOR_BayerRG2GRAY_MHT = 262,
COLOR_BayerGR2GRAY_MHT = 263
};
/** @brief Converts an image from Bayer pattern to RGB or grayscale.
@param src Source image (8-bit or 16-bit single channel).
@param dst Destination image.
@param code Color space conversion code (see the description below).
@param dcn Number of channels in the destination image. If the parameter is 0, the number of the
channels is derived automatically from src and the code .
@param stream Stream for the asynchronous version.
The function can do the following transformations:
- Demosaicing using bilinear interpolation
> - COLOR_BayerBG2GRAY , COLOR_BayerGB2GRAY , COLOR_BayerRG2GRAY , COLOR_BayerGR2GRAY
> - COLOR_BayerBG2BGR , COLOR_BayerGB2BGR , COLOR_BayerRG2BGR , COLOR_BayerGR2BGR
- Demosaicing using Malvar-He-Cutler algorithm (@cite MHT2011)
> - COLOR_BayerBG2GRAY_MHT , COLOR_BayerGB2GRAY_MHT , COLOR_BayerRG2GRAY_MHT ,
> COLOR_BayerGR2GRAY_MHT
> - COLOR_BayerBG2BGR_MHT , COLOR_BayerGB2BGR_MHT , COLOR_BayerRG2BGR_MHT ,
> COLOR_BayerGR2BGR_MHT
@sa cvtColor
*/
CV_EXPORTS_W void demosaicing(InputArray src, OutputArray dst, int code, int dcn = -1, Stream& stream = Stream::Null());
/** @brief Exchanges the color channels of an image in-place.
@param image Source image. Supports only CV_8UC4 type.
@param dstOrder Integer array describing how channel values are permutated. The n-th entry of the
array contains the number of the channel that is stored in the n-th channel of the output image.
E.g. Given an RGBA image, aDstOrder = [3,2,1,0] converts this to ABGR channel order.
@param stream Stream for the asynchronous version.
The methods support arbitrary permutations of the original channels, including replication.
*/
CV_EXPORTS void swapChannels(InputOutputArray image, const int dstOrder[4], Stream& stream = Stream::Null());
/** @brief Routines for correcting image color gamma.
@param src Source image (3- or 4-channel 8 bit).
@param dst Destination image.
@param forward true for forward gamma correction or false for inverse gamma correction.
@param stream Stream for the asynchronous version.
Gamma correction is conformant to BT.709 @cite BT.709 with γ=0.45.
For the forward transform, RGB values are normalised to fit in the range L=[0..1], then:
- For L < 0.018
+ V = 4.5*L
- For L >= 0.018
+ V = 1.099 * L^0.45 - 0.099
With V then being scaled back to [0..255].
![image](pics/gammacorrection.png)
*/
CV_EXPORTS_W void gammaCorrection(InputArray src, OutputArray dst, bool forward = true, Stream& stream = Stream::Null());
enum AlphaCompTypes { ALPHA_OVER, ALPHA_IN, ALPHA_OUT, ALPHA_ATOP, ALPHA_XOR, ALPHA_PLUS, ALPHA_OVER_PREMUL, ALPHA_IN_PREMUL, ALPHA_OUT_PREMUL,
ALPHA_ATOP_PREMUL, ALPHA_XOR_PREMUL, ALPHA_PLUS_PREMUL, ALPHA_PREMUL};
/** @brief Composites two images using alpha opacity values contained in each image.
@param img1 First image. Supports CV_8UC4 , CV_16UC4 , CV_32SC4 and CV_32FC4 types.
@param img2 Second image. Must have the same size and the same type as img1 .
@param dst Destination image.
@param alpha_op Flag specifying the alpha-blending operation:
- **ALPHA_OVER**
- **ALPHA_IN**
- **ALPHA_OUT**
- **ALPHA_ATOP**
- **ALPHA_XOR**
- **ALPHA_PLUS**
- **ALPHA_OVER_PREMUL**
- **ALPHA_IN_PREMUL**
- **ALPHA_OUT_PREMUL**
- **ALPHA_ATOP_PREMUL**
- **ALPHA_XOR_PREMUL**
- **ALPHA_PLUS_PREMUL**
- **ALPHA_PREMUL**
@param stream Stream for the asynchronous version.
@note
- An example demonstrating the use of alphaComp can be found at
opencv_source_code/samples/gpu/alpha_comp.cpp
*/
CV_EXPORTS_W void alphaComp(InputArray img1, InputArray img2, OutputArray dst, int alpha_op, Stream& stream = Stream::Null());
//! @} cudaimgproc_color
////////////////////////////// Histogram ///////////////////////////////
//! @addtogroup cudaimgproc_hist
//! @{
/** @brief Calculates histogram for one channel 8-bit image.
@param src Source image with CV_8UC1 type.
@param hist Destination histogram with one row, 256 columns, and the CV_32SC1 type.
@param stream Stream for the asynchronous version.
*/
CV_EXPORTS_W void calcHist(InputArray src, OutputArray hist, Stream& stream = Stream::Null());
/** @brief Calculates histogram for one channel 8-bit image confined in given mask.
@param src Source image with CV_8UC1 type.
@param hist Destination histogram with one row, 256 columns, and the CV_32SC1 type.
@param mask A mask image same size as src and of type CV_8UC1.
@param stream Stream for the asynchronous version.
*/
CV_EXPORTS_W void calcHist(InputArray src, InputArray mask, OutputArray hist, Stream& stream = Stream::Null());
/** @brief Equalizes the histogram of a grayscale image.
@param src Source image with CV_8UC1 type.
@param dst Destination image.
@param stream Stream for the asynchronous version.
@sa equalizeHist
*/
CV_EXPORTS_W void equalizeHist(InputArray src, OutputArray dst, Stream& stream = Stream::Null());
/** @brief Base class for Contrast Limited Adaptive Histogram Equalization. :
*/
class CV_EXPORTS_W CLAHE : public cv::CLAHE
{
public:
using cv::CLAHE::apply;
/** @brief Equalizes the histogram of a grayscale image using Contrast Limited Adaptive Histogram Equalization.
@param src Source image with CV_8UC1 type.
@param dst Destination image.
@param stream Stream for the asynchronous version.
*/
CV_WRAP virtual void apply(InputArray src, OutputArray dst, Stream& stream) = 0;
};
/** @brief Creates implementation for cuda::CLAHE .
@param clipLimit Threshold for contrast limiting.
@param tileGridSize Size of grid for histogram equalization. Input image will be divided into
equally sized rectangular tiles. tileGridSize defines the number of tiles in row and column.
*/
CV_EXPORTS_W Ptr<cuda::CLAHE> createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8));
/** @brief Computes levels with even distribution.
@param levels Destination array. levels has 1 row, nLevels columns, and the CV_32SC1 type.
@param nLevels Number of computed levels. nLevels must be at least 2.
@param lowerLevel Lower boundary value of the lowest level.
@param upperLevel Upper boundary value of the greatest level.
@param stream Stream for the asynchronous version.
*/
CV_EXPORTS_W void evenLevels(OutputArray levels, int nLevels, int lowerLevel, int upperLevel, Stream& stream = Stream::Null());
/** @brief Calculates a histogram with evenly distributed bins.
@param src Source image. CV_8U, CV_16U, or CV_16S depth and 1 or 4 channels are supported. For
a four-channel image, all channels are processed separately.
@param hist Destination histogram with one row, histSize columns, and the CV_32S type.
@param histSize Size of the histogram.
@param lowerLevel Lower boundary of lowest-level bin.
@param upperLevel Upper boundary of highest-level bin.
@param stream Stream for the asynchronous version.
*/
CV_EXPORTS_W void histEven(InputArray src, OutputArray hist, int histSize, int lowerLevel, int upperLevel, Stream& stream = Stream::Null());
/** @overload */
CV_EXPORTS_W void histEven(InputArray src, GpuMat hist[4], int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream = Stream::Null());
/** @brief Calculates a histogram with bins determined by the levels array.
@param src Source image. CV_8U , CV_16U , or CV_16S depth and 1 or 4 channels are supported.
For a four-channel image, all channels are processed separately.
@param hist Destination histogram with one row, (levels.cols-1) columns, and the CV_32SC1 type.
@param levels Number of levels in the histogram.
@param stream Stream for the asynchronous version.
*/
CV_EXPORTS_W void histRange(InputArray src, OutputArray hist, InputArray levels, Stream& stream = Stream::Null());
/** @overload */
CV_EXPORTS_W void histRange(InputArray src, GpuMat hist[4], const GpuMat levels[4], Stream& stream = Stream::Null());
//! @} cudaimgproc_hist
//////////////////////////////// Canny ////////////////////////////////
/** @brief Base class for Canny Edge Detector. :
*/
class CV_EXPORTS_W CannyEdgeDetector : public Algorithm
{
public:
/** @brief Finds edges in an image using the @cite Canny86 algorithm.
@param image Single-channel 8-bit input image.
@param edges Output edge map. It has the same size and type as image.
@param stream Stream for the asynchronous version.
*/
CV_WRAP virtual void detect(InputArray image, OutputArray edges, Stream& stream = Stream::Null()) = 0;
/** @overload
@param dx First derivative of image in the vertical direction. Support only CV_32S type.
@param dy First derivative of image in the horizontal direction. Support only CV_32S type.
@param edges Output edge map. It has the same size and type as image.
@param stream Stream for the asynchronous version.
*/
CV_WRAP virtual void detect(InputArray dx, InputArray dy, OutputArray edges, Stream& stream = Stream::Null()) = 0;
CV_WRAP virtual void setLowThreshold(double low_thresh) = 0;
CV_WRAP virtual double getLowThreshold() const = 0;
CV_WRAP virtual void setHighThreshold(double high_thresh) = 0;
CV_WRAP virtual double getHighThreshold() const = 0;
CV_WRAP virtual void setAppertureSize(int apperture_size) = 0;
CV_WRAP virtual int getAppertureSize() const = 0;
CV_WRAP virtual void setL2Gradient(bool L2gradient) = 0;
CV_WRAP virtual bool getL2Gradient() const = 0;
};
/** @brief Creates implementation for cuda::CannyEdgeDetector .
@param low_thresh First threshold for the hysteresis procedure.
@param high_thresh Second threshold for the hysteresis procedure.
@param apperture_size Aperture size for the Sobel operator.
@param L2gradient Flag indicating whether a more accurate \f$L_2\f$ norm
\f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to compute the image gradient magnitude (
L2gradient=true ), or a faster default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough ( L2gradient=false
).
*/
CV_EXPORTS_W Ptr<CannyEdgeDetector> createCannyEdgeDetector(double low_thresh, double high_thresh, int apperture_size = 3, bool L2gradient = false);
/////////////////////////// Hough Transform ////////////////////////////
//////////////////////////////////////
// HoughLines
//! @addtogroup cudaimgproc_hough
//! @{
/** @brief Base class for lines detector algorithm. :
*/
class CV_EXPORTS_W HoughLinesDetector : public Algorithm
{
public:
/** @brief Finds lines in a binary image using the classical Hough transform.
@param src 8-bit, single-channel binary source image.
@param lines Output vector of lines. Each line is represented by a two-element vector
\f$(\rho, \theta)\f$ . \f$\rho\f$ is the distance from the coordinate origin \f$(0,0)\f$ (top-left corner of
the image). \f$\theta\f$ is the line rotation angle in radians (
\f$0 \sim \textrm{vertical line}, \pi/2 \sim \textrm{horizontal line}\f$ ).
@param stream Stream for the asynchronous version.
@sa HoughLines
*/
CV_WRAP virtual void detect(InputArray src, OutputArray lines, Stream& stream = Stream::Null()) = 0;
/** @brief Downloads results from cuda::HoughLinesDetector::detect to host memory.
@param d_lines Result of cuda::HoughLinesDetector::detect .
@param h_lines Output host array.
@param h_votes Optional output array for line's votes.
@param stream Stream for the asynchronous version.
*/
CV_WRAP virtual void downloadResults(InputArray d_lines, OutputArray h_lines, OutputArray h_votes = noArray(), Stream& stream = Stream::Null()) = 0;
CV_WRAP virtual void setRho(float rho) = 0;
CV_WRAP virtual float getRho() const = 0;
CV_WRAP virtual void setTheta(float theta) = 0;
CV_WRAP virtual float getTheta() const = 0;
CV_WRAP virtual void setThreshold(int threshold) = 0;
CV_WRAP virtual int getThreshold() const = 0;
CV_WRAP virtual void setDoSort(bool doSort) = 0;
CV_WRAP virtual bool getDoSort() const = 0;
CV_WRAP virtual void setMaxLines(int maxLines) = 0;
CV_WRAP virtual int getMaxLines() const = 0;
};
/** @brief Creates implementation for cuda::HoughLinesDetector .
@param rho Distance resolution of the accumulator in pixels.
@param theta Angle resolution of the accumulator in radians.
@param threshold Accumulator threshold parameter. Only those lines are returned that get enough
votes ( \f$>\texttt{threshold}\f$ ).
@param doSort Performs lines sort by votes.
@param maxLines Maximum number of output lines.
*/
CV_EXPORTS_W Ptr<HoughLinesDetector> createHoughLinesDetector(float rho, float theta, int threshold, bool doSort = false, int maxLines = 4096);
//////////////////////////////////////
// HoughLinesP
/** @brief Base class for line segments detector algorithm. :
*/
class CV_EXPORTS_W HoughSegmentDetector : public Algorithm
{
public:
/** @brief Finds line segments in a binary image using the probabilistic Hough transform.
@param src 8-bit, single-channel binary source image.
@param lines Output vector of lines. Each line is represented by a 4-element vector
\f$(x_1, y_1, x_2, y_2)\f$ , where \f$(x_1,y_1)\f$ and \f$(x_2, y_2)\f$ are the ending points of each detected
line segment.
@param stream Stream for the asynchronous version.
@sa HoughLinesP
*/
CV_WRAP virtual void detect(InputArray src, OutputArray lines, Stream& stream = Stream::Null()) = 0;
CV_WRAP virtual void setRho(float rho) = 0;
CV_WRAP virtual float getRho() const = 0;
CV_WRAP virtual void setTheta(float theta) = 0;
CV_WRAP virtual float getTheta() const = 0;
CV_WRAP virtual void setMinLineLength(int minLineLength) = 0;
CV_WRAP virtual int getMinLineLength() const = 0;
CV_WRAP virtual void setMaxLineGap(int maxLineGap) = 0;
CV_WRAP virtual int getMaxLineGap() const = 0;
CV_WRAP virtual void setMaxLines(int maxLines) = 0;
CV_WRAP virtual int getMaxLines() const = 0;
CV_WRAP virtual void setThreshold(int threshold) = 0;
CV_WRAP virtual int getThreshold() const = 0;
};
/** @brief Creates implementation for cuda::HoughSegmentDetector .
@param rho Distance resolution of the accumulator in pixels.
@param theta Angle resolution of the accumulator in radians.
@param minLineLength Minimum line length. Line segments shorter than that are rejected.
@param maxLineGap Maximum allowed gap between points on the same line to link them.
@param maxLines Maximum number of output lines.
@param threshold %Accumulator threshold parameter. Only those lines are returned that get enough
votes ( \f$>\texttt{threshold}\f$ ).
*/
CV_EXPORTS_W Ptr<HoughSegmentDetector> createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines = 4096, int threshold = -1);
//////////////////////////////////////
// HoughCircles
/** @brief Base class for circles detector algorithm. :
*/
class CV_EXPORTS_W HoughCirclesDetector : public Algorithm
{
public:
/** @brief Finds circles in a grayscale image using the Hough transform.
@param src 8-bit, single-channel grayscale input image.
@param circles Output vector of found circles. Each vector is encoded as a 3-element
floating-point vector \f$(x, y, radius)\f$ .
@param stream Stream for the asynchronous version.
@sa HoughCircles
*/
CV_WRAP virtual void detect(InputArray src, OutputArray circles, Stream& stream = Stream::Null()) = 0;
CV_WRAP virtual void setDp(float dp) = 0;
CV_WRAP virtual float getDp() const = 0;
CV_WRAP virtual void setMinDist(float minDist) = 0;
CV_WRAP virtual float getMinDist() const = 0;
CV_WRAP virtual void setCannyThreshold(int cannyThreshold) = 0;
CV_WRAP virtual int getCannyThreshold() const = 0;
CV_WRAP virtual void setVotesThreshold(int votesThreshold) = 0;
CV_WRAP virtual int getVotesThreshold() const = 0;
CV_WRAP virtual void setMinRadius(int minRadius) = 0;
CV_WRAP virtual int getMinRadius() const = 0;
CV_WRAP virtual void setMaxRadius(int maxRadius) = 0;
CV_WRAP virtual int getMaxRadius() const = 0;
CV_WRAP virtual void setMaxCircles(int maxCircles) = 0;
CV_WRAP virtual int getMaxCircles() const = 0;
};
/** @brief Creates implementation for cuda::HoughCirclesDetector .
@param dp Inverse ratio of the accumulator resolution to the image resolution. For example, if
dp=1 , the accumulator has the same resolution as the input image. If dp=2 , the accumulator has
half as big width and height.
@param minDist Minimum distance between the centers of the detected circles. If the parameter is
too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is
too large, some circles may be missed.
@param cannyThreshold The higher threshold of the two passed to Canny edge detector (the lower one
is twice smaller).
@param votesThreshold The accumulator threshold for the circle centers at the detection stage. The
smaller it is, the more false circles may be detected.
@param minRadius Minimum circle radius.
@param maxRadius Maximum circle radius.
@param maxCircles Maximum number of output circles.
*/
CV_EXPORTS_W Ptr<HoughCirclesDetector> createHoughCirclesDetector(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles = 4096);
//////////////////////////////////////
// GeneralizedHough
/** @brief Creates implementation for generalized hough transform from @cite Ballard1981 .
*/
CV_EXPORTS_W Ptr<GeneralizedHoughBallard> createGeneralizedHoughBallard();
/** @brief Creates implementation for generalized hough transform from @cite Guil1999 .
*/
CV_EXPORTS_W Ptr<GeneralizedHoughGuil> createGeneralizedHoughGuil();
//! @} cudaimgproc_hough
///////////////////////////// Mean Shift //////////////////////////////
/** @brief Performs mean-shift filtering for each point of the source image.
@param src Source image. Only CV_8UC4 images are supported for now.
@param dst Destination image containing the color of mapped points. It has the same size and type
as src .
@param sp Spatial window radius.
@param sr Color window radius.
@param criteria Termination criteria. See TermCriteria.
@param stream Stream for the asynchronous version.
It maps each point of the source image into another point. As a result, you have a new color and new
position of each point.
*/
CV_EXPORTS_W void meanShiftFiltering(InputArray src, OutputArray dst, int sp, int sr,
TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1),
Stream& stream = Stream::Null());
/** @brief Performs a mean-shift procedure and stores information about processed points (their colors and
positions) in two images.
@param src Source image. Only CV_8UC4 images are supported for now.
@param dstr Destination image containing the color of mapped points. The size and type is the same
as src .
@param dstsp Destination image containing the position of mapped points. The size is the same as
src size. The type is CV_16SC2 .
@param sp Spatial window radius.
@param sr Color window radius.
@param criteria Termination criteria. See TermCriteria.
@param stream Stream for the asynchronous version.
@sa cuda::meanShiftFiltering
*/
CV_EXPORTS_W void meanShiftProc(InputArray src, OutputArray dstr, OutputArray dstsp, int sp, int sr,
TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1),
Stream& stream = Stream::Null());
/** @brief Performs a mean-shift segmentation of the source image and eliminates small segments.
@param src Source image. Only CV_8UC4 images are supported for now.
@param dst Segmented image with the same size and type as src (host or gpu memory).
@param sp Spatial window radius.
@param sr Color window radius.
@param minsize Minimum segment size. Smaller segments are merged.
@param criteria Termination criteria. See TermCriteria.
@param stream Stream for the asynchronous version.
*/
CV_EXPORTS_W void meanShiftSegmentation(InputArray src, OutputArray dst, int sp, int sr, int minsize,
TermCriteria criteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1),
Stream& stream = Stream::Null());
/////////////////////////// Match Template ////////////////////////////
/** @brief Base class for Template Matching. :
*/
class CV_EXPORTS_W TemplateMatching : public Algorithm
{
public:
/** @brief Computes a proximity map for a raster template and an image where the template is searched for.
@param image Source image.
@param templ Template image with the size and type the same as image .
@param result Map containing comparison results ( CV_32FC1 ). If image is *W x H* and templ is *w
x h*, then result must be *W-w+1 x H-h+1*.
@param stream Stream for the asynchronous version.
*/
CV_WRAP virtual void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null()) = 0;
};
/** @brief Creates implementation for cuda::TemplateMatching .
@param srcType Input source type. CV_32F and CV_8U depth images (1..4 channels) are supported
for now.
@param method Specifies the way to compare the template with the image.
@param user_block_size You can use field user_block_size to set specific block size. If you
leave its default value Size(0,0) then automatic estimation of block size will be used (which is
optimized for speed). By varying user_block_size you can reduce memory requirements at the cost
of speed.
The following methods are supported for the CV_8U depth images for now:
- CV_TM_SQDIFF
- CV_TM_SQDIFF_NORMED
- CV_TM_CCORR
- CV_TM_CCORR_NORMED
- CV_TM_CCOEFF
- CV_TM_CCOEFF_NORMED
The following methods are supported for the CV_32F images for now:
- CV_TM_SQDIFF
- CV_TM_CCORR
@sa matchTemplate
*/
CV_EXPORTS_W Ptr<TemplateMatching> createTemplateMatching(int srcType, int method, Size user_block_size = Size());
////////////////////////// Bilateral Filter ///////////////////////////
/** @brief Performs bilateral filtering of passed image
@param src Source image. Supports only (channels != 2 && depth() != CV_8S && depth() != CV_32S
&& depth() != CV_64F).
@param dst Destination imagwe.
@param kernel_size Kernel window size.
@param sigma_color Filter sigma in the color space.
@param sigma_spatial Filter sigma in the coordinate space.
@param borderMode Border type. See borderInterpolate for details. BORDER_REFLECT101 ,
BORDER_REPLICATE , BORDER_CONSTANT , BORDER_REFLECT and BORDER_WRAP are supported for now.
@param stream Stream for the asynchronous version.
@sa bilateralFilter
*/
CV_EXPORTS_W void bilateralFilter(InputArray src, OutputArray dst, int kernel_size, float sigma_color, float sigma_spatial,
int borderMode = BORDER_DEFAULT, Stream& stream = Stream::Null());
///////////////////////////// Blending ////////////////////////////////
/** @brief Performs linear blending of two images.
@param img1 First image. Supports only CV_8U and CV_32F depth.
@param img2 Second image. Must have the same size and the same type as img1 .
@param weights1 Weights for first image. Must have tha same size as img1 . Supports only CV_32F
type.
@param weights2 Weights for second image. Must have tha same size as img2 . Supports only CV_32F
type.
@param result Destination image.
@param stream Stream for the asynchronous version.
*/
CV_EXPORTS_W void blendLinear(InputArray img1, InputArray img2, InputArray weights1, InputArray weights2,
OutputArray result, Stream& stream = Stream::Null());
/////////////////// Connected Components Labeling /////////////////////
//! Connected Components Algorithm
enum ConnectedComponentsAlgorithmsTypes {
CCL_DEFAULT = -1, //!< BKE @cite Allegretti2019 algorithm for 8-way connectivity.
CCL_BKE = 0, //!< BKE @cite Allegretti2019 algorithm for 8-way connectivity.
};
/** @brief Computes the Connected Components Labeled image of a binary image.
The function takes as input a binary image and performs Connected Components Labeling. The output
is an image where each Connected Component is assigned a unique label (integer value).
ltype specifies the output label image type, an important consideration based on the total
number of labels or alternatively the total number of pixels in the source image.
ccltype specifies the connected components labeling algorithm to use, currently
BKE @cite Allegretti2019 is supported, see the #ConnectedComponentsAlgorithmsTypes
for details. Note that labels in the output are not required to be sequential.
@param image The 8-bit single-channel image to be labeled.
@param labels Destination labeled image.
@param connectivity Connectivity to use for the labeling procedure. 8 for 8-way connectivity is supported.
@param ltype Output image label type. Currently CV_32S is supported.
@param ccltype Connected components algorithm type (see the #ConnectedComponentsAlgorithmsTypes).
@note A sample program demonstrating Connected Components Labeling in CUDA can be found at\n
opencv_contrib_source_code/modules/cudaimgproc/samples/connected_components.cpp
*/
CV_EXPORTS_AS(connectedComponentsWithAlgorithm) void connectedComponents(InputArray image, OutputArray labels,
int connectivity, int ltype, cv::cuda::ConnectedComponentsAlgorithmsTypes ccltype);
/** @overload
@param image The 8-bit single-channel image to be labeled.
@param labels Destination labeled image.
@param connectivity Connectivity to use for the labeling procedure. 8 for 8-way connectivity is supported.
@param ltype Output image label type. Currently CV_32S is supported.
*/
CV_EXPORTS_W void connectedComponents(InputArray image, OutputArray labels,
int connectivity = 8, int ltype = CV_32S);
//! @}
//! @addtogroup cudaimgproc_shape
//! @{
/** @brief Order of image moments.
* @param FIRST_ORDER_MOMENTS First order moments
* @param SECOND_ORDER_MOMENTS Second order moments.
* @param THIRD_ORDER_MOMENTS Third order moments.
* */
enum MomentsOrder {
FIRST_ORDER_MOMENTS = 1,
SECOND_ORDER_MOMENTS = 2,
THIRD_ORDER_MOMENTS = 3
};
/** @brief Returns the number of image moments less than or equal to the largest image moments \a order.
@param order Order of largest moments to calculate with lower order moments requiring less computation.
@returns number of image moments.
@sa cuda::spatialMoments, cuda::moments, cuda::MomentsOrder
*/
CV_EXPORTS_W int numMoments(const MomentsOrder order);
/** @brief Converts the spatial image moments returned from cuda::spatialMoments to cv::Moments.
@param spatialMoments Spatial moments returned from cuda::spatialMoments.
@param order Order used when calculating image moments with cuda::spatialMoments.
@param momentsType Precision used when calculating image moments with cuda::spatialMoments.
@returns cv::Moments.
@sa cuda::spatialMoments, cuda::moments, cuda::convertSpatialMoments, cuda::numMoments, cuda::MomentsOrder
*/
CV_EXPORTS_W Moments convertSpatialMoments(Mat spatialMoments, const MomentsOrder order, const int momentsType);
/** @brief Calculates all of the spatial moments up to the 3rd order of a rasterized shape.
Asynchronous version of cuda::moments() which only calculates the spatial (not centralized or normalized) moments, up to the 3rd order, of a rasterized shape.
Each moment is returned as a column entry in the 1D \a moments array.
@param src Raster image (single-channel 2D array).
@param [out] moments 1D array with each column entry containing a spatial image moment.
@param binaryImage If it is true, all non-zero image pixels are treated as 1's.
@param order Order of largest moments to calculate with lower order moments requiring less computation.
@param momentsType Precision to use when calculating moments. Available types are \ref CV_32F and \ref CV_64F with the performance of \ref CV_32F an order of magnitude greater than \ref CV_64F. If the image is small the accuracy from \ref CV_32F can be equal or very close to \ref CV_64F.
@param stream Stream for the asynchronous version.
@note For maximum performance pre-allocate a 1D GpuMat for \a moments of the correct type and size large enough to store the all the image moments of up to the desired \a order. e.g. With \a order === MomentsOrder::SECOND_ORDER_MOMENTS and \a momentsType == \ref CV_32F \a moments can be allocated as
```
GpuMat momentsDevice(1,numMoments(MomentsOrder::SECOND_ORDER_MOMENTS),CV_32F)
```
The central and normalized moments can easily be calculated on the host by downloading the \a moments array and using the cuda::convertSpatialMoments helper function. e.g.
```
HostMem spatialMomentsHostMem(1, numMoments(MomentsOrder::SECOND_ORDER_MOMENTS), CV_32F);
spatialMomentsDevice.download(spatialMomentsHostMem, stream);
stream.waitForCompletion();
Mat spatialMoments = spatialMomentsHostMem.createMatHeader();
cv::Moments cvMoments = convertSpatialMoments<float>(spatialMoments, order);
```
see the \a CUDA_TEST_P(Moments, Async) test inside opencv_contrib_source_code/modules/cudaimgproc/test/test_moments.cpp for an example.
@sa cuda::moments, cuda::convertSpatialMoments, cuda::numMoments, cuda::MomentsOrder
*/
CV_EXPORTS_W void spatialMoments(InputArray src, OutputArray moments, const bool binaryImage = false, const MomentsOrder order = MomentsOrder::THIRD_ORDER_MOMENTS, const int momentsType = CV_64F, Stream& stream = Stream::Null());
/** @brief Calculates all of the moments up to the 3rd order of a rasterized shape.
The function computes moments, up to the 3rd order, of a rasterized shape. The
results are returned in the structure cv::Moments.
@param src Raster image (single-channel 2D array).
@param binaryImage If it is true, all non-zero image pixels are treated as 1's.
@param order Order of largest moments to calculate with lower order moments requiring less computation.
@param momentsType Precision to use when calculating moments. Available types are \ref CV_32F and \ref CV_64F with the performance of \ref CV_32F an order of magnitude greater than \ref CV_64F. If the image is small the accuracy from \ref CV_32F can be equal or very close to \ref CV_64F.
@note For maximum performance use the asynchronous version cuda::spatialMoments() as this version interally allocates and deallocates both GpuMat and HostMem to respectively perform the calculation on the device and download the result to the host.
The costly HostMem allocation cannot be avoided however the GpuMat device allocation can be by using BufferPool, e.g.
```
setBufferPoolUsage(true);
setBufferPoolConfig(getDevice(), numMoments(order) * ((momentsType == CV_64F) ? sizeof(double) : sizeof(float)), 1);
```
see the \a CUDA_TEST_P(Moments, Accuracy) test inside opencv_contrib_source_code/modules/cudaimgproc/test/test_moments.cpp for an example.
@returns cv::Moments.
@sa cuda::spatialMoments, cuda::convertSpatialMoments, cuda::numMoments, cuda::MomentsOrder
*/
CV_EXPORTS_W Moments moments(InputArray src, const bool binaryImage = false, const MomentsOrder order = MomentsOrder::THIRD_ORDER_MOMENTS, const int momentsType = CV_64F);
//! @} cudaimgproc_shape
}} // namespace cv { namespace cuda {
#endif /* OPENCV_CUDAIMGPROC_HPP */
@@ -0,0 +1,118 @@
#!/usr/bin/env python
import os
import cv2 as cv
import numpy as np
from tests_common import NewOpenCVTests, unittest
class cudaimgproc_test(NewOpenCVTests):
def setUp(self):
super(cudaimgproc_test, self).setUp()
if not cv.cuda.getCudaEnabledDeviceCount():
self.skipTest("No CUDA-capable device is detected")
def test_cudaimgproc(self):
npC1 = (np.random.random((128, 128)) * 255).astype(np.uint8)
npC3 = (np.random.random((128, 128, 3)) * 255).astype(np.uint8)
npC4 = (np.random.random((128, 128, 4)) * 255).astype(np.uint8)
cuC1 = cv.cuda_GpuMat()
cuC3 = cv.cuda_GpuMat()
cuC4 = cv.cuda_GpuMat()
cuC1.upload(npC1)
cuC3.upload(npC3)
cuC4.upload(npC4)
cv.cuda.cvtColor(cuC3, cv.COLOR_RGB2HSV)
cv.cuda.demosaicing(cuC1, cv.cuda.COLOR_BayerGR2BGR_MHT)
cv.cuda.gammaCorrection(cuC3)
cv.cuda.alphaComp(cuC4, cuC4, cv.cuda.ALPHA_XOR)
cv.cuda.calcHist(cuC1)
cv.cuda.equalizeHist(cuC1)
cv.cuda.evenLevels(3, 0, 255)
cv.cuda.meanShiftFiltering(cuC4, 10, 5)
cv.cuda.meanShiftProc(cuC4, 10, 5)
cv.cuda.bilateralFilter(cuC3, 3, 16, 3)
cv.cuda.blendLinear
cuRes = cv.cuda.meanShiftSegmentation(cuC4, 10, 5, 5)
cuDst = cv.cuda_GpuMat(cuC4.size(),cuC4.type())
cv.cuda.meanShiftSegmentation(cuC4, 10, 5, 5, cuDst)
self.assertTrue(np.allclose(cuRes.download(),cuDst.download()))
clahe = cv.cuda.createCLAHE()
clahe.apply(cuC1, cv.cuda_Stream.Null())
histLevels = cv.cuda.histEven(cuC3, 20, 0, 255)
cv.cuda.histRange(cuC1, histLevels)
detector = cv.cuda.createCannyEdgeDetector(0, 100)
detector.detect(cuC1)
detector = cv.cuda.createHoughLinesDetector(3, np.pi / 180, 20)
detector.detect(cuC1)
detector = cv.cuda.createHoughSegmentDetector(3, np.pi / 180, 20, 5)
detector.detect(cuC1)
detector = cv.cuda.createHoughCirclesDetector(3, 20, 10, 10, 20, 100)
detector.detect(cuC1)
detector = cv.cuda.createGeneralizedHoughBallard()
#BUG: detect accept only Mat!
#Even if generate_gpumat_decls is set to True, it only wraps overload CUDA functions.
#The problem is that Mat and GpuMat are not fully compatible to enable system-wide overloading
#detector.detect(cuC1, cuC1, cuC1)
detector = cv.cuda.createGeneralizedHoughGuil()
#BUG: same as above..
#detector.detect(cuC1, cuC1, cuC1)
detector = cv.cuda.createHarrisCorner(cv.CV_8UC1, 15, 5, 1)
detector.compute(cuC1)
detector = cv.cuda.createMinEigenValCorner(cv.CV_8UC1, 15, 5, 1)
detector.compute(cuC1)
detector = cv.cuda.createGoodFeaturesToTrackDetector(cv.CV_8UC1)
detector.detect(cuC1)
matcher = cv.cuda.createTemplateMatching(cv.CV_8UC1, cv.TM_CCOEFF_NORMED)
matcher.match(cuC3, cuC3)
self.assertTrue(True) #It is sufficient that no exceptions have been there
def test_cvtColor(self):
npMat = (np.random.random((128, 128, 3)) * 255).astype(np.uint8)
cuMat = cv.cuda_GpuMat()
cuMat.upload(npMat)
self.assertTrue(np.allclose(cv.cuda.cvtColor(cuMat, cv.COLOR_BGR2HSV).download(),
cv.cvtColor(npMat, cv.COLOR_BGR2HSV)))
def test_moments(self):
# setup
src_host = (np.ones([10,10])).astype(np.uint8)*255
cpu_moments = cv.moments(src_host, True)
moments_order = cv.cuda.THIRD_ORDER_MOMENTS
n_moments = cv.cuda.numMoments(cv.cuda.THIRD_ORDER_MOMENTS)
src_device = cv.cuda.GpuMat(src_host)
# synchronous
cv.cuda.setBufferPoolUsage(True)
cv.cuda.setBufferPoolConfig(cv.cuda.getDevice(), n_moments * np.dtype(float).itemsize, 1);
gpu_moments = cv.cuda.moments(src_device, True, moments_order, cv.CV_64F)
self.assertTrue(len([1 for moment_type in cpu_moments if moment_type in gpu_moments and cpu_moments[moment_type] == gpu_moments[moment_type]]) == 24)
# asynchronous
stream = cv.cuda.Stream()
moments_array_host = np.empty([1, n_moments], np.float64)
cv.cuda.registerPageLocked(moments_array_host)
moments_array_device = cv.cuda.GpuMat(1, n_moments, cv.CV_64F)
cv.cuda.spatialMoments(src_device, moments_array_device, True, moments_order, cv.CV_64F, stream)
moments_array_device.download(stream, moments_array_host);
stream.waitForCompletion()
cv.cuda.unregisterPageLocked(moments_array_host)
self.assertTrue(len([ 1 for moment_type,gpu_moment in zip(cpu_moments,moments_array_host[0]) if cpu_moments[moment_type] == gpu_moment]) == 10)
if __name__ == '__main__':
NewOpenCVTests.bootstrap()
@@ -0,0 +1,93 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
//////////////////////////////////////////////////////////////////////
// BilateralFilter
DEF_PARAM_TEST(Sz_Depth_Cn_KernelSz, cv::Size, MatDepth, MatCn, int);
PERF_TEST_P(Sz_Depth_Cn_KernelSz, BilateralFilter,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(CV_8U, CV_32F),
CUDA_CHANNELS_1_3,
Values(3, 5, 9)))
{
declare.time(60.0);
const cv::Size size = GET_PARAM(0);
const int depth = GET_PARAM(1);
const int channels = GET_PARAM(2);
const int kernel_size = GET_PARAM(3);
const float sigma_color = 7;
const float sigma_spatial = 5;
const int borderMode = cv::BORDER_REFLECT101;
const int type = CV_MAKE_TYPE(depth, channels);
cv::Mat src(size, type);
declare.in(src, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::bilateralFilter(d_src, dst, kernel_size, sigma_color, sigma_spatial, borderMode);
CUDA_SANITY_CHECK(dst);
}
else
{
cv::Mat dst;
TEST_CYCLE() cv::bilateralFilter(src, dst, kernel_size, sigma_color, sigma_spatial, borderMode);
CPU_SANITY_CHECK(dst);
}
}
}} // namespace
+88
View File
@@ -0,0 +1,88 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
//////////////////////////////////////////////////////////////////////
// BlendLinear
DEF_PARAM_TEST(Sz_Depth_Cn, cv::Size, MatDepth, MatCn);
PERF_TEST_P(Sz_Depth_Cn, BlendLinear,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(CV_8U, CV_32F),
CUDA_CHANNELS_1_3_4))
{
const cv::Size size = GET_PARAM(0);
const int depth = GET_PARAM(1);
const int channels = GET_PARAM(2);
const int type = CV_MAKE_TYPE(depth, channels);
cv::Mat img1(size, type);
cv::Mat img2(size, type);
declare.in(img1, img2, WARMUP_RNG);
const cv::Mat weights1(size, CV_32FC1, cv::Scalar::all(0.5));
const cv::Mat weights2(size, CV_32FC1, cv::Scalar::all(0.5));
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_img1(img1);
const cv::cuda::GpuMat d_img2(img2);
const cv::cuda::GpuMat d_weights1(weights1);
const cv::cuda::GpuMat d_weights2(weights2);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::blendLinear(d_img1, d_img2, d_weights1, d_weights2, dst);
CUDA_SANITY_CHECK(dst);
}
else
{
FAIL_NO_CPU();
}
}
}} // namespace
+88
View File
@@ -0,0 +1,88 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
//////////////////////////////////////////////////////////////////////
// Canny
DEF_PARAM_TEST(Image_AppertureSz_L2gradient, string, int, bool);
PERF_TEST_P(Image_AppertureSz_L2gradient, Canny,
Combine(Values("perf/800x600.png", "perf/1280x1024.png", "perf/1680x1050.png"),
Values(3, 5),
Bool()))
{
const string fileName = GET_PARAM(0);
const int apperture_size = GET_PARAM(1);
const bool useL2gradient = GET_PARAM(2);
const cv::Mat image = readImage(fileName, cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(image.empty());
const double low_thresh = 50.0;
const double high_thresh = 100.0;
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_image(image);
cv::cuda::GpuMat dst;
cv::Ptr<cv::cuda::CannyEdgeDetector> canny = cv::cuda::createCannyEdgeDetector(low_thresh, high_thresh, apperture_size, useL2gradient);
TEST_CYCLE() canny->detect(d_image, dst);
CUDA_SANITY_CHECK(dst);
}
else
{
cv::Mat dst;
TEST_CYCLE() cv::Canny(image, dst, low_thresh, high_thresh, apperture_size, useL2gradient);
CPU_SANITY_CHECK(dst);
}
}
}} // namespace
+253
View File
@@ -0,0 +1,253 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
//////////////////////////////////////////////////////////////////////
// CvtColor
DEF_PARAM_TEST(Sz_Depth_Code, cv::Size, MatDepth, CvtColorInfo);
PERF_TEST_P(Sz_Depth_Code, CvtColor,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(CV_8U, CV_32F),
Values(CvtColorInfo(4, 4, cv::COLOR_RGBA2BGRA),
CvtColorInfo(4, 1, cv::COLOR_BGRA2GRAY),
CvtColorInfo(1, 4, cv::COLOR_GRAY2BGRA),
CvtColorInfo(3, 3, cv::COLOR_BGR2XYZ),
CvtColorInfo(3, 3, cv::COLOR_XYZ2BGR),
CvtColorInfo(3, 3, cv::COLOR_BGR2YCrCb),
CvtColorInfo(3, 3, cv::COLOR_YCrCb2BGR),
CvtColorInfo(3, 3, cv::COLOR_BGR2YUV),
CvtColorInfo(3, 3, cv::COLOR_YUV2BGR),
CvtColorInfo(3, 3, cv::COLOR_BGR2HSV),
CvtColorInfo(3, 3, cv::COLOR_HSV2BGR),
CvtColorInfo(3, 3, cv::COLOR_BGR2HLS),
CvtColorInfo(3, 3, cv::COLOR_HLS2BGR),
CvtColorInfo(3, 3, cv::COLOR_BGR2Lab),
CvtColorInfo(3, 3, cv::COLOR_LBGR2Lab),
CvtColorInfo(3, 3, cv::COLOR_BGR2Luv),
CvtColorInfo(3, 3, cv::COLOR_LBGR2Luv),
CvtColorInfo(3, 3, cv::COLOR_Lab2BGR),
CvtColorInfo(3, 3, cv::COLOR_Lab2LBGR),
CvtColorInfo(3, 3, cv::COLOR_Luv2RGB),
CvtColorInfo(3, 3, cv::COLOR_Luv2LRGB))))
{
const cv::Size size = GET_PARAM(0);
const int depth = GET_PARAM(1);
const CvtColorInfo info = GET_PARAM(2);
cv::Mat src(size, CV_MAKETYPE(depth, info.scn));
cv::randu(src, 0, depth == CV_8U ? 255.0 : 1.0);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::cvtColor(d_src, dst, info.code, info.dcn);
CUDA_SANITY_CHECK(dst, 1e-4);
}
else
{
cv::Mat dst;
TEST_CYCLE() cv::cvtColor(src, dst, info.code, info.dcn);
CPU_SANITY_CHECK(dst);
}
}
PERF_TEST_P(Sz_Depth_Code, CvtColorBayer,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(CV_8U, CV_16U),
Values(CvtColorInfo(1, 3, cv::COLOR_BayerBG2BGR),
CvtColorInfo(1, 3, cv::COLOR_BayerGB2BGR),
CvtColorInfo(1, 3, cv::COLOR_BayerRG2BGR),
CvtColorInfo(1, 3, cv::COLOR_BayerGR2BGR),
CvtColorInfo(1, 1, cv::COLOR_BayerBG2GRAY),
CvtColorInfo(1, 1, cv::COLOR_BayerGB2GRAY),
CvtColorInfo(1, 1, cv::COLOR_BayerRG2GRAY),
CvtColorInfo(1, 1, cv::COLOR_BayerGR2GRAY))))
{
const cv::Size size = GET_PARAM(0);
const int depth = GET_PARAM(1);
const CvtColorInfo info = GET_PARAM(2);
cv::Mat src(size, CV_MAKETYPE(depth, info.scn));
declare.in(src, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::cvtColor(d_src, dst, info.code, info.dcn);
CUDA_SANITY_CHECK(dst);
}
else
{
cv::Mat dst;
TEST_CYCLE() cv::cvtColor(src, dst, info.code, info.dcn);
CPU_SANITY_CHECK(dst);
}
}
//////////////////////////////////////////////////////////////////////
// Demosaicing
CV_ENUM(DemosaicingCode,
cv::COLOR_BayerBG2BGR, cv::COLOR_BayerGB2BGR, cv::COLOR_BayerRG2BGR, cv::COLOR_BayerGR2BGR,
cv::COLOR_BayerBG2GRAY, cv::COLOR_BayerGB2GRAY, cv::COLOR_BayerRG2GRAY, cv::COLOR_BayerGR2GRAY,
cv::cuda::COLOR_BayerBG2BGR_MHT, cv::cuda::COLOR_BayerGB2BGR_MHT, cv::cuda::COLOR_BayerRG2BGR_MHT, cv::cuda::COLOR_BayerGR2BGR_MHT,
cv::cuda::COLOR_BayerBG2GRAY_MHT, cv::cuda::COLOR_BayerGB2GRAY_MHT, cv::cuda::COLOR_BayerRG2GRAY_MHT, cv::cuda::COLOR_BayerGR2GRAY_MHT)
DEF_PARAM_TEST(Sz_Code, cv::Size, DemosaicingCode);
PERF_TEST_P(Sz_Code, Demosaicing,
Combine(CUDA_TYPICAL_MAT_SIZES,
DemosaicingCode::all()))
{
const cv::Size size = GET_PARAM(0);
const int code = GET_PARAM(1);
cv::Mat src(size, CV_8UC1);
declare.in(src, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::demosaicing(d_src, dst, code);
CUDA_SANITY_CHECK(dst);
}
else
{
if (code >= cv::COLOR_COLORCVT_MAX)
{
FAIL_NO_CPU();
}
else
{
cv::Mat dst;
TEST_CYCLE() cv::cvtColor(src, dst, code);
CPU_SANITY_CHECK(dst);
}
}
}
//////////////////////////////////////////////////////////////////////
// SwapChannels
PERF_TEST_P(Sz, SwapChannels,
CUDA_TYPICAL_MAT_SIZES)
{
const cv::Size size = GetParam();
cv::Mat src(size, CV_8UC4);
declare.in(src, WARMUP_RNG);
const int dstOrder[] = {2, 1, 0, 3};
if (PERF_RUN_CUDA())
{
cv::cuda::GpuMat dst(src);
TEST_CYCLE() cv::cuda::swapChannels(dst, dstOrder);
CUDA_SANITY_CHECK(dst);
}
else
{
FAIL_NO_CPU();
}
}
//////////////////////////////////////////////////////////////////////
// AlphaComp
CV_ENUM(AlphaOp, cv::cuda::ALPHA_OVER, cv::cuda::ALPHA_IN, cv::cuda::ALPHA_OUT, cv::cuda::ALPHA_ATOP, cv::cuda::ALPHA_XOR, cv::cuda::ALPHA_PLUS, cv::cuda::ALPHA_OVER_PREMUL, cv::cuda::ALPHA_IN_PREMUL, cv::cuda::ALPHA_OUT_PREMUL, cv::cuda::ALPHA_ATOP_PREMUL, cv::cuda::ALPHA_XOR_PREMUL, cv::cuda::ALPHA_PLUS_PREMUL, cv::cuda::ALPHA_PREMUL)
DEF_PARAM_TEST(Sz_Type_Op, cv::Size, MatType, AlphaOp);
PERF_TEST_P(Sz_Type_Op, AlphaComp,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(CV_8UC4, CV_16UC4, CV_32SC4, CV_32FC4),
AlphaOp::all()))
{
const cv::Size size = GET_PARAM(0);
const int type = GET_PARAM(1);
const int alpha_op = GET_PARAM(2);
cv::Mat img1(size, type);
cv::Mat img2(size, type);
declare.in(img1, img2, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_img1(img1);
const cv::cuda::GpuMat d_img2(img2);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::alphaComp(d_img1, d_img2, dst, alpha_op);
// The function is a just wrapper for NPP. We can't control its results.
SANITY_CHECK_NOTHING();
}
else
{
FAIL_NO_CPU();
}
}
}} // namespace
+221
View File
@@ -0,0 +1,221 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
//////////////////////////////////////////////////////////////////////
// HistEvenC1
DEF_PARAM_TEST(Sz_Depth, cv::Size, MatDepth);
PERF_TEST_P(Sz_Depth, HistEvenC1,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(CV_8U, CV_16U, CV_16S)))
{
const cv::Size size = GET_PARAM(0);
const int depth = GET_PARAM(1);
cv::Mat src(size, depth);
declare.in(src, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::histEven(d_src, dst, 30, 0, 180);
CUDA_SANITY_CHECK(dst);
}
else
{
const int hbins = 30;
const float hranges[] = {0.0f, 180.0f};
const int histSize[] = {hbins};
const float* ranges[] = {hranges};
const int channels[] = {0};
cv::Mat dst;
TEST_CYCLE() cv::calcHist(&src, 1, channels, cv::Mat(), dst, 1, histSize, ranges);
CPU_SANITY_CHECK(dst);
}
}
//////////////////////////////////////////////////////////////////////
// HistEvenC4
PERF_TEST_P(Sz_Depth, HistEvenC4,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(CV_8U, CV_16U, CV_16S)))
{
const cv::Size size = GET_PARAM(0);
const int depth = GET_PARAM(1);
cv::Mat src(size, CV_MAKE_TYPE(depth, 4));
declare.in(src, WARMUP_RNG);
int histSize[] = {30, 30, 30, 30};
int lowerLevel[] = {0, 0, 0, 0};
int upperLevel[] = {180, 180, 180, 180};
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat d_hist[4];
TEST_CYCLE() cv::cuda::histEven(d_src, d_hist, histSize, lowerLevel, upperLevel);
cv::Mat cpu_hist0, cpu_hist1, cpu_hist2, cpu_hist3;
d_hist[0].download(cpu_hist0);
d_hist[1].download(cpu_hist1);
d_hist[2].download(cpu_hist2);
d_hist[3].download(cpu_hist3);
SANITY_CHECK(cpu_hist0);
SANITY_CHECK(cpu_hist1);
SANITY_CHECK(cpu_hist2);
SANITY_CHECK(cpu_hist3);
}
else
{
FAIL_NO_CPU();
}
}
//////////////////////////////////////////////////////////////////////
// CalcHist
PERF_TEST_P(Sz, CalcHist,
CUDA_TYPICAL_MAT_SIZES)
{
const cv::Size size = GetParam();
cv::Mat src(size, CV_8UC1);
declare.in(src, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::calcHist(d_src, dst);
CUDA_SANITY_CHECK(dst);
}
else
{
FAIL_NO_CPU();
}
}
//////////////////////////////////////////////////////////////////////
// EqualizeHist
PERF_TEST_P(Sz, EqualizeHist,
CUDA_TYPICAL_MAT_SIZES)
{
const cv::Size size = GetParam();
cv::Mat src(size, CV_8UC1);
declare.in(src, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::equalizeHist(d_src, dst);
CUDA_SANITY_CHECK(dst);
}
else
{
cv::Mat dst;
TEST_CYCLE() cv::equalizeHist(src, dst);
CPU_SANITY_CHECK(dst);
}
}
//////////////////////////////////////////////////////////////////////
// CLAHE
DEF_PARAM_TEST(Sz_ClipLimit, cv::Size, double, MatType);
PERF_TEST_P(Sz_ClipLimit, CLAHE,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(0.0, 40.0),
Values(MatType(CV_8UC1), MatType(CV_16UC1))))
{
const cv::Size size = GET_PARAM(0);
const double clipLimit = GET_PARAM(1);
const int type = GET_PARAM(2);
cv::Mat src(size, type);
declare.in(src, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
cv::Ptr<cv::cuda::CLAHE> clahe = cv::cuda::createCLAHE(clipLimit);
cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat dst;
TEST_CYCLE() clahe->apply(d_src, dst);
CUDA_SANITY_CHECK(dst);
}
else
{
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(clipLimit);
cv::Mat dst;
TEST_CYCLE() clahe->apply(src, dst);
CPU_SANITY_CHECK(dst);
}
}
}} // namespace
+348
View File
@@ -0,0 +1,348 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
//////////////////////////////////////////////////////////////////////
// HoughLines
namespace
{
struct Vec4iComparator
{
bool operator()(const cv::Vec4i& a, const cv::Vec4i b) const
{
if (a[0] != b[0]) return a[0] < b[0];
else if(a[1] != b[1]) return a[1] < b[1];
else if(a[2] != b[2]) return a[2] < b[2];
else return a[3] < b[3];
}
};
struct Vec3fComparator
{
bool operator()(const cv::Vec3f& a, const cv::Vec3f b) const
{
if(a[0] != b[0]) return a[0] < b[0];
else if(a[1] != b[1]) return a[1] < b[1];
else return a[2] < b[2];
}
};
struct Vec2fComparator
{
bool operator()(const cv::Vec2f& a, const cv::Vec2f b) const
{
if(a[0] != b[0]) return a[0] < b[0];
else return a[1] < b[1];
}
};
}
PERF_TEST_P(Sz, HoughLines,
CUDA_TYPICAL_MAT_SIZES)
{
declare.time(30.0);
const cv::Size size = GetParam();
const float rho = 1.0f;
const float theta = static_cast<float>(CV_PI / 180.0);
const int threshold = 300;
cv::Mat src(size, CV_8UC1, cv::Scalar::all(0));
cv::line(src, cv::Point(0, 100), cv::Point(src.cols, 100), cv::Scalar::all(255), 1);
cv::line(src, cv::Point(0, 200), cv::Point(src.cols, 200), cv::Scalar::all(255), 1);
cv::line(src, cv::Point(0, 400), cv::Point(src.cols, 400), cv::Scalar::all(255), 1);
cv::line(src, cv::Point(100, 0), cv::Point(100, src.rows), cv::Scalar::all(255), 1);
cv::line(src, cv::Point(200, 0), cv::Point(200, src.rows), cv::Scalar::all(255), 1);
cv::line(src, cv::Point(400, 0), cv::Point(400, src.rows), cv::Scalar::all(255), 1);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat d_lines;
cv::Ptr<cv::cuda::HoughLinesDetector> hough = cv::cuda::createHoughLinesDetector(rho, theta, threshold);
TEST_CYCLE() hough->detect(d_src, d_lines);
cv::Mat gpu_lines(d_lines.row(0));
cv::Vec2f* begin = gpu_lines.ptr<cv::Vec2f>(0);
cv::Vec2f* end = begin + gpu_lines.cols;
std::sort(begin, end, Vec2fComparator());
SANITY_CHECK(gpu_lines);
}
else
{
std::vector<cv::Vec2f> cpu_lines;
TEST_CYCLE() cv::HoughLines(src, cpu_lines, rho, theta, threshold);
SANITY_CHECK(cpu_lines);
}
}
//////////////////////////////////////////////////////////////////////
// HoughLinesP
DEF_PARAM_TEST_1(Image, std::string);
PERF_TEST_P(Image, HoughLinesP,
testing::Values("cv/shared/pic5.png", "stitching/a1.png"))
{
declare.time(30.0);
const std::string fileName = getDataPath(GetParam());
const float rho = 1.0f;
const float theta = static_cast<float>(CV_PI / 180.0);
const int threshold = 100;
const int minLineLength = 50;
const int maxLineGap = 5;
const cv::Mat image = cv::imread(fileName, cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(image.empty());
cv::Mat mask;
cv::Canny(image, mask, 50, 100);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_mask(mask);
cv::cuda::GpuMat d_lines;
cv::Ptr<cv::cuda::HoughSegmentDetector> hough = cv::cuda::createHoughSegmentDetector(rho, theta, minLineLength, maxLineGap);
TEST_CYCLE() hough->detect(d_mask, d_lines);
cv::Mat gpu_lines(d_lines);
cv::Vec4i* begin = gpu_lines.ptr<cv::Vec4i>();
cv::Vec4i* end = begin + gpu_lines.cols;
std::sort(begin, end, Vec4iComparator());
SANITY_CHECK(gpu_lines);
}
else
{
std::vector<cv::Vec4i> cpu_lines;
TEST_CYCLE() cv::HoughLinesP(mask, cpu_lines, rho, theta, threshold, minLineLength, maxLineGap);
SANITY_CHECK(cpu_lines);
}
}
//////////////////////////////////////////////////////////////////////
// HoughCircles
DEF_PARAM_TEST(Sz_Dp_MinDist, cv::Size, float, float);
PERF_TEST_P(Sz_Dp_MinDist, HoughCircles,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(1.0f, 2.0f, 4.0f),
Values(1.0f)))
{
declare.time(30.0);
const cv::Size size = GET_PARAM(0);
const float dp = GET_PARAM(1);
const float minDist = GET_PARAM(2);
const int minRadius = 10;
const int maxRadius = 30;
const int cannyThreshold = 100;
const int votesThreshold = 15;
cv::Mat src(size, CV_8UC1, cv::Scalar::all(0));
cv::circle(src, cv::Point(100, 100), 20, cv::Scalar::all(255), -1);
cv::circle(src, cv::Point(200, 200), 25, cv::Scalar::all(255), -1);
cv::circle(src, cv::Point(200, 100), 25, cv::Scalar::all(255), -1);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(src);
cv::cuda::GpuMat d_circles;
cv::Ptr<cv::cuda::HoughCirclesDetector> houghCircles = cv::cuda::createHoughCirclesDetector(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius);
TEST_CYCLE() houghCircles->detect(d_src, d_circles);
cv::Mat gpu_circles(d_circles);
cv::Vec3f* begin = gpu_circles.ptr<cv::Vec3f>(0);
cv::Vec3f* end = begin + gpu_circles.cols;
std::sort(begin, end, Vec3fComparator());
SANITY_CHECK(gpu_circles);
}
else
{
std::vector<cv::Vec3f> cpu_circles;
TEST_CYCLE() cv::HoughCircles(src, cpu_circles, cv::HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius);
SANITY_CHECK(cpu_circles);
}
}
//////////////////////////////////////////////////////////////////////
// GeneralizedHough
PERF_TEST_P(Sz, GeneralizedHoughBallard, CUDA_TYPICAL_MAT_SIZES)
{
declare.time(10);
const cv::Size imageSize = GetParam();
const cv::Mat templ = readImage("cv/shared/templ.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(templ.empty());
cv::Mat image(imageSize, CV_8UC1, cv::Scalar::all(0));
templ.copyTo(image(cv::Rect(50, 50, templ.cols, templ.rows)));
cv::Mat edges;
cv::Canny(image, edges, 50, 100);
cv::Mat dx, dy;
cv::Sobel(image, dx, CV_32F, 1, 0);
cv::Sobel(image, dy, CV_32F, 0, 1);
if (PERF_RUN_CUDA())
{
cv::Ptr<cv::GeneralizedHoughBallard> alg = cv::cuda::createGeneralizedHoughBallard();
const cv::cuda::GpuMat d_edges(edges);
const cv::cuda::GpuMat d_dx(dx);
const cv::cuda::GpuMat d_dy(dy);
cv::cuda::GpuMat positions;
alg->setTemplate(cv::cuda::GpuMat(templ));
TEST_CYCLE() alg->detect(d_edges, d_dx, d_dy, positions);
CUDA_SANITY_CHECK(positions);
}
else
{
cv::Ptr<cv::GeneralizedHoughBallard> alg = cv::createGeneralizedHoughBallard();
cv::Mat positions;
alg->setTemplate(templ);
TEST_CYCLE() alg->detect(edges, dx, dy, positions);
CPU_SANITY_CHECK(positions);
}
}
PERF_TEST_P(Sz, DISABLED_GeneralizedHoughGuil, CUDA_TYPICAL_MAT_SIZES)
{
declare.time(10);
const cv::Size imageSize = GetParam();
const cv::Mat templ = readImage("cv/shared/templ.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(templ.empty());
cv::Mat image(imageSize, CV_8UC1, cv::Scalar::all(0));
templ.copyTo(image(cv::Rect(50, 50, templ.cols, templ.rows)));
cv::RNG rng(123456789);
const int objCount = rng.uniform(5, 15);
for (int i = 0; i < objCount; ++i)
{
double scale = rng.uniform(0.7, 1.3);
bool rotate = 1 == rng.uniform(0, 2);
cv::Mat obj;
cv::resize(templ, obj, cv::Size(), scale, scale);
if (rotate)
obj = obj.t();
cv::Point pos;
pos.x = rng.uniform(0, image.cols - obj.cols);
pos.y = rng.uniform(0, image.rows - obj.rows);
cv::Mat roi = image(cv::Rect(pos, obj.size()));
cv::add(roi, obj, roi);
}
cv::Mat edges;
cv::Canny(image, edges, 50, 100);
cv::Mat dx, dy;
cv::Sobel(image, dx, CV_32F, 1, 0);
cv::Sobel(image, dy, CV_32F, 0, 1);
if (PERF_RUN_CUDA())
{
cv::Ptr<cv::GeneralizedHoughGuil> alg = cv::cuda::createGeneralizedHoughGuil();
alg->setMaxAngle(90.0);
alg->setAngleStep(2.0);
const cv::cuda::GpuMat d_edges(edges);
const cv::cuda::GpuMat d_dx(dx);
const cv::cuda::GpuMat d_dy(dy);
cv::cuda::GpuMat positions;
alg->setTemplate(cv::cuda::GpuMat(templ));
TEST_CYCLE() alg->detect(d_edges, d_dx, d_dy, positions);
}
else
{
cv::Ptr<cv::GeneralizedHoughGuil> alg = cv::createGeneralizedHoughGuil();
alg->setMaxAngle(90.0);
alg->setAngleStep(2.0);
cv::Mat positions;
alg->setTemplate(templ);
TEST_CYCLE() alg->detect(edges, dx, dy, positions);
}
// The algorithm is not stable yet.
SANITY_CHECK_NOTHING();
}
}} // namespace
+47
View File
@@ -0,0 +1,47 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
using namespace perf;
CV_PERF_TEST_CUDA_MAIN(cudaimgproc)
@@ -0,0 +1,135 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
////////////////////////////////////////////////////////////////////////////////
// MatchTemplate8U
CV_ENUM(TemplateMethod, TM_SQDIFF, TM_SQDIFF_NORMED, TM_CCORR, TM_CCORR_NORMED, TM_CCOEFF, TM_CCOEFF_NORMED)
DEF_PARAM_TEST(Sz_TemplateSz_Cn_Method, cv::Size, cv::Size, MatCn, TemplateMethod);
PERF_TEST_P(Sz_TemplateSz_Cn_Method, MatchTemplate8U,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(cv::Size(5, 5), cv::Size(16, 16), cv::Size(30, 30)),
CUDA_CHANNELS_1_3_4,
TemplateMethod::all()))
{
declare.time(300.0);
const cv::Size size = GET_PARAM(0);
const cv::Size templ_size = GET_PARAM(1);
const int cn = GET_PARAM(2);
const int method = GET_PARAM(3);
cv::Mat image(size, CV_MAKE_TYPE(CV_8U, cn));
cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_8U, cn));
declare.in(image, templ, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_image(image);
const cv::cuda::GpuMat d_templ(templ);
cv::cuda::GpuMat dst;
cv::Ptr<cv::cuda::TemplateMatching> alg = cv::cuda::createTemplateMatching(image.type(), method);
TEST_CYCLE() alg->match(d_image, d_templ, dst);
CUDA_SANITY_CHECK(dst, 1e-5, ERROR_RELATIVE);
}
else
{
cv::Mat dst;
TEST_CYCLE() cv::matchTemplate(image, templ, dst, method);
CPU_SANITY_CHECK(dst);
}
}
////////////////////////////////////////////////////////////////////////////////
// MatchTemplate32F
PERF_TEST_P(Sz_TemplateSz_Cn_Method, MatchTemplate32F,
Combine(CUDA_TYPICAL_MAT_SIZES,
Values(cv::Size(5, 5), cv::Size(16, 16), cv::Size(30, 30)),
CUDA_CHANNELS_1_3_4,
Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_CCORR))))
{
declare.time(300.0);
const cv::Size size = GET_PARAM(0);
const cv::Size templ_size = GET_PARAM(1);
const int cn = GET_PARAM(2);
int method = GET_PARAM(3);
cv::Mat image(size, CV_MAKE_TYPE(CV_32F, cn));
cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_32F, cn));
declare.in(image, templ, WARMUP_RNG);
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_image(image);
const cv::cuda::GpuMat d_templ(templ);
cv::cuda::GpuMat dst;
cv::Ptr<cv::cuda::TemplateMatching> alg = cv::cuda::createTemplateMatching(image.type(), method);
TEST_CYCLE() alg->match(d_image, d_templ, dst);
CUDA_SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE);
}
else
{
cv::Mat dst;
TEST_CYCLE() cv::matchTemplate(image, templ, dst, method);
CPU_SANITY_CHECK(dst);
}
}
}} // namespace
@@ -0,0 +1,152 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
//////////////////////////////////////////////////////////////////////
// MeanShiftFiltering
DEF_PARAM_TEST_1(Image, string);
PERF_TEST_P(Image, MeanShiftFiltering,
Values<string>("gpu/meanshift/cones.png"))
{
declare.time(300.0);
const cv::Mat img = readImage(GetParam());
ASSERT_FALSE(img.empty());
cv::Mat rgba;
cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA);
const int sp = 50;
const int sr = 50;
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(rgba);
cv::cuda::GpuMat dst;
TEST_CYCLE() cv::cuda::meanShiftFiltering(d_src, dst, sp, sr);
CUDA_SANITY_CHECK(dst);
}
else
{
cv::Mat dst;
TEST_CYCLE() cv::pyrMeanShiftFiltering(img, dst, sp, sr);
CPU_SANITY_CHECK(dst);
}
}
//////////////////////////////////////////////////////////////////////
// MeanShiftProc
PERF_TEST_P(Image, MeanShiftProc,
Values<string>("gpu/meanshift/cones.png"))
{
declare.time(300.0);
const cv::Mat img = readImage(GetParam());
ASSERT_FALSE(img.empty());
cv::Mat rgba;
cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA);
const int sp = 50;
const int sr = 50;
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(rgba);
cv::cuda::GpuMat dstr;
cv::cuda::GpuMat dstsp;
TEST_CYCLE() cv::cuda::meanShiftProc(d_src, dstr, dstsp, sp, sr);
CUDA_SANITY_CHECK(dstr);
CUDA_SANITY_CHECK(dstsp);
}
else
{
FAIL_NO_CPU();
}
}
//////////////////////////////////////////////////////////////////////
// MeanShiftSegmentation
PERF_TEST_P(Image, MeanShiftSegmentation,
Values<string>("gpu/meanshift/cones.png"))
{
declare.time(300.0);
const cv::Mat img = readImage(GetParam());
ASSERT_FALSE(img.empty());
cv::Mat rgba;
cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA);
const int sp = 10;
const int sr = 10;
const int minsize = 20;
if (PERF_RUN_CUDA())
{
const cv::cuda::GpuMat d_src(rgba);
cv::Mat dst;
TEST_CYCLE() cv::cuda::meanShiftSegmentation(d_src, dst, sp, sr, minsize);
CUDA_SANITY_CHECK(dst);
}
else
{
FAIL_NO_CPU();
}
}
}} // namespace
+61
View File
@@ -0,0 +1,61 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "perf_precomp.hpp"
namespace opencv_test { namespace {
static void drawCircle(cv::Mat& dst, const cv::Vec3i& circle, bool fill)
{
dst.setTo(Scalar::all(0));
cv::circle(dst, Point2i(circle[0], circle[1]), circle[2], Scalar::all(255), fill ? -1 : 1, cv::LINE_AA);
}
DEF_PARAM_TEST(Sz_Depth, Size, MatDepth);
PERF_TEST_P(Sz_Depth, SpatialMoments, Combine(CUDA_TYPICAL_MAT_SIZES, Values(MatDepth(CV_32F), MatDepth((CV_64F)))))
{
const cv::Size size = GET_PARAM(0);
const int momentsType = GET_PARAM(1);
Mat imgHost(size, CV_8U);
const Vec3i circle(size.width / 2, size.height / 2, static_cast<int>(static_cast<float>(size.width / 2) * 0.9));
drawCircle(imgHost, circle, true);
if (PERF_RUN_CUDA()) {
const MomentsOrder order = MomentsOrder::THIRD_ORDER_MOMENTS;
const int nMoments = numMoments(order);
GpuMat momentsDevice(1, nMoments, momentsType);
const GpuMat imgDevice(imgHost);
TEST_CYCLE() cuda::spatialMoments(imgDevice, momentsDevice, false, order, momentsType);
SANITY_CHECK_NOTHING();
}
else {
cv::Moments momentsHost;
TEST_CYCLE() momentsHost = cv::moments(imgHost, false);
SANITY_CHECK_NOTHING();
}
}
PERF_TEST_P(Sz_Depth, Moments, Combine(CUDA_TYPICAL_MAT_SIZES, Values(MatDepth(CV_32F), MatDepth(CV_64F))))
{
const cv::Size size = GET_PARAM(0);
const int momentsType = GET_PARAM(1);
Mat imgHost(size, CV_8U);
const Vec3i circle(size.width / 2, size.height / 2, static_cast<int>(static_cast<float>(size.width / 2) * 0.9));
drawCircle(imgHost, circle, true);
if (PERF_RUN_CUDA()) {
const MomentsOrder order = MomentsOrder::THIRD_ORDER_MOMENTS;
const int nMoments = numMoments(order);
setBufferPoolUsage(true);
setBufferPoolConfig(getDevice(), nMoments * ((momentsType == CV_64F) ? sizeof(double) : sizeof(float)), 1);
const GpuMat imgDevice(imgHost);
cv::Moments momentsHost;
TEST_CYCLE() momentsHost = cuda::moments(imgDevice, false, order, momentsType);
SANITY_CHECK_NOTHING();
}
else {
cv::Moments momentsHost;
TEST_CYCLE() momentsHost = cv::moments(imgHost, false);
SANITY_CHECK_NOTHING();
}
}
}}
+55
View File
@@ -0,0 +1,55 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __OPENCV_PERF_PRECOMP_HPP__
#define __OPENCV_PERF_PRECOMP_HPP__
#include "opencv2/ts.hpp"
#include "opencv2/ts/cuda_perf.hpp"
#include "opencv2/cudaimgproc.hpp"
#include "opencv2/geometry.hpp"
namespace opencv_test {
using namespace perf;
using namespace testing;
}
#endif
@@ -0,0 +1,58 @@
#include <iostream>
#include <opencv2/core/utility.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/cudaimgproc.hpp"
using namespace cv;
using namespace std;
using namespace cv::cuda;
void colorLabels(const Mat1i& labels, Mat3b& colors) {
colors.create(labels.size());
for (int r = 0; r < labels.rows; ++r) {
int const* labels_row = labels.ptr<int>(r);
Vec3b* colors_row = colors.ptr<Vec3b>(r);
for (int c = 0; c < labels.cols; ++c) {
colors_row[c] = Vec3b(labels_row[c] * 131 % 255, labels_row[c] * 241 % 255, labels_row[c] * 251 % 255);
}
}
}
int main(int argc, const char** argv)
{
CommandLineParser parser(argc, argv, "{@image|stuff.jpg|image for converting to a grayscale}");
parser.about("This program finds connected components in a binary image and assign each of them a different color.\n"
"The connected components labeling is performed in GPU.\n");
parser.printMessage();
String inputImage = parser.get<string>(0);
Mat1b img = imread(samples::findFile(inputImage), IMREAD_GRAYSCALE);
Mat1i labels;
if (img.empty())
{
cout << "Could not read input image file: " << inputImage << endl;
return EXIT_FAILURE;
}
GpuMat d_img, d_labels;
d_img.upload(img);
cuda::connectedComponents(d_img, d_labels, 8, CV_32S);
d_labels.download(labels);
Mat3b colors;
colorLabels(labels, colors);
imshow("Labels", colors);
waitKey(0);
return EXIT_SUCCESS;
}
@@ -0,0 +1,99 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
void cv::cuda::bilateralFilter(InputArray, OutputArray, int, float, float, int, Stream&) { throw_no_cuda(); }
#else
namespace cv { namespace cuda { namespace device
{
namespace imgproc
{
template<typename T>
void bilateral_filter_gpu(const PtrStepSzb& src, PtrStepSzb dst, int kernel_size, float sigma_spatial, float sigma_color, int borderMode, cudaStream_t stream);
}
}}}
void cv::cuda::bilateralFilter(InputArray _src, OutputArray _dst, int kernel_size, float sigma_color, float sigma_spatial, int borderMode, Stream& stream)
{
using cv::cuda::device::imgproc::bilateral_filter_gpu;
typedef void (*func_t)(const PtrStepSzb& src, PtrStepSzb dst, int kernel_size, float sigma_spatial, float sigma_color, int borderMode, cudaStream_t s);
static const func_t funcs[6][4] =
{
{bilateral_filter_gpu<uchar> , 0 /*bilateral_filter_gpu<uchar2>*/ , bilateral_filter_gpu<uchar3> , bilateral_filter_gpu<uchar4> },
{0 /*bilateral_filter_gpu<schar>*/, 0 /*bilateral_filter_gpu<schar2>*/ , 0 /*bilateral_filter_gpu<schar3>*/, 0 /*bilateral_filter_gpu<schar4>*/},
{bilateral_filter_gpu<ushort> , 0 /*bilateral_filter_gpu<ushort2>*/, bilateral_filter_gpu<ushort3> , bilateral_filter_gpu<ushort4> },
{bilateral_filter_gpu<short> , 0 /*bilateral_filter_gpu<short2>*/ , bilateral_filter_gpu<short3> , bilateral_filter_gpu<short4> },
{0 /*bilateral_filter_gpu<int>*/ , 0 /*bilateral_filter_gpu<int2>*/ , 0 /*bilateral_filter_gpu<int3>*/ , 0 /*bilateral_filter_gpu<int4>*/ },
{bilateral_filter_gpu<float> , 0 /*bilateral_filter_gpu<float2>*/ , bilateral_filter_gpu<float3> , bilateral_filter_gpu<float4> }
};
sigma_color = (sigma_color <= 0 ) ? 1 : sigma_color;
sigma_spatial = (sigma_spatial <= 0 ) ? 1 : sigma_spatial;
int radius = (kernel_size <= 0) ? cvRound(sigma_spatial*1.5) : kernel_size/2;
kernel_size = std::max(radius, 1)*2 + 1;
GpuMat src = _src.getGpuMat();
CV_Assert( src.depth() <= CV_32F && src.channels() <= 4 );
CV_Assert( borderMode == BORDER_REFLECT101 || borderMode == BORDER_REPLICATE || borderMode == BORDER_CONSTANT || borderMode == BORDER_REFLECT || borderMode == BORDER_WRAP );
const func_t func = funcs[src.depth()][src.channels() - 1];
CV_Assert( func != 0 );
_dst.create(src.size(), src.type());
GpuMat dst = _dst.getGpuMat();
func(src, dst, kernel_size, sigma_spatial, sigma_color, borderMode, StreamAccessor::getStream(stream));
}
#endif
+109
View File
@@ -0,0 +1,109 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
void cv::cuda::blendLinear(InputArray, InputArray, InputArray, InputArray, OutputArray, Stream&) { throw_no_cuda(); }
#else
////////////////////////////////////////////////////////////////////////
// blendLinear
namespace cv { namespace cuda { namespace device
{
namespace blend
{
template <typename T>
void blendLinearCaller(int rows, int cols, int cn, PtrStep<T> img1, PtrStep<T> img2, PtrStepf weights1, PtrStepf weights2, PtrStep<T> result, cudaStream_t stream);
void blendLinearCaller8UC4(int rows, int cols, PtrStepb img1, PtrStepb img2, PtrStepf weights1, PtrStepf weights2, PtrStepb result, cudaStream_t stream);
}
}}}
using namespace ::cv::cuda::device::blend;
void cv::cuda::blendLinear(InputArray _img1, InputArray _img2, InputArray _weights1, InputArray _weights2,
OutputArray _result, Stream& stream)
{
GpuMat img1 = _img1.getGpuMat();
GpuMat img2 = _img2.getGpuMat();
GpuMat weights1 = _weights1.getGpuMat();
GpuMat weights2 = _weights2.getGpuMat();
CV_Assert( img1.size() == img2.size() );
CV_Assert( img1.type() == img2.type() );
CV_Assert( weights1.size() == img1.size() );
CV_Assert( weights2.size() == img2.size() );
CV_Assert( weights1.type() == CV_32FC1 );
CV_Assert( weights2.type() == CV_32FC1 );
const Size size = img1.size();
const int depth = img1.depth();
const int cn = img1.channels();
_result.create(size, CV_MAKE_TYPE(depth, cn));
GpuMat result = _result.getGpuMat();
switch (depth)
{
case CV_8U:
if (cn != 4)
blendLinearCaller<uchar>(size.height, size.width, cn, img1, img2, weights1, weights2, result, StreamAccessor::getStream(stream));
else
blendLinearCaller8UC4(size.height, size.width, img1, img2, weights1, weights2, result, StreamAccessor::getStream(stream));
break;
case CV_32F:
blendLinearCaller<float>(size.height, size.width, cn, img1, img2, weights1, weights2, result, StreamAccessor::getStream(stream));
break;
default:
CV_Error(cv::Error::StsUnsupportedFormat, "bad image depth in linear blending function");
}
}
#endif
+245
View File
@@ -0,0 +1,245 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
Ptr<CannyEdgeDetector> cv::cuda::createCannyEdgeDetector(double, double, int, bool) { throw_no_cuda(); return Ptr<CannyEdgeDetector>(); }
#else /* !defined (HAVE_CUDA) */
namespace canny
{
void calcMagnitude(PtrStepSzb srcWhole, int xoff, int yoff, PtrStepSzi dx, PtrStepSzi dy, PtrStepSzf mag, bool L2Grad, cudaStream_t stream);
void calcMagnitude(PtrStepSzi dx, PtrStepSzi dy, PtrStepSzf mag, bool L2Grad, cudaStream_t stream);
void calcMap(PtrStepSzi dx, PtrStepSzi dy, PtrStepSzf mag, PtrStepSzi map, float low_thresh, float high_thresh, cudaStream_t stream);
void edgesHysteresisLocal(PtrStepSzi map, short2* st1, int* d_counter, cudaStream_t stream);
void edgesHysteresisGlobal(PtrStepSzi map, short2* st1, short2* st2, int* d_counter, cudaStream_t stream);
void getEdges(PtrStepSzi map, PtrStepSzb dst, cudaStream_t stream);
}
namespace
{
class CannyImpl : public CannyEdgeDetector
{
public:
CannyImpl(double low_thresh, double high_thresh, int apperture_size, bool L2gradient) :
low_thresh_(low_thresh), high_thresh_(high_thresh), apperture_size_(apperture_size), L2gradient_(L2gradient)
{
old_apperture_size_ = -1;
d_counter = nullptr;
}
void detect(InputArray image, OutputArray edges, Stream& stream);
void detect(InputArray dx, InputArray dy, OutputArray edges, Stream& stream);
void setLowThreshold(double low_thresh) { low_thresh_ = low_thresh; }
double getLowThreshold() const { return low_thresh_; }
void setHighThreshold(double high_thresh) { high_thresh_ = high_thresh; }
double getHighThreshold() const { return high_thresh_; }
void setAppertureSize(int apperture_size) { apperture_size_ = apperture_size; }
int getAppertureSize() const { return apperture_size_; }
void setL2Gradient(bool L2gradient) { L2gradient_ = L2gradient; }
bool getL2Gradient() const { return L2gradient_; }
void write(FileStorage& fs) const
{
writeFormat(fs);
fs << "name" << "Canny_CUDA"
<< "low_thresh" << low_thresh_
<< "high_thresh" << high_thresh_
<< "apperture_size" << apperture_size_
<< "L2gradient" << L2gradient_;
}
void read(const FileNode& fn)
{
CV_Assert( String(fn["name"]) == "Canny_CUDA" );
low_thresh_ = (double)fn["low_thresh"];
high_thresh_ = (double)fn["high_thresh"];
apperture_size_ = (int)fn["apperture_size"];
L2gradient_ = (int)fn["L2gradient"] != 0;
}
private:
void createBuf(Size image_size);
void CannyCaller(GpuMat& edges, Stream& stream);
double low_thresh_;
double high_thresh_;
int apperture_size_;
bool L2gradient_;
GpuMat dx_, dy_;
GpuMat mag_;
GpuMat map_;
GpuMat st1_, st2_;
#ifdef HAVE_OPENCV_CUDAFILTERS
Ptr<Filter> filterDX_, filterDY_;
#endif
int old_apperture_size_;
int *d_counter;
};
void CannyImpl::detect(InputArray _image, OutputArray _edges, Stream& stream)
{
GpuMat image = _image.getGpuMat();
CV_Assert( image.type() == CV_8UC1 );
CV_Assert( deviceSupports(SHARED_ATOMICS) );
if (low_thresh_ > high_thresh_)
std::swap(low_thresh_, high_thresh_);
createBuf(image.size());
_edges.create(image.size(), CV_8UC1);
GpuMat edges = _edges.getGpuMat();
if (apperture_size_ == 3)
{
Size wholeSize;
Point ofs;
image.locateROI(wholeSize, ofs);
GpuMat srcWhole(wholeSize, image.type(), image.datastart, image.step);
canny::calcMagnitude(srcWhole, ofs.x, ofs.y, dx_, dy_, mag_, L2gradient_, StreamAccessor::getStream(stream));
}
else
{
#ifndef HAVE_OPENCV_CUDAFILTERS
throw_no_cuda();
#else
filterDX_->apply(image, dx_, stream);
filterDY_->apply(image, dy_, stream);
canny::calcMagnitude(dx_, dy_, mag_, L2gradient_, StreamAccessor::getStream(stream));
#endif
}
CannyCaller(edges, stream);
}
void CannyImpl::detect(InputArray _dx, InputArray _dy, OutputArray _edges, Stream& stream)
{
GpuMat dx = _dx.getGpuMat();
GpuMat dy = _dy.getGpuMat();
CV_Assert( dx.type() == CV_32SC1 );
CV_Assert( dy.type() == dx.type() && dy.size() == dx.size() );
CV_Assert( deviceSupports(SHARED_ATOMICS) );
dx.copyTo(dx_, stream);
dy.copyTo(dy_, stream);
if (low_thresh_ > high_thresh_)
std::swap(low_thresh_, high_thresh_);
createBuf(dx.size());
_edges.create(dx.size(), CV_8UC1);
GpuMat edges = _edges.getGpuMat();
canny::calcMagnitude(dx_, dy_, mag_, L2gradient_, StreamAccessor::getStream(stream));
CannyCaller(edges, stream);
}
void CannyImpl::createBuf(Size image_size)
{
CV_Assert(image_size.width < std::numeric_limits<short>::max() && image_size.height < std::numeric_limits<short>::max());
ensureSizeIsEnough(image_size, CV_32SC1, dx_);
ensureSizeIsEnough(image_size, CV_32SC1, dy_);
#ifdef HAVE_OPENCV_CUDAFILTERS
if (apperture_size_ != 3 && apperture_size_ != old_apperture_size_)
{
filterDX_ = cuda::createDerivFilter(CV_8UC1, CV_32S, 1, 0, apperture_size_, false, 1, BORDER_REPLICATE);
filterDY_ = cuda::createDerivFilter(CV_8UC1, CV_32S, 0, 1, apperture_size_, false, 1, BORDER_REPLICATE);
old_apperture_size_ = apperture_size_;
}
#endif
ensureSizeIsEnough(image_size, CV_32FC1, mag_);
ensureSizeIsEnough(image_size, CV_32SC1, map_);
ensureSizeIsEnough(1, image_size.area(), CV_16SC2, st1_);
ensureSizeIsEnough(1, image_size.area(), CV_16SC2, st2_);
}
void CannyImpl::CannyCaller(GpuMat& edges, Stream& stream)
{
map_.setTo(Scalar::all(0), stream);
canny::calcMap(dx_, dy_, mag_, map_, static_cast<float>(low_thresh_), static_cast<float>(high_thresh_), StreamAccessor::getStream(stream));
cudaSafeCall( cudaMalloc(&d_counter, sizeof(int)) );
canny::edgesHysteresisLocal(map_, st1_.ptr<short2>(), d_counter, StreamAccessor::getStream(stream));
canny::edgesHysteresisGlobal(map_, st1_.ptr<short2>(), st2_.ptr<short2>(), d_counter, StreamAccessor::getStream(stream));
cudaSafeCall( cudaFree(d_counter) );
canny::getEdges(map_, edges, StreamAccessor::getStream(stream));
}
}
Ptr<CannyEdgeDetector> cv::cuda::createCannyEdgeDetector(double low_thresh, double high_thresh, int apperture_size, bool L2gradient)
{
return makePtr<CannyImpl>(low_thresh, high_thresh, apperture_size, L2gradient);
}
#endif /* !defined (HAVE_CUDA) */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,49 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
void cv::cuda::connectedComponents(InputArray, OutputArray, int, int, ConnectedComponentsAlgorithmsTypes) { throw_no_cuda(); }
void cv::cuda::connectedComponents(InputArray, OutputArray, int, int) { throw_no_cuda(); }
#else /* !defined (HAVE_CUDA) */
namespace cv { namespace cuda { namespace device { namespace imgproc {
void BlockBasedKomuraEquivalence(const cv::cuda::GpuMat& img, cv::cuda::GpuMat& labels);
}}}}
void cv::cuda::connectedComponents(InputArray img_, OutputArray labels_, int connectivity,
int ltype, ConnectedComponentsAlgorithmsTypes ccltype) {
const cv::cuda::GpuMat img = img_.getGpuMat();
cv::cuda::GpuMat& labels = labels_.getGpuMatRef();
CV_Assert(img.channels() == 1);
CV_Assert(connectivity == 8);
CV_Assert(ltype == CV_32S);
CV_Assert(ccltype == CCL_BKE || ccltype == CCL_DEFAULT);
int iDepth = img_.depth();
CV_Assert(iDepth == CV_8U || iDepth == CV_8S);
labels.create(img.size(), CV_MAT_DEPTH(ltype));
if ((ccltype == CCL_BKE || ccltype == CCL_DEFAULT) && connectivity == 8 && ltype == CV_32S) {
using cv::cuda::device::imgproc::BlockBasedKomuraEquivalence;
BlockBasedKomuraEquivalence(img, labels);
}
}
void cv::cuda::connectedComponents(InputArray img_, OutputArray labels_, int connectivity, int ltype) {
cv::cuda::connectedComponents(img_, labels_, connectivity, ltype, CCL_DEFAULT);
}
#endif /* !defined (HAVE_CUDA) */
@@ -0,0 +1,199 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/vec_traits.hpp"
#include "opencv2/core/cuda/vec_math.hpp"
#include "opencv2/core/cuda/border_interpolate.hpp"
using namespace cv::cuda;
typedef unsigned char uchar;
typedef unsigned short ushort;
//////////////////////////////////////////////////////////////////////////////////
/// Bilateral filtering
namespace cv { namespace cuda { namespace device
{
namespace imgproc
{
__device__ __forceinline__ float norm_l1(const float& a) { return ::fabs(a); }
__device__ __forceinline__ float norm_l1(const float2& a) { return ::fabs(a.x) + ::fabs(a.y); }
__device__ __forceinline__ float norm_l1(const float3& a) { return ::fabs(a.x) + ::fabs(a.y) + ::fabs(a.z); }
__device__ __forceinline__ float norm_l1(const float4& a) { return ::fabs(a.x) + ::fabs(a.y) + ::fabs(a.z) + ::fabs(a.w); }
__device__ __forceinline__ float sqr(const float& a) { return a * a; }
template<typename T, typename B>
__global__ void bilateral_kernel(const PtrStepSz<T> src, PtrStep<T> dst, const B b, const int ksz, const float sigma_spatial2_inv_half, const float sigma_color2_inv_half)
{
typedef typename TypeVec<float, VecTraits<T>::cn>::vec_type value_type;
int x = threadIdx.x + blockIdx.x * blockDim.x;
int y = threadIdx.y + blockIdx.y * blockDim.y;
if (x >= src.cols || y >= src.rows)
return;
value_type center = saturate_cast<value_type>(src(y, x));
value_type sum1 = VecTraits<value_type>::all(0);
float sum2 = 0;
int r = ksz / 2;
float r2 = (float)(r * r);
int tx = x - r + ksz;
int ty = y - r + ksz;
if (x - ksz/2 >=0 && y - ksz/2 >=0 && tx < src.cols && ty < src.rows)
{
for (int cy = y - r; cy < ty; ++cy)
for (int cx = x - r; cx < tx; ++cx)
{
float space2 = (x - cx) * (x - cx) + (y - cy) * (y - cy);
if (space2 > r2)
continue;
value_type value = saturate_cast<value_type>(src(cy, cx));
float weight = ::exp(space2 * sigma_spatial2_inv_half + sqr(norm_l1(value - center)) * sigma_color2_inv_half);
sum1 = sum1 + weight * value;
sum2 = sum2 + weight;
}
}
else
{
for (int cy = y - r; cy < ty; ++cy)
for (int cx = x - r; cx < tx; ++cx)
{
float space2 = (x - cx) * (x - cx) + (y - cy) * (y - cy);
if (space2 > r2)
continue;
value_type value = saturate_cast<value_type>(b.at(cy, cx, src.data, src.step));
float weight = ::exp(space2 * sigma_spatial2_inv_half + sqr(norm_l1(value - center)) * sigma_color2_inv_half);
sum1 = sum1 + weight * value;
sum2 = sum2 + weight;
}
}
dst(y, x) = saturate_cast<T>(sum1 / sum2);
}
template<typename T, template <typename> class B>
void bilateral_caller(const PtrStepSzb& src, PtrStepSzb dst, int kernel_size, float sigma_spatial, float sigma_color, cudaStream_t stream)
{
dim3 block (32, 8);
dim3 grid (divUp (src.cols, block.x), divUp (src.rows, block.y));
B<T> b(src.rows, src.cols);
float sigma_spatial2_inv_half = -0.5f/(sigma_spatial * sigma_spatial);
float sigma_color2_inv_half = -0.5f/(sigma_color * sigma_color);
cudaSafeCall( cudaFuncSetCacheConfig (bilateral_kernel<T, B<T> >, cudaFuncCachePreferL1) );
bilateral_kernel<<<grid, block, 0, stream>>>((PtrStepSz<T>)src, (PtrStepSz<T>)dst, b, kernel_size, sigma_spatial2_inv_half, sigma_color2_inv_half);
cudaSafeCall ( cudaGetLastError () );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
template<typename T>
void bilateral_filter_gpu(const PtrStepSzb& src, PtrStepSzb dst, int kernel_size, float gauss_spatial_coeff, float gauss_color_coeff, int borderMode, cudaStream_t stream)
{
typedef void (*caller_t)(const PtrStepSzb& src, PtrStepSzb dst, int kernel_size, float sigma_spatial, float sigma_color, cudaStream_t stream);
static caller_t funcs[] =
{
bilateral_caller<T, BrdConstant>,
bilateral_caller<T, BrdReplicate>,
bilateral_caller<T, BrdReflect>,
bilateral_caller<T, BrdWrap>,
bilateral_caller<T, BrdReflect101>
};
funcs[borderMode](src, dst, kernel_size, gauss_spatial_coeff, gauss_color_coeff, stream);
}
}
}}}
#define OCV_INSTANTIATE_BILATERAL_FILTER(T) \
template void cv::cuda::device::imgproc::bilateral_filter_gpu<T>(const PtrStepSzb&, PtrStepSzb, int, float, float, int, cudaStream_t);
OCV_INSTANTIATE_BILATERAL_FILTER(uchar)
//OCV_INSTANTIATE_BILATERAL_FILTER(uchar2)
OCV_INSTANTIATE_BILATERAL_FILTER(uchar3)
OCV_INSTANTIATE_BILATERAL_FILTER(uchar4)
//OCV_INSTANTIATE_BILATERAL_FILTER(schar)
//OCV_INSTANTIATE_BILATERAL_FILTER(schar2)
//OCV_INSTANTIATE_BILATERAL_FILTER(schar3)
//OCV_INSTANTIATE_BILATERAL_FILTER(schar4)
OCV_INSTANTIATE_BILATERAL_FILTER(short)
//OCV_INSTANTIATE_BILATERAL_FILTER(short2)
OCV_INSTANTIATE_BILATERAL_FILTER(short3)
OCV_INSTANTIATE_BILATERAL_FILTER(short4)
OCV_INSTANTIATE_BILATERAL_FILTER(ushort)
//OCV_INSTANTIATE_BILATERAL_FILTER(ushort2)
OCV_INSTANTIATE_BILATERAL_FILTER(ushort3)
OCV_INSTANTIATE_BILATERAL_FILTER(ushort4)
//OCV_INSTANTIATE_BILATERAL_FILTER(int)
//OCV_INSTANTIATE_BILATERAL_FILTER(int2)
//OCV_INSTANTIATE_BILATERAL_FILTER(int3)
//OCV_INSTANTIATE_BILATERAL_FILTER(int4)
OCV_INSTANTIATE_BILATERAL_FILTER(float)
//OCV_INSTANTIATE_BILATERAL_FILTER(float2)
OCV_INSTANTIATE_BILATERAL_FILTER(float3)
OCV_INSTANTIATE_BILATERAL_FILTER(float4)
#endif /* CUDA_DISABLER */
+121
View File
@@ -0,0 +1,121 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
namespace cv { namespace cuda { namespace device
{
namespace blend
{
template <typename T>
__global__ void blendLinearKernel(int rows, int cols, int cn, const PtrStep<T> img1, const PtrStep<T> img2,
const PtrStepf weights1, const PtrStepf weights2, PtrStep<T> result)
{
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
if (y < rows && x < cols)
{
int x_ = x / cn;
float w1 = weights1.ptr(y)[x_];
float w2 = weights2.ptr(y)[x_];
T p1 = img1.ptr(y)[x];
T p2 = img2.ptr(y)[x];
result.ptr(y)[x] = (p1 * w1 + p2 * w2) / (w1 + w2 + 1e-5f);
}
}
template <typename T>
void blendLinearCaller(int rows, int cols, int cn, PtrStep<T> img1, PtrStep<T> img2, PtrStepf weights1, PtrStepf weights2, PtrStep<T> result, cudaStream_t stream)
{
dim3 threads(16, 16);
dim3 grid(divUp(cols * cn, threads.x), divUp(rows, threads.y));
blendLinearKernel<<<grid, threads, 0, stream>>>(rows, cols * cn, cn, img1, img2, weights1, weights2, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall(cudaDeviceSynchronize());
}
template void blendLinearCaller<uchar>(int, int, int, PtrStep<uchar>, PtrStep<uchar>, PtrStepf, PtrStepf, PtrStep<uchar>, cudaStream_t stream);
template void blendLinearCaller<float>(int, int, int, PtrStep<float>, PtrStep<float>, PtrStepf, PtrStepf, PtrStep<float>, cudaStream_t stream);
__global__ void blendLinearKernel8UC4(int rows, int cols, const PtrStepb img1, const PtrStepb img2,
const PtrStepf weights1, const PtrStepf weights2, PtrStepb result)
{
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
if (y < rows && x < cols)
{
float w1 = weights1.ptr(y)[x];
float w2 = weights2.ptr(y)[x];
float sum_inv = 1.f / (w1 + w2 + 1e-5f);
w1 *= sum_inv;
w2 *= sum_inv;
uchar4 p1 = ((const uchar4*)img1.ptr(y))[x];
uchar4 p2 = ((const uchar4*)img2.ptr(y))[x];
((uchar4*)result.ptr(y))[x] = make_uchar4(p1.x * w1 + p2.x * w2, p1.y * w1 + p2.y * w2,
p1.z * w1 + p2.z * w2, p1.w * w1 + p2.w * w2);
}
}
void blendLinearCaller8UC4(int rows, int cols, PtrStepb img1, PtrStepb img2, PtrStepf weights1, PtrStepf weights2, PtrStepb result, cudaStream_t stream)
{
dim3 threads(16, 16);
dim3 grid(divUp(cols, threads.x), divUp(rows, threads.y));
blendLinearKernel8UC4<<<grid, threads, 0, stream>>>(rows, cols, img1, img2, weights1, weights2, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall(cudaDeviceSynchronize());
}
} // namespace blend
}}} // namespace cv { namespace cuda { namespace cudev
#endif /* CUDA_DISABLER */
@@ -0,0 +1,132 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/emulation.hpp"
namespace cv { namespace cuda { namespace device
{
namespace hough
{
template <int PIXELS_PER_THREAD>
__global__ void buildPointList(const PtrStepSzb src, unsigned int* list, int* counterPtr)
{
__shared__ unsigned int s_queues[4][32 * PIXELS_PER_THREAD];
__shared__ int s_qsize[4];
__shared__ int s_globStart[4];
const int x = blockIdx.x * blockDim.x * PIXELS_PER_THREAD + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (threadIdx.x == 0)
s_qsize[threadIdx.y] = 0;
__syncthreads();
if (y < src.rows)
{
// fill the queue
const uchar* srcRow = src.ptr(y);
for (int i = 0, xx = x; i < PIXELS_PER_THREAD && xx < src.cols; ++i, xx += blockDim.x)
{
if (srcRow[xx])
{
const unsigned int val = (y << 16) | xx;
const int qidx = Emulation::smem::atomicAdd(&s_qsize[threadIdx.y], 1);
s_queues[threadIdx.y][qidx] = val;
}
}
}
__syncthreads();
// let one thread reserve the space required in the global list
if (threadIdx.x == 0 && threadIdx.y == 0)
{
// find how many items are stored in each list
int totalSize = 0;
for (int i = 0; i < blockDim.y; ++i)
{
s_globStart[i] = totalSize;
totalSize += s_qsize[i];
}
// calculate the offset in the global list
const int globalOffset = atomicAdd(counterPtr, totalSize);
for (int i = 0; i < blockDim.y; ++i)
s_globStart[i] += globalOffset;
}
__syncthreads();
// copy local queues to global queue
const int qsize = s_qsize[threadIdx.y];
int gidx = s_globStart[threadIdx.y] + threadIdx.x;
for(int i = threadIdx.x; i < qsize; i += blockDim.x, gidx += blockDim.x)
list[gidx] = s_queues[threadIdx.y][i];
}
int buildPointList_gpu(PtrStepSzb src, unsigned int* list, int* counterPtr, cudaStream_t stream)
{
const int PIXELS_PER_THREAD = 16;
cudaSafeCall( cudaMemsetAsync(counterPtr, 0, sizeof(int), stream) );
const dim3 block(32, 4);
const dim3 grid(divUp(src.cols, block.x * PIXELS_PER_THREAD), divUp(src.rows, block.y));
cudaSafeCall( cudaFuncSetCacheConfig(buildPointList<PIXELS_PER_THREAD>, cudaFuncCachePreferShared) );
buildPointList<PIXELS_PER_THREAD><<<grid, block, 0, stream>>>(src, list, counterPtr);
cudaSafeCall( cudaGetLastError() );
int totalCount;
cudaSafeCall( cudaMemcpyAsync(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost, stream) );
cudaSafeCall( cudaStreamSynchronize(stream) );
return totalCount;
}
}
}}}
#endif /* CUDA_DISABLER */
+484
View File
@@ -0,0 +1,484 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/emulation.hpp"
#include "opencv2/core/cuda/transform.hpp"
#include "opencv2/core/cuda/functional.hpp"
#include "opencv2/core/cuda/utility.hpp"
#include "opencv2/core/cuda.hpp"
#include <opencv2/cudev/ptr2d/texture.hpp>
using namespace cv::cuda;
using namespace cv::cuda::device;
namespace canny
{
struct L1 : binary_function<int, int, float>
{
__device__ __forceinline__ float operator ()(int x, int y) const
{
return ::abs(x) + ::abs(y);
}
__host__ __device__ __forceinline__ L1() {}
__host__ __device__ __forceinline__ L1(const L1&) {}
};
struct L2 : binary_function<int, int, float>
{
__device__ __forceinline__ float operator ()(int x, int y) const
{
return ::sqrtf(x * x + y * y);
}
__host__ __device__ __forceinline__ L2() {}
__host__ __device__ __forceinline__ L2(const L2&) {}
};
}
namespace cv { namespace cuda { namespace device
{
template <> struct TransformFunctorTraits<canny::L1> : DefaultTransformFunctorTraits<canny::L1>
{
enum { smart_shift = 4 };
};
template <> struct TransformFunctorTraits<canny::L2> : DefaultTransformFunctorTraits<canny::L2>
{
enum { smart_shift = 4 };
};
}}}
namespace canny
{
template <class Norm>
__global__ void calcMagnitudeKernel(cv::cudev::TextureOffPtr<uchar> texSrc, PtrStepi dx, PtrStepi dy, PtrStepSzf mag, const Norm norm)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (y >= mag.rows || x >= mag.cols)
return;
int dxVal = (texSrc(y - 1, x + 1) + 2 * texSrc(y, x + 1) + texSrc(y + 1, x + 1)) - (texSrc(y - 1, x - 1) + 2 * texSrc(y, x - 1) + texSrc(y + 1, x - 1));
int dyVal = (texSrc(y + 1, x - 1) + 2 * texSrc(y + 1, x) + texSrc(y + 1, x + 1)) - (texSrc(y - 1, x - 1) + 2 * texSrc(y - 1, x) + texSrc(y - 1, x + 1));
dx(y, x) = dxVal;
dy(y, x) = dyVal;
mag(y, x) = norm(dxVal, dyVal);
}
void calcMagnitude(PtrStepSzb srcWhole, int xoff, int yoff, PtrStepSzi dx, PtrStepSzi dy, PtrStepSzf mag, bool L2Grad, cudaStream_t stream)
{
const dim3 block(16, 16);
const dim3 grid(divUp(mag.cols, block.x), divUp(mag.rows, block.y));
cv::cudev::TextureOff<uchar> texSrc(srcWhole, yoff, xoff);
if (L2Grad)
{
L2 norm;
calcMagnitudeKernel<<<grid, block, 0, stream>>>(texSrc, dx, dy, mag, norm);
}
else
{
L1 norm;
calcMagnitudeKernel<<<grid, block, 0, stream>>>(texSrc, dx, dy, mag, norm);
}
if (stream == NULL)
cudaSafeCall(cudaDeviceSynchronize());
}
void calcMagnitude(PtrStepSzi dx, PtrStepSzi dy, PtrStepSzf mag, bool L2Grad, cudaStream_t stream)
{
if (L2Grad)
{
L2 norm;
transform(dx, dy, mag, norm, WithOutMask(), stream);
}
else
{
L1 norm;
transform(dx, dy, mag, norm, WithOutMask(), stream);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
namespace canny
{
__global__ void calcMapKernel(cv::cudev::TexturePtr<float> texMag, const PtrStepSzi dx, const PtrStepi dy, PtrStepi map, const float low_thresh, const float high_thresh)
{
const int CANNY_SHIFT = 15;
const int TG22 = (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5);
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x == 0 || x >= dx.cols - 1 || y == 0 || y >= dx.rows - 1)
return;
int dxVal = dx(y, x);
int dyVal = dy(y, x);
const int s = (dxVal ^ dyVal) < 0 ? -1 : 1;
const float m = texMag(y, x);
dxVal = ::abs(dxVal);
dyVal = ::abs(dyVal);
// 0 - the pixel can not belong to an edge
// 1 - the pixel might belong to an edge
// 2 - the pixel does belong to an edge
int edge_type = 0;
if (m > low_thresh)
{
const int tg22x = dxVal * TG22;
const int tg67x = tg22x + ((dxVal + dxVal) << CANNY_SHIFT);
dyVal <<= CANNY_SHIFT;
if (dyVal < tg22x)
{
if (m > texMag(y, x - 1) && m >= texMag(y, x + 1))
edge_type = 1 + (int)(m > high_thresh);
}
else if(dyVal > tg67x)
{
if (m > texMag(y - 1, x) && m >= texMag(y + 1, x))
edge_type = 1 + (int)(m > high_thresh);
}
else
{
if (m > texMag(y - 1, x - s) && m >= texMag(y + 1, x + s))
edge_type = 1 + (int)(m > high_thresh);
}
}
map(y, x) = edge_type;
}
void calcMap(PtrStepSzi dx, PtrStepSzi dy, PtrStepSzf mag, PtrStepSzi map, float low_thresh, float high_thresh, cudaStream_t stream)
{
const dim3 block(16, 16);
const dim3 grid(divUp(dx.cols, block.x), divUp(dx.rows, block.y));
cv::cudev::Texture<float> texMag(mag);
calcMapKernel<<<grid, block, 0, stream>>>(texMag, dx, dy, map, low_thresh, high_thresh);
if (stream == NULL)
cudaSafeCall( cudaDeviceSynchronize() );
}
}
//////////////////////////////////////////////////////////////////////////////////////////
namespace canny
{
__device__ __forceinline__ bool checkIdx(int y, int x, int rows, int cols)
{
return (y >= 0) && (y < rows) && (x >= 0) && (x < cols);
}
__global__ void edgesHysteresisLocalKernel(PtrStepSzi map, short2* st, int* d_counter)
{
__shared__ volatile int smem[18][18];
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
smem[threadIdx.y + 1][threadIdx.x + 1] = checkIdx(y, x, map.rows, map.cols) ? map(y, x) : 0;
if (threadIdx.y == 0)
smem[0][threadIdx.x + 1] = checkIdx(y - 1, x, map.rows, map.cols) ? map(y - 1, x) : 0;
if (threadIdx.y == blockDim.y - 1)
smem[blockDim.y + 1][threadIdx.x + 1] = checkIdx(y + 1, x, map.rows, map.cols) ? map(y + 1, x) : 0;
if (threadIdx.x == 0)
smem[threadIdx.y + 1][0] = checkIdx(y, x - 1, map.rows, map.cols) ? map(y, x - 1) : 0;
if (threadIdx.x == blockDim.x - 1)
smem[threadIdx.y + 1][blockDim.x + 1] = checkIdx(y, x + 1, map.rows, map.cols) ? map(y, x + 1) : 0;
if (threadIdx.x == 0 && threadIdx.y == 0)
smem[0][0] = checkIdx(y - 1, x - 1, map.rows, map.cols) ? map(y - 1, x - 1) : 0;
if (threadIdx.x == blockDim.x - 1 && threadIdx.y == 0)
smem[0][blockDim.x + 1] = checkIdx(y - 1, x + 1, map.rows, map.cols) ? map(y - 1, x + 1) : 0;
if (threadIdx.x == 0 && threadIdx.y == blockDim.y - 1)
smem[blockDim.y + 1][0] = checkIdx(y + 1, x - 1, map.rows, map.cols) ? map(y + 1, x - 1) : 0;
if (threadIdx.x == blockDim.x - 1 && threadIdx.y == blockDim.y - 1)
smem[blockDim.y + 1][blockDim.x + 1] = checkIdx(y + 1, x + 1, map.rows, map.cols) ? map(y + 1, x + 1) : 0;
__syncthreads();
if (x >= map.cols || y >= map.rows)
return;
int n;
#pragma unroll
for (int k = 0; k < 16; ++k)
{
n = 0;
if (smem[threadIdx.y + 1][threadIdx.x + 1] == 1)
{
n += smem[threadIdx.y ][threadIdx.x ] == 2;
n += smem[threadIdx.y ][threadIdx.x + 1] == 2;
n += smem[threadIdx.y ][threadIdx.x + 2] == 2;
n += smem[threadIdx.y + 1][threadIdx.x ] == 2;
n += smem[threadIdx.y + 1][threadIdx.x + 2] == 2;
n += smem[threadIdx.y + 2][threadIdx.x ] == 2;
n += smem[threadIdx.y + 2][threadIdx.x + 1] == 2;
n += smem[threadIdx.y + 2][threadIdx.x + 2] == 2;
}
__syncthreads();
if (n > 0)
smem[threadIdx.y + 1][threadIdx.x + 1] = 2;
__syncthreads();
}
const int e = smem[threadIdx.y + 1][threadIdx.x + 1];
map(y, x) = e;
n = 0;
if (e == 2)
{
n += smem[threadIdx.y ][threadIdx.x ] == 1;
n += smem[threadIdx.y ][threadIdx.x + 1] == 1;
n += smem[threadIdx.y ][threadIdx.x + 2] == 1;
n += smem[threadIdx.y + 1][threadIdx.x ] == 1;
n += smem[threadIdx.y + 1][threadIdx.x + 2] == 1;
n += smem[threadIdx.y + 2][threadIdx.x ] == 1;
n += smem[threadIdx.y + 2][threadIdx.x + 1] == 1;
n += smem[threadIdx.y + 2][threadIdx.x + 2] == 1;
}
if (n > 0)
{
const int ind = ::atomicAdd(d_counter, 1);
st[ind] = make_short2(x, y);
}
}
void edgesHysteresisLocal(PtrStepSzi map, short2* st1, int* d_counter, cudaStream_t stream)
{
cudaSafeCall( cudaMemsetAsync(d_counter, 0, sizeof(int), stream) );
const dim3 block(16, 16);
const dim3 grid(divUp(map.cols, block.x), divUp(map.rows, block.y));
edgesHysteresisLocalKernel<<<grid, block, 0, stream>>>(map, st1, d_counter);
cudaSafeCall( cudaGetLastError() );
if (stream == NULL)
cudaSafeCall( cudaDeviceSynchronize() );
}
}
//////////////////////////////////////////////////////////////////////////////////////////
namespace canny
{
__constant__ int c_dx[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
__constant__ int c_dy[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
__global__ void edgesHysteresisGlobalKernel(PtrStepSzi map, short2* st1, short2* st2, int* d_counter, const int count)
{
const int stack_size = 512;
__shared__ int s_counter;
__shared__ int s_ind;
__shared__ short2 s_st[stack_size];
if (threadIdx.x == 0)
s_counter = 0;
__syncthreads();
int ind = blockIdx.y * gridDim.x + blockIdx.x;
if (ind >= count)
return;
short2 pos = st1[ind];
if (threadIdx.x < 8)
{
pos.x += c_dx[threadIdx.x];
pos.y += c_dy[threadIdx.x];
if (pos.x > 0 && pos.x < map.cols - 1 && pos.y > 0 && pos.y < map.rows - 1 && map(pos.y, pos.x) == 1)
{
map(pos.y, pos.x) = 2;
ind = Emulation::smem::atomicAdd(&s_counter, 1);
s_st[ind] = pos;
}
}
__syncthreads();
while (s_counter > 0 && s_counter <= stack_size - blockDim.x)
{
const int subTaskIdx = threadIdx.x >> 3;
const int portion = ::min(s_counter, blockDim.x >> 3);
if (subTaskIdx < portion)
pos = s_st[s_counter - 1 - subTaskIdx];
__syncthreads();
if (threadIdx.x == 0)
s_counter -= portion;
__syncthreads();
if (subTaskIdx < portion)
{
pos.x += c_dx[threadIdx.x & 7];
pos.y += c_dy[threadIdx.x & 7];
if (pos.x > 0 && pos.x < map.cols - 1 && pos.y > 0 && pos.y < map.rows - 1 && map(pos.y, pos.x) == 1)
{
map(pos.y, pos.x) = 2;
ind = Emulation::smem::atomicAdd(&s_counter, 1);
s_st[ind] = pos;
}
}
__syncthreads();
}
if (s_counter > 0)
{
if (threadIdx.x == 0)
{
s_ind = ::atomicAdd(d_counter, s_counter);
if (s_ind + s_counter > map.cols * map.rows)
s_counter = 0;
}
__syncthreads();
ind = s_ind;
for (int i = threadIdx.x; i < s_counter; i += blockDim.x)
st2[ind + i] = s_st[i];
}
}
void edgesHysteresisGlobal(PtrStepSzi map, short2* st1, short2* st2, int* d_counter, cudaStream_t stream)
{
int count;
cudaSafeCall( cudaMemcpyAsync(&count, d_counter, sizeof(int), cudaMemcpyDeviceToHost, stream) );
cudaSafeCall( cudaStreamSynchronize(stream) );
while (count > 0)
{
cudaSafeCall( cudaMemsetAsync(d_counter, 0, sizeof(int), stream) );
const dim3 block(128);
const dim3 grid(std::min(count, 65535), divUp(count, 65535), 1);
edgesHysteresisGlobalKernel<<<grid, block, 0, stream>>>(map, st1, st2, d_counter, count);
cudaSafeCall( cudaGetLastError() );
if (stream == NULL)
cudaSafeCall( cudaDeviceSynchronize() );
cudaSafeCall( cudaMemcpyAsync(&count, d_counter, sizeof(int), cudaMemcpyDeviceToHost, stream) );
cudaSafeCall( cudaStreamSynchronize(stream) );
count = std::min(count, map.cols * map.rows);
//std::swap(st1, st2);
short2* tmp = st1;
st1 = st2;
st2 = tmp;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
namespace canny
{
struct GetEdges : unary_function<int, uchar>
{
__device__ __forceinline__ uchar operator ()(int e) const
{
return (uchar)(-(e >> 1));
}
__host__ __device__ __forceinline__ GetEdges() {}
__host__ __device__ __forceinline__ GetEdges(const GetEdges&) {}
};
}
namespace cv { namespace cuda { namespace device
{
template <> struct TransformFunctorTraits<canny::GetEdges> : DefaultTransformFunctorTraits<canny::GetEdges>
{
enum { smart_shift = 4 };
};
}}}
namespace canny
{
void getEdges(PtrStepSzi map, PtrStepSzb dst, cudaStream_t stream)
{
transform(map, dst, GetEdges(), WithOutMask(), stream);
}
}
#endif /* CUDA_DISABLER */
+408
View File
@@ -0,0 +1,408 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/cudev.hpp"
using namespace cv::cudev;
namespace clahe
{
__global__ void calcLutKernel_8U(const PtrStepb src, PtrStepb lut,
const int2 tileSize, const int tilesX,
const int clipLimit, const float lutScale)
{
__shared__ int smem[256];
const int tx = blockIdx.x;
const int ty = blockIdx.y;
const unsigned int tid = threadIdx.y * blockDim.x + threadIdx.x;
smem[tid] = 0;
__syncthreads();
for (int i = threadIdx.y; i < tileSize.y; i += blockDim.y)
{
const uchar* srcPtr = src.ptr(ty * tileSize.y + i) + tx * tileSize.x;
for (int j = threadIdx.x; j < tileSize.x; j += blockDim.x)
{
const int data = srcPtr[j];
::atomicAdd(&smem[data], 1);
}
}
__syncthreads();
int tHistVal = smem[tid];
__syncthreads();
if (clipLimit > 0)
{
// clip histogram bar
int clipped = 0;
if (tHistVal > clipLimit)
{
clipped = tHistVal - clipLimit;
tHistVal = clipLimit;
}
// find number of overall clipped samples
blockReduce<256>(smem, clipped, tid, plus<int>());
// broadcast evaluated value
__shared__ int totalClipped;
__shared__ int redistBatch;
__shared__ int residual;
__shared__ int rStep;
if (tid == 0)
{
totalClipped = clipped;
redistBatch = totalClipped / 256;
residual = totalClipped - redistBatch * 256;
rStep = 1;
if (residual != 0)
rStep = 256 / residual;
}
__syncthreads();
// redistribute clipped samples evenly
tHistVal += redistBatch;
if (residual && tid % rStep == 0 && tid / rStep < residual)
++tHistVal;
}
const int lutVal = blockScanInclusive<256>(tHistVal, smem, tid);
lut(ty * tilesX + tx, tid) = saturate_cast<uchar>(__float2int_rn(lutScale * lutVal));
}
__global__ void calcLutKernel_16U(const PtrStepus src, PtrStepus lut,
const int2 tileSize, const int tilesX,
const int clipLimit, const float lutScale,
PtrStepSzi hist)
{
#define histSize 65536
#define blockSize 256
__shared__ int smem[blockSize];
const int tx = blockIdx.x;
const int ty = blockIdx.y;
const unsigned int tid = threadIdx.y * blockDim.x + threadIdx.x;
const int histRow = ty * tilesX + tx;
// build histogram
for (int i = tid; i < histSize; i += blockSize)
hist(histRow, i) = 0;
__syncthreads();
for (int i = threadIdx.y; i < tileSize.y; i += blockDim.y)
{
const ushort* srcPtr = src.ptr(ty * tileSize.y + i) + tx * tileSize.x;
for (int j = threadIdx.x; j < tileSize.x; j += blockDim.x)
{
const int data = srcPtr[j];
::atomicAdd(&hist(histRow, data), 1);
}
}
__syncthreads();
if (clipLimit > 0)
{
// clip histogram bar &&
// find number of overall clipped samples
__shared__ int partialSum[blockSize];
for (int i = tid; i < histSize; i += blockSize)
{
int histVal = hist(histRow, i);
int clipped = 0;
if (histVal > clipLimit)
{
clipped = histVal - clipLimit;
hist(histRow, i) = clipLimit;
}
// Following code block is in effect equivalent to:
//
// blockReduce<blockSize>(smem, clipped, tid, plus<int>());
//
{
for (int j = 16; j >= 1; j /= 2)
{
#if __CUDACC_VER_MAJOR__ >= 9
int val = __shfl_down_sync(0xFFFFFFFFU, clipped, j);
#else
int val = __shfl_down(clipped, j);
#endif
clipped += val;
}
if (tid % 32 == 0)
smem[tid / 32] = clipped;
__syncthreads();
if (tid < 8)
{
clipped = smem[tid];
for (int j = 4; j >= 1; j /= 2)
{
#if __CUDACC_VER_MAJOR__ >= 9
int val = __shfl_down_sync(0x000000FFU, clipped, j);
#else
int val = __shfl_down(clipped, j);
#endif
clipped += val;
}
}
}
// end of code block
if (tid == 0)
partialSum[i / blockSize] = clipped;
__syncthreads();
}
int partialSum_ = partialSum[tid];
// Following code block is in effect equivalent to:
//
// blockReduce<blockSize>(smem, partialSum_, tid, plus<int>());
//
{
for (int j = 16; j >= 1; j /= 2)
{
#if __CUDACC_VER_MAJOR__ >= 9
int val = __shfl_down_sync(0xFFFFFFFFU, partialSum_, j);
#else
int val = __shfl_down(partialSum_, j);
#endif
partialSum_ += val;
}
if (tid % 32 == 0)
smem[tid / 32] = partialSum_;
__syncthreads();
if (tid < 8)
{
partialSum_ = smem[tid];
for (int j = 4; j >= 1; j /= 2)
{
#if __CUDACC_VER_MAJOR__ >= 9
int val = __shfl_down_sync(0x000000FFU, partialSum_, j);
#else
int val = __shfl_down(partialSum_, j);
#endif
partialSum_ += val;
}
}
}
// end of code block
// broadcast evaluated value &&
// redistribute clipped samples evenly
__shared__ int totalClipped;
__shared__ int redistBatch;
__shared__ int residual;
__shared__ int rStep;
if (tid == 0)
{
totalClipped = partialSum_;
redistBatch = totalClipped / histSize;
residual = totalClipped - redistBatch * histSize;
rStep = 1;
if (residual != 0)
rStep = histSize / residual;
}
__syncthreads();
for (int i = tid; i < histSize; i += blockSize)
{
int histVal = hist(histRow, i);
int equalized = histVal + redistBatch;
if (residual && i % rStep == 0 && i / rStep < residual)
++equalized;
hist(histRow, i) = equalized;
}
}
__shared__ int partialScan[blockSize];
for (int i = tid; i < histSize; i += blockSize)
{
int equalized = hist(histRow, i);
equalized = blockScanInclusive<blockSize>(equalized, smem, tid);
if (tid == blockSize - 1)
partialScan[i / blockSize] = equalized;
hist(histRow, i) = equalized;
}
__syncthreads();
int partialScan_ = partialScan[tid];
partialScan[tid] = blockScanExclusive<blockSize>(partialScan_, smem, tid);
__syncthreads();
for (int i = tid; i < histSize; i += blockSize)
{
const int lutVal = hist(histRow, i) + partialScan[i / blockSize];
lut(histRow, i) = saturate_cast<ushort>(__float2int_rn(lutScale * lutVal));
}
#undef histSize
#undef blockSize
}
void calcLut_8U(PtrStepSzb src, PtrStepb lut, int tilesX, int tilesY, int2 tileSize, int clipLimit, float lutScale, cudaStream_t stream)
{
const dim3 block(32, 8);
const dim3 grid(tilesX, tilesY);
calcLutKernel_8U<<<grid, block, 0, stream>>>(src, lut, tileSize, tilesX, clipLimit, lutScale);
CV_CUDEV_SAFE_CALL( cudaGetLastError() );
if (stream == 0)
CV_CUDEV_SAFE_CALL( cudaDeviceSynchronize() );
}
void calcLut_16U(PtrStepSzus src, PtrStepus lut, int tilesX, int tilesY, int2 tileSize, int clipLimit, float lutScale, PtrStepSzi hist, cudaStream_t stream)
{
const dim3 block(32, 8);
const dim3 grid(tilesX, tilesY);
calcLutKernel_16U<<<grid, block, 0, stream>>>(src, lut, tileSize, tilesX, clipLimit, lutScale, hist);
CV_CUDEV_SAFE_CALL( cudaGetLastError() );
if (stream == 0)
CV_CUDEV_SAFE_CALL( cudaDeviceSynchronize() );
}
template <typename T>
__global__ void transformKernel(const PtrStepSz<T> src, PtrStep<T> dst, const PtrStep<T> lut, const int2 tileSize, const int tilesX, const int tilesY)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x >= src.cols || y >= src.rows)
return;
const float tyf = (static_cast<float>(y) / tileSize.y) - 0.5f;
int ty1 = __float2int_rd(tyf);
int ty2 = ty1 + 1;
const float ya = tyf - ty1;
ty1 = ::max(ty1, 0);
ty2 = ::min(ty2, tilesY - 1);
const float txf = (static_cast<float>(x) / tileSize.x) - 0.5f;
int tx1 = __float2int_rd(txf);
int tx2 = tx1 + 1;
const float xa = txf - tx1;
tx1 = ::max(tx1, 0);
tx2 = ::min(tx2, tilesX - 1);
const int srcVal = src(y, x);
float res = 0;
res += lut(ty1 * tilesX + tx1, srcVal) * ((1.0f - xa) * (1.0f - ya));
res += lut(ty1 * tilesX + tx2, srcVal) * ((xa) * (1.0f - ya));
res += lut(ty2 * tilesX + tx1, srcVal) * ((1.0f - xa) * (ya));
res += lut(ty2 * tilesX + tx2, srcVal) * ((xa) * (ya));
dst(y, x) = saturate_cast<T>(res);
}
template <typename T>
void transform(PtrStepSz<T> src, PtrStepSz<T> dst, PtrStep<T> lut, int tilesX, int tilesY, int2 tileSize, cudaStream_t stream)
{
const dim3 block(32, 8);
const dim3 grid(divUp(src.cols, block.x), divUp(src.rows, block.y));
CV_CUDEV_SAFE_CALL( cudaFuncSetCacheConfig(transformKernel<T>, cudaFuncCachePreferL1) );
transformKernel<T><<<grid, block, 0, stream>>>(src, dst, lut, tileSize, tilesX, tilesY);
CV_CUDEV_SAFE_CALL( cudaGetLastError() );
if (stream == 0)
CV_CUDEV_SAFE_CALL( cudaDeviceSynchronize() );
}
template void transform<uchar>(PtrStepSz<uchar> src, PtrStepSz<uchar> dst, PtrStep<uchar> lut, int tilesX, int tilesY, int2 tileSize, cudaStream_t stream);
template void transform<ushort>(PtrStepSz<ushort> src, PtrStepSz<ushort> dst, PtrStep<ushort> lut, int tilesX, int tilesY, int2 tileSize, cudaStream_t stream);
}
#endif // CUDA_DISABLER
+297
View File
@@ -0,0 +1,297 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "opencv2/opencv_modules.hpp"
#ifndef HAVE_OPENCV_CUDEV
#error "opencv_cudev is required"
#else
#include "../cvt_color_internal.h"
#include "opencv2/cudev.hpp"
using namespace cv;
using namespace cv::cuda;
using namespace cv::cudev;
namespace cv { namespace cuda { namespace device
{
#define OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name, func_t) \
void name(const GpuMat& src, GpuMat& dst, Stream& stream) \
{ \
func_t op; \
typedef typename func_t::argument_type src_t; \
typedef typename func_t::result_type dst_t; \
gridTransformUnary(globPtr<src_t>(src), globPtr<dst_t>(dst), op, stream); \
}
#define OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(name) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name, name ## _func)
#define OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(name) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name ## _8u, name ## _func<uchar>) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name ## _16u, name ## _func<ushort>) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name ## _32f, name ## _func<float>)
#define OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(name) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name ## _8u, name ## _func<uchar>) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name ## _32f, name ## _func<float>)
#define OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(name) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name ## _8u, name ## _func<uchar>) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name ## _32f, name ## _func<float>) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name ## _FULL_8u, name ## _FULL_func<uchar>) \
OPENCV_CUDA_IMPLEMENT_CVTCOLOR(name ## _FULL_32f, name ## _FULL_func<float>)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGB_to_GRAY)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_GRAY)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGBA_to_GRAY)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_GRAY)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(GRAY_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(GRAY_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGB_to_YUV)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGBA_to_YUV)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGB_to_YUV4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGBA_to_YUV4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_YUV)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_YUV)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_YUV4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_YUV4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YUV_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YUV_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YUV4_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YUV4_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YUV_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YUV_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YUV4_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YUV4_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGB_to_YCrCb)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGBA_to_YCrCb)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGB_to_YCrCb4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGBA_to_YCrCb4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_YCrCb)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_YCrCb)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_YCrCb4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_YCrCb4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YCrCb_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YCrCb_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YCrCb4_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YCrCb4_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YCrCb_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YCrCb_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YCrCb4_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(YCrCb4_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGB_to_XYZ)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGBA_to_XYZ)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGB_to_XYZ4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(RGBA_to_XYZ4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_XYZ)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_XYZ)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGR_to_XYZ4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(BGRA_to_XYZ4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(XYZ_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(XYZ4_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(XYZ_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(XYZ4_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(XYZ_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(XYZ4_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(XYZ_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL(XYZ4_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(RGB_to_HSV)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(RGBA_to_HSV)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(RGB_to_HSV4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(RGBA_to_HSV4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(BGR_to_HSV)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(BGRA_to_HSV)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(BGR_to_HSV4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(BGRA_to_HSV4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HSV_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HSV_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HSV4_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HSV4_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HSV_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HSV_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HSV4_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HSV4_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(RGB_to_HLS)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(RGBA_to_HLS)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(RGB_to_HLS4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(RGBA_to_HLS4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(BGR_to_HLS)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(BGRA_to_HLS)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(BGR_to_HLS4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(BGRA_to_HLS4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HLS_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HLS_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HLS4_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HLS4_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HLS_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HLS_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HLS4_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL(HLS4_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(RGB_to_Lab)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(RGBA_to_Lab)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(RGB_to_Lab4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(RGBA_to_Lab4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(BGR_to_Lab)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(BGRA_to_Lab)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(BGR_to_Lab4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(BGRA_to_Lab4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LRGB_to_Lab)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LRGBA_to_Lab)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LRGB_to_Lab4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LRGBA_to_Lab4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LBGR_to_Lab)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LBGRA_to_Lab)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LBGR_to_Lab4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LBGRA_to_Lab4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab4_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab4_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab4_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab4_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab_to_LRGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab4_to_LRGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab_to_LRGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab4_to_LRGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab_to_LBGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab4_to_LBGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab_to_LBGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Lab4_to_LBGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(RGB_to_Luv)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(RGBA_to_Luv)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(RGB_to_Luv4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(RGBA_to_Luv4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(BGR_to_Luv)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(BGRA_to_Luv)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(BGR_to_Luv4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(BGRA_to_Luv4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LRGB_to_Luv)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LRGBA_to_Luv)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LRGB_to_Luv4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LRGBA_to_Luv4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LBGR_to_Luv)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LBGRA_to_Luv)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LBGR_to_Luv4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(LBGRA_to_Luv4)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv4_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv4_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv4_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv4_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv_to_LRGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv4_to_LRGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv_to_LRGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv4_to_LRGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv_to_LBGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv4_to_LBGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv_to_LBGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F(Luv4_to_LBGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR_to_BGR555)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR_to_BGR565)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(RGB_to_BGR555)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(RGB_to_BGR565)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGRA_to_BGR555)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGRA_to_BGR565)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(RGBA_to_BGR555)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(RGBA_to_BGR565)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR555_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR565_to_RGB)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR555_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR565_to_BGR)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR555_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR565_to_RGBA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR555_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR565_to_BGRA)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(GRAY_to_BGR555)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(GRAY_to_BGR565)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR555_to_GRAY)
OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE(BGR565_to_GRAY)
#undef OPENCV_CUDA_IMPLEMENT_CVTCOLOR
#undef OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ONE
#undef OPENCV_CUDA_IMPLEMENT_CVTCOLOR_ALL
#undef OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F
#undef OPENCV_CUDA_IMPLEMENT_CVTCOLOR_8U32F_FULL
}}}
#endif
@@ -0,0 +1,345 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/emulation.hpp"
#include "opencv2/core/cuda/transform.hpp"
#include "opencv2/core/cuda/functional.hpp"
#include "opencv2/core/cuda/utility.hpp"
#include "opencv2/core/cuda.hpp"
using namespace cv::cuda;
using namespace cv::cuda::device;
namespace cv { namespace cuda { namespace device { namespace imgproc {
constexpr int kblock_rows = 16;
constexpr int kblock_cols = 16;
namespace {
enum class Info : unsigned char { a = 0, b = 1, c = 2, d = 3, P = 4, Q = 5, R = 6, S = 7 };
// Only use it with unsigned numeric types
template <typename T>
__device__ __forceinline__ unsigned char HasBit(T bitmap, Info pos) {
return (bitmap >> static_cast<unsigned char>(pos)) & 1;
}
template <typename T>
__device__ __forceinline__ unsigned char HasBit(T bitmap, unsigned char pos) {
return (bitmap >> pos) & 1;
}
// Only use it with unsigned numeric types
__device__ __forceinline__ void SetBit(unsigned char& bitmap, Info pos) {
bitmap |= (1 << static_cast<unsigned char>(pos));
}
// Returns the root index of the UFTree
__device__ unsigned Find(const int* s_buf, unsigned n) {
while (s_buf[n] != n) {
n = s_buf[n];
}
return n;
}
__device__ unsigned FindAndCompress(int* s_buf, unsigned n) {
unsigned id = n;
while (s_buf[n] != n) {
n = s_buf[n];
s_buf[id] = n;
}
return n;
}
// Merges the UFTrees of a and b, linking one root to the other
__device__ void Union(int* s_buf, unsigned a, unsigned b) {
bool done;
do {
a = Find(s_buf, a);
b = Find(s_buf, b);
if (a < b) {
int old = atomicMin(s_buf + b, a);
done = (old == b);
b = old;
}
else if (b < a) {
int old = atomicMin(s_buf + a, b);
done = (old == a);
a = old;
}
else {
done = true;
}
} while (!done);
}
__global__ void InitLabeling(const cuda::PtrStepSzb img, cuda::PtrStepSzi labels, unsigned char* last_pixel) {
unsigned row = (blockIdx.y * kblock_rows + threadIdx.y) * 2;
unsigned col = (blockIdx.x * kblock_cols + threadIdx.x) * 2;
unsigned img_index = row * img.step + col;
unsigned labels_index = row * (labels.step / labels.elem_size) + col;
if (row < labels.rows && col < labels.cols) {
unsigned P = 0;
// Bitmask representing two kinds of information
// Bits 0, 1, 2, 3 are set if pixel a, b, c, d are foreground, respectively
// Bits 4, 5, 6, 7 are set if block P, Q, R, S need to be merged to X in Merge phase
unsigned char info = 0;
char buffer alignas(int)[4];
*(reinterpret_cast<int*>(buffer)) = 0;
// Read pairs of consecutive values in memory at once
if (col + 1 < img.cols) {
// This does not depend on endianness
*(reinterpret_cast<int16_t*>(buffer)) = *(reinterpret_cast<int16_t*>(img.data + img_index));
if (row + 1 < img.rows) {
*(reinterpret_cast<int16_t*>(buffer + 2)) = *(reinterpret_cast<int16_t*>(img.data + img_index + img.step));
}
}
else {
buffer[0] = img.data[img_index];
if (row + 1 < img.rows) {
buffer[2] = img.data[img_index + img.step];
}
}
if (buffer[0]) {
P |= 0x777;
SetBit(info, Info::a);
}
if (buffer[1]) {
P |= (0x777 << 1);
SetBit(info, Info::b);
}
if (buffer[2]) {
P |= (0x777 << 4);
SetBit(info, Info::c);
}
if (buffer[3]) {
SetBit(info, Info::d);
}
if (col == 0) {
P &= 0xEEEE;
}
if (col + 1 >= img.cols) {
P &= 0x3333;
}
else if (col + 2 >= img.cols) {
P &= 0x7777;
}
if (row == 0) {
P &= 0xFFF0;
}
if (row + 1 >= img.rows) {
P &= 0x00FF;
}
else if (row + 2 >= img.rows) {
P &= 0x0FFF;
}
// P is now ready to be used to find neighbor blocks
// P value avoids range errors
int father_offset = 0;
// P square
if (HasBit(P, 0) && img.data[img_index - img.step - 1]) {
father_offset = -(2 * (labels.step / labels.elem_size) + 2);
}
// Q square
if ((HasBit(P, 1) && img.data[img_index - img.step]) || (HasBit(P, 2) && img.data[img_index + 1 - img.step])) {
if (!father_offset) {
father_offset = -(2 * (labels.step / labels.elem_size));
}
else {
SetBit(info, Info::Q);
}
}
// R square
if (HasBit(P, 3) && img.data[img_index + 2 - img.step]) {
if (!father_offset) {
father_offset = -(2 * (labels.step / labels.elem_size) - 2);
}
else {
SetBit(info, Info::R);
}
}
// S square
if ((HasBit(P, 4) && img.data[img_index - 1]) || (HasBit(P, 8) && img.data[img_index + img.step - 1])) {
if (!father_offset) {
father_offset = -2;
}
else {
SetBit(info, Info::S);
}
}
labels.data[labels_index] = labels_index + father_offset;
if (col + 1 < labels.cols) {
last_pixel = reinterpret_cast<unsigned char*>(labels.data + labels_index + 1);
}
else if (row + 1 < labels.rows) {
last_pixel = reinterpret_cast<unsigned char*>(labels.data + labels_index + labels.step / labels.elem_size);
}
*last_pixel = info;
}
}
__global__ void Merge(cuda::PtrStepSzi labels, unsigned char* last_pixel) {
unsigned row = (blockIdx.y * kblock_rows + threadIdx.y) * 2;
unsigned col = (blockIdx.x * kblock_cols + threadIdx.x) * 2;
unsigned labels_index = row * (labels.step / labels.elem_size) + col;
if (row < labels.rows && col < labels.cols) {
if (col + 1 < labels.cols) {
last_pixel = reinterpret_cast<unsigned char*>(labels.data + labels_index + 1);
}
else if (row + 1 < labels.rows) {
last_pixel = reinterpret_cast<unsigned char*>(labels.data + labels_index + labels.step / labels.elem_size);
}
unsigned char info = *last_pixel;
if (HasBit(info, Info::Q)) {
Union(labels.data, labels_index, labels_index - 2 * (labels.step / labels.elem_size));
}
if (HasBit(info, Info::R)) {
Union(labels.data, labels_index, labels_index - 2 * (labels.step / labels.elem_size) + 2);
}
if (HasBit(info, Info::S)) {
Union(labels.data, labels_index, labels_index - 2);
}
}
}
__global__ void Compression(cuda::PtrStepSzi labels) {
unsigned row = (blockIdx.y * kblock_rows + threadIdx.y) * 2;
unsigned col = (blockIdx.x * kblock_cols + threadIdx.x) * 2;
unsigned labels_index = row * (labels.step / labels.elem_size) + col;
if (row < labels.rows && col < labels.cols) {
FindAndCompress(labels.data, labels_index);
}
}
__global__ void FinalLabeling(const cuda::PtrStepSzb img, cuda::PtrStepSzi labels) {
unsigned row = (blockIdx.y * kblock_rows + threadIdx.y) * 2;
unsigned col = (blockIdx.x * kblock_cols + threadIdx.x) * 2;
unsigned labels_index = row * (labels.step / labels.elem_size) + col;
if (row < labels.rows && col < labels.cols) {
int label;
unsigned char info;
unsigned long long buffer;
if (col + 1 < labels.cols) {
buffer = *reinterpret_cast<unsigned long long*>(labels.data + labels_index);
label = (buffer & (0xFFFFFFFF)) + 1;
info = (buffer >> 32) & 0xFFFFFFFF;
}
else {
label = labels[labels_index] + 1;
if (row + 1 < labels.rows) {
info = labels[labels_index + labels.step / labels.elem_size];
}
else {
// Read from the input image
// "a" is already in position 0
info = img[row * img.step + col];
}
}
if (col + 1 < labels.cols) {
*reinterpret_cast<unsigned long long*>(labels.data + labels_index) =
(static_cast<unsigned long long>(HasBit(info, Info::b) * label) << 32) | (HasBit(info, Info::a) * label);
if (row + 1 < labels.rows) {
*reinterpret_cast<unsigned long long*>(labels.data + labels_index + labels.step / labels.elem_size) =
(static_cast<unsigned long long>(HasBit(info, Info::d) * label) << 32) | (HasBit(info, Info::c) * label);
}
}
else {
labels[labels_index] = HasBit(info, Info::a) * label;
if (row + 1 < labels.rows) {
labels[labels_index + (labels.step / labels.elem_size)] = HasBit(info, Info::c) * label;
}
}
}
}
}
void BlockBasedKomuraEquivalence(const cv::cuda::GpuMat& img, cv::cuda::GpuMat& labels) {
dim3 grid_size;
dim3 block_size;
unsigned char* last_pixel;
bool last_pixel_allocated;
last_pixel_allocated = false;
if ((img.rows == 1 || img.cols == 1) && !((img.rows + img.cols) % 2)) {
cudaSafeCall(cudaMalloc(&last_pixel, sizeof(unsigned char)));
last_pixel_allocated = true;
}
else {
last_pixel = labels.data + ((labels.rows - 2) * labels.step) + (labels.cols - 2) * labels.elemSize();
}
grid_size = dim3((((img.cols + 1) / 2) - 1) / kblock_cols + 1, (((img.rows + 1) / 2) - 1) / kblock_rows + 1, 1);
block_size = dim3(kblock_cols, kblock_rows, 1);
InitLabeling <<<grid_size, block_size >>> (img, labels, last_pixel);
cudaSafeCall(cudaGetLastError());
Compression <<<grid_size, block_size >>> (labels);
cudaSafeCall(cudaGetLastError());
Merge <<<grid_size, block_size >>> (labels, last_pixel);
cudaSafeCall(cudaGetLastError());
Compression <<<grid_size, block_size >>> (labels);
cudaSafeCall(cudaGetLastError());
FinalLabeling <<<grid_size, block_size >>> (img, labels);
cudaSafeCall(cudaGetLastError());
if (last_pixel_allocated) {
cudaSafeCall(cudaFree(last_pixel));
}
cudaSafeCall(cudaDeviceSynchronize());
}
}}}}
#endif /* CUDA_DISABLER */
+566
View File
@@ -0,0 +1,566 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/vec_traits.hpp"
#include "opencv2/core/cuda/vec_math.hpp"
#include "opencv2/core/cuda/limits.hpp"
#include "opencv2/core/cuda/color.hpp"
#include "opencv2/core/cuda/saturate_cast.hpp"
#include "opencv2/cudev/ptr2d/texture.hpp"
namespace cv { namespace cuda { namespace device
{
template <typename T> struct Bayer2BGR;
template <> struct Bayer2BGR<uchar>
{
uchar3 res0;
uchar3 res1;
uchar3 res2;
uchar3 res3;
__device__ void apply(const PtrStepSzb& src, int s_x, int s_y, bool blue_last, bool start_with_green)
{
uchar4 patch[3][3];
patch[0][1] = ((const uchar4*) src.ptr(s_y - 1))[s_x];
patch[0][0] = ((const uchar4*) src.ptr(s_y - 1))[::max(s_x - 1, 0)];
patch[0][2] = ((const uchar4*) src.ptr(s_y - 1))[::min(s_x + 1, ((src.cols + 3) >> 2) - 1)];
patch[1][1] = ((const uchar4*) src.ptr(s_y))[s_x];
patch[1][0] = ((const uchar4*) src.ptr(s_y))[::max(s_x - 1, 0)];
patch[1][2] = ((const uchar4*) src.ptr(s_y))[::min(s_x + 1, ((src.cols + 3) >> 2) - 1)];
patch[2][1] = ((const uchar4*) src.ptr(s_y + 1))[s_x];
patch[2][0] = ((const uchar4*) src.ptr(s_y + 1))[::max(s_x - 1, 0)];
patch[2][2] = ((const uchar4*) src.ptr(s_y + 1))[::min(s_x + 1, ((src.cols + 3) >> 2) - 1)];
if ((s_y & 1) ^ start_with_green)
{
const int t0 = (patch[0][1].x + patch[2][1].x + 1) >> 1;
const int t1 = (patch[1][0].w + patch[1][1].y + 1) >> 1;
const int t2 = (patch[0][1].x + patch[0][1].z + patch[2][1].x + patch[2][1].z + 2) >> 2;
const int t3 = (patch[0][1].y + patch[1][1].x + patch[1][1].z + patch[2][1].y + 2) >> 2;
const int t4 = (patch[0][1].z + patch[2][1].z + 1) >> 1;
const int t5 = (patch[1][1].y + patch[1][1].w + 1) >> 1;
const int t6 = (patch[0][1].z + patch[0][2].x + patch[2][1].z + patch[2][2].x + 2) >> 2;
const int t7 = (patch[0][1].w + patch[1][1].z + patch[1][2].x + patch[2][1].w + 2) >> 2;
if ((s_y & 1) ^ blue_last)
{
res0.x = t1;
res0.y = patch[1][1].x;
res0.z = t0;
res1.x = patch[1][1].y;
res1.y = t3;
res1.z = t2;
res2.x = t5;
res2.y = patch[1][1].z;
res2.z = t4;
res3.x = patch[1][1].w;
res3.y = t7;
res3.z = t6;
}
else
{
res0.x = t0;
res0.y = patch[1][1].x;
res0.z = t1;
res1.x = t2;
res1.y = t3;
res1.z = patch[1][1].y;
res2.x = t4;
res2.y = patch[1][1].z;
res2.z = t5;
res3.x = t6;
res3.y = t7;
res3.z = patch[1][1].w;
}
}
else
{
const int t0 = (patch[0][0].w + patch[0][1].y + patch[2][0].w + patch[2][1].y + 2) >> 2;
const int t1 = (patch[0][1].x + patch[1][0].w + patch[1][1].y + patch[2][1].x + 2) >> 2;
const int t2 = (patch[0][1].y + patch[2][1].y + 1) >> 1;
const int t3 = (patch[1][1].x + patch[1][1].z + 1) >> 1;
const int t4 = (patch[0][1].y + patch[0][1].w + patch[2][1].y + patch[2][1].w + 2) >> 2;
const int t5 = (patch[0][1].z + patch[1][1].y + patch[1][1].w + patch[2][1].z + 2) >> 2;
const int t6 = (patch[0][1].w + patch[2][1].w + 1) >> 1;
const int t7 = (patch[1][1].z + patch[1][2].x + 1) >> 1;
if ((s_y & 1) ^ blue_last)
{
res0.x = patch[1][1].x;
res0.y = t1;
res0.z = t0;
res1.x = t3;
res1.y = patch[1][1].y;
res1.z = t2;
res2.x = patch[1][1].z;
res2.y = t5;
res2.z = t4;
res3.x = t7;
res3.y = patch[1][1].w;
res3.z = t6;
}
else
{
res0.x = t0;
res0.y = t1;
res0.z = patch[1][1].x;
res1.x = t2;
res1.y = patch[1][1].y;
res1.z = t3;
res2.x = t4;
res2.y = t5;
res2.z = patch[1][1].z;
res3.x = t6;
res3.y = patch[1][1].w;
res3.z = t7;
}
}
}
};
template <typename D> __device__ __forceinline__ D toDst(const uchar3& pix);
template <> __device__ __forceinline__ uchar toDst<uchar>(const uchar3& pix)
{
typename bgr_to_gray_traits<uchar>::functor_type f = bgr_to_gray_traits<uchar>::create_functor();
return f(pix);
}
template <> __device__ __forceinline__ uchar3 toDst<uchar3>(const uchar3& pix)
{
return pix;
}
template <> __device__ __forceinline__ uchar4 toDst<uchar4>(const uchar3& pix)
{
return make_uchar4(pix.x, pix.y, pix.z, 255);
}
template <typename D>
__global__ void Bayer2BGR_8u(const PtrStepSzb src, PtrStep<D> dst, const bool blue_last, const bool start_with_green)
{
const int s_x = blockIdx.x * blockDim.x + threadIdx.x;
int s_y = blockIdx.y * blockDim.y + threadIdx.y;
if (s_y >= src.rows || (s_x << 2) >= src.cols)
return;
s_y = ::min(::max(s_y, 1), src.rows - 2);
Bayer2BGR<uchar> bayer;
bayer.apply(src, s_x, s_y, blue_last, start_with_green);
const int d_x = (blockIdx.x * blockDim.x + threadIdx.x) << 2;
const int d_y = blockIdx.y * blockDim.y + threadIdx.y;
dst(d_y, d_x) = toDst<D>(bayer.res0);
if (d_x + 1 < src.cols)
dst(d_y, d_x + 1) = toDst<D>(bayer.res1);
if (d_x + 2 < src.cols)
dst(d_y, d_x + 2) = toDst<D>(bayer.res2);
if (d_x + 3 < src.cols)
dst(d_y, d_x + 3) = toDst<D>(bayer.res3);
}
template <> struct Bayer2BGR<ushort>
{
ushort3 res0;
ushort3 res1;
__device__ void apply(const PtrStepSzb& src, int s_x, int s_y, bool blue_last, bool start_with_green)
{
ushort2 patch[3][3];
patch[0][1] = ((const ushort2*) src.ptr(s_y - 1))[s_x];
patch[0][0] = ((const ushort2*) src.ptr(s_y - 1))[::max(s_x - 1, 0)];
patch[0][2] = ((const ushort2*) src.ptr(s_y - 1))[::min(s_x + 1, ((src.cols + 1) >> 1) - 1)];
patch[1][1] = ((const ushort2*) src.ptr(s_y))[s_x];
patch[1][0] = ((const ushort2*) src.ptr(s_y))[::max(s_x - 1, 0)];
patch[1][2] = ((const ushort2*) src.ptr(s_y))[::min(s_x + 1, ((src.cols + 1) >> 1) - 1)];
patch[2][1] = ((const ushort2*) src.ptr(s_y + 1))[s_x];
patch[2][0] = ((const ushort2*) src.ptr(s_y + 1))[::max(s_x - 1, 0)];
patch[2][2] = ((const ushort2*) src.ptr(s_y + 1))[::min(s_x + 1, ((src.cols + 1) >> 1) - 1)];
if ((s_y & 1) ^ start_with_green)
{
const int t0 = (patch[0][1].x + patch[2][1].x + 1) >> 1;
const int t1 = (patch[1][0].y + patch[1][1].y + 1) >> 1;
const int t2 = (patch[0][1].x + patch[0][2].x + patch[2][1].x + patch[2][2].x + 2) >> 2;
const int t3 = (patch[0][1].y + patch[1][1].x + patch[1][2].x + patch[2][1].y + 2) >> 2;
if ((s_y & 1) ^ blue_last)
{
res0.x = t1;
res0.y = patch[1][1].x;
res0.z = t0;
res1.x = patch[1][1].y;
res1.y = t3;
res1.z = t2;
}
else
{
res0.x = t0;
res0.y = patch[1][1].x;
res0.z = t1;
res1.x = t2;
res1.y = t3;
res1.z = patch[1][1].y;
}
}
else
{
const int t0 = (patch[0][0].y + patch[0][1].y + patch[2][0].y + patch[2][1].y + 2) >> 2;
const int t1 = (patch[0][1].x + patch[1][0].y + patch[1][1].y + patch[2][1].x + 2) >> 2;
const int t2 = (patch[0][1].y + patch[2][1].y + 1) >> 1;
const int t3 = (patch[1][1].x + patch[1][2].x + 1) >> 1;
if ((s_y & 1) ^ blue_last)
{
res0.x = patch[1][1].x;
res0.y = t1;
res0.z = t0;
res1.x = t3;
res1.y = patch[1][1].y;
res1.z = t2;
}
else
{
res0.x = t0;
res0.y = t1;
res0.z = patch[1][1].x;
res1.x = t2;
res1.y = patch[1][1].y;
res1.z = t3;
}
}
}
};
template <typename D> __device__ __forceinline__ D toDst(const ushort3& pix);
template <> __device__ __forceinline__ ushort toDst<ushort>(const ushort3& pix)
{
typename bgr_to_gray_traits<ushort>::functor_type f = bgr_to_gray_traits<ushort>::create_functor();
return f(pix);
}
template <> __device__ __forceinline__ ushort3 toDst<ushort3>(const ushort3& pix)
{
return pix;
}
template <> __device__ __forceinline__ ushort4 toDst<ushort4>(const ushort3& pix)
{
return make_ushort4(pix.x, pix.y, pix.z, numeric_limits<ushort>::max());
}
template <typename D>
__global__ void Bayer2BGR_16u(const PtrStepSzb src, PtrStep<D> dst, const bool blue_last, const bool start_with_green)
{
const int s_x = blockIdx.x * blockDim.x + threadIdx.x;
int s_y = blockIdx.y * blockDim.y + threadIdx.y;
if (s_y >= src.rows || (s_x << 1) >= src.cols)
return;
s_y = ::min(::max(s_y, 1), src.rows - 2);
Bayer2BGR<ushort> bayer;
bayer.apply(src, s_x, s_y, blue_last, start_with_green);
const int d_x = (blockIdx.x * blockDim.x + threadIdx.x) << 1;
const int d_y = blockIdx.y * blockDim.y + threadIdx.y;
dst(d_y, d_x) = toDst<D>(bayer.res0);
if (d_x + 1 < src.cols)
dst(d_y, d_x + 1) = toDst<D>(bayer.res1);
}
template <int cn>
void Bayer2BGR_8u_gpu(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream)
{
typedef typename TypeVec<uchar, cn>::vec_type dst_t;
const dim3 block(32, 8);
const dim3 grid(divUp(src.cols, 4 * block.x), divUp(src.rows, block.y));
cudaSafeCall( cudaFuncSetCacheConfig(Bayer2BGR_8u<dst_t>, cudaFuncCachePreferL1) );
Bayer2BGR_8u<dst_t><<<grid, block, 0, stream>>>(src, (PtrStepSz<dst_t>)dst, blue_last, start_with_green);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
template <int cn>
void Bayer2BGR_16u_gpu(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream)
{
typedef typename TypeVec<ushort, cn>::vec_type dst_t;
const dim3 block(32, 8);
const dim3 grid(divUp(src.cols, 2 * block.x), divUp(src.rows, block.y));
cudaSafeCall( cudaFuncSetCacheConfig(Bayer2BGR_16u<dst_t>, cudaFuncCachePreferL1) );
Bayer2BGR_16u<dst_t><<<grid, block, 0, stream>>>(src, (PtrStepSz<dst_t>)dst, blue_last, start_with_green);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
template void Bayer2BGR_8u_gpu<1>(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream);
template void Bayer2BGR_8u_gpu<3>(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream);
template void Bayer2BGR_8u_gpu<4>(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream);
template void Bayer2BGR_16u_gpu<1>(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream);
template void Bayer2BGR_16u_gpu<3>(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream);
template void Bayer2BGR_16u_gpu<4>(PtrStepSzb src, PtrStepSzb dst, bool blue_last, bool start_with_green, cudaStream_t stream);
//////////////////////////////////////////////////////////////
// Bayer Demosaicing (Malvar, He, and Cutler)
//
// by Morgan McGuire, Williams College
// http://graphics.cs.williams.edu/papers/BayerJGT09/#shaders
//
// ported to CUDA
template<typename Depth> __device__
typename TypeVec<Depth, 3>::vec_type make_3(Depth x, Depth y, Depth z);
template<> __device__ TypeVec<uchar, 3>::vec_type make_3<uchar>(uchar x, uchar y, uchar z) {
return make_uchar3(x, y, z);
}
template<> __device__ TypeVec<ushort, 3>::vec_type make_3<ushort>(ushort x, ushort y, ushort z) {
return make_ushort3(x, y, z);
}
template <typename DstType, class Ptr2D>
__global__ void MHCdemosaic(PtrStepSz<DstType> dst, Ptr2D src, const int2 firstRed)
{
const float kAx = -1.0f / 8.0f, kAy = -1.5f / 8.0f, kAz = 0.5f / 8.0f /*kAw = -1.0f / 8.0f*/;
const float kBx = 2.0f / 8.0f, /*kBy = 0.0f / 8.0f,*/ /*kBz = 0.0f / 8.0f,*/ kBw = 4.0f / 8.0f ;
const float kCx = 4.0f / 8.0f, kCy = 6.0f / 8.0f, kCz = 5.0f / 8.0f /*kCw = 5.0f / 8.0f*/;
const float /*kDx = 0.0f / 8.0f,*/ kDy = 2.0f / 8.0f, kDz = -1.0f / 8.0f /*kDw = -1.0f / 8.0f*/;
const float kEx = -1.0f / 8.0f, kEy = -1.5f / 8.0f, /*kEz = -1.0f / 8.0f,*/ kEw = 0.5f / 8.0f ;
const float kFx = 2.0f / 8.0f, /*kFy = 0.0f / 8.0f,*/ kFz = 4.0f / 8.0f /*kFw = 0.0f / 8.0f*/;
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x == 0 || x >= dst.cols - 1 || y == 0 || y >= dst.rows - 1)
return;
int2 center;
center.x = x;
center.y = y;
int4 xCoord;
xCoord.x = center.x - 2;
xCoord.y = center.x - 1;
xCoord.z = center.x + 1;
xCoord.w = center.x + 2;
int4 yCoord;
yCoord.x = center.y - 2;
yCoord.y = center.y - 1;
yCoord.z = center.y + 1;
yCoord.w = center.y + 2;
float C = src(center.y, center.x); // ( 0, 0)
float4 Dvec;
Dvec.x = src(yCoord.y, xCoord.y); // (-1,-1)
Dvec.y = src(yCoord.z, xCoord.y); // (-1, 1)
Dvec.z = src(yCoord.y, xCoord.z); // ( 1,-1)
Dvec.w = src(yCoord.z, xCoord.z); // ( 1, 1)
float4 value;
value.x = src(yCoord.x, center.x); // ( 0,-2) A0
value.y = src(yCoord.y, center.x); // ( 0,-1) B0
value.z = src(center.y, xCoord.x); // (-2, 0) E0
value.w = src(center.y, xCoord.y); // (-1, 0) F0
// (A0 + A1), (B0 + B1), (E0 + E1), (F0 + F1)
value.x += src(yCoord.w, center.x); // ( 0, 2) A1
value.y += src(yCoord.z, center.x); // ( 0, 1) B1
value.z += src(center.y, xCoord.w); // ( 2, 0) E1
value.w += src(center.y, xCoord.z); // ( 1, 0) F1
float4 PATTERN;
PATTERN.x = kCx * C;
PATTERN.y = kCy * C;
PATTERN.z = kCz * C;
PATTERN.w = PATTERN.z;
float D = Dvec.x + Dvec.y + Dvec.z + Dvec.w;
// There are five filter patterns (identity, cross, checker,
// theta, phi). Precompute the terms from all of them and then
// use swizzles to assign to color channels.
//
// Channel Matches
// x cross (e.g., EE G)
// y checker (e.g., EE B)
// z theta (e.g., EO R)
// w phi (e.g., EO B)
#define A value.x // A0 + A1
#define B value.y // B0 + B1
#define E value.z // E0 + E1
#define F value.w // F0 + F1
float3 temp;
// PATTERN.yzw += (kD.yz * D).xyy;
temp.x = kDy * D;
temp.y = kDz * D;
PATTERN.y += temp.x;
PATTERN.z += temp.y;
PATTERN.w += temp.y;
// PATTERN += (kA.xyz * A).xyzx;
temp.x = kAx * A;
temp.y = kAy * A;
temp.z = kAz * A;
PATTERN.x += temp.x;
PATTERN.y += temp.y;
PATTERN.z += temp.z;
PATTERN.w += temp.x;
// PATTERN += (kE.xyw * E).xyxz;
temp.x = kEx * E;
temp.y = kEy * E;
temp.z = kEw * E;
PATTERN.x += temp.x;
PATTERN.y += temp.y;
PATTERN.z += temp.x;
PATTERN.w += temp.z;
// PATTERN.xw += kB.xw * B;
PATTERN.x += kBx * B;
PATTERN.w += kBw * B;
// PATTERN.xz += kF.xz * F;
PATTERN.x += kFx * F;
PATTERN.z += kFz * F;
// Determine which of four types of pixels we are on.
int2 alternate;
alternate.x = (x + firstRed.x) % 2;
alternate.y = (y + firstRed.y) % 2;
typedef typename VecTraits<DstType>::elem_type SrcElemType;
typedef typename TypeVec<SrcElemType, 3>::vec_type SrcType;
SrcType pixelColor =
(alternate.y == 0) ?
((alternate.x == 0) ?
make_3<SrcElemType>(saturate_cast<SrcElemType>(PATTERN.y), saturate_cast<SrcElemType>(PATTERN.x), saturate_cast<SrcElemType>(C)) :
make_3<SrcElemType>(saturate_cast<SrcElemType>(PATTERN.w), saturate_cast<SrcElemType>(C), saturate_cast<SrcElemType>(PATTERN.z))) :
((alternate.x == 0) ?
make_3<SrcElemType>(saturate_cast<SrcElemType>(PATTERN.z), saturate_cast<SrcElemType>(C), saturate_cast<SrcElemType>(PATTERN.w)) :
make_3<SrcElemType>(saturate_cast<SrcElemType>(C), saturate_cast<SrcElemType>(PATTERN.x), saturate_cast<SrcElemType>(PATTERN.y)));
dst(y, x) = toDst<DstType>(pixelColor);
}
template <int cn, typename Depth>
void MHCdemosaic(PtrStepSz<Depth> src, int2 sourceOffset, PtrStepSz<Depth> dst, int2 firstRed, cudaStream_t stream)
{
typedef typename TypeVec<Depth, cn>::vec_type dst_t;
const dim3 block(32, 8);
const dim3 grid(divUp(src.cols, block.x), divUp(src.rows, block.y));
if (sourceOffset.x || sourceOffset.y) {
cv::cudev::TextureOff<Depth> texSrc(src, sourceOffset.y, sourceOffset.x);
MHCdemosaic<dst_t, cv::cudev::TextureOffPtr<Depth>><<<grid, block, 0, stream>>>((PtrStepSz<dst_t>)dst, texSrc, firstRed);
}
else {
cv::cudev::Texture<Depth> texSrc(src);
MHCdemosaic<dst_t, cv::cudev::TexturePtr<Depth>><<<grid, block, 0, stream>>>((PtrStepSz<dst_t>)dst, texSrc, firstRed);
}
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
template void MHCdemosaic<1, uchar>(PtrStepSzb src, int2 sourceOffset, PtrStepSzb dst, int2 firstRed, cudaStream_t stream);
template void MHCdemosaic<3, uchar>(PtrStepSzb src, int2 sourceOffset, PtrStepSzb dst, int2 firstRed, cudaStream_t stream);
template void MHCdemosaic<4, uchar>(PtrStepSzb src, int2 sourceOffset, PtrStepSzb dst, int2 firstRed, cudaStream_t stream);
template void MHCdemosaic<1, ushort>(PtrStepSz<ushort> src, int2 sourceOffset, PtrStepSz<ushort> dst, int2 firstRed, cudaStream_t stream);
template void MHCdemosaic<3, ushort>(PtrStepSz<ushort> src, int2 sourceOffset, PtrStepSz<ushort> dst, int2 firstRed, cudaStream_t stream);
template void MHCdemosaic<4, ushort>(PtrStepSz<ushort> src, int2 sourceOffset, PtrStepSz<ushort> dst, int2 firstRed, cudaStream_t stream);
}}}
#endif /* CUDA_DISABLER */
@@ -0,0 +1,824 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include <thrust/device_ptr.h>
#include <thrust/transform.h>
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/emulation.hpp"
#include "opencv2/core/cuda/vec_math.hpp"
#include "opencv2/core/cuda/functional.hpp"
#include "opencv2/opencv_modules.hpp"
#ifdef HAVE_OPENCV_CUDAARITHM
namespace cv { namespace cuda { namespace device
{
namespace ght
{
__device__ int g_counter;
template <typename T, int PIXELS_PER_THREAD>
__global__ void buildEdgePointList(const PtrStepSzb edges, const PtrStep<T> dx, const PtrStep<T> dy,
unsigned int* coordList, float* thetaList)
{
__shared__ unsigned int s_coordLists[4][32 * PIXELS_PER_THREAD];
__shared__ float s_thetaLists[4][32 * PIXELS_PER_THREAD];
__shared__ int s_sizes[4];
__shared__ int s_globStart[4];
const int x = blockIdx.x * blockDim.x * PIXELS_PER_THREAD + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (threadIdx.x == 0)
s_sizes[threadIdx.y] = 0;
__syncthreads();
if (y < edges.rows)
{
// fill the queue
const uchar* edgesRow = edges.ptr(y);
const T* dxRow = dx.ptr(y);
const T* dyRow = dy.ptr(y);
for (int i = 0, xx = x; i < PIXELS_PER_THREAD && xx < edges.cols; ++i, xx += blockDim.x)
{
const T dxVal = dxRow[xx];
const T dyVal = dyRow[xx];
if (edgesRow[xx] && (dxVal != 0 || dyVal != 0))
{
const unsigned int coord = (y << 16) | xx;
float theta = ::atan2f(dyVal, dxVal);
if (theta < 0)
theta += 2.0f * CV_PI_F;
const int qidx = Emulation::smem::atomicAdd(&s_sizes[threadIdx.y], 1);
s_coordLists[threadIdx.y][qidx] = coord;
s_thetaLists[threadIdx.y][qidx] = theta;
}
}
}
__syncthreads();
// let one thread reserve the space required in the global list
if (threadIdx.x == 0 && threadIdx.y == 0)
{
// find how many items are stored in each list
int totalSize = 0;
for (int i = 0; i < blockDim.y; ++i)
{
s_globStart[i] = totalSize;
totalSize += s_sizes[i];
}
// calculate the offset in the global list
const int globalOffset = atomicAdd(&g_counter, totalSize);
for (int i = 0; i < blockDim.y; ++i)
s_globStart[i] += globalOffset;
}
__syncthreads();
// copy local queues to global queue
const int qsize = s_sizes[threadIdx.y];
int gidx = s_globStart[threadIdx.y] + threadIdx.x;
for(int i = threadIdx.x; i < qsize; i += blockDim.x, gidx += blockDim.x)
{
coordList[gidx] = s_coordLists[threadIdx.y][i];
thetaList[gidx] = s_thetaLists[threadIdx.y][i];
}
}
template <typename T>
int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList)
{
const int PIXELS_PER_THREAD = 8;
void* counterPtr;
cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) );
cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) );
const dim3 block(32, 4);
const dim3 grid(divUp(edges.cols, block.x * PIXELS_PER_THREAD), divUp(edges.rows, block.y));
cudaSafeCall( cudaFuncSetCacheConfig(buildEdgePointList<T, PIXELS_PER_THREAD>, cudaFuncCachePreferShared) );
buildEdgePointList<T, PIXELS_PER_THREAD><<<grid, block>>>(edges, (PtrStepSz<T>) dx, (PtrStepSz<T>) dy, coordList, thetaList);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaDeviceSynchronize() );
int totalCount;
cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) );
return totalCount;
}
template int buildEdgePointList_gpu<short>(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList);
template int buildEdgePointList_gpu<int>(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList);
template int buildEdgePointList_gpu<float>(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList);
__global__ void buildRTable(const unsigned int* coordList, const float* thetaList, const int pointsCount,
PtrStep<short2> r_table, int* r_sizes, int maxSize,
const short2 templCenter, const float thetaScale)
{
const int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid >= pointsCount)
return;
const unsigned int coord = coordList[tid];
short2 p;
p.x = (coord & 0xFFFF);
p.y = (coord >> 16) & 0xFFFF;
const float theta = thetaList[tid];
const int n = __float2int_rn(theta * thetaScale);
const int ind = ::atomicAdd(r_sizes + n, 1);
if (ind < maxSize)
r_table(n, ind) = saturate_cast<short2>(p - templCenter);
}
void buildRTable_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
PtrStepSz<short2> r_table, int* r_sizes,
short2 templCenter, int levels)
{
const dim3 block(256);
const dim3 grid(divUp(pointsCount, block.x));
const float thetaScale = levels / (2.0f * CV_PI_F);
buildRTable<<<grid, block>>>(coordList, thetaList, pointsCount, r_table, r_sizes, r_table.cols, templCenter, thetaScale);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaDeviceSynchronize() );
}
////////////////////////////////////////////////////////////////////////
// Ballard_Pos
__global__ void Ballard_Pos_calcHist(const unsigned int* coordList, const float* thetaList, const int pointsCount,
const PtrStep<short2> r_table, const int* r_sizes,
PtrStepSzi hist,
const float idp, const float thetaScale)
{
const int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid >= pointsCount)
return;
const unsigned int coord = coordList[tid];
short2 p;
p.x = (coord & 0xFFFF);
p.y = (coord >> 16) & 0xFFFF;
const float theta = thetaList[tid];
const int n = __float2int_rn(theta * thetaScale);
const short2* r_row = r_table.ptr(n);
const int r_row_size = r_sizes[n];
for (int j = 0; j < r_row_size; ++j)
{
short2 c = saturate_cast<short2>(p - r_row[j]);
c.x = __float2int_rn(c.x * idp);
c.y = __float2int_rn(c.y * idp);
if (c.x >= 0 && c.x < hist.cols - 2 && c.y >= 0 && c.y < hist.rows - 2)
::atomicAdd(hist.ptr(c.y + 1) + c.x + 1, 1);
}
}
void Ballard_Pos_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
PtrStepSz<short2> r_table, const int* r_sizes,
PtrStepSzi hist,
float dp, int levels)
{
const dim3 block(256);
const dim3 grid(divUp(pointsCount, block.x));
const float idp = 1.0f / dp;
const float thetaScale = levels / (2.0f * CV_PI_F);
Ballard_Pos_calcHist<<<grid, block>>>(coordList, thetaList, pointsCount, r_table, r_sizes, hist, idp, thetaScale);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void Ballard_Pos_findPosInHist(const PtrStepSzi hist, float4* out, int3* votes,
const int maxSize, const float dp, const int threshold)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x >= hist.cols - 2 || y >= hist.rows - 2)
return;
const int curVotes = hist(y + 1, x + 1);
if (curVotes > threshold &&
curVotes > hist(y + 1, x) &&
curVotes >= hist(y + 1, x + 2) &&
curVotes > hist(y, x + 1) &&
curVotes >= hist(y + 2, x + 1))
{
const int ind = ::atomicAdd(&g_counter, 1);
if (ind < maxSize)
{
out[ind] = make_float4(x * dp, y * dp, 1.0f, 0.0f);
votes[ind] = make_int3(curVotes, 0, 0);
}
}
}
int Ballard_Pos_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int maxSize, float dp, int threshold)
{
void* counterPtr;
cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) );
cudaSafeCall( cudaMemset(counterPtr, 0, sizeof(int)) );
const dim3 block(32, 8);
const dim3 grid(divUp(hist.cols - 2, block.x), divUp(hist.rows - 2, block.y));
cudaSafeCall( cudaFuncSetCacheConfig(Ballard_Pos_findPosInHist, cudaFuncCachePreferL1) );
Ballard_Pos_findPosInHist<<<grid, block>>>(hist, out, votes, maxSize, dp, threshold);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaDeviceSynchronize() );
int totalCount;
cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) );
totalCount = std::min(totalCount, maxSize);
return totalCount;
}
////////////////////////////////////////////////////////////////////////
// Guil_Full
struct FeatureTable
{
uchar* p1_pos_data;
size_t p1_pos_step;
uchar* p1_theta_data;
size_t p1_theta_step;
uchar* p2_pos_data;
size_t p2_pos_step;
uchar* d12_data;
size_t d12_step;
uchar* r1_data;
size_t r1_step;
uchar* r2_data;
size_t r2_step;
};
__constant__ FeatureTable c_templFeatures;
__constant__ FeatureTable c_imageFeatures;
void Guil_Full_setTemplFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2)
{
FeatureTable tbl;
tbl.p1_pos_data = p1_pos.data;
tbl.p1_pos_step = p1_pos.step;
tbl.p1_theta_data = p1_theta.data;
tbl.p1_theta_step = p1_theta.step;
tbl.p2_pos_data = p2_pos.data;
tbl.p2_pos_step = p2_pos.step;
tbl.d12_data = d12.data;
tbl.d12_step = d12.step;
tbl.r1_data = r1.data;
tbl.r1_step = r1.step;
tbl.r2_data = r2.data;
tbl.r2_step = r2.step;
cudaSafeCall( cudaMemcpyToSymbol(c_templFeatures, &tbl, sizeof(FeatureTable)) );
}
void Guil_Full_setImageFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2)
{
FeatureTable tbl;
tbl.p1_pos_data = p1_pos.data;
tbl.p1_pos_step = p1_pos.step;
tbl.p1_theta_data = p1_theta.data;
tbl.p1_theta_step = p1_theta.step;
tbl.p2_pos_data = p2_pos.data;
tbl.p2_pos_step = p2_pos.step;
tbl.d12_data = d12.data;
tbl.d12_step = d12.step;
tbl.r1_data = r1.data;
tbl.r1_step = r1.step;
tbl.r2_data = r2.data;
tbl.r2_step = r2.step;
cudaSafeCall( cudaMemcpyToSymbol(c_imageFeatures, &tbl, sizeof(FeatureTable)) );
}
struct TemplFeatureTable
{
static __device__ float2* p1_pos(int n)
{
return (float2*)(c_templFeatures.p1_pos_data + n * c_templFeatures.p1_pos_step);
}
static __device__ float* p1_theta(int n)
{
return (float*)(c_templFeatures.p1_theta_data + n * c_templFeatures.p1_theta_step);
}
static __device__ float2* p2_pos(int n)
{
return (float2*)(c_templFeatures.p2_pos_data + n * c_templFeatures.p2_pos_step);
}
static __device__ float* d12(int n)
{
return (float*)(c_templFeatures.d12_data + n * c_templFeatures.d12_step);
}
static __device__ float2* r1(int n)
{
return (float2*)(c_templFeatures.r1_data + n * c_templFeatures.r1_step);
}
static __device__ float2* r2(int n)
{
return (float2*)(c_templFeatures.r2_data + n * c_templFeatures.r2_step);
}
};
struct ImageFeatureTable
{
static __device__ float2* p1_pos(int n)
{
return (float2*)(c_imageFeatures.p1_pos_data + n * c_imageFeatures.p1_pos_step);
}
static __device__ float* p1_theta(int n)
{
return (float*)(c_imageFeatures.p1_theta_data + n * c_imageFeatures.p1_theta_step);
}
static __device__ float2* p2_pos(int n)
{
return (float2*)(c_imageFeatures.p2_pos_data + n * c_imageFeatures.p2_pos_step);
}
static __device__ float* d12(int n)
{
return (float*)(c_imageFeatures.d12_data + n * c_imageFeatures.d12_step);
}
static __device__ float2* r1(int n)
{
return (float2*)(c_imageFeatures.r1_data + n * c_imageFeatures.r1_step);
}
static __device__ float2* r2(int n)
{
return (float2*)(c_imageFeatures.r2_data + n * c_imageFeatures.r2_step);
}
};
__device__ float clampAngle(float a)
{
float res = a;
while (res > 2.0f * CV_PI_F)
res -= 2.0f * CV_PI_F;
while (res < 0.0f)
res += 2.0f * CV_PI_F;
return res;
}
__device__ bool angleEq(float a, float b, float eps)
{
return (::fabs(clampAngle(a - b)) <= eps);
}
template <class FT, bool isTempl>
__global__ void Guil_Full_buildFeatureList(const unsigned int* coordList, const float* thetaList, const int pointsCount,
int* sizes, const int maxSize,
const float xi, const float angleEpsilon, const float alphaScale,
const float2 center, const float maxDist)
{
const float p1_theta = thetaList[blockIdx.x];
const unsigned int coord1 = coordList[blockIdx.x];
float2 p1_pos;
p1_pos.x = (coord1 & 0xFFFF);
p1_pos.y = (coord1 >> 16) & 0xFFFF;
for (int i = threadIdx.x; i < pointsCount; i += blockDim.x)
{
const float p2_theta = thetaList[i];
const unsigned int coord2 = coordList[i];
float2 p2_pos;
p2_pos.x = (coord2 & 0xFFFF);
p2_pos.y = (coord2 >> 16) & 0xFFFF;
if (angleEq(p1_theta - p2_theta, xi, angleEpsilon))
{
const float2 d = p1_pos - p2_pos;
float alpha12 = clampAngle(::atan2(d.y, d.x) - p1_theta);
float d12 = ::sqrtf(d.x * d.x + d.y * d.y);
if (d12 > maxDist)
continue;
float2 r1 = p1_pos - center;
float2 r2 = p2_pos - center;
const int n = __float2int_rn(alpha12 * alphaScale);
const int ind = ::atomicAdd(sizes + n, 1);
if (ind < maxSize)
{
if (!isTempl)
{
FT::p1_pos(n)[ind] = p1_pos;
FT::p2_pos(n)[ind] = p2_pos;
}
FT::p1_theta(n)[ind] = p1_theta;
FT::d12(n)[ind] = d12;
if (isTempl)
{
FT::r1(n)[ind] = r1;
FT::r2(n)[ind] = r2;
}
}
}
}
}
template <class FT, bool isTempl>
void Guil_Full_buildFeatureList_caller(const unsigned int* coordList, const float* thetaList, int pointsCount,
int* sizes, int maxSize,
float xi, float angleEpsilon, int levels,
float2 center, float maxDist)
{
const dim3 block(256);
const dim3 grid(pointsCount);
const float alphaScale = levels / (2.0f * CV_PI_F);
Guil_Full_buildFeatureList<FT, isTempl><<<grid, block>>>(coordList, thetaList, pointsCount,
sizes, maxSize,
xi * (CV_PI_F / 180.0f), angleEpsilon * (CV_PI_F / 180.0f), alphaScale,
center, maxDist);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaDeviceSynchronize() );
thrust::device_ptr<int> sizesPtr(sizes);
thrust::transform(sizesPtr, sizesPtr + levels + 1, sizesPtr, device::bind2nd(device::minimum<int>(), maxSize));
}
void Guil_Full_buildTemplFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
int* sizes, int maxSize,
float xi, float angleEpsilon, int levels,
float2 center, float maxDist)
{
Guil_Full_buildFeatureList_caller<TemplFeatureTable, true>(coordList, thetaList, pointsCount,
sizes, maxSize,
xi, angleEpsilon, levels,
center, maxDist);
}
void Guil_Full_buildImageFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
int* sizes, int maxSize,
float xi, float angleEpsilon, int levels,
float2 center, float maxDist)
{
Guil_Full_buildFeatureList_caller<ImageFeatureTable, false>(coordList, thetaList, pointsCount,
sizes, maxSize,
xi, angleEpsilon, levels,
center, maxDist);
}
__global__ void Guil_Full_calcOHist(const int* templSizes, const int* imageSizes, int* OHist,
const float minAngle, const float maxAngle, const float iAngleStep, const int angleRange)
{
extern __shared__ int s_OHist[];
for (int i = threadIdx.x; i <= angleRange; i += blockDim.x)
s_OHist[i] = 0;
__syncthreads();
const int tIdx = blockIdx.x;
const int level = blockIdx.y;
const int tSize = templSizes[level];
if (tIdx < tSize)
{
const int imSize = imageSizes[level];
const float t_p1_theta = TemplFeatureTable::p1_theta(level)[tIdx];
for (int i = threadIdx.x; i < imSize; i += blockDim.x)
{
const float im_p1_theta = ImageFeatureTable::p1_theta(level)[i];
const float angle = clampAngle(im_p1_theta - t_p1_theta);
if (angle >= minAngle && angle <= maxAngle)
{
const int n = __float2int_rn((angle - minAngle) * iAngleStep);
Emulation::smem::atomicAdd(&s_OHist[n], 1);
}
}
}
__syncthreads();
for (int i = threadIdx.x; i <= angleRange; i += blockDim.x)
::atomicAdd(OHist + i, s_OHist[i]);
}
void Guil_Full_calcOHist_gpu(const int* templSizes, const int* imageSizes, int* OHist,
float minAngle, float maxAngle, float angleStep, int angleRange,
int levels, int tMaxSize)
{
const dim3 block(256);
const dim3 grid(tMaxSize, levels + 1);
minAngle *= (CV_PI_F / 180.0f);
maxAngle *= (CV_PI_F / 180.0f);
angleStep *= (CV_PI_F / 180.0f);
const size_t smemSize = (angleRange + 1) * sizeof(float);
Guil_Full_calcOHist<<<grid, block, smemSize>>>(templSizes, imageSizes, OHist,
minAngle, maxAngle, 1.0f / angleStep, angleRange);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void Guil_Full_calcSHist(const int* templSizes, const int* imageSizes, int* SHist,
const float angle, const float angleEpsilon,
const float minScale, const float maxScale, const float iScaleStep, const int scaleRange)
{
extern __shared__ int s_SHist[];
for (int i = threadIdx.x; i <= scaleRange; i += blockDim.x)
s_SHist[i] = 0;
__syncthreads();
const int tIdx = blockIdx.x;
const int level = blockIdx.y;
const int tSize = templSizes[level];
if (tIdx < tSize)
{
const int imSize = imageSizes[level];
const float t_p1_theta = TemplFeatureTable::p1_theta(level)[tIdx] + angle;
const float t_d12 = TemplFeatureTable::d12(level)[tIdx] + angle;
for (int i = threadIdx.x; i < imSize; i += blockDim.x)
{
const float im_p1_theta = ImageFeatureTable::p1_theta(level)[i];
const float im_d12 = ImageFeatureTable::d12(level)[i];
if (angleEq(im_p1_theta, t_p1_theta, angleEpsilon))
{
const float scale = im_d12 / t_d12;
if (scale >= minScale && scale <= maxScale)
{
const int s = __float2int_rn((scale - minScale) * iScaleStep);
Emulation::smem::atomicAdd(&s_SHist[s], 1);
}
}
}
}
__syncthreads();
for (int i = threadIdx.x; i <= scaleRange; i += blockDim.x)
::atomicAdd(SHist + i, s_SHist[i]);
}
void Guil_Full_calcSHist_gpu(const int* templSizes, const int* imageSizes, int* SHist,
float angle, float angleEpsilon,
float minScale, float maxScale, float iScaleStep, int scaleRange,
int levels, int tMaxSize)
{
const dim3 block(256);
const dim3 grid(tMaxSize, levels + 1);
angle *= (CV_PI_F / 180.0f);
angleEpsilon *= (CV_PI_F / 180.0f);
const size_t smemSize = (scaleRange + 1) * sizeof(float);
Guil_Full_calcSHist<<<grid, block, smemSize>>>(templSizes, imageSizes, SHist,
angle, angleEpsilon,
minScale, maxScale, iScaleStep, scaleRange);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void Guil_Full_calcPHist(const int* templSizes, const int* imageSizes, PtrStepSzi PHist,
const float angle, const float sinVal, const float cosVal, const float angleEpsilon, const float scale,
const float idp)
{
const int tIdx = blockIdx.x;
const int level = blockIdx.y;
const int tSize = templSizes[level];
if (tIdx < tSize)
{
const int imSize = imageSizes[level];
const float t_p1_theta = TemplFeatureTable::p1_theta(level)[tIdx] + angle;
float2 r1 = TemplFeatureTable::r1(level)[tIdx];
float2 r2 = TemplFeatureTable::r2(level)[tIdx];
r1 = r1 * scale;
r2 = r2 * scale;
r1 = make_float2(cosVal * r1.x - sinVal * r1.y, sinVal * r1.x + cosVal * r1.y);
r2 = make_float2(cosVal * r2.x - sinVal * r2.y, sinVal * r2.x + cosVal * r2.y);
for (int i = threadIdx.x; i < imSize; i += blockDim.x)
{
const float im_p1_theta = ImageFeatureTable::p1_theta(level)[i];
const float2 im_p1_pos = ImageFeatureTable::p1_pos(level)[i];
const float2 im_p2_pos = ImageFeatureTable::p2_pos(level)[i];
if (angleEq(im_p1_theta, t_p1_theta, angleEpsilon))
{
float2 c1, c2;
c1 = im_p1_pos - r1;
c1 = c1 * idp;
c2 = im_p2_pos - r2;
c2 = c2 * idp;
if (::fabs(c1.x - c2.x) > 1 || ::fabs(c1.y - c2.y) > 1)
continue;
if (c1.y >= 0 && c1.y < PHist.rows - 2 && c1.x >= 0 && c1.x < PHist.cols - 2)
::atomicAdd(PHist.ptr(__float2int_rn(c1.y) + 1) + __float2int_rn(c1.x) + 1, 1);
}
}
}
}
void Guil_Full_calcPHist_gpu(const int* templSizes, const int* imageSizes, PtrStepSzi PHist,
float angle, float angleEpsilon, float scale,
float dp,
int levels, int tMaxSize)
{
const dim3 block(256);
const dim3 grid(tMaxSize, levels + 1);
angle *= (CV_PI_F / 180.0f);
angleEpsilon *= (CV_PI_F / 180.0f);
const float sinVal = ::sinf(angle);
const float cosVal = ::cosf(angle);
cudaSafeCall( cudaFuncSetCacheConfig(Guil_Full_calcPHist, cudaFuncCachePreferL1) );
Guil_Full_calcPHist<<<grid, block>>>(templSizes, imageSizes, PHist,
angle, sinVal, cosVal, angleEpsilon, scale,
1.0f / dp);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void Guil_Full_findPosInHist(const PtrStepSzi hist, float4* out, int3* votes, const int maxSize,
const float angle, const int angleVotes, const float scale, const int scaleVotes,
const float dp, const int threshold)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x >= hist.cols - 2 || y >= hist.rows - 2)
return;
const int curVotes = hist(y + 1, x + 1);
if (curVotes > threshold &&
curVotes > hist(y + 1, x) &&
curVotes >= hist(y + 1, x + 2) &&
curVotes > hist(y, x + 1) &&
curVotes >= hist(y + 2, x + 1))
{
const int ind = ::atomicAdd(&g_counter, 1);
if (ind < maxSize)
{
out[ind] = make_float4(x * dp, y * dp, scale, angle);
votes[ind] = make_int3(curVotes, scaleVotes, angleVotes);
}
}
}
int Guil_Full_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int curSize, int maxSize,
float angle, int angleVotes, float scale, int scaleVotes,
float dp, int threshold)
{
void* counterPtr;
cudaSafeCall( cudaGetSymbolAddress(&counterPtr, g_counter) );
cudaSafeCall( cudaMemcpy(counterPtr, &curSize, sizeof(int), cudaMemcpyHostToDevice) );
const dim3 block(32, 8);
const dim3 grid(divUp(hist.cols - 2, block.x), divUp(hist.rows - 2, block.y));
cudaSafeCall( cudaFuncSetCacheConfig(Guil_Full_findPosInHist, cudaFuncCachePreferL1) );
Guil_Full_findPosInHist<<<grid, block>>>(hist, out, votes, maxSize,
angle, angleVotes, scale, scaleVotes,
dp, threshold);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaDeviceSynchronize() );
int totalCount;
cudaSafeCall( cudaMemcpy(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost) );
totalCount = std::min(totalCount, maxSize);
return totalCount;
}
}
}}}
#endif // HAVE_OPENCV_CUDAARITHM
#endif /* CUDA_DISABLER */
+437
View File
@@ -0,0 +1,437 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/functional.hpp"
#include "opencv2/core/cuda/emulation.hpp"
#include "opencv2/core/cuda/transform.hpp"
using namespace cv::cuda;
using namespace cv::cuda::device;
namespace hist
{
template<bool fourByteAligned>
__global__ void histogram256Kernel(const uchar* src, int cols, int rows, size_t step, int* hist, const int offsetX = 0)
{
__shared__ int shist[256];
const int y = blockIdx.x * blockDim.y + threadIdx.y;
const int tid = threadIdx.y * blockDim.x + threadIdx.x;
const int alignedOffset = fourByteAligned ? 0 : 4 - offsetX;
shist[tid] = 0;
__syncthreads();
if (y < rows) {
const uchar* rowPtr = &src[y * step];
// load uncoalesced head
if (!fourByteAligned && threadIdx.x == 0) {
for (int x = 0; x < min(alignedOffset, cols); x++)
Emulation::smem::atomicAdd(&shist[static_cast<int>(rowPtr[x])], 1);
}
// coalesced loads
const unsigned int* rowPtrIntAligned = (const unsigned int*)(fourByteAligned ? &src[y * step] : &src[alignedOffset + y * step]);
const int cols_4 = fourByteAligned ? cols / 4 : (cols - alignedOffset) / 4;
for (int x = threadIdx.x; x < cols_4; x += blockDim.x) {
const unsigned int data = rowPtrIntAligned[x];
Emulation::smem::atomicAdd(&shist[(data >> 0) & 0xFFU], 1);
Emulation::smem::atomicAdd(&shist[(data >> 8) & 0xFFU], 1);
Emulation::smem::atomicAdd(&shist[(data >> 16) & 0xFFU], 1);
Emulation::smem::atomicAdd(&shist[(data >> 24) & 0xFFU], 1);
}
// load uncoalesced tail
if (threadIdx.x == 0) {
const int iTailStart = fourByteAligned ? cols_4 * 4 : cols_4 * 4 + alignedOffset;
for (int x = iTailStart; x < cols; x++)
Emulation::smem::atomicAdd(&shist[static_cast<int>(rowPtr[x])], 1);
}
}
__syncthreads();
const int histVal = shist[tid];
if (histVal > 0)
::atomicAdd(hist + tid, histVal);
}
void histogram256(PtrStepSzb src, int* hist, const int offsetX, cudaStream_t stream)
{
const dim3 block(32, 8);
const dim3 grid(divUp(src.rows, block.y));
if(offsetX)
histogram256Kernel<false><<<grid, block, 0, stream>>>(src.data, src.cols, src.rows, src.step, hist, offsetX);
else
histogram256Kernel<true><<<grid, block, 0, stream>>>(src.data, src.cols, src.rows, src.step, hist, offsetX);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
template<bool fourByteAligned>
__global__ void histogram256Kernel(const uchar* src, int cols, int rows, size_t srcStep, const uchar* mask, size_t maskStep, int* hist, const int offsetX = 0)
{
__shared__ int shist[256];
const int y = blockIdx.x * blockDim.y + threadIdx.y;
const int tid = threadIdx.y * blockDim.x + threadIdx.x;
const int alignedOffset = fourByteAligned ? 0 : 4 - offsetX;
shist[tid] = 0;
__syncthreads();
if (y < rows)
{
const uchar* rowPtr = &src[y * srcStep];
const uchar* maskRowPtr = &mask[y * maskStep];
// load uncoalesced head
if (!fourByteAligned && threadIdx.x == 0) {
for (int x = 0; x < min(alignedOffset, cols); x++) {
if (maskRowPtr[x])
Emulation::smem::atomicAdd(&shist[rowPtr[x]], 1);
}
}
// coalesced loads
const unsigned int* rowPtrIntAligned = (const unsigned int*)(fourByteAligned ? &src[y * srcStep] : &src[alignedOffset + y * maskStep]);
const unsigned int* maskRowPtrIntAligned = (const unsigned int*)(fourByteAligned ? &mask[y * maskStep] : &mask[alignedOffset + y * maskStep]);
const int cols_4 = fourByteAligned ? cols / 4 : (cols - alignedOffset) / 4;
for (int x = threadIdx.x; x < cols_4; x += blockDim.x) {
const unsigned int data = rowPtrIntAligned[x];
const unsigned int m = maskRowPtrIntAligned[x];
if ((m >> 0) & 0xFFU)
Emulation::smem::atomicAdd(&shist[(data >> 0) & 0xFFU], 1);
if ((m >> 8) & 0xFFU)
Emulation::smem::atomicAdd(&shist[(data >> 8) & 0xFFU], 1);
if ((m >> 16) & 0xFFU)
Emulation::smem::atomicAdd(&shist[(data >> 16) & 0xFFU], 1);
if ((m >> 24) & 0xFFU)
Emulation::smem::atomicAdd(&shist[(data >> 24) & 0xFFU], 1);
}
// load uncoalesced tail
if (threadIdx.x == 0) {
const int iTailStart = fourByteAligned ? cols_4 * 4 : cols_4 * 4 + alignedOffset;
for (int x = iTailStart; x < cols; x++) {
if (maskRowPtr[x])
Emulation::smem::atomicAdd(&shist[static_cast<int>(rowPtr[x])], 1);
}
}
}
__syncthreads();
const int histVal = shist[tid];
if (histVal > 0)
::atomicAdd(hist + tid, histVal);
}
void histogram256(PtrStepSzb src, PtrStepSzb mask, int* hist, const int offsetX, cudaStream_t stream)
{
const dim3 block(32, 8);
const dim3 grid(divUp(src.rows, block.y));
if(offsetX)
histogram256Kernel<false><<<grid, block, 0, stream>>>(src.data, src.cols, src.rows, src.step, mask.data, mask.step, hist, offsetX);
else
histogram256Kernel<true><<<grid, block, 0, stream>>>(src.data, src.cols, src.rows, src.step, mask.data, mask.step, hist, offsetX);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
}
/////////////////////////////////////////////////////////////////////////
namespace hist
{
__device__ __forceinline__ void histEvenInc(int* shist, uint data, int binSize, int lowerLevel, int upperLevel)
{
if (data >= lowerLevel && data <= upperLevel)
{
const uint ind = (data - lowerLevel) / binSize;
Emulation::smem::atomicAdd(shist + ind, 1);
}
}
template<bool fourByteAligned>
__global__ void histEven8u(const uchar* src, const size_t step, const int rows, const int cols, int* hist, const int binCount, const int binSize,
const int lowerLevel, const int upperLevel, const int offsetX)
{
extern __shared__ int shist[];
const int y = blockIdx.x * blockDim.y + threadIdx.y;
const int tid = threadIdx.y * blockDim.x + threadIdx.x;
const int alignedOffset = fourByteAligned ? 0 : 4 - offsetX;
if (tid < binCount)
shist[tid] = 0;
__syncthreads();
if (y < rows)
{
const uchar* rowPtr = &src[y * step];
// load uncoalesced head
if (!fourByteAligned && threadIdx.x == 0) {
for (int x = 0; x < min(alignedOffset, cols); x++)
histEvenInc(shist, rowPtr[x], binSize, lowerLevel, upperLevel);
}
// coalesced loads
const unsigned int* rowPtrIntAligned = (const unsigned int*)(fourByteAligned ? &src[y * step] : &src[alignedOffset + y * step]);
const int cols_4 = fourByteAligned ? cols / 4 : (cols - alignedOffset) / 4;
for (int x = threadIdx.x; x < cols_4; x += blockDim.x) {
const unsigned int data = rowPtrIntAligned[x];
histEvenInc(shist, (data >> 0) & 0xFFU, binSize, lowerLevel, upperLevel);
histEvenInc(shist, (data >> 8) & 0xFFU, binSize, lowerLevel, upperLevel);
histEvenInc(shist, (data >> 16) & 0xFFU, binSize, lowerLevel, upperLevel);
histEvenInc(shist, (data >> 24) & 0xFFU, binSize, lowerLevel, upperLevel);
}
// load uncoalesced tail
if (threadIdx.x == 0) {
const int iTailStart = fourByteAligned ? cols_4 * 4 : cols_4 * 4 + alignedOffset;
for (int x = iTailStart; x < cols; x++)
histEvenInc(shist, rowPtr[x], binSize, lowerLevel, upperLevel);
}
}
__syncthreads();
if (tid < binCount)
{
const int histVal = shist[tid];
if (histVal > 0)
::atomicAdd(hist + tid, histVal);
}
}
void histEven8u(PtrStepSzb src, int* hist, int binCount, int lowerLevel, int upperLevel, const int offsetX, cudaStream_t stream)
{
const dim3 block(32, 8);
const dim3 grid(divUp(src.rows, block.y));
const int binSize = divUp(upperLevel - lowerLevel, binCount);
const size_t smem_size = binCount * sizeof(int);
if(offsetX)
histEven8u<false><<<grid, block, smem_size, stream>>>(src.data, src.step, src.rows, src.cols, hist, binCount, binSize, lowerLevel, upperLevel, offsetX);
else
histEven8u<true><<<grid, block, smem_size, stream>>>(src.data, src.step, src.rows, src.cols, hist, binCount, binSize, lowerLevel, upperLevel, offsetX);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
}
/////////////////////////////////////////////////////////////////////////
namespace hist
{
struct EqualizeHist : unary_function<uchar, uchar>
{
const uchar* lut;
__host__ EqualizeHist(const uchar* _lut) : lut(_lut) {}
__device__ __forceinline__ uchar operator ()(uchar val) const
{
return lut[val];
}
};
}
namespace cv { namespace cuda { namespace device
{
template <> struct TransformFunctorTraits<hist::EqualizeHist> : DefaultTransformFunctorTraits<hist::EqualizeHist>
{
enum { smart_shift = 4 };
};
}}}
namespace hist
{
void equalizeHist(PtrStepSzb src, PtrStepSzb dst, const uchar* lut, cudaStream_t stream)
{
device::transform(src, dst, EqualizeHist(lut), WithOutMask(), stream);
}
__global__ void buildLutKernel(int* hist, unsigned char* lut, int size)
{
__shared__ int warp_smem[8];
__shared__ int hist_smem[8][33];
#define HIST_SMEM_NO_BANK_CONFLICT(idx) hist_smem[(idx) >> 5][(idx) & 31]
const int tId = threadIdx.x;
const int warpId = threadIdx.x / 32;
const int laneId = threadIdx.x % 32;
// Step1 - Find minimum non-zero value in hist and make it zero
HIST_SMEM_NO_BANK_CONFLICT(tId) = hist[tId];
int nonZeroIdx = HIST_SMEM_NO_BANK_CONFLICT(tId) > 0 ? tId : 256;
__syncthreads();
for (int delta = 16; delta > 0; delta /= 2)
{
#if __CUDACC_VER_MAJOR__ >= 9
int shflVal = __shfl_down_sync(0xFFFFFFFF, nonZeroIdx, delta);
#else
int shflVal = __shfl_down(nonZeroIdx, delta);
#endif
if (laneId < delta)
nonZeroIdx = min(nonZeroIdx, shflVal);
}
if (laneId == 0)
warp_smem[warpId] = nonZeroIdx;
__syncthreads();
if (tId < 8)
{
int warpVal = warp_smem[tId];
for (int delta = 4; delta > 0; delta /= 2)
{
#if __CUDACC_VER_MAJOR__ >= 9
int shflVal = __shfl_down_sync(0x000000FF, warpVal, delta);
#else
int shflVal = __shfl_down(warpVal, delta);
#endif
if (tId < delta)
warpVal = min(warpVal, shflVal);
}
if (tId == 0)
{
warp_smem[0] = warpVal; // warpVal - minimum index
}
}
__syncthreads();
const int minNonZeroIdx = warp_smem[0];
const int minNonZeroVal = HIST_SMEM_NO_BANK_CONFLICT(minNonZeroIdx);
if (minNonZeroVal == size)
{
// This is a special case: the whole image has the same color
lut[tId] = 0;
if (tId == minNonZeroIdx)
lut[tId] = minNonZeroIdx;
return;
}
if (tId == 0)
HIST_SMEM_NO_BANK_CONFLICT(minNonZeroIdx) = 0;
__syncthreads();
// Step2 - Inclusive sum
// Algorithm from GPU Gems 3 (A Work-Efficient Parallel Scan)
// https://developer.nvidia.com/gpugems/gpugems3/part-vi-gpu-computing/chapter-39-parallel-prefix-sum-scan-cuda
// Step2 Phase1 - The Up-Sweep Phase
for (int delta = 1; delta < 256; delta *= 2)
{
if (tId < 128 / delta)
{
int idx = 255 - 2 * tId * delta;
HIST_SMEM_NO_BANK_CONFLICT(idx) += HIST_SMEM_NO_BANK_CONFLICT(idx - delta);
}
__syncthreads();
}
// Step2 Phase2 - The Down-Sweep Phase
if (tId == 0)
HIST_SMEM_NO_BANK_CONFLICT(255) = 0;
for (int delta = 128; delta >= 1; delta /= 2)
{
if (tId < 128 / delta)
{
int rootIdx = 255 - tId * delta * 2;
int leftIdx = rootIdx - delta;
int tmp = HIST_SMEM_NO_BANK_CONFLICT(leftIdx);
HIST_SMEM_NO_BANK_CONFLICT(leftIdx) = HIST_SMEM_NO_BANK_CONFLICT(rootIdx);
HIST_SMEM_NO_BANK_CONFLICT(rootIdx) += tmp;
}
__syncthreads();
}
// Step2 Phase3 - Convert exclusive sum to inclusive sum
int tmp = HIST_SMEM_NO_BANK_CONFLICT(tId);
__syncthreads();
if (tId >= 1)
HIST_SMEM_NO_BANK_CONFLICT(tId - 1) = tmp;
if (tId == 255)
HIST_SMEM_NO_BANK_CONFLICT(tId) = tmp + hist[tId];
__syncthreads();
// Step3 - Scale values to build lut
lut[tId] = saturate_cast<unsigned char>(HIST_SMEM_NO_BANK_CONFLICT(tId) * (255.0f / (size - minNonZeroVal)));
#undef HIST_SMEM_NO_BANK_CONFLICT
}
void buildLut(PtrStepSzi hist, PtrStepSzb lut, int size, cudaStream_t stream)
{
buildLutKernel<<<1, 256, 0, stream>>>(hist.data, lut.data, size);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
}
#endif /* CUDA_DISABLER */
@@ -0,0 +1,250 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/emulation.hpp"
#include "opencv2/core/cuda/dynamic_smem.hpp"
#include "opencv2/opencv_modules.hpp"
#ifdef HAVE_OPENCV_CUDAFILTERS
namespace cv { namespace cuda { namespace device
{
namespace hough_circles
{
////////////////////////////////////////////////////////////////////////
// circlesAccumCenters
__global__ void circlesAccumCenters(const unsigned int* list, const int count, const PtrStepi dx, const PtrStepi dy,
PtrStepi accum, const int width, const int height, const int minRadius, const int maxRadius, const float idp)
{
const int SHIFT = 10;
const int ONE = 1 << SHIFT;
const int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid >= count)
return;
const unsigned int val = list[tid];
const int x = (val & 0xFFFF);
const int y = (val >> 16) & 0xFFFF;
const int vx = dx(y, x);
const int vy = dy(y, x);
if (vx == 0 && vy == 0)
return;
const float mag = ::sqrtf(vx * vx + vy * vy);
const int x0 = __float2int_rn((x * idp) * ONE);
const int y0 = __float2int_rn((y * idp) * ONE);
int sx = __float2int_rn((vx * idp) * ONE / mag);
int sy = __float2int_rn((vy * idp) * ONE / mag);
// Step from minRadius to maxRadius in both directions of the gradient
for (int k1 = 0; k1 < 2; ++k1)
{
int x1 = x0 + minRadius * sx;
int y1 = y0 + minRadius * sy;
for (int r = minRadius; r <= maxRadius; x1 += sx, y1 += sy, ++r)
{
const int x2 = x1 >> SHIFT;
const int y2 = y1 >> SHIFT;
if (x2 < 0 || x2 >= width || y2 < 0 || y2 >= height)
break;
::atomicAdd(accum.ptr(y2 + 1) + x2 + 1, 1);
}
sx = -sx;
sy = -sy;
}
}
void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, PtrStepSzi accum, int minRadius, int maxRadius, float idp, cudaStream_t stream)
{
const dim3 block(256);
const dim3 grid(divUp(count, block.x));
cudaSafeCall( cudaFuncSetCacheConfig(circlesAccumCenters, cudaFuncCachePreferL1) );
circlesAccumCenters<<<grid, block, 0, stream>>>(list, count, dx, dy, accum, accum.cols - 2, accum.rows - 2, minRadius, maxRadius, idp);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaStreamSynchronize(stream) );
}
////////////////////////////////////////////////////////////////////////
// buildCentersList
__global__ void buildCentersList(const PtrStepSzi accum, unsigned int* centers, const int threshold, int* counterPtr)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < accum.cols - 2 && y < accum.rows - 2)
{
const int top = accum(y, x + 1);
const int left = accum(y + 1, x);
const int cur = accum(y + 1, x + 1);
const int right = accum(y + 1, x + 2);
const int bottom = accum(y + 2, x + 1);
if (cur > threshold && cur > top && cur >= bottom && cur > left && cur >= right)
{
const unsigned int val = (y << 16) | x;
const int idx = ::atomicAdd(counterPtr, 1);
centers[idx] = val;
}
}
}
int buildCentersList_gpu(PtrStepSzi accum, unsigned int* centers, int threshold, int* counterPtr, cudaStream_t stream)
{
cudaSafeCall( cudaMemsetAsync(counterPtr, 0, sizeof(int), stream) );
const dim3 block(32, 8);
const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y));
cudaSafeCall( cudaFuncSetCacheConfig(buildCentersList, cudaFuncCachePreferL1) );
buildCentersList<<<grid, block, 0, stream>>>(accum, centers, threshold, counterPtr);
cudaSafeCall( cudaGetLastError() );
int totalCount;
cudaSafeCall( cudaMemcpyAsync(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost, stream) );
cudaSafeCall( cudaStreamSynchronize(stream) );
return totalCount;
}
////////////////////////////////////////////////////////////////////////
// circlesAccumRadius
__global__ void circlesAccumRadius(const unsigned int* centers, const unsigned int* list, const int count,
float3* circles, const int maxCircles, const float dp,
const int minRadius, const int maxRadius, const int histSize, const int threshold,
int* counterPtr)
{
int* smem = DynamicSharedMem<int>();
for (int i = threadIdx.x; i < histSize + 2; i += blockDim.x)
smem[i] = 0;
__syncthreads();
unsigned int val = centers[blockIdx.x];
float cx = (val & 0xFFFF);
float cy = (val >> 16) & 0xFFFF;
cx = (cx + 0.5f) * dp;
cy = (cy + 0.5f) * dp;
for (int i = threadIdx.x; i < count; i += blockDim.x)
{
val = list[i];
const int x = (val & 0xFFFF);
const int y = (val >> 16) & 0xFFFF;
const float rad = ::sqrtf((cx - x) * (cx - x) + (cy - y) * (cy - y));
if (rad >= minRadius && rad <= maxRadius)
{
const int r = __float2int_rn(rad - minRadius);
Emulation::smem::atomicAdd(&smem[r + 1], 1);
}
}
__syncthreads();
for (int i = threadIdx.x; i < histSize; i += blockDim.x)
{
const int curVotes = smem[i + 1];
if (curVotes >= threshold && curVotes > smem[i] && curVotes >= smem[i + 2])
{
const int ind = ::atomicAdd(counterPtr, 1);
if (ind < maxCircles)
circles[ind] = make_float3(cx, cy, i + minRadius);
}
}
}
int circlesAccumRadius_gpu(const unsigned int* centers, int centersCount, const unsigned int* list, int count,
float3* circles, int maxCircles, float dp, int minRadius, int maxRadius, int threshold, bool has20, int* counterPtr, cudaStream_t stream)
{
cudaSafeCall( cudaMemsetAsync(counterPtr, 0, sizeof(int), stream) );
const dim3 block(has20 ? 1024 : 512);
const dim3 grid(centersCount);
const int histSize = maxRadius - minRadius + 1;
size_t smemSize = (histSize + 2) * sizeof(int);
circlesAccumRadius<<<grid, block, smemSize, stream>>>(centers, list, count, circles, maxCircles, dp, minRadius, maxRadius, histSize, threshold, counterPtr);
cudaSafeCall( cudaGetLastError() );
int totalCount;
cudaSafeCall( cudaMemcpyAsync(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost, stream) );
cudaSafeCall( cudaStreamSynchronize(stream) );
totalCount = std::min(totalCount, maxCircles);
return totalCount;
}
}
}}}
#endif // HAVE_OPENCV_CUDAFILTERS
#endif /* CUDA_DISABLER */
+207
View File
@@ -0,0 +1,207 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include <thrust/device_ptr.h>
#include <thrust/sort.h>
#include <thrust/system/cuda/execution_policy.h>
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/emulation.hpp"
#include "opencv2/core/cuda/dynamic_smem.hpp"
namespace cv { namespace cuda { namespace device
{
namespace hough_lines
{
////////////////////////////////////////////////////////////////////////
// linesAccum
__global__ void linesAccumGlobal(const unsigned int* list, const int count, PtrStepi accum, const float irho, const float theta, const int numrho)
{
const int n = blockIdx.x;
const float ang = n * theta;
float sinVal;
float cosVal;
sincosf(ang, &sinVal, &cosVal);
sinVal *= irho;
cosVal *= irho;
const int shift = (numrho - 1) / 2;
int* accumRow = accum.ptr(n + 1);
for (int i = threadIdx.x; i < count; i += blockDim.x)
{
const unsigned int val = list[i];
const int x = (val & 0xFFFF);
const int y = (val >> 16) & 0xFFFF;
int r = __float2int_rn(x * cosVal + y * sinVal);
r += shift;
::atomicAdd(accumRow + r + 1, 1);
}
}
__global__ void linesAccumShared(const unsigned int* list, const int count, PtrStepi accum, const float irho, const float theta, const int numrho)
{
int* smem = DynamicSharedMem<int>();
for (int i = threadIdx.x; i < numrho + 1; i += blockDim.x)
smem[i] = 0;
__syncthreads();
const int n = blockIdx.x;
const float ang = n * theta;
float sinVal;
float cosVal;
sincosf(ang, &sinVal, &cosVal);
sinVal *= irho;
cosVal *= irho;
const int shift = (numrho - 1) / 2;
for (int i = threadIdx.x; i < count; i += blockDim.x)
{
const unsigned int val = list[i];
const int x = (val & 0xFFFF);
const int y = (val >> 16) & 0xFFFF;
int r = __float2int_rn(x * cosVal + y * sinVal);
r += shift;
Emulation::smem::atomicAdd(&smem[r + 1], 1);
}
__syncthreads();
int* accumRow = accum.ptr(n + 1);
for (int i = threadIdx.x; i < numrho + 1; i += blockDim.x)
accumRow[i] = smem[i];
}
void linesAccum_gpu(const unsigned int* list, int count, PtrStepSzi accum, float rho, float theta, size_t sharedMemPerBlock, bool has20, cudaStream_t stream)
{
const dim3 block(has20 ? 1024 : 512);
const dim3 grid(accum.rows - 2);
size_t smemSize = (accum.cols - 1) * sizeof(int);
if (smemSize < sharedMemPerBlock - 1000)
linesAccumShared<<<grid, block, smemSize, stream>>>(list, count, accum, 1.0f / rho, theta, accum.cols - 2);
else
linesAccumGlobal<<<grid, block, 0, stream>>>(list, count, accum, 1.0f / rho, theta, accum.cols - 2);
cudaSafeCall( cudaGetLastError() );
cudaSafeCall( cudaStreamSynchronize(stream) );
}
////////////////////////////////////////////////////////////////////////
// linesGetResult
__global__ void linesGetResult(const PtrStepSzi accum, float2* out, int* votes, const int maxSize, const float rho, const float theta, const int threshold, const int numrho, int* counterPtr)
{
const int r = blockIdx.x * blockDim.x + threadIdx.x;
const int n = blockIdx.y * blockDim.y + threadIdx.y;
if (r >= accum.cols - 2 || n >= accum.rows - 2)
return;
const int curVotes = accum(n + 1, r + 1);
if (curVotes > threshold &&
curVotes > accum(n + 1, r) &&
curVotes >= accum(n + 1, r + 2) &&
curVotes > accum(n, r + 1) &&
curVotes >= accum(n + 2, r + 1))
{
const float radius = (r - (numrho - 1) * 0.5f) * rho;
const float angle = n * theta;
const int ind = ::atomicAdd(counterPtr, 1);
if (ind < maxSize)
{
out[ind] = make_float2(radius, angle);
votes[ind] = curVotes;
}
}
}
int linesGetResult_gpu(PtrStepSzi accum, float2* out, int* votes, int maxSize, float rho, float theta, int threshold, bool doSort, int* counterPtr, cudaStream_t stream)
{
cudaSafeCall( cudaMemsetAsync(counterPtr, 0, sizeof(int), stream) );
const dim3 block(32, 8);
const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y));
cudaSafeCall( cudaFuncSetCacheConfig(linesGetResult, cudaFuncCachePreferL1) );
linesGetResult<<<grid, block, 0, stream>>>(accum, out, votes, maxSize, rho, theta, threshold, accum.cols - 2, counterPtr);
cudaSafeCall( cudaGetLastError() );
int totalCount;
cudaSafeCall( cudaMemcpyAsync(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost, stream) );
cudaSafeCall( cudaStreamSynchronize(stream) );
totalCount = std::min(totalCount, maxSize);
if (doSort && totalCount > 0)
{
thrust::device_ptr<float2> outPtr(out);
thrust::device_ptr<int> votesPtr(votes);
thrust::sort_by_key(thrust::cuda::par.on(stream), votesPtr, votesPtr + totalCount, outPtr, thrust::greater<int>());
}
return totalCount;
}
}
}}}
#endif /* CUDA_DISABLER */
@@ -0,0 +1,251 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/vec_math.hpp"
#include "opencv2/cudev.hpp"
namespace cv { namespace cuda { namespace device
{
namespace hough_segments
{
template<class Ptr2D>
__global__ void houghLinesProbabilistic(Ptr2D src, const PtrStepSzi accum,
int4* out, const int maxSize,
const float rho, const float theta,
const int lineGap, const int lineLength,
const int threshold,
const int rows, const int cols,
int* counterPtr)
{
const int r = blockIdx.x * blockDim.x + threadIdx.x;
const int n = blockIdx.y * blockDim.y + threadIdx.y;
if (r >= accum.cols - 2 || n >= accum.rows - 2)
return;
const int curVotes = accum(n + 1, r + 1);
const int threshold_ = (threshold > 0) ? threshold : lineLength;
if (curVotes >= threshold_ &&
curVotes > accum(n, r) &&
curVotes > accum(n, r + 1) &&
curVotes > accum(n, r + 2) &&
curVotes > accum(n + 1, r) &&
curVotes > accum(n + 1, r + 2) &&
curVotes > accum(n + 2, r) &&
curVotes > accum(n + 2, r + 1) &&
curVotes > accum(n + 2, r + 2))
{
const float radius = (r - (accum.cols - 2 - 1) * 0.5f) * rho;
const float angle = n * theta;
float cosa;
float sina;
sincosf(angle, &sina, &cosa);
float2 p0 = make_float2(cosa * radius, sina * radius);
float2 dir = make_float2(-sina, cosa);
float2 pb[4] = {make_float2(-1, -1), make_float2(-1, -1), make_float2(-1, -1), make_float2(-1, -1)};
float a;
if (dir.x != 0)
{
a = -p0.x / dir.x;
pb[0].x = 0;
pb[0].y = p0.y + a * dir.y;
a = (cols - 1 - p0.x) / dir.x;
pb[1].x = cols - 1;
pb[1].y = p0.y + a * dir.y;
}
if (dir.y != 0)
{
a = -p0.y / dir.y;
pb[2].x = p0.x + a * dir.x;
pb[2].y = 0;
a = (rows - 1 - p0.y) / dir.y;
pb[3].x = p0.x + a * dir.x;
pb[3].y = rows - 1;
}
if (pb[0].x == 0 && (pb[0].y >= 0 && pb[0].y < rows))
{
p0 = pb[0];
if (dir.x < 0)
dir = -dir;
}
else if (pb[1].x == cols - 1 && (pb[1].y >= 0 && pb[1].y < rows))
{
p0 = pb[1];
if (dir.x > 0)
dir = -dir;
}
else if (pb[2].y == 0 && (pb[2].x >= 0 && pb[2].x < cols))
{
p0 = pb[2];
if (dir.y < 0)
dir = -dir;
}
else if (pb[3].y == rows - 1 && (pb[3].x >= 0 && pb[3].x < cols))
{
p0 = pb[3];
if (dir.y > 0)
dir = -dir;
}
float2 d;
if (::fabsf(dir.x) > ::fabsf(dir.y))
{
d.x = dir.x > 0 ? 1 : -1;
d.y = dir.y / ::fabsf(dir.x);
}
else
{
d.x = dir.x / ::fabsf(dir.y);
d.y = dir.y > 0 ? 1 : -1;
}
float2 line_end[2];
int gap;
bool inLine = false;
float2 p1 = p0;
if (p1.x < 0 || p1.x >= cols || p1.y < 0 || p1.y >= rows)
return;
for (;;)
{
if (src(p1.y, p1.x))
{
gap = 0;
if (!inLine)
{
line_end[0] = p1;
line_end[1] = p1;
inLine = true;
}
else
{
line_end[1] = p1;
}
}
else if (inLine)
{
if (++gap > lineGap)
{
bool good_line = ::abs(line_end[1].x - line_end[0].x) >= lineLength ||
::abs(line_end[1].y - line_end[0].y) >= lineLength;
if (good_line)
{
const int ind = ::atomicAdd(counterPtr, 1);
if (ind < maxSize)
out[ind] = make_int4(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y);
}
gap = 0;
inLine = false;
}
}
p1 = p1 + d;
if (p1.x < 0 || p1.x >= cols || p1.y < 0 || p1.y >= rows)
{
if (inLine)
{
bool good_line = ::abs(line_end[1].x - line_end[0].x) >= lineLength ||
::abs(line_end[1].y - line_end[0].y) >= lineLength;
if (good_line)
{
const int ind = ::atomicAdd(counterPtr, 1);
if (ind < maxSize)
out[ind] = make_int4(line_end[0].x, line_end[0].y, line_end[1].x, line_end[1].y);
}
}
break;
}
}
}
}
int houghLinesProbabilistic_gpu(GpuMat &mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength, int threshold, int* counterPtr, cudaStream_t stream)
{
cudaSafeCall( cudaMemsetAsync(counterPtr, 0, sizeof(int), stream) );
const dim3 block(32, 8);
const dim3 grid(divUp(accum.cols - 2, block.x), divUp(accum.rows - 2, block.y));
Size wholeSize;
Point ofs;
mask.locateROI(wholeSize, ofs);
if (ofs.x || ofs.y) {
cv::cudev::TextureOff<uchar> texMask(wholeSize.height, wholeSize.width, mask.datastart, mask.step, ofs.y, ofs.x);
houghLinesProbabilistic<cv::cudev::TextureOffPtr<uchar>><<<grid, block, 0, stream>>>(texMask, accum, out, maxSize, rho, theta, lineGap, lineLength, threshold, mask.rows, mask.cols, counterPtr);
}
else {
cv::cudev::Texture<uchar> texMask(mask);
houghLinesProbabilistic<cv::cudev::TexturePtr<uchar>><<<grid, block, 0, stream>>>(texMask, accum, out, maxSize, rho, theta, lineGap, lineLength, threshold, mask.rows, mask.cols, counterPtr);
}
cudaSafeCall( cudaGetLastError() );
int totalCount;
cudaSafeCall( cudaMemcpyAsync(&totalCount, counterPtr, sizeof(int), cudaMemcpyDeviceToHost, stream) );
cudaSafeCall( cudaStreamSynchronize(stream) );
totalCount = std::min(totalCount, maxSize);
return totalCount;
}
}
}}}
#endif /* CUDA_DISABLER */
@@ -0,0 +1,916 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/vec_math.hpp"
namespace cv { namespace cuda { namespace device
{
namespace match_template
{
__device__ __forceinline__ float sum(float v) { return v; }
__device__ __forceinline__ float sum(float2 v) { return v.x + v.y; }
__device__ __forceinline__ float sum(float3 v) { return v.x + v.y + v.z; }
__device__ __forceinline__ float sum(float4 v) { return v.x + v.y + v.z + v.w; }
__device__ __forceinline__ float first(float v) { return v; }
__device__ __forceinline__ float first(float2 v) { return v.x; }
__device__ __forceinline__ float first(float3 v) { return v.x; }
__device__ __forceinline__ float first(float4 v) { return v.x; }
__device__ __forceinline__ float mul(float a, float b) { return a * b; }
__device__ __forceinline__ float2 mul(float2 a, float2 b) { return make_float2(a.x * b.x, a.y * b.y); }
__device__ __forceinline__ float3 mul(float3 a, float3 b) { return make_float3(a.x * b.x, a.y * b.y, a.z * b.z); }
__device__ __forceinline__ float4 mul(float4 a, float4 b) { return make_float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); }
__device__ __forceinline__ float mul(uchar a, uchar b) { return a * b; }
__device__ __forceinline__ float2 mul(uchar2 a, uchar2 b) { return make_float2(a.x * b.x, a.y * b.y); }
__device__ __forceinline__ float3 mul(uchar3 a, uchar3 b) { return make_float3(a.x * b.x, a.y * b.y, a.z * b.z); }
__device__ __forceinline__ float4 mul(uchar4 a, uchar4 b) { return make_float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); }
__device__ __forceinline__ float sub(float a, float b) { return a - b; }
__device__ __forceinline__ float2 sub(float2 a, float2 b) { return make_float2(a.x - b.x, a.y - b.y); }
__device__ __forceinline__ float3 sub(float3 a, float3 b) { return make_float3(a.x - b.x, a.y - b.y, a.z - b.z); }
__device__ __forceinline__ float4 sub(float4 a, float4 b) { return make_float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); }
__device__ __forceinline__ float sub(uchar a, uchar b) { return a - b; }
__device__ __forceinline__ float2 sub(uchar2 a, uchar2 b) { return make_float2(a.x - b.x, a.y - b.y); }
__device__ __forceinline__ float3 sub(uchar3 a, uchar3 b) { return make_float3(a.x - b.x, a.y - b.y, a.z - b.z); }
__device__ __forceinline__ float4 sub(uchar4 a, uchar4 b) { return make_float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); }
//////////////////////////////////////////////////////////////////////
// Naive_CCORR
template <typename T, int cn>
__global__ void matchTemplateNaiveKernel_CCORR(int w, int h, const PtrStepb image, const PtrStepb templ, PtrStepSzf result)
{
typedef typename TypeVec<T, cn>::vec_type Type;
typedef typename TypeVec<float, cn>::vec_type Typef;
int x = blockDim.x * blockIdx.x + threadIdx.x;
int y = blockDim.y * blockIdx.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
Typef res = VecTraits<Typef>::all(0);
for (int i = 0; i < h; ++i)
{
const Type* image_ptr = (const Type*)image.ptr(y + i);
const Type* templ_ptr = (const Type*)templ.ptr(i);
for (int j = 0; j < w; ++j)
res = res + mul(image_ptr[x + j], templ_ptr[j]);
}
result.ptr(y)[x] = sum(res);
}
}
template <typename T, int cn>
void matchTemplateNaive_CCORR(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, cudaStream_t stream)
{
const dim3 threads(32, 8);
const dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
matchTemplateNaiveKernel_CCORR<T, cn><<<grid, threads, 0, stream>>>(templ.cols, templ.rows, image, templ, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
void matchTemplateNaive_CCORR_32F(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, int cn, cudaStream_t stream)
{
typedef void (*caller_t)(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, cudaStream_t stream);
static const caller_t callers[] =
{
0, matchTemplateNaive_CCORR<float, 1>, matchTemplateNaive_CCORR<float, 2>, matchTemplateNaive_CCORR<float, 3>, matchTemplateNaive_CCORR<float, 4>
};
callers[cn](image, templ, result, stream);
}
void matchTemplateNaive_CCORR_8U(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, int cn, cudaStream_t stream)
{
typedef void (*caller_t)(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, cudaStream_t stream);
static const caller_t callers[] =
{
0, matchTemplateNaive_CCORR<uchar, 1>, matchTemplateNaive_CCORR<uchar, 2>, matchTemplateNaive_CCORR<uchar, 3>, matchTemplateNaive_CCORR<uchar, 4>
};
callers[cn](image, templ, result, stream);
}
//////////////////////////////////////////////////////////////////////
// Naive_SQDIFF
template <typename T, int cn>
__global__ void matchTemplateNaiveKernel_SQDIFF(int w, int h, const PtrStepb image, const PtrStepb templ, PtrStepSzf result)
{
typedef typename TypeVec<T, cn>::vec_type Type;
typedef typename TypeVec<float, cn>::vec_type Typef;
int x = blockDim.x * blockIdx.x + threadIdx.x;
int y = blockDim.y * blockIdx.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
Typef res = VecTraits<Typef>::all(0);
Typef delta;
for (int i = 0; i < h; ++i)
{
const Type* image_ptr = (const Type*)image.ptr(y + i);
const Type* templ_ptr = (const Type*)templ.ptr(i);
for (int j = 0; j < w; ++j)
{
delta = sub(image_ptr[x + j], templ_ptr[j]);
res = res + delta * delta;
}
}
result.ptr(y)[x] = sum(res);
}
}
template <typename T, int cn>
void matchTemplateNaive_SQDIFF(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, cudaStream_t stream)
{
const dim3 threads(32, 8);
const dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
matchTemplateNaiveKernel_SQDIFF<T, cn><<<grid, threads, 0, stream>>>(templ.cols, templ.rows, image, templ, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
void matchTemplateNaive_SQDIFF_32F(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, int cn, cudaStream_t stream)
{
typedef void (*caller_t)(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, cudaStream_t stream);
static const caller_t callers[] =
{
0, matchTemplateNaive_SQDIFF<float, 1>, matchTemplateNaive_SQDIFF<float, 2>, matchTemplateNaive_SQDIFF<float, 3>, matchTemplateNaive_SQDIFF<float, 4>
};
callers[cn](image, templ, result, stream);
}
void matchTemplateNaive_SQDIFF_8U(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, int cn, cudaStream_t stream)
{
typedef void (*caller_t)(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, cudaStream_t stream);
static const caller_t callers[] =
{
0, matchTemplateNaive_SQDIFF<uchar, 1>, matchTemplateNaive_SQDIFF<uchar, 2>, matchTemplateNaive_SQDIFF<uchar, 3>, matchTemplateNaive_SQDIFF<uchar, 4>
};
callers[cn](image, templ, result, stream);
}
//////////////////////////////////////////////////////////////////////
// Prepared_SQDIFF
template <int cn>
__global__ void matchTemplatePreparedKernel_SQDIFF_8U(int w, int h, const PtrStep<double> image_sqsum, double templ_sqsum, PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sqsum_ = (float)(
(image_sqsum.ptr(y + h)[(x + w) * cn] - image_sqsum.ptr(y)[(x + w) * cn]) -
(image_sqsum.ptr(y + h)[x * cn] - image_sqsum.ptr(y)[x * cn]));
float ccorr = result.ptr(y)[x];
result.ptr(y)[x] = image_sqsum_ - 2.f * ccorr + templ_sqsum;
}
}
template <int cn>
void matchTemplatePrepared_SQDIFF_8U(int w, int h, const PtrStepSz<double> image_sqsum, double templ_sqsum, PtrStepSzf result, cudaStream_t stream)
{
const dim3 threads(32, 8);
const dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
matchTemplatePreparedKernel_SQDIFF_8U<cn><<<grid, threads, 0, stream>>>(w, h, image_sqsum, templ_sqsum, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
void matchTemplatePrepared_SQDIFF_8U(int w, int h, const PtrStepSz<double> image_sqsum, double templ_sqsum, PtrStepSzf result, int cn,
cudaStream_t stream)
{
typedef void (*caller_t)(int w, int h, const PtrStepSz<double> image_sqsum, double templ_sqsum, PtrStepSzf result, cudaStream_t stream);
static const caller_t callers[] =
{
0, matchTemplatePrepared_SQDIFF_8U<1>, matchTemplatePrepared_SQDIFF_8U<2>, matchTemplatePrepared_SQDIFF_8U<3>, matchTemplatePrepared_SQDIFF_8U<4>
};
callers[cn](w, h, image_sqsum, templ_sqsum, result, stream);
}
//////////////////////////////////////////////////////////////////////
// Prepared_SQDIFF_NORMED
// normAcc* are accurate normalization routines which make CUDA matchTemplate
// consistent with CPU one
__device__ float normAcc(float num, float denum)
{
if (::fabs(num) < denum)
return num / denum;
if (::fabs(num) < denum * 1.125f)
return num > 0 ? 1 : -1;
return 0;
}
__device__ float normAcc_SQDIFF(float num, float denum)
{
if (::fabs(num) < denum)
return num / denum;
if (::fabs(num) < denum * 1.125f)
return num > 0 ? 1 : -1;
return 1;
}
template <int cn>
__global__ void matchTemplatePreparedKernel_SQDIFF_NORMED_8U(
int w, int h, const PtrStep<double> image_sqsum,
double templ_sqsum, PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sqsum_ = (float)(
(image_sqsum.ptr(y + h)[(x + w) * cn] - image_sqsum.ptr(y)[(x + w) * cn]) -
(image_sqsum.ptr(y + h)[x * cn] - image_sqsum.ptr(y)[x * cn]));
float ccorr = result.ptr(y)[x];
result.ptr(y)[x] = normAcc_SQDIFF(image_sqsum_ - 2.f * ccorr + templ_sqsum,
sqrtf(image_sqsum_ * templ_sqsum));
}
}
template <int cn>
void matchTemplatePrepared_SQDIFF_NORMED_8U(int w, int h, const PtrStepSz<double> image_sqsum, double templ_sqsum,
PtrStepSzf result, cudaStream_t stream)
{
const dim3 threads(32, 8);
const dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
matchTemplatePreparedKernel_SQDIFF_NORMED_8U<cn><<<grid, threads, 0, stream>>>(w, h, image_sqsum, templ_sqsum, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
void matchTemplatePrepared_SQDIFF_NORMED_8U(int w, int h, const PtrStepSz<double> image_sqsum, double templ_sqsum,
PtrStepSzf result, int cn, cudaStream_t stream)
{
typedef void (*caller_t)(int w, int h, const PtrStepSz<double> image_sqsum, double templ_sqsum, PtrStepSzf result, cudaStream_t stream);
static const caller_t callers[] =
{
0, matchTemplatePrepared_SQDIFF_NORMED_8U<1>, matchTemplatePrepared_SQDIFF_NORMED_8U<2>, matchTemplatePrepared_SQDIFF_NORMED_8U<3>, matchTemplatePrepared_SQDIFF_NORMED_8U<4>
};
callers[cn](w, h, image_sqsum, templ_sqsum, result, stream);
}
//////////////////////////////////////////////////////////////////////
// Prepared_CCOFF
__global__ void matchTemplatePreparedKernel_CCOFF_8U(int w, int h, float templ_sum_scale, const PtrStep<int> image_sum, PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sum_ = (float)(
(image_sum.ptr(y + h)[x + w] - image_sum.ptr(y)[x + w]) -
(image_sum.ptr(y + h)[x] - image_sum.ptr(y)[x]));
float ccorr = result.ptr(y)[x];
result.ptr(y)[x] = ccorr - image_sum_ * templ_sum_scale;
}
}
void matchTemplatePrepared_CCOFF_8U(int w, int h, const PtrStepSz<int> image_sum, int templ_sum, PtrStepSzf result, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
matchTemplatePreparedKernel_CCOFF_8U<<<grid, threads, 0, stream>>>(w, h, (float)templ_sum / (w * h), image_sum, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void matchTemplatePreparedKernel_CCOFF_8UC2(
int w, int h, float templ_sum_scale_r, float templ_sum_scale_g,
const PtrStep<int> image_sum_r,
const PtrStep<int> image_sum_g,
PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sum_r_ = (float)(
(image_sum_r.ptr(y + h)[x + w] - image_sum_r.ptr(y)[x + w]) -
(image_sum_r.ptr(y + h)[x] - image_sum_r.ptr(y)[x]));
float image_sum_g_ = (float)(
(image_sum_g.ptr(y + h)[x + w] - image_sum_g.ptr(y)[x + w]) -
(image_sum_g.ptr(y + h)[x] - image_sum_g.ptr(y)[x]));
float ccorr = result.ptr(y)[x];
result.ptr(y)[x] = ccorr - image_sum_r_ * templ_sum_scale_r
- image_sum_g_ * templ_sum_scale_g;
}
}
void matchTemplatePrepared_CCOFF_8UC2(
int w, int h,
const PtrStepSz<int> image_sum_r,
const PtrStepSz<int> image_sum_g,
int templ_sum_r, int templ_sum_g,
PtrStepSzf result, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
matchTemplatePreparedKernel_CCOFF_8UC2<<<grid, threads, 0, stream>>>(
w, h, (float)templ_sum_r / (w * h), (float)templ_sum_g / (w * h),
image_sum_r, image_sum_g, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void matchTemplatePreparedKernel_CCOFF_8UC3(
int w, int h,
float templ_sum_scale_r,
float templ_sum_scale_g,
float templ_sum_scale_b,
const PtrStep<int> image_sum_r,
const PtrStep<int> image_sum_g,
const PtrStep<int> image_sum_b,
PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sum_r_ = (float)(
(image_sum_r.ptr(y + h)[x + w] - image_sum_r.ptr(y)[x + w]) -
(image_sum_r.ptr(y + h)[x] - image_sum_r.ptr(y)[x]));
float image_sum_g_ = (float)(
(image_sum_g.ptr(y + h)[x + w] - image_sum_g.ptr(y)[x + w]) -
(image_sum_g.ptr(y + h)[x] - image_sum_g.ptr(y)[x]));
float image_sum_b_ = (float)(
(image_sum_b.ptr(y + h)[x + w] - image_sum_b.ptr(y)[x + w]) -
(image_sum_b.ptr(y + h)[x] - image_sum_b.ptr(y)[x]));
float ccorr = result.ptr(y)[x];
result.ptr(y)[x] = ccorr - image_sum_r_ * templ_sum_scale_r
- image_sum_g_ * templ_sum_scale_g
- image_sum_b_ * templ_sum_scale_b;
}
}
void matchTemplatePrepared_CCOFF_8UC3(
int w, int h,
const PtrStepSz<int> image_sum_r,
const PtrStepSz<int> image_sum_g,
const PtrStepSz<int> image_sum_b,
int templ_sum_r,
int templ_sum_g,
int templ_sum_b,
PtrStepSzf result, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
matchTemplatePreparedKernel_CCOFF_8UC3<<<grid, threads, 0, stream>>>(
w, h,
(float)templ_sum_r / (w * h),
(float)templ_sum_g / (w * h),
(float)templ_sum_b / (w * h),
image_sum_r, image_sum_g, image_sum_b, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void matchTemplatePreparedKernel_CCOFF_8UC4(
int w, int h,
float templ_sum_scale_r,
float templ_sum_scale_g,
float templ_sum_scale_b,
float templ_sum_scale_a,
const PtrStep<int> image_sum_r,
const PtrStep<int> image_sum_g,
const PtrStep<int> image_sum_b,
const PtrStep<int> image_sum_a,
PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sum_r_ = (float)(
(image_sum_r.ptr(y + h)[x + w] - image_sum_r.ptr(y)[x + w]) -
(image_sum_r.ptr(y + h)[x] - image_sum_r.ptr(y)[x]));
float image_sum_g_ = (float)(
(image_sum_g.ptr(y + h)[x + w] - image_sum_g.ptr(y)[x + w]) -
(image_sum_g.ptr(y + h)[x] - image_sum_g.ptr(y)[x]));
float image_sum_b_ = (float)(
(image_sum_b.ptr(y + h)[x + w] - image_sum_b.ptr(y)[x + w]) -
(image_sum_b.ptr(y + h)[x] - image_sum_b.ptr(y)[x]));
float image_sum_a_ = (float)(
(image_sum_a.ptr(y + h)[x + w] - image_sum_a.ptr(y)[x + w]) -
(image_sum_a.ptr(y + h)[x] - image_sum_a.ptr(y)[x]));
float ccorr = result.ptr(y)[x];
result.ptr(y)[x] = ccorr - image_sum_r_ * templ_sum_scale_r
- image_sum_g_ * templ_sum_scale_g
- image_sum_b_ * templ_sum_scale_b
- image_sum_a_ * templ_sum_scale_a;
}
}
void matchTemplatePrepared_CCOFF_8UC4(
int w, int h,
const PtrStepSz<int> image_sum_r,
const PtrStepSz<int> image_sum_g,
const PtrStepSz<int> image_sum_b,
const PtrStepSz<int> image_sum_a,
int templ_sum_r,
int templ_sum_g,
int templ_sum_b,
int templ_sum_a,
PtrStepSzf result, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
matchTemplatePreparedKernel_CCOFF_8UC4<<<grid, threads, 0, stream>>>(
w, h,
(float)templ_sum_r / (w * h),
(float)templ_sum_g / (w * h),
(float)templ_sum_b / (w * h),
(float)templ_sum_a / (w * h),
image_sum_r, image_sum_g, image_sum_b, image_sum_a,
result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
//////////////////////////////////////////////////////////////////////
// Prepared_CCOFF_NORMED
__global__ void matchTemplatePreparedKernel_CCOFF_NORMED_8U(
int w, int h, float weight,
float templ_sum_scale, float templ_sqsum_scale,
const PtrStep<int> image_sum,
const PtrStep<double> image_sqsum,
PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float ccorr = result.ptr(y)[x];
float image_sum_ = (float)(
(image_sum.ptr(y + h)[x + w] - image_sum.ptr(y)[x + w]) -
(image_sum.ptr(y + h)[x] - image_sum.ptr(y)[x]));
float image_sqsum_ = (float)(
(image_sqsum.ptr(y + h)[x + w] - image_sqsum.ptr(y)[x + w]) -
(image_sqsum.ptr(y + h)[x] - image_sqsum.ptr(y)[x]));
result.ptr(y)[x] = normAcc(ccorr - image_sum_ * templ_sum_scale,
sqrtf(templ_sqsum_scale * (image_sqsum_ - weight * image_sum_ * image_sum_)));
}
}
void matchTemplatePrepared_CCOFF_NORMED_8U(
int w, int h, const PtrStepSz<int> image_sum,
const PtrStepSz<double> image_sqsum,
int templ_sum, double templ_sqsum,
PtrStepSzf result, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
float weight = 1.f / (w * h);
float templ_sum_scale = templ_sum * weight;
float templ_sqsum_scale = templ_sqsum - weight * templ_sum * templ_sum;
matchTemplatePreparedKernel_CCOFF_NORMED_8U<<<grid, threads, 0, stream>>>(
w, h, weight, templ_sum_scale, templ_sqsum_scale,
image_sum, image_sqsum, result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void matchTemplatePreparedKernel_CCOFF_NORMED_8UC2(
int w, int h, float weight,
float templ_sum_scale_r, float templ_sum_scale_g,
float templ_sqsum_scale,
const PtrStep<int> image_sum_r, const PtrStep<double> image_sqsum_r,
const PtrStep<int> image_sum_g, const PtrStep<double> image_sqsum_g,
PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sum_r_ = (float)(
(image_sum_r.ptr(y + h)[x + w] - image_sum_r.ptr(y)[x + w]) -
(image_sum_r.ptr(y + h)[x] - image_sum_r.ptr(y)[x]));
float image_sqsum_r_ = (float)(
(image_sqsum_r.ptr(y + h)[x + w] - image_sqsum_r.ptr(y)[x + w]) -
(image_sqsum_r.ptr(y + h)[x] - image_sqsum_r.ptr(y)[x]));
float image_sum_g_ = (float)(
(image_sum_g.ptr(y + h)[x + w] - image_sum_g.ptr(y)[x + w]) -
(image_sum_g.ptr(y + h)[x] - image_sum_g.ptr(y)[x]));
float image_sqsum_g_ = (float)(
(image_sqsum_g.ptr(y + h)[x + w] - image_sqsum_g.ptr(y)[x + w]) -
(image_sqsum_g.ptr(y + h)[x] - image_sqsum_g.ptr(y)[x]));
float num = result.ptr(y)[x] - image_sum_r_ * templ_sum_scale_r
- image_sum_g_ * templ_sum_scale_g;
float denum = sqrtf(templ_sqsum_scale * (image_sqsum_r_ - weight * image_sum_r_ * image_sum_r_
+ image_sqsum_g_ - weight * image_sum_g_ * image_sum_g_));
result.ptr(y)[x] = normAcc(num, denum);
}
}
void matchTemplatePrepared_CCOFF_NORMED_8UC2(
int w, int h,
const PtrStepSz<int> image_sum_r, const PtrStepSz<double> image_sqsum_r,
const PtrStepSz<int> image_sum_g, const PtrStepSz<double> image_sqsum_g,
int templ_sum_r, double templ_sqsum_r,
int templ_sum_g, double templ_sqsum_g,
PtrStepSzf result, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
float weight = 1.f / (w * h);
float templ_sum_scale_r = templ_sum_r * weight;
float templ_sum_scale_g = templ_sum_g * weight;
float templ_sqsum_scale = templ_sqsum_r - weight * templ_sum_r * templ_sum_r
+ templ_sqsum_g - weight * templ_sum_g * templ_sum_g;
matchTemplatePreparedKernel_CCOFF_NORMED_8UC2<<<grid, threads, 0, stream>>>(
w, h, weight,
templ_sum_scale_r, templ_sum_scale_g,
templ_sqsum_scale,
image_sum_r, image_sqsum_r,
image_sum_g, image_sqsum_g,
result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void matchTemplatePreparedKernel_CCOFF_NORMED_8UC3(
int w, int h, float weight,
float templ_sum_scale_r, float templ_sum_scale_g, float templ_sum_scale_b,
float templ_sqsum_scale,
const PtrStep<int> image_sum_r, const PtrStep<double> image_sqsum_r,
const PtrStep<int> image_sum_g, const PtrStep<double> image_sqsum_g,
const PtrStep<int> image_sum_b, const PtrStep<double> image_sqsum_b,
PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sum_r_ = (float)(
(image_sum_r.ptr(y + h)[x + w] - image_sum_r.ptr(y)[x + w]) -
(image_sum_r.ptr(y + h)[x] - image_sum_r.ptr(y)[x]));
float image_sqsum_r_ = (float)(
(image_sqsum_r.ptr(y + h)[x + w] - image_sqsum_r.ptr(y)[x + w]) -
(image_sqsum_r.ptr(y + h)[x] - image_sqsum_r.ptr(y)[x]));
float image_sum_g_ = (float)(
(image_sum_g.ptr(y + h)[x + w] - image_sum_g.ptr(y)[x + w]) -
(image_sum_g.ptr(y + h)[x] - image_sum_g.ptr(y)[x]));
float image_sqsum_g_ = (float)(
(image_sqsum_g.ptr(y + h)[x + w] - image_sqsum_g.ptr(y)[x + w]) -
(image_sqsum_g.ptr(y + h)[x] - image_sqsum_g.ptr(y)[x]));
float image_sum_b_ = (float)(
(image_sum_b.ptr(y + h)[x + w] - image_sum_b.ptr(y)[x + w]) -
(image_sum_b.ptr(y + h)[x] - image_sum_b.ptr(y)[x]));
float image_sqsum_b_ = (float)(
(image_sqsum_b.ptr(y + h)[x + w] - image_sqsum_b.ptr(y)[x + w]) -
(image_sqsum_b.ptr(y + h)[x] - image_sqsum_b.ptr(y)[x]));
float num = result.ptr(y)[x] - image_sum_r_ * templ_sum_scale_r
- image_sum_g_ * templ_sum_scale_g
- image_sum_b_ * templ_sum_scale_b;
float denum = sqrtf(templ_sqsum_scale * (image_sqsum_r_ - weight * image_sum_r_ * image_sum_r_
+ image_sqsum_g_ - weight * image_sum_g_ * image_sum_g_
+ image_sqsum_b_ - weight * image_sum_b_ * image_sum_b_));
result.ptr(y)[x] = normAcc(num, denum);
}
}
void matchTemplatePrepared_CCOFF_NORMED_8UC3(
int w, int h,
const PtrStepSz<int> image_sum_r, const PtrStepSz<double> image_sqsum_r,
const PtrStepSz<int> image_sum_g, const PtrStepSz<double> image_sqsum_g,
const PtrStepSz<int> image_sum_b, const PtrStepSz<double> image_sqsum_b,
int templ_sum_r, double templ_sqsum_r,
int templ_sum_g, double templ_sqsum_g,
int templ_sum_b, double templ_sqsum_b,
PtrStepSzf result, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
float weight = 1.f / (w * h);
float templ_sum_scale_r = templ_sum_r * weight;
float templ_sum_scale_g = templ_sum_g * weight;
float templ_sum_scale_b = templ_sum_b * weight;
float templ_sqsum_scale = templ_sqsum_r - weight * templ_sum_r * templ_sum_r
+ templ_sqsum_g - weight * templ_sum_g * templ_sum_g
+ templ_sqsum_b - weight * templ_sum_b * templ_sum_b;
matchTemplatePreparedKernel_CCOFF_NORMED_8UC3<<<grid, threads, 0, stream>>>(
w, h, weight,
templ_sum_scale_r, templ_sum_scale_g, templ_sum_scale_b,
templ_sqsum_scale,
image_sum_r, image_sqsum_r,
image_sum_g, image_sqsum_g,
image_sum_b, image_sqsum_b,
result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void matchTemplatePreparedKernel_CCOFF_NORMED_8UC4(
int w, int h, float weight,
float templ_sum_scale_r, float templ_sum_scale_g, float templ_sum_scale_b,
float templ_sum_scale_a, float templ_sqsum_scale,
const PtrStep<int> image_sum_r, const PtrStep<double> image_sqsum_r,
const PtrStep<int> image_sum_g, const PtrStep<double> image_sqsum_g,
const PtrStep<int> image_sum_b, const PtrStep<double> image_sqsum_b,
const PtrStep<int> image_sum_a, const PtrStep<double> image_sqsum_a,
PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sum_r_ = (float)(
(image_sum_r.ptr(y + h)[x + w] - image_sum_r.ptr(y)[x + w]) -
(image_sum_r.ptr(y + h)[x] - image_sum_r.ptr(y)[x]));
float image_sqsum_r_ = (float)(
(image_sqsum_r.ptr(y + h)[x + w] - image_sqsum_r.ptr(y)[x + w]) -
(image_sqsum_r.ptr(y + h)[x] - image_sqsum_r.ptr(y)[x]));
float image_sum_g_ = (float)(
(image_sum_g.ptr(y + h)[x + w] - image_sum_g.ptr(y)[x + w]) -
(image_sum_g.ptr(y + h)[x] - image_sum_g.ptr(y)[x]));
float image_sqsum_g_ = (float)(
(image_sqsum_g.ptr(y + h)[x + w] - image_sqsum_g.ptr(y)[x + w]) -
(image_sqsum_g.ptr(y + h)[x] - image_sqsum_g.ptr(y)[x]));
float image_sum_b_ = (float)(
(image_sum_b.ptr(y + h)[x + w] - image_sum_b.ptr(y)[x + w]) -
(image_sum_b.ptr(y + h)[x] - image_sum_b.ptr(y)[x]));
float image_sqsum_b_ = (float)(
(image_sqsum_b.ptr(y + h)[x + w] - image_sqsum_b.ptr(y)[x + w]) -
(image_sqsum_b.ptr(y + h)[x] - image_sqsum_b.ptr(y)[x]));
float image_sum_a_ = (float)(
(image_sum_a.ptr(y + h)[x + w] - image_sum_a.ptr(y)[x + w]) -
(image_sum_a.ptr(y + h)[x] - image_sum_a.ptr(y)[x]));
float image_sqsum_a_ = (float)(
(image_sqsum_a.ptr(y + h)[x + w] - image_sqsum_a.ptr(y)[x + w]) -
(image_sqsum_a.ptr(y + h)[x] - image_sqsum_a.ptr(y)[x]));
float num = result.ptr(y)[x] - image_sum_r_ * templ_sum_scale_r - image_sum_g_ * templ_sum_scale_g
- image_sum_b_ * templ_sum_scale_b - image_sum_a_ * templ_sum_scale_a;
float denum = sqrtf(templ_sqsum_scale * (image_sqsum_r_ - weight * image_sum_r_ * image_sum_r_
+ image_sqsum_g_ - weight * image_sum_g_ * image_sum_g_
+ image_sqsum_b_ - weight * image_sum_b_ * image_sum_b_
+ image_sqsum_a_ - weight * image_sum_a_ * image_sum_a_));
result.ptr(y)[x] = normAcc(num, denum);
}
}
void matchTemplatePrepared_CCOFF_NORMED_8UC4(
int w, int h,
const PtrStepSz<int> image_sum_r, const PtrStepSz<double> image_sqsum_r,
const PtrStepSz<int> image_sum_g, const PtrStepSz<double> image_sqsum_g,
const PtrStepSz<int> image_sum_b, const PtrStepSz<double> image_sqsum_b,
const PtrStepSz<int> image_sum_a, const PtrStepSz<double> image_sqsum_a,
int templ_sum_r, double templ_sqsum_r,
int templ_sum_g, double templ_sqsum_g,
int templ_sum_b, double templ_sqsum_b,
int templ_sum_a, double templ_sqsum_a,
PtrStepSzf result, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
float weight = 1.f / (w * h);
float templ_sum_scale_r = templ_sum_r * weight;
float templ_sum_scale_g = templ_sum_g * weight;
float templ_sum_scale_b = templ_sum_b * weight;
float templ_sum_scale_a = templ_sum_a * weight;
float templ_sqsum_scale = templ_sqsum_r - weight * templ_sum_r * templ_sum_r
+ templ_sqsum_g - weight * templ_sum_g * templ_sum_g
+ templ_sqsum_b - weight * templ_sum_b * templ_sum_b
+ templ_sqsum_a - weight * templ_sum_a * templ_sum_a;
matchTemplatePreparedKernel_CCOFF_NORMED_8UC4<<<grid, threads, 0, stream>>>(
w, h, weight,
templ_sum_scale_r, templ_sum_scale_g, templ_sum_scale_b, templ_sum_scale_a,
templ_sqsum_scale,
image_sum_r, image_sqsum_r,
image_sum_g, image_sqsum_g,
image_sum_b, image_sqsum_b,
image_sum_a, image_sqsum_a,
result);
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
//////////////////////////////////////////////////////////////////////
// normalize
template <int cn>
__global__ void normalizeKernel_8U(
int w, int h, const PtrStep<double> image_sqsum,
double templ_sqsum, PtrStepSzf result)
{
const int x = blockIdx.x * blockDim.x + threadIdx.x;
const int y = blockIdx.y * blockDim.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
float image_sqsum_ = (float)(
(image_sqsum.ptr(y + h)[(x + w) * cn] - image_sqsum.ptr(y)[(x + w) * cn]) -
(image_sqsum.ptr(y + h)[x * cn] - image_sqsum.ptr(y)[x * cn]));
result.ptr(y)[x] = normAcc(result.ptr(y)[x], sqrtf(image_sqsum_ * templ_sqsum));
}
}
void normalize_8U(int w, int h, const PtrStepSz<double> image_sqsum,
double templ_sqsum, PtrStepSzf result, int cn, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
switch (cn)
{
case 1:
normalizeKernel_8U<1><<<grid, threads, 0, stream>>>(w, h, image_sqsum, templ_sqsum, result);
break;
case 2:
normalizeKernel_8U<2><<<grid, threads, 0, stream>>>(w, h, image_sqsum, templ_sqsum, result);
break;
case 3:
normalizeKernel_8U<3><<<grid, threads, 0, stream>>>(w, h, image_sqsum, templ_sqsum, result);
break;
case 4:
normalizeKernel_8U<4><<<grid, threads, 0, stream>>>(w, h, image_sqsum, templ_sqsum, result);
break;
}
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
//////////////////////////////////////////////////////////////////////
// extractFirstChannel
template <int cn>
__global__ void extractFirstChannel_32F(const PtrStepb image, PtrStepSzf result)
{
typedef typename TypeVec<float, cn>::vec_type Typef;
int x = blockDim.x * blockIdx.x + threadIdx.x;
int y = blockDim.y * blockIdx.y + threadIdx.y;
if (x < result.cols && y < result.rows)
{
Typef val = ((const Typef*)image.ptr(y))[x];
result.ptr(y)[x] = first(val);
}
}
void extractFirstChannel_32F(const PtrStepSzb image, PtrStepSzf result, int cn, cudaStream_t stream)
{
dim3 threads(32, 8);
dim3 grid(divUp(result.cols, threads.x), divUp(result.rows, threads.y));
switch (cn)
{
case 1:
extractFirstChannel_32F<1><<<grid, threads, 0, stream>>>(image, result);
break;
case 2:
extractFirstChannel_32F<2><<<grid, threads, 0, stream>>>(image, result);
break;
case 3:
extractFirstChannel_32F<3><<<grid, threads, 0, stream>>>(image, result);
break;
case 4:
extractFirstChannel_32F<4><<<grid, threads, 0, stream>>>(image, result);
break;
}
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
} //namespace match_template
}}} // namespace cv { namespace cuda { namespace cudev
#endif /* CUDA_DISABLER */
+169
View File
@@ -0,0 +1,169 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#if !defined CUDA_DISABLER
#include "opencv2/core/cuda/common.hpp"
#include "opencv2/core/cuda/vec_traits.hpp"
#include "opencv2/core/cuda/vec_math.hpp"
#include "opencv2/core/cuda/saturate_cast.hpp"
#include "opencv2/core/cuda/border_interpolate.hpp"
#include <opencv2/cudev/ptr2d/texture.hpp>
namespace cv { namespace cuda { namespace device
{
namespace imgproc
{
__device__ short2 do_mean_shift(cv::cudev::TexturePtr<uchar4> tex, int x0, int y0, unsigned char* out,size_t out_step, int cols, int rows, int sp, int sr, int maxIter, float eps)
{
int isr2 = sr*sr;
uchar4 c = tex(y0, x0);
// iterate meanshift procedure
for( int iter = 0; iter < maxIter; iter++ )
{
int count = 0;
int s0 = 0, s1 = 0, s2 = 0, sx = 0, sy = 0;
float icount;
//mean shift: process pixels in window (p-sigmaSp)x(p+sigmaSp)
int minx = x0-sp;
int miny = y0-sp;
int maxx = x0+sp;
int maxy = y0+sp;
for( int y = miny; y <= maxy; y++)
{
int rowCount = 0;
for( int x = minx; x <= maxx; x++ )
{
uchar4 t = tex(y, x);
int norm2 = (t.x - c.x) * (t.x - c.x) + (t.y - c.y) * (t.y - c.y) + (t.z - c.z) * (t.z - c.z);
if( norm2 <= isr2 )
{
s0 += t.x; s1 += t.y; s2 += t.z;
sx += x; rowCount++;
}
}
count += rowCount;
sy += y*rowCount;
}
if( count == 0 )
break;
icount = 1.f/count;
int x1 = __float2int_rz(sx*icount);
int y1 = __float2int_rz(sy*icount);
s0 = __float2int_rz(s0*icount);
s1 = __float2int_rz(s1*icount);
s2 = __float2int_rz(s2*icount);
int norm2 = (s0 - c.x) * (s0 - c.x) + (s1 - c.y) * (s1 - c.y) + (s2 - c.z) * (s2 - c.z);
bool stopFlag = (x0 == x1 && y0 == y1) || (::abs(x1-x0) + ::abs(y1-y0) + norm2 <= eps);
x0 = x1; y0 = y1;
c.x = s0; c.y = s1; c.z = s2;
if( stopFlag )
break;
}
int base = (blockIdx.y * blockDim.y + threadIdx.y) * out_step + (blockIdx.x * blockDim.x + threadIdx.x) * 4 * sizeof(uchar);
*(uchar4*)(out + base) = c;
return make_short2((short)x0, (short)y0);
}
__global__ void meanshift_kernel(cv::cudev::TexturePtr<uchar4> tex, unsigned char* out, size_t out_step, int cols, int rows, int sp, int sr, int maxIter, float eps )
{
int x0 = blockIdx.x * blockDim.x + threadIdx.x;
int y0 = blockIdx.y * blockDim.y + threadIdx.y;
if( x0 < cols && y0 < rows )
do_mean_shift(tex, x0, y0, out, out_step, cols, rows, sp, sr, maxIter, eps);
}
void meanShiftFiltering_gpu(const PtrStepSzb& src, PtrStepSzb dst, int sp, int sr, int maxIter, float eps, cudaStream_t stream)
{
dim3 grid(1, 1, 1);
dim3 threads(32, 8, 1);
grid.x = divUp(src.cols, threads.x);
grid.y = divUp(src.rows, threads.y);
cv::cudev::Texture<uchar4> tex(src.rows, src.cols, (uchar4*)src.data, src.step);
meanshift_kernel<<< grid, threads, 0, stream >>>( tex, dst.data, dst.step, dst.cols, dst.rows, sp, sr, maxIter, eps );
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
__global__ void meanshiftproc_kernel(cv::cudev::TexturePtr<uchar4> tex, unsigned char* outr, size_t outrstep, unsigned char* outsp, size_t outspstep,
int cols, int rows,int sp, int sr, int maxIter, float eps)
{
int x0 = blockIdx.x * blockDim.x + threadIdx.x;
int y0 = blockIdx.y * blockDim.y + threadIdx.y;
if( x0 < cols && y0 < rows )
{
int basesp = (blockIdx.y * blockDim.y + threadIdx.y) * outspstep + (blockIdx.x * blockDim.x + threadIdx.x) * 2 * sizeof(short);
*(short2*)(outsp + basesp) = do_mean_shift(tex, x0, y0, outr, outrstep, cols, rows, sp, sr, maxIter, eps);
}
}
void meanShiftProc_gpu(const PtrStepSzb& src, PtrStepSzb dstr, PtrStepSzb dstsp, int sp, int sr, int maxIter, float eps, cudaStream_t stream)
{
dim3 grid(1, 1, 1);
dim3 threads(32, 8, 1);
grid.x = divUp(src.cols, threads.x);
grid.y = divUp(src.rows, threads.y);
cv::cudev::Texture<uchar4> tex(src.rows, src.cols, (uchar4*)src.data, src.step);
meanshiftproc_kernel<<< grid, threads, 0, stream >>>( tex, dstr.data, dstr.step, dstsp.data, dstsp.step, dstr.cols, dstr.rows, sp, sr, maxIter, eps );
cudaSafeCall( cudaGetLastError() );
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
}
}}}
#endif
+194
View File
@@ -0,0 +1,194 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#if !defined CUDA_DISABLER
#include <opencv2/core/cuda/common.hpp>
#include <opencv2/cudev/util/atomic.hpp>
#include "moments.cuh"
namespace cv { namespace cuda { namespace device { namespace imgproc {
constexpr int blockSizeX = 32;
constexpr int blockSizeY = 16;
template <typename T>
__device__ T butterflyWarpReduction(T value) {
for (int i = 16; i >= 1; i /= 2)
#if (CUDART_VERSION >= 9000)
value += __shfl_xor_sync(0xffffffff, value, i, 32);
#else
value += __shfl_xor(value, i, 32);
#endif
return value;
}
template <typename T>
__device__ T butterflyHalfWarpReduction(T value) {
for (int i = 8; i >= 1; i /= 2)
#if (CUDART_VERSION >= 9000)
value += __shfl_xor_sync(0xffff, value, i, 16);
#else
value += __shfl_xor(value, i, 16);
#endif
return value;
}
template<typename T, int nMoments>
__device__ void updateSums(const T val, const unsigned int x, T r[4]) {
const T x2 = x * x;
const T x3 = static_cast<T>(x) * x2;
r[0] += val;
r[1] += val * x;
if (nMoments >= n12) r[2] += val * x2;
if (nMoments >= n123) r[3] += val * x3;
}
template<typename TSrc, typename TMoments, int nMoments>
__device__ void rowReductions(const PtrStepSz<TSrc> img, const bool binary, const unsigned int y, TMoments r[4], TMoments smem[][nMoments + 1]) {
for (int x = threadIdx.x; x < img.cols; x += blockDim.x) {
const TMoments val = (!binary || img(y, x) == 0) ? img(y, x) : 1;
updateSums<TMoments,nMoments>(val, x, r);
}
}
template<typename TSrc, typename TMoments, bool fourByteAligned, int nMoments>
__device__ void rowReductionsCoalesced(const PtrStepSz<TSrc> img, const bool binary, const unsigned int y, TMoments r[4], const int offsetX, TMoments smem[][nMoments + 1]) {
const int alignedOffset = fourByteAligned ? 0 : 4 - offsetX;
// load uncoalesced head
if (!fourByteAligned && threadIdx.x == 0) {
for (int x = 0; x < ::min(alignedOffset, static_cast<int>(img.cols)); x++) {
const TMoments val = (!binary || img(y, x) == 0) ? img(y, x) : 1;
updateSums<TMoments, nMoments>(val, x, r);
}
}
// coalesced loads
const unsigned int* rowPtrIntAligned = (const unsigned int*)(fourByteAligned ? img.ptr(y) : img.ptr(y) + alignedOffset);
const int cols4 = fourByteAligned ? img.cols / 4 : (img.cols - alignedOffset) / 4;
for (int x = threadIdx.x; x < cols4; x += blockDim.x) {
const unsigned int data = rowPtrIntAligned[x];
#pragma unroll 4
for (int i = 0; i < 4; i++) {
const int iX = alignedOffset + 4 * x + i;
const uchar ucharVal = ((data >> i * 8) & 0xFFU);
const TMoments val = (!binary || ucharVal == 0) ? ucharVal : 1;
updateSums<TMoments, nMoments>(val, iX, r);
}
}
// load uncoalesced tail
if (threadIdx.x == 0) {
const int iTailStart = fourByteAligned ? cols4 * 4 : cols4 * 4 + alignedOffset;
for (int x = iTailStart; x < img.cols; x++) {
const TMoments val = (!binary || img(y, x) == 0) ? img(y, x) : 1;
updateSums<TMoments, nMoments>(val, x, r);
}
}
}
template <typename TSrc, typename TMoments, bool coalesced = false, bool fourByteAligned = false, int nMoments>
__global__ void spatialMoments(const PtrStepSz<TSrc> img, const bool binary, TMoments* moments, const int offsetX = 0) {
const unsigned int y = blockIdx.x * blockDim.y + threadIdx.y;
__shared__ TMoments smem[blockSizeY][nMoments + 1];
if (threadIdx.y < nMoments && threadIdx.x < blockSizeY)
smem[threadIdx.x][threadIdx.y] = 0;
__syncthreads();
TMoments r[4] = { 0 };
if (y < img.rows) {
if (coalesced)
rowReductionsCoalesced<TSrc, TMoments, fourByteAligned, nMoments>(img, binary, y, r, offsetX, smem);
else
rowReductions<TSrc, TMoments, nMoments>(img, binary, y, r, smem);
}
const unsigned long y2 = y * y;
const TMoments y3 = static_cast<TMoments>(y2) * y;
const TMoments res = butterflyWarpReduction<float>(r[0]);
if (res) {
smem[threadIdx.y][0] = res; //0th
smem[threadIdx.y][1] = butterflyWarpReduction(r[1]); //1st
smem[threadIdx.y][2] = y * res; //1st
if (nMoments >= n12) {
smem[threadIdx.y][3] = butterflyWarpReduction(r[2]); //2nd
smem[threadIdx.y][4] = smem[threadIdx.y][1] * y; //2nd
smem[threadIdx.y][5] = y2 * res; //2nd
}
if (nMoments >= n123) {
smem[threadIdx.y][6] = butterflyWarpReduction(r[3]); //3rd
smem[threadIdx.y][7] = smem[threadIdx.y][3] * y; //3rd
smem[threadIdx.y][8] = smem[threadIdx.y][1] * y2; //3rd
smem[threadIdx.y][9] = y3 * res; //3rd
}
}
__syncthreads();
if (threadIdx.x < blockSizeY && threadIdx.y < nMoments)
smem[threadIdx.y][nMoments] = butterflyHalfWarpReduction(smem[threadIdx.x][threadIdx.y]);
__syncthreads();
if (threadIdx.y == 0 && threadIdx.x < nMoments) {
if (smem[threadIdx.x][nMoments])
cudev::atomicAdd(&moments[threadIdx.x], smem[threadIdx.x][nMoments]);
}
}
template <typename TSrc, typename TMoments, int nMoments> struct momentsDispatcherNonChar {
static void call(const PtrStepSz<TSrc> src, PtrStepSz<TMoments> moments, const bool binary, const int offsetX, const cudaStream_t stream) {
dim3 blockSize(blockSizeX, blockSizeY);
dim3 gridSize = dim3(divUp(src.rows, blockSizeY));
spatialMoments<TSrc, TMoments, false, false, nMoments> <<<gridSize, blockSize, 0, stream >>> (src, binary, moments.ptr());
if (stream == 0)
cudaSafeCall(cudaStreamSynchronize(stream));
};
};
template <typename TSrc, int nMoments> struct momentsDispatcherChar {
static void call(const PtrStepSz<TSrc> src, PtrStepSz<float> moments, const bool binary, const int offsetX, const cudaStream_t stream) {
dim3 blockSize(blockSizeX, blockSizeY);
dim3 gridSize = dim3(divUp(src.rows, blockSizeY));
if (offsetX)
spatialMoments<TSrc, float, true, false, nMoments> <<<gridSize, blockSize, 0, stream >>> (src, binary, moments.ptr(), offsetX);
else
spatialMoments<TSrc, float, true, true, nMoments> <<<gridSize, blockSize, 0, stream >>> (src, binary, moments.ptr());
if (stream == 0)
cudaSafeCall(cudaStreamSynchronize(stream));
};
};
template <typename TSrc, typename TMoments, int nMoments> struct momentsDispatcher : momentsDispatcherNonChar<TSrc, TMoments, nMoments> {};
template <int nMoments> struct momentsDispatcher<uchar, float, nMoments> : momentsDispatcherChar<uchar, nMoments> {};
template <int nMoments> struct momentsDispatcher<schar, float, nMoments> : momentsDispatcherChar<schar, nMoments> {};
template <typename TSrc, typename TMoments>
void moments(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream) {
if (order == 1)
momentsDispatcher<TSrc, TMoments, n1>::call(static_cast<PtrStepSz<TSrc>>(src), static_cast<PtrStepSz<TMoments>>(moments), binary, offsetX, stream);
else if (order == 2)
momentsDispatcher<TSrc, TMoments, n12>::call(static_cast<PtrStepSz<TSrc>>(src), static_cast<PtrStepSz<TMoments>>(moments), binary, offsetX, stream);
else if (order == 3)
momentsDispatcher<TSrc, TMoments, n123>::call(static_cast<PtrStepSz<TSrc>>(src), static_cast<PtrStepSz<TMoments>>(moments), binary, offsetX, stream);
};
template void moments<uchar, float>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<schar, float>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<ushort, float>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<short, float>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<int, float>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<float, float>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<double, float>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<uchar, double>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<schar, double>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<ushort, double>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<short, double>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<int, double>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<float, double>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
template void moments<double, double>(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
}}}}
#endif /* CUDA_DISABLER */
+6
View File
@@ -0,0 +1,6 @@
#pragma once
namespace cv { namespace cuda { namespace device { namespace imgproc {
constexpr int n1 = 3;
constexpr int n12 = 6;
constexpr int n123 = 10;
}}}}
@@ -0,0 +1,275 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __cvt_color_internal_h__
#define __cvt_color_internal_h__
#include "opencv2/core/cuda.hpp"
namespace cv { namespace cuda { namespace device
{
#define OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name) \
void name(const GpuMat& _src, GpuMat& _dst, Stream& stream);
#define OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(name) \
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name ## _8u) \
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name ## _16u) \
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name ## _32f)
#define OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(name) \
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name ## _8u) \
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name ## _32f)
#define OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(name) \
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name ## _8u) \
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name ## _32f) \
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name ## _FULL_8u) \
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(name ## _FULL_32f)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGB_to_GRAY)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_GRAY)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGBA_to_GRAY)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_GRAY)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(GRAY_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(GRAY_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGB_to_YUV)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGBA_to_YUV)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGB_to_YUV4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGBA_to_YUV4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_YUV)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_YUV)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_YUV4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_YUV4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YUV_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YUV_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YUV4_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YUV4_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YUV_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YUV_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YUV4_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YUV4_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGB_to_YCrCb)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGBA_to_YCrCb)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGB_to_YCrCb4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGBA_to_YCrCb4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_YCrCb)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_YCrCb)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_YCrCb4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_YCrCb4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YCrCb_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YCrCb_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YCrCb4_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YCrCb4_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YCrCb_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YCrCb_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YCrCb4_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(YCrCb4_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGB_to_XYZ)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGBA_to_XYZ)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGB_to_XYZ4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(RGBA_to_XYZ4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_XYZ)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_XYZ)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGR_to_XYZ4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(BGRA_to_XYZ4)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(XYZ_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(XYZ4_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(XYZ_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(XYZ4_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(XYZ_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(XYZ4_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(XYZ_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ALL(XYZ4_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(RGB_to_HSV)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(RGBA_to_HSV)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(RGB_to_HSV4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(RGBA_to_HSV4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(BGR_to_HSV)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(BGRA_to_HSV)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(BGR_to_HSV4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(BGRA_to_HSV4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HSV_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HSV_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HSV4_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HSV4_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HSV_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HSV_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HSV4_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HSV4_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(RGB_to_HLS)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(RGBA_to_HLS)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(RGB_to_HLS4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(RGBA_to_HLS4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(BGR_to_HLS)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(BGRA_to_HLS)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(BGR_to_HLS4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(BGRA_to_HLS4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HLS_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HLS_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HLS4_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HLS4_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HLS_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HLS_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HLS4_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL(HLS4_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(RGB_to_Lab)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(RGBA_to_Lab)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(RGB_to_Lab4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(RGBA_to_Lab4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(BGR_to_Lab)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(BGRA_to_Lab)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(BGR_to_Lab4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(BGRA_to_Lab4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LRGB_to_Lab)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LRGBA_to_Lab)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LRGB_to_Lab4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LRGBA_to_Lab4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LBGR_to_Lab)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LBGRA_to_Lab)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LBGR_to_Lab4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LBGRA_to_Lab4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab4_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab4_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab4_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab4_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab_to_LRGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab4_to_LRGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab_to_LRGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab4_to_LRGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab_to_LBGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab4_to_LBGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab_to_LBGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Lab4_to_LBGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(RGB_to_Luv)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(RGBA_to_Luv)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(RGB_to_Luv4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(RGBA_to_Luv4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(BGR_to_Luv)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(BGRA_to_Luv)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(BGR_to_Luv4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(BGRA_to_Luv4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LRGB_to_Luv)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LRGBA_to_Luv)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LRGB_to_Luv4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LRGBA_to_Luv4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LBGR_to_Luv)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LBGRA_to_Luv)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LBGR_to_Luv4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(LBGRA_to_Luv4)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv4_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv4_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv4_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv4_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv_to_LRGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv4_to_LRGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv_to_LRGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv4_to_LRGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv_to_LBGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv4_to_LBGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv_to_LBGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F(Luv4_to_LBGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR_to_BGR555)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR_to_BGR565)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(RGB_to_BGR555)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(RGB_to_BGR565)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGRA_to_BGR555)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGRA_to_BGR565)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(RGBA_to_BGR555)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(RGBA_to_BGR565)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR555_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR565_to_RGB)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR555_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR565_to_BGR)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR555_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR565_to_RGBA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR555_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR565_to_BGRA)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(GRAY_to_BGR555)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(GRAY_to_BGR565)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR555_to_GRAY)
OPENCV_CUDA_DECLARE_CVTCOLOR_ONE(BGR565_to_GRAY)
#undef OPENCV_CUDA_DECLARE_CVTCOLOR_ONE
#undef OPENCV_CUDA_DECLARE_CVTCOLOR_ALL
#undef OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F
#undef OPENCV_CUDA_DECLARE_CVTCOLOR_8U32F_FULL
}}}
#endif
@@ -0,0 +1,885 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || !defined(HAVE_OPENCV_CUDAARITHM)
Ptr<GeneralizedHoughBallard> cv::cuda::createGeneralizedHoughBallard() { throw_no_cuda(); return Ptr<GeneralizedHoughBallard>(); }
Ptr<GeneralizedHoughGuil> cv::cuda::createGeneralizedHoughGuil() { throw_no_cuda(); return Ptr<GeneralizedHoughGuil>(); }
#else /* !defined (HAVE_CUDA) */
namespace cv { namespace cuda { namespace device
{
namespace ght
{
template <typename T>
int buildEdgePointList_gpu(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList);
void buildRTable_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
PtrStepSz<short2> r_table, int* r_sizes,
short2 templCenter, int levels);
void Ballard_Pos_calcHist_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
PtrStepSz<short2> r_table, const int* r_sizes,
PtrStepSzi hist,
float dp, int levels);
int Ballard_Pos_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int maxSize, float dp, int threshold);
void Guil_Full_setTemplFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2);
void Guil_Full_setImageFeatures(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2);
void Guil_Full_buildTemplFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
int* sizes, int maxSize,
float xi, float angleEpsilon, int levels,
float2 center, float maxDist);
void Guil_Full_buildImageFeatureList_gpu(const unsigned int* coordList, const float* thetaList, int pointsCount,
int* sizes, int maxSize,
float xi, float angleEpsilon, int levels,
float2 center, float maxDist);
void Guil_Full_calcOHist_gpu(const int* templSizes, const int* imageSizes, int* OHist,
float minAngle, float maxAngle, float angleStep, int angleRange,
int levels, int tMaxSize);
void Guil_Full_calcSHist_gpu(const int* templSizes, const int* imageSizes, int* SHist,
float angle, float angleEpsilon,
float minScale, float maxScale, float iScaleStep, int scaleRange,
int levels, int tMaxSize);
void Guil_Full_calcPHist_gpu(const int* templSizes, const int* imageSizes, PtrStepSzi PHist,
float angle, float angleEpsilon, float scale,
float dp,
int levels, int tMaxSize);
int Guil_Full_findPosInHist_gpu(PtrStepSzi hist, float4* out, int3* votes, int curSize, int maxSize,
float angle, int angleVotes, float scale, int scaleVotes,
float dp, int threshold);
}
}}}
// common
namespace
{
class GeneralizedHoughBase
{
protected:
GeneralizedHoughBase();
virtual ~GeneralizedHoughBase() {}
void setTemplateImpl(InputArray templ, Point templCenter);
void setTemplateImpl(InputArray edges, InputArray dx, InputArray dy, Point templCenter);
void detectImpl(InputArray image, OutputArray positions, OutputArray votes);
void detectImpl(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes);
void buildEdgePointList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy);
virtual void processTempl() = 0;
virtual void processImage() = 0;
int cannyLowThresh_;
int cannyHighThresh_;
double minDist_;
double dp_;
int maxBufferSize_;
Size templSize_;
Point templCenter_;
GpuMat templEdges_;
GpuMat templDx_;
GpuMat templDy_;
Size imageSize_;
GpuMat imageEdges_;
GpuMat imageDx_;
GpuMat imageDy_;
GpuMat edgePointList_;
GpuMat outBuf_;
int posCount_;
private:
#ifdef HAVE_OPENCV_CUDAFILTERS
void calcEdges(InputArray src, GpuMat& edges, GpuMat& dx, GpuMat& dy);
#endif
void filterMinDist();
void convertTo(OutputArray positions, OutputArray votes);
#ifdef HAVE_OPENCV_CUDAFILTERS
Ptr<cuda::CannyEdgeDetector> canny_;
Ptr<cuda::Filter> filterDx_;
Ptr<cuda::Filter> filterDy_;
#endif
std::vector<float4> oldPosBuf_;
std::vector<int3> oldVoteBuf_;
std::vector<float4> newPosBuf_;
std::vector<int3> newVoteBuf_;
std::vector<int> indexies_;
};
GeneralizedHoughBase::GeneralizedHoughBase()
{
cannyLowThresh_ = 50;
cannyHighThresh_ = 100;
minDist_ = 1.0;
dp_ = 1.0;
maxBufferSize_ = 10000;
#ifdef HAVE_OPENCV_CUDAFILTERS
canny_ = cuda::createCannyEdgeDetector(cannyLowThresh_, cannyHighThresh_);
filterDx_ = cuda::createSobelFilter(CV_8UC1, CV_32S, 1, 0);
filterDy_ = cuda::createSobelFilter(CV_8UC1, CV_32S, 0, 1);
#endif
}
#ifdef HAVE_OPENCV_CUDAFILTERS
void GeneralizedHoughBase::calcEdges(InputArray _src, GpuMat& edges, GpuMat& dx, GpuMat& dy)
{
GpuMat src = _src.getGpuMat();
CV_Assert( src.type() == CV_8UC1 );
CV_Assert( cannyLowThresh_ > 0 && cannyLowThresh_ < cannyHighThresh_ );
ensureSizeIsEnough(src.size(), CV_32SC1, dx);
ensureSizeIsEnough(src.size(), CV_32SC1, dy);
filterDx_->apply(src, dx);
filterDy_->apply(src, dy);
ensureSizeIsEnough(src.size(), CV_8UC1, edges);
canny_->setLowThreshold(cannyLowThresh_);
canny_->setHighThreshold(cannyHighThresh_);
canny_->detect(dx, dy, edges);
}
#endif
void GeneralizedHoughBase::setTemplateImpl(InputArray templ, Point templCenter)
{
#ifndef HAVE_OPENCV_CUDAFILTERS
CV_UNUSED(templ);
CV_UNUSED(templCenter);
throw_no_cuda();
#else
calcEdges(templ, templEdges_, templDx_, templDy_);
if (templCenter == Point(-1, -1))
templCenter = Point(templEdges_.cols / 2, templEdges_.rows / 2);
templSize_ = templEdges_.size();
templCenter_ = templCenter;
processTempl();
#endif
}
void GeneralizedHoughBase::setTemplateImpl(InputArray edges, InputArray dx, InputArray dy, Point templCenter)
{
edges.getGpuMat().copyTo(templEdges_);
dx.getGpuMat().copyTo(templDx_);
dy.getGpuMat().copyTo(templDy_);
CV_Assert( templEdges_.type() == CV_8UC1 );
CV_Assert( templDx_.type() == CV_32FC1 && templDx_.size() == templEdges_.size() );
CV_Assert( templDy_.type() == templDx_.type() && templDy_.size() == templEdges_.size() );
if (templCenter == Point(-1, -1))
templCenter = Point(templEdges_.cols / 2, templEdges_.rows / 2);
templSize_ = templEdges_.size();
templCenter_ = templCenter;
processTempl();
}
void GeneralizedHoughBase::detectImpl(InputArray image, OutputArray positions, OutputArray votes)
{
#ifndef HAVE_OPENCV_CUDAFILTERS
CV_UNUSED(image);
CV_UNUSED(positions);
CV_UNUSED(votes);
throw_no_cuda();
#else
calcEdges(image, imageEdges_, imageDx_, imageDy_);
imageSize_ = imageEdges_.size();
posCount_ = 0;
processImage();
if (posCount_ == 0)
{
positions.release();
if (votes.needed())
votes.release();
}
else
{
if (minDist_ > 1)
filterMinDist();
convertTo(positions, votes);
}
#endif
}
void GeneralizedHoughBase::detectImpl(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes)
{
edges.getGpuMat().copyTo(imageEdges_);
dx.getGpuMat().copyTo(imageDx_);
dy.getGpuMat().copyTo(imageDy_);
CV_Assert( imageEdges_.type() == CV_8UC1 );
CV_Assert( imageDx_.type() == CV_32FC1 && imageDx_.size() == imageEdges_.size() );
CV_Assert( imageDy_.type() == imageDx_.type() && imageDy_.size() == imageEdges_.size() );
imageSize_ = imageEdges_.size();
posCount_ = 0;
processImage();
if (posCount_ == 0)
{
positions.release();
if (votes.needed())
votes.release();
}
else
{
if (minDist_ > 1)
filterMinDist();
convertTo(positions, votes);
}
}
void GeneralizedHoughBase::buildEdgePointList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy)
{
using namespace cv::cuda::device::ght;
typedef int (*func_t)(PtrStepSzb edges, PtrStepSzb dx, PtrStepSzb dy, unsigned int* coordList, float* thetaList);
static const func_t funcs[] =
{
0,
0,
0,
buildEdgePointList_gpu<short>,
buildEdgePointList_gpu<int>,
buildEdgePointList_gpu<float>,
0
};
CV_Assert( edges.type() == CV_8UC1 );
CV_Assert( dx.size() == edges.size() );
CV_Assert( dy.type() == dx.type() && dy.size() == edges.size() );
const func_t func = funcs[dx.depth()];
CV_Assert( func != 0 );
edgePointList_.cols = (int) (edgePointList_.step / sizeof(int));
ensureSizeIsEnough(2, edges.size().area(), CV_32SC1, edgePointList_);
edgePointList_.cols = func(edges, dx, dy, edgePointList_.ptr<unsigned int>(0), edgePointList_.ptr<float>(1));
}
struct IndexCmp
{
const int3* aux;
explicit IndexCmp(const int3* _aux) : aux(_aux) {}
bool operator ()(int l1, int l2) const
{
return aux[l1].x > aux[l2].x;
}
};
void GeneralizedHoughBase::filterMinDist()
{
oldPosBuf_.resize(posCount_);
oldVoteBuf_.resize(posCount_);
cudaSafeCall( cudaMemcpy(&oldPosBuf_[0], outBuf_.ptr(0), posCount_ * sizeof(float4), cudaMemcpyDeviceToHost) );
cudaSafeCall( cudaMemcpy(&oldVoteBuf_[0], outBuf_.ptr(1), posCount_ * sizeof(int3), cudaMemcpyDeviceToHost) );
indexies_.resize(posCount_);
for (int i = 0; i < posCount_; ++i)
indexies_[i] = i;
std::sort(indexies_.begin(), indexies_.end(), IndexCmp(&oldVoteBuf_[0]));
newPosBuf_.clear();
newVoteBuf_.clear();
newPosBuf_.reserve(posCount_);
newVoteBuf_.reserve(posCount_);
const int cellSize = cvRound(minDist_);
const int gridWidth = (imageSize_.width + cellSize - 1) / cellSize;
const int gridHeight = (imageSize_.height + cellSize - 1) / cellSize;
std::vector< std::vector<Point2f> > grid(gridWidth * gridHeight);
const double minDist2 = minDist_ * minDist_;
for (int i = 0; i < posCount_; ++i)
{
const int ind = indexies_[i];
Point2f p(oldPosBuf_[ind].x, oldPosBuf_[ind].y);
bool good = true;
const int xCell = static_cast<int>(p.x / cellSize);
const int yCell = static_cast<int>(p.y / cellSize);
int x1 = xCell - 1;
int y1 = yCell - 1;
int x2 = xCell + 1;
int y2 = yCell + 1;
// boundary check
x1 = std::max(0, x1);
y1 = std::max(0, y1);
x2 = std::min(gridWidth - 1, x2);
y2 = std::min(gridHeight - 1, y2);
for (int yy = y1; yy <= y2; ++yy)
{
for (int xx = x1; xx <= x2; ++xx)
{
const std::vector<Point2f>& m = grid[yy * gridWidth + xx];
for(size_t j = 0; j < m.size(); ++j)
{
const Point2f d = p - m[j];
if (d.ddot(d) < minDist2)
{
good = false;
goto break_out;
}
}
}
}
break_out:
if(good)
{
grid[yCell * gridWidth + xCell].push_back(p);
newPosBuf_.push_back(oldPosBuf_[ind]);
newVoteBuf_.push_back(oldVoteBuf_[ind]);
}
}
posCount_ = static_cast<int>(newPosBuf_.size());
cudaSafeCall( cudaMemcpy(outBuf_.ptr(0), &newPosBuf_[0], posCount_ * sizeof(float4), cudaMemcpyHostToDevice) );
cudaSafeCall( cudaMemcpy(outBuf_.ptr(1), &newVoteBuf_[0], posCount_ * sizeof(int3), cudaMemcpyHostToDevice) );
}
void GeneralizedHoughBase::convertTo(OutputArray positions, OutputArray votes)
{
ensureSizeIsEnough(1, posCount_, CV_32FC4, positions);
GpuMat(1, posCount_, CV_32FC4, outBuf_.ptr(0), outBuf_.step).copyTo(positions);
if (votes.needed())
{
ensureSizeIsEnough(1, posCount_, CV_32FC3, votes);
GpuMat(1, posCount_, CV_32FC4, outBuf_.ptr(1), outBuf_.step).copyTo(votes);
}
}
}
// GeneralizedHoughBallard
namespace
{
class GeneralizedHoughBallardImpl : public GeneralizedHoughBallard, private GeneralizedHoughBase
{
public:
GeneralizedHoughBallardImpl();
void setTemplate(InputArray templ, Point templCenter) { setTemplateImpl(templ, templCenter); }
void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter) { setTemplateImpl(edges, dx, dy, templCenter); }
void detect(InputArray image, OutputArray positions, OutputArray votes) { detectImpl(image, positions, votes); }
void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes) { detectImpl(edges, dx, dy, positions, votes); }
void setCannyLowThresh(int cannyLowThresh) { cannyLowThresh_ = cannyLowThresh; }
int getCannyLowThresh() const { return cannyLowThresh_; }
void setCannyHighThresh(int cannyHighThresh) { cannyHighThresh_ = cannyHighThresh; }
int getCannyHighThresh() const { return cannyHighThresh_; }
void setMinDist(double minDist) { minDist_ = minDist; }
double getMinDist() const { return minDist_; }
void setDp(double dp) { dp_ = dp; }
double getDp() const { return dp_; }
void setMaxBufferSize(int maxBufferSize) { maxBufferSize_ = maxBufferSize; }
int getMaxBufferSize() const { return maxBufferSize_; }
void setLevels(int levels) { levels_ = levels; }
int getLevels() const { return levels_; }
void setVotesThreshold(int votesThreshold) { votesThreshold_ = votesThreshold; }
int getVotesThreshold() const { return votesThreshold_; }
private:
void processTempl();
void processImage();
void calcHist();
void findPosInHist();
int levels_;
int votesThreshold_;
GpuMat r_table_;
GpuMat r_sizes_;
GpuMat hist_;
};
GeneralizedHoughBallardImpl::GeneralizedHoughBallardImpl()
{
levels_ = 360;
votesThreshold_ = 100;
}
void GeneralizedHoughBallardImpl::processTempl()
{
using namespace cv::cuda::device::ght;
CV_Assert( levels_ > 0 );
buildEdgePointList(templEdges_, templDx_, templDy_);
ensureSizeIsEnough(levels_ + 1, maxBufferSize_, CV_16SC2, r_table_);
ensureSizeIsEnough(1, levels_ + 1, CV_32SC1, r_sizes_);
r_sizes_.setTo(Scalar::all(0));
if (edgePointList_.cols > 0)
{
buildRTable_gpu(edgePointList_.ptr<unsigned int>(0), edgePointList_.ptr<float>(1), edgePointList_.cols,
r_table_, r_sizes_.ptr<int>(), make_short2(templCenter_.x, templCenter_.y), levels_);
cuda::min(r_sizes_, maxBufferSize_, r_sizes_);
}
}
void GeneralizedHoughBallardImpl::processImage()
{
calcHist();
findPosInHist();
}
void GeneralizedHoughBallardImpl::calcHist()
{
using namespace cv::cuda::device::ght;
CV_Assert( levels_ > 0 && r_table_.rows == (levels_ + 1) && r_sizes_.cols == (levels_ + 1) );
CV_Assert( dp_ > 0.0);
const double idp = 1.0 / dp_;
buildEdgePointList(imageEdges_, imageDx_, imageDy_);
ensureSizeIsEnough(cvCeil(imageSize_.height * idp) + 2, cvCeil(imageSize_.width * idp) + 2, CV_32SC1, hist_);
hist_.setTo(Scalar::all(0));
if (edgePointList_.cols > 0)
{
Ballard_Pos_calcHist_gpu(edgePointList_.ptr<unsigned int>(0), edgePointList_.ptr<float>(1), edgePointList_.cols,
r_table_, r_sizes_.ptr<int>(),
hist_,
(float)dp_, levels_);
}
}
void GeneralizedHoughBallardImpl::findPosInHist()
{
using namespace cv::cuda::device::ght;
CV_Assert( votesThreshold_ > 0 );
ensureSizeIsEnough(2, maxBufferSize_, CV_32FC4, outBuf_);
posCount_ = Ballard_Pos_findPosInHist_gpu(hist_, outBuf_.ptr<float4>(0), outBuf_.ptr<int3>(1), maxBufferSize_, (float)dp_, votesThreshold_);
}
}
Ptr<GeneralizedHoughBallard> cv::cuda::createGeneralizedHoughBallard()
{
return makePtr<GeneralizedHoughBallardImpl>();
}
// GeneralizedHoughGuil
namespace
{
class GeneralizedHoughGuilImpl : public GeneralizedHoughGuil, private GeneralizedHoughBase
{
public:
GeneralizedHoughGuilImpl();
void setTemplate(InputArray templ, Point templCenter) { setTemplateImpl(templ, templCenter); }
void setTemplate(InputArray edges, InputArray dx, InputArray dy, Point templCenter) { setTemplateImpl(edges, dx, dy, templCenter); }
void detect(InputArray image, OutputArray positions, OutputArray votes) { detectImpl(image, positions, votes); }
void detect(InputArray edges, InputArray dx, InputArray dy, OutputArray positions, OutputArray votes) { detectImpl(edges, dx, dy, positions, votes); }
void setCannyLowThresh(int cannyLowThresh) { cannyLowThresh_ = cannyLowThresh; }
int getCannyLowThresh() const { return cannyLowThresh_; }
void setCannyHighThresh(int cannyHighThresh) { cannyHighThresh_ = cannyHighThresh; }
int getCannyHighThresh() const { return cannyHighThresh_; }
void setMinDist(double minDist) { minDist_ = minDist; }
double getMinDist() const { return minDist_; }
void setDp(double dp) { dp_ = dp; }
double getDp() const { return dp_; }
void setMaxBufferSize(int maxBufferSize) { maxBufferSize_ = maxBufferSize; }
int getMaxBufferSize() const { return maxBufferSize_; }
void setXi(double xi) { xi_ = xi; }
double getXi() const { return xi_; }
void setLevels(int levels) { levels_ = levels; }
int getLevels() const { return levels_; }
void setAngleEpsilon(double angleEpsilon) { angleEpsilon_ = angleEpsilon; }
double getAngleEpsilon() const { return angleEpsilon_; }
void setMinAngle(double minAngle) { minAngle_ = minAngle; }
double getMinAngle() const { return minAngle_; }
void setMaxAngle(double maxAngle) { maxAngle_ = maxAngle; }
double getMaxAngle() const { return maxAngle_; }
void setAngleStep(double angleStep) { angleStep_ = angleStep; }
double getAngleStep() const { return angleStep_; }
void setAngleThresh(int angleThresh) { angleThresh_ = angleThresh; }
int getAngleThresh() const { return angleThresh_; }
void setMinScale(double minScale) { minScale_ = minScale; }
double getMinScale() const { return minScale_; }
void setMaxScale(double maxScale) { maxScale_ = maxScale; }
double getMaxScale() const { return maxScale_; }
void setScaleStep(double scaleStep) { scaleStep_ = scaleStep; }
double getScaleStep() const { return scaleStep_; }
void setScaleThresh(int scaleThresh) { scaleThresh_ = scaleThresh; }
int getScaleThresh() const { return scaleThresh_; }
void setPosThresh(int posThresh) { posThresh_ = posThresh; }
int getPosThresh() const { return posThresh_; }
private:
void processTempl();
void processImage();
double xi_;
int levels_;
double angleEpsilon_;
double minAngle_;
double maxAngle_;
double angleStep_;
int angleThresh_;
double minScale_;
double maxScale_;
double scaleStep_;
int scaleThresh_;
int posThresh_;
struct Feature
{
GpuMat p1_pos;
GpuMat p1_theta;
GpuMat p2_pos;
GpuMat d12;
GpuMat r1;
GpuMat r2;
GpuMat sizes;
int maxSize;
void create(int levels, int maxCapacity, bool isTempl);
};
typedef void (*set_func_t)(PtrStepb p1_pos, PtrStepb p1_theta, PtrStepb p2_pos, PtrStepb d12, PtrStepb r1, PtrStepb r2);
typedef void (*build_func_t)(const unsigned int* coordList, const float* thetaList, int pointsCount,
int* sizes, int maxSize,
float xi, float angleEpsilon, int levels,
float2 center, float maxDist);
void buildFeatureList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Feature& features,
set_func_t set_func, build_func_t build_func, bool isTempl, Point2d center = Point2d());
void calcOrientation();
void calcScale(double angle);
void calcPosition(double angle, int angleVotes, double scale, int scaleVotes);
Feature templFeatures_;
Feature imageFeatures_;
std::vector< std::pair<double, int> > angles_;
std::vector< std::pair<double, int> > scales_;
GpuMat hist_;
std::vector<int> h_buf_;
};
GeneralizedHoughGuilImpl::GeneralizedHoughGuilImpl()
{
maxBufferSize_ = 1000;
xi_ = 90.0;
levels_ = 360;
angleEpsilon_ = 1.0;
minAngle_ = 0.0;
maxAngle_ = 360.0;
angleStep_ = 1.0;
angleThresh_ = 15000;
minScale_ = 0.5;
maxScale_ = 2.0;
scaleStep_ = 0.05;
scaleThresh_ = 1000;
posThresh_ = 100;
}
void GeneralizedHoughGuilImpl::processTempl()
{
using namespace cv::cuda::device::ght;
buildFeatureList(templEdges_, templDx_, templDy_, templFeatures_,
Guil_Full_setTemplFeatures, Guil_Full_buildTemplFeatureList_gpu,
true, templCenter_);
h_buf_.resize(templFeatures_.sizes.cols);
cudaSafeCall( cudaMemcpy(&h_buf_[0], templFeatures_.sizes.data, h_buf_.size() * sizeof(int), cudaMemcpyDeviceToHost) );
templFeatures_.maxSize = *std::max_element(h_buf_.begin(), h_buf_.end());
}
void GeneralizedHoughGuilImpl::processImage()
{
using namespace cv::cuda::device::ght;
CV_Assert( levels_ > 0 );
CV_Assert( templFeatures_.sizes.cols == levels_ + 1 );
CV_Assert( minAngle_ >= 0.0 && minAngle_ < maxAngle_ && maxAngle_ <= 360.0 );
CV_Assert( angleStep_ > 0.0 && angleStep_ < 360.0 );
CV_Assert( angleThresh_ > 0 );
CV_Assert( minScale_ > 0.0 && minScale_ < maxScale_ );
CV_Assert( scaleStep_ > 0.0 );
CV_Assert( scaleThresh_ > 0 );
CV_Assert( dp_ > 0.0 );
CV_Assert( posThresh_ > 0 );
const double iAngleStep = 1.0 / angleStep_;
const int angleRange = cvCeil((maxAngle_ - minAngle_) * iAngleStep);
const double iScaleStep = 1.0 / scaleStep_;
const int scaleRange = cvCeil((maxScale_ - minScale_) * iScaleStep);
const double idp = 1.0 / dp_;
const int histRows = cvCeil(imageSize_.height * idp);
const int histCols = cvCeil(imageSize_.width * idp);
ensureSizeIsEnough(histRows + 2, std::max(angleRange + 1, std::max(scaleRange + 1, histCols + 2)), CV_32SC1, hist_);
h_buf_.resize(std::max(angleRange + 1, scaleRange + 1));
ensureSizeIsEnough(2, maxBufferSize_, CV_32FC4, outBuf_);
buildFeatureList(imageEdges_, imageDx_, imageDy_, imageFeatures_,
Guil_Full_setImageFeatures, Guil_Full_buildImageFeatureList_gpu,
false);
calcOrientation();
for (size_t i = 0; i < angles_.size(); ++i)
{
const double angle = angles_[i].first;
const int angleVotes = angles_[i].second;
calcScale(angle);
for (size_t j = 0; j < scales_.size(); ++j)
{
const double scale = scales_[j].first;
const int scaleVotes = scales_[j].second;
calcPosition(angle, angleVotes, scale, scaleVotes);
}
}
}
void GeneralizedHoughGuilImpl::Feature::create(int levels, int maxCapacity, bool isTempl)
{
if (!isTempl)
{
ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, p1_pos);
ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, p2_pos);
}
ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC1, p1_theta);
ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC1, d12);
if (isTempl)
{
ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, r1);
ensureSizeIsEnough(levels + 1, maxCapacity, CV_32FC2, r2);
}
ensureSizeIsEnough(1, levels + 1, CV_32SC1, sizes);
sizes.setTo(Scalar::all(0));
maxSize = 0;
}
void GeneralizedHoughGuilImpl::buildFeatureList(const GpuMat& edges, const GpuMat& dx, const GpuMat& dy, Feature& features,
set_func_t set_func, build_func_t build_func, bool isTempl, Point2d center)
{
CV_Assert( levels_ > 0 );
const double maxDist = sqrt((double) templSize_.width * templSize_.width + templSize_.height * templSize_.height) * maxScale_;
features.create(levels_, maxBufferSize_, isTempl);
set_func(features.p1_pos, features.p1_theta, features.p2_pos, features.d12, features.r1, features.r2);
buildEdgePointList(edges, dx, dy);
if (edgePointList_.cols > 0)
{
build_func(edgePointList_.ptr<unsigned int>(0), edgePointList_.ptr<float>(1), edgePointList_.cols,
features.sizes.ptr<int>(), maxBufferSize_, (float)xi_, (float)angleEpsilon_, levels_, make_float2((float)center.x, (float)center.y), (float)maxDist);
}
}
void GeneralizedHoughGuilImpl::calcOrientation()
{
using namespace cv::cuda::device::ght;
const double iAngleStep = 1.0 / angleStep_;
const int angleRange = cvCeil((maxAngle_ - minAngle_) * iAngleStep);
hist_.setTo(Scalar::all(0));
Guil_Full_calcOHist_gpu(templFeatures_.sizes.ptr<int>(), imageFeatures_.sizes.ptr<int>(0), hist_.ptr<int>(),
(float)minAngle_, (float)maxAngle_, (float)angleStep_, angleRange, levels_, templFeatures_.maxSize);
cudaSafeCall( cudaMemcpy(&h_buf_[0], hist_.data, h_buf_.size() * sizeof(int), cudaMemcpyDeviceToHost) );
angles_.clear();
for (int n = 0; n < angleRange; ++n)
{
if (h_buf_[n] >= angleThresh_)
{
const double angle = minAngle_ + n * angleStep_;
angles_.push_back(std::make_pair(angle, h_buf_[n]));
}
}
}
void GeneralizedHoughGuilImpl::calcScale(double angle)
{
using namespace cv::cuda::device::ght;
const double iScaleStep = 1.0 / scaleStep_;
const int scaleRange = cvCeil((maxScale_ - minScale_) * iScaleStep);
hist_.setTo(Scalar::all(0));
Guil_Full_calcSHist_gpu(templFeatures_.sizes.ptr<int>(), imageFeatures_.sizes.ptr<int>(0), hist_.ptr<int>(),
(float)angle, (float)angleEpsilon_, (float)minScale_, (float)maxScale_,
(float)iScaleStep, scaleRange, levels_, templFeatures_.maxSize);
cudaSafeCall( cudaMemcpy(&h_buf_[0], hist_.data, h_buf_.size() * sizeof(int), cudaMemcpyDeviceToHost) );
scales_.clear();
for (int s = 0; s < scaleRange; ++s)
{
if (h_buf_[s] >= scaleThresh_)
{
const double scale = minScale_ + s * scaleStep_;
scales_.push_back(std::make_pair(scale, h_buf_[s]));
}
}
}
void GeneralizedHoughGuilImpl::calcPosition(double angle, int angleVotes, double scale, int scaleVotes)
{
using namespace cv::cuda::device::ght;
hist_.setTo(Scalar::all(0));
Guil_Full_calcPHist_gpu(templFeatures_.sizes.ptr<int>(), imageFeatures_.sizes.ptr<int>(0), hist_,
(float)angle, (float)angleEpsilon_, (float)scale, (float)dp_, levels_, templFeatures_.maxSize);
posCount_ = Guil_Full_findPosInHist_gpu(hist_, outBuf_.ptr<float4>(0), outBuf_.ptr<int3>(1),
posCount_, maxBufferSize_, (float)angle, angleVotes,
(float)scale, scaleVotes, (float)dp_, posThresh_);
}
}
Ptr<GeneralizedHoughGuil> cv::cuda::createGeneralizedHoughGuil()
{
return makePtr<GeneralizedHoughGuilImpl>();
}
#endif /* !defined (HAVE_CUDA) */
+718
View File
@@ -0,0 +1,718 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
void cv::cuda::calcHist(InputArray, OutputArray, Stream&) { throw_no_cuda(); }
void cv::cuda::calcHist(InputArray, InputArray, OutputArray, Stream&) { throw_no_cuda(); }
void cv::cuda::equalizeHist(InputArray, OutputArray, Stream&) { throw_no_cuda(); }
cv::Ptr<cv::cuda::CLAHE> cv::cuda::createCLAHE(double, cv::Size) { throw_no_cuda(); return cv::Ptr<cv::cuda::CLAHE>(); }
void cv::cuda::evenLevels(OutputArray, int, int, int, Stream&) { throw_no_cuda(); }
void cv::cuda::histEven(InputArray, OutputArray, int, int, int, Stream&) { throw_no_cuda(); }
void cv::cuda::histEven(InputArray, GpuMat*, int*, int*, int*, Stream&) { throw_no_cuda(); }
void cv::cuda::histRange(InputArray, OutputArray, InputArray, Stream&) { throw_no_cuda(); }
void cv::cuda::histRange(InputArray, GpuMat*, const GpuMat*, Stream&) { throw_no_cuda(); }
#else /* !defined (HAVE_CUDA) */
#include <opencv2/core/utils/logger.hpp>
////////////////////////////////////////////////////////////////////////
// calcHist
namespace hist
{
void histogram256(PtrStepSzb src, int* hist, const int offsetX, cudaStream_t stream);
void histogram256(PtrStepSzb src, PtrStepSzb mask, int* hist, const int offsetX, cudaStream_t stream);
}
void cv::cuda::calcHist(InputArray _src, OutputArray _hist, Stream& stream)
{
calcHist(_src, cv::cuda::GpuMat(), _hist, stream);
}
void cv::cuda::calcHist(InputArray _src, InputArray _mask, OutputArray _hist, Stream& stream)
{
GpuMat src = _src.getGpuMat();
GpuMat mask = _mask.getGpuMat();
CV_Assert( src.type() == CV_8UC1 );
CV_Assert( mask.empty() || mask.type() == CV_8UC1 );
CV_Assert( mask.empty() || mask.size() == src.size() );
_hist.create(1, 256, CV_32SC1);
GpuMat hist = _hist.getGpuMat();
hist.setTo(Scalar::all(0), stream);
Point ofs; Size wholeSize;
src.locateROI(wholeSize, ofs);
if (mask.empty())
hist::histogram256(src, hist.ptr<int>(), ofs.x, StreamAccessor::getStream(stream));
else
hist::histogram256(src, mask, hist.ptr<int>(), ofs.x, StreamAccessor::getStream(stream));
}
////////////////////////////////////////////////////////////////////////
// equalizeHist
namespace hist
{
void equalizeHist(PtrStepSzb src, PtrStepSzb dst, const uchar* lut, cudaStream_t stream);
void buildLut(PtrStepSzi hist, PtrStepSzb lut, int size, cudaStream_t stream);
}
void cv::cuda::equalizeHist(InputArray _src, OutputArray _dst, Stream& _stream)
{
GpuMat src = getInputMat(_src, _stream);
CV_Assert( src.type() == CV_8UC1 );
_dst.create(src.size(), src.type());
GpuMat dst = _dst.getGpuMat();
size_t bufSize = 256 * sizeof(int) + 256 * sizeof(uchar);
BufferPool pool(_stream);
GpuMat buf = pool.getBuffer(1, static_cast<int>(bufSize), CV_8UC1);
GpuMat hist(1, 256, CV_32SC1, buf.data);
GpuMat lut(1, 256, CV_8UC1, buf.data + 256 * sizeof(int));
cuda::calcHist(src, hist, _stream);
cudaStream_t stream = StreamAccessor::getStream(_stream);
hist::buildLut(hist, lut, src.rows * src.cols, stream);
hist::equalizeHist(src, dst, lut.data, stream);
}
////////////////////////////////////////////////////////////////////////
// CLAHE
namespace clahe
{
void calcLut_8U(PtrStepSzb src, PtrStepb lut, int tilesX, int tilesY, int2 tileSize, int clipLimit, float lutScale, cudaStream_t stream);
void calcLut_16U(PtrStepSzus src, PtrStepus lut, int tilesX, int tilesY, int2 tileSize, int clipLimit, float lutScale, PtrStepSzi hist, cudaStream_t stream);
template <typename T> void transform(PtrStepSz<T> src, PtrStepSz<T> dst, PtrStep<T> lut, int tilesX, int tilesY, int2 tileSize, cudaStream_t stream);
}
namespace
{
class CLAHE_Impl : public cv::cuda::CLAHE
{
public:
CLAHE_Impl(double clipLimit = 40.0, int tilesX = 8, int tilesY = 8);
void apply(cv::InputArray src, cv::OutputArray dst);
void apply(InputArray src, OutputArray dst, Stream& stream);
void setClipLimit(double clipLimit);
double getClipLimit() const;
void setTilesGridSize(cv::Size tileGridSize);
cv::Size getTilesGridSize() const;
void collectGarbage();
void setBitShift(int) override
{
CV_LOG_WARNING(NULL, "CUDA implementation of CLAHE algorithm does not support bit shift option");
};
int getBitShift() const override
{
CV_LOG_WARNING(NULL, "CUDA implementation of CLAHE algorithm does not support bit shift option");
return 0;
}
private:
double clipLimit_;
int tilesX_;
int tilesY_;
GpuMat srcExt_;
GpuMat lut_;
GpuMat hist_; // histogram on global memory for CV_16UC1 case
};
CLAHE_Impl::CLAHE_Impl(double clipLimit, int tilesX, int tilesY) :
clipLimit_(clipLimit), tilesX_(tilesX), tilesY_(tilesY)
{
}
void CLAHE_Impl::apply(cv::InputArray _src, cv::OutputArray _dst)
{
apply(_src, _dst, Stream::Null());
}
void CLAHE_Impl::apply(InputArray _src, OutputArray _dst, Stream& s)
{
GpuMat src = _src.getGpuMat();
const int type = src.type();
CV_Assert( type == CV_8UC1 || type == CV_16UC1 );
_dst.create( src.size(), type );
GpuMat dst = _dst.getGpuMat();
const int histSize = type == CV_8UC1 ? 256 : 65536;
ensureSizeIsEnough(tilesX_ * tilesY_, histSize, type, lut_);
cudaStream_t stream = StreamAccessor::getStream(s);
cv::Size tileSize;
GpuMat srcForLut;
if (src.cols % tilesX_ == 0 && src.rows % tilesY_ == 0)
{
tileSize = cv::Size(src.cols / tilesX_, src.rows / tilesY_);
srcForLut = src;
}
else
{
#ifndef HAVE_OPENCV_CUDAARITHM
throw_no_cuda();
#else
cv::cuda::copyMakeBorder(src, srcExt_, 0, tilesY_ - (src.rows % tilesY_), 0, tilesX_ - (src.cols % tilesX_), cv::BORDER_REFLECT_101, cv::Scalar(), s);
#endif
tileSize = cv::Size(srcExt_.cols / tilesX_, srcExt_.rows / tilesY_);
srcForLut = srcExt_;
}
const int tileSizeTotal = tileSize.area();
const float lutScale = static_cast<float>(histSize - 1) / tileSizeTotal;
int clipLimit = 0;
if (clipLimit_ > 0.0)
{
clipLimit = static_cast<int>(clipLimit_ * tileSizeTotal / histSize);
clipLimit = std::max(clipLimit, 1);
}
if (type == CV_8UC1)
clahe::calcLut_8U(srcForLut, lut_, tilesX_, tilesY_, make_int2(tileSize.width, tileSize.height), clipLimit, lutScale, stream);
else // type == CV_16UC1
{
ensureSizeIsEnough(tilesX_ * tilesY_, histSize, CV_32SC1, hist_);
clahe::calcLut_16U(srcForLut, lut_, tilesX_, tilesY_, make_int2(tileSize.width, tileSize.height), clipLimit, lutScale, hist_, stream);
}
if (type == CV_8UC1)
clahe::transform<uchar>(src, dst, lut_, tilesX_, tilesY_, make_int2(tileSize.width, tileSize.height), stream);
else // type == CV_16UC1
clahe::transform<ushort>(src, dst, lut_, tilesX_, tilesY_, make_int2(tileSize.width, tileSize.height), stream);
}
void CLAHE_Impl::setClipLimit(double clipLimit)
{
clipLimit_ = clipLimit;
}
double CLAHE_Impl::getClipLimit() const
{
return clipLimit_;
}
void CLAHE_Impl::setTilesGridSize(cv::Size tileGridSize)
{
tilesX_ = tileGridSize.width;
tilesY_ = tileGridSize.height;
}
cv::Size CLAHE_Impl::getTilesGridSize() const
{
return cv::Size(tilesX_, tilesY_);
}
void CLAHE_Impl::collectGarbage()
{
srcExt_.release();
lut_.release();
}
}
cv::Ptr<cv::cuda::CLAHE> cv::cuda::createCLAHE(double clipLimit, cv::Size tileGridSize)
{
return makePtr<CLAHE_Impl>(clipLimit, tileGridSize.width, tileGridSize.height);
}
////////////////////////////////////////////////////////////////////////
// NPP Histogram
namespace
{
#if (NPP_VERSION >= 12205)
typedef NppStatus(*get_buf_size_c1_t)(NppiSize oSizeROI, int nLevels, size_t* hpBufferSize, NppStreamContext ctx);
typedef NppStatus(*get_buf_size_c4_t)(NppiSize oSizeROI, int nLevels[], size_t* hpBufferSize, NppStreamContext ctx);
#else
typedef NppStatus(*get_buf_size_c1_t)(NppiSize oSizeROI, int nLevels, int* hpBufferSize);
typedef NppStatus(*get_buf_size_c4_t)(NppiSize oSizeROI, int nLevels[], int* hpBufferSize);
#endif
template<int SDEPTH> struct NppHistogramEvenFuncC1
{
typedef typename NPPTypeTraits<SDEPTH>::npp_type src_t;
#if USE_NPP_STREAM_CTX
typedef NppStatus(*func_ptr)(const src_t* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s* pHist,
int nLevels, Npp32s nLowerLevel, Npp32s nUpperLevel, Npp8u* pBuffer, NppStreamContext ctx);
#else
typedef NppStatus (*func_ptr)(const src_t* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s * pHist,
int nLevels, Npp32s nLowerLevel, Npp32s nUpperLevel, Npp8u * pBuffer);
#endif
};
template<int SDEPTH> struct NppHistogramEvenFuncC4
{
typedef typename NPPTypeTraits<SDEPTH>::npp_type src_t;
#if USE_NPP_STREAM_CTX
typedef NppStatus(*func_ptr)(const src_t* pSrc, int nSrcStep, NppiSize oSizeROI,
Npp32s* pHist[4], int nLevels[4], Npp32s nLowerLevel[4], Npp32s nUpperLevel[4], Npp8u* pBuffer, NppStreamContext ctx);
#else
typedef NppStatus (*func_ptr)(const src_t* pSrc, int nSrcStep, NppiSize oSizeROI,
Npp32s * pHist[4], int nLevels[4], Npp32s nLowerLevel[4], Npp32s nUpperLevel[4], Npp8u * pBuffer);
#endif
};
template<int SDEPTH, typename NppHistogramEvenFuncC1<SDEPTH>::func_ptr func, get_buf_size_c1_t get_buf_size>
struct NppHistogramEvenC1
{
typedef typename NppHistogramEvenFuncC1<SDEPTH>::src_t src_t;
static void hist(const GpuMat& src, OutputArray _hist, int histSize, int lowerLevel, int upperLevel, Stream& stream)
{
const int levels = histSize + 1;
_hist.create(1, histSize, CV_32S);
GpuMat hist = _hist.getGpuMat();
NppiSize sz;
sz.width = src.cols;
sz.height = src.rows;
NppStreamHandler h(stream);
#if (NPP_VERSION >= 12205)
size_t buf_size;
get_buf_size(sz, levels, &buf_size, h);
#else
int buf_size;
get_buf_size(sz, levels, &buf_size);
#endif
BufferPool pool(stream);
CV_Assert(buf_size <= std::numeric_limits<int>::max());
GpuMat buf = pool.getBuffer(1, static_cast<int>(buf_size), CV_8UC1);
#if USE_NPP_STREAM_CTX
nppSafeCall(func(src.ptr<src_t>(), static_cast<int>(src.step), sz, hist.ptr<Npp32s>(), levels,
lowerLevel, upperLevel, buf.ptr<Npp8u>(), h));
#else
nppSafeCall( func(src.ptr<src_t>(), static_cast<int>(src.step), sz, hist.ptr<Npp32s>(), levels,
lowerLevel, upperLevel, buf.ptr<Npp8u>()) );
#endif
if (!stream)
cudaSafeCall( cudaDeviceSynchronize() );
}
};
template<int SDEPTH, typename NppHistogramEvenFuncC4<SDEPTH>::func_ptr func, get_buf_size_c4_t get_buf_size>
struct NppHistogramEvenC4
{
typedef typename NppHistogramEvenFuncC4<SDEPTH>::src_t src_t;
static void hist(const GpuMat& src, GpuMat hist[4], int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream)
{
int levels[] = {histSize[0] + 1, histSize[1] + 1, histSize[2] + 1, histSize[3] + 1};
hist[0].create(1, histSize[0], CV_32S);
hist[1].create(1, histSize[1], CV_32S);
hist[2].create(1, histSize[2], CV_32S);
hist[3].create(1, histSize[3], CV_32S);
NppiSize sz;
sz.width = src.cols;
sz.height = src.rows;
Npp32s* pHist[] = {hist[0].ptr<Npp32s>(), hist[1].ptr<Npp32s>(), hist[2].ptr<Npp32s>(), hist[3].ptr<Npp32s>()};
NppStreamHandler h(stream);
#if (NPP_VERSION >= 12205)
size_t buf_size;
get_buf_size(sz, levels, &buf_size, h);
#else
int buf_size;
get_buf_size(sz, levels, &buf_size);
#endif
BufferPool pool(stream);
CV_Assert(buf_size <= std::numeric_limits<int>::max());
GpuMat buf = pool.getBuffer(1, static_cast<int>(buf_size), CV_8UC1);
#if USE_NPP_STREAM_CTX
nppSafeCall( func(src.ptr<src_t>(), static_cast<int>(src.step), sz, pHist, levels, lowerLevel, upperLevel, buf.ptr<Npp8u>(), h));
#else
nppSafeCall(func(src.ptr<src_t>(), static_cast<int>(src.step), sz, pHist, levels, lowerLevel, upperLevel, buf.ptr<Npp8u>()));
#endif
if (!stream)
cudaSafeCall( cudaDeviceSynchronize() );
}
};
template<int SDEPTH> struct NppHistogramRangeFuncC1
{
typedef typename NPPTypeTraits<SDEPTH>::npp_type src_t;
typedef Npp32s level_t;
enum {LEVEL_TYPE_CODE=CV_32SC1};
#if USE_NPP_STREAM_CTX
typedef NppStatus(*func_ptr)(const src_t* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s* pHist,
const Npp32s* pLevels, int nLevels, Npp8u* pBuffer, NppStreamContext ctx);
#else
typedef NppStatus (*func_ptr)(const src_t* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s* pHist,
const Npp32s* pLevels, int nLevels, Npp8u* pBuffer);
#endif
};
template<> struct NppHistogramRangeFuncC1<CV_32F>
{
typedef Npp32f src_t;
typedef Npp32f level_t;
enum {LEVEL_TYPE_CODE=CV_32FC1};
#if USE_NPP_STREAM_CTX
typedef NppStatus(*func_ptr)(const Npp32f* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s* pHist,
const Npp32f* pLevels, int nLevels, Npp8u* pBuffer, NppStreamContext ctx);
#else
typedef NppStatus (*func_ptr)(const Npp32f* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s* pHist,
const Npp32f* pLevels, int nLevels, Npp8u* pBuffer);
#endif
};
template<int SDEPTH> struct NppHistogramRangeFuncC4
{
typedef typename NPPTypeTraits<SDEPTH>::npp_type src_t;
typedef Npp32s level_t;
enum {LEVEL_TYPE_CODE=CV_32SC1};
#if USE_NPP_STREAM_CTX
typedef NppStatus(*func_ptr)(const src_t* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s* pHist[4],
const Npp32s* pLevels[4], int nLevels[4], Npp8u* pBuffer, NppStreamContext ctx);
#else
typedef NppStatus (*func_ptr)(const src_t* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s* pHist[4],
const Npp32s* pLevels[4], int nLevels[4], Npp8u* pBuffer);
#endif
};
template<> struct NppHistogramRangeFuncC4<CV_32F>
{
typedef Npp32f src_t;
typedef Npp32f level_t;
enum {LEVEL_TYPE_CODE=CV_32FC1};
#if USE_NPP_STREAM_CTX
typedef NppStatus(*func_ptr)(const Npp32f* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s* pHist[4],
const Npp32f* pLevels[4], int nLevels[4], Npp8u* pBuffer, NppStreamContext ctx);
#else
typedef NppStatus (*func_ptr)(const Npp32f* pSrc, int nSrcStep, NppiSize oSizeROI, Npp32s* pHist[4],
const Npp32f* pLevels[4], int nLevels[4], Npp8u* pBuffer);
#endif
};
template<int SDEPTH, typename NppHistogramRangeFuncC1<SDEPTH>::func_ptr func, get_buf_size_c1_t get_buf_size>
struct NppHistogramRangeC1
{
typedef typename NppHistogramRangeFuncC1<SDEPTH>::src_t src_t;
typedef typename NppHistogramRangeFuncC1<SDEPTH>::level_t level_t;
enum {LEVEL_TYPE_CODE=NppHistogramRangeFuncC1<SDEPTH>::LEVEL_TYPE_CODE};
static void hist(const GpuMat& src, OutputArray _hist, const GpuMat& levels, Stream& stream)
{
CV_Assert( levels.type() == LEVEL_TYPE_CODE && levels.rows == 1 );
_hist.create(1, levels.cols - 1, CV_32S);
GpuMat hist = _hist.getGpuMat();
NppiSize sz;
sz.width = src.cols;
sz.height = src.rows;
NppStreamHandler h(stream);
#if (NPP_VERSION >= 12205)
size_t buf_size;
get_buf_size(sz, levels.cols, &buf_size, h);
#else
int buf_size;
get_buf_size(sz, levels.cols, &buf_size);
#endif
BufferPool pool(stream);
CV_Assert(buf_size <= std::numeric_limits<int>::max());
GpuMat buf = pool.getBuffer(1, static_cast<int>(buf_size), CV_8UC1);
#if USE_NPP_STREAM_CTX
nppSafeCall(func(src.ptr<src_t>(), static_cast<int>(src.step), sz, hist.ptr<Npp32s>(), levels.ptr<level_t>(), levels.cols, buf.ptr<Npp8u>(), h));
#else
nppSafeCall( func(src.ptr<src_t>(), static_cast<int>(src.step), sz, hist.ptr<Npp32s>(), levels.ptr<level_t>(), levels.cols, buf.ptr<Npp8u>()) );
#endif
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
};
template<int SDEPTH, typename NppHistogramRangeFuncC4<SDEPTH>::func_ptr func, get_buf_size_c4_t get_buf_size>
struct NppHistogramRangeC4
{
typedef typename NppHistogramRangeFuncC4<SDEPTH>::src_t src_t;
typedef typename NppHistogramRangeFuncC1<SDEPTH>::level_t level_t;
enum {LEVEL_TYPE_CODE=NppHistogramRangeFuncC1<SDEPTH>::LEVEL_TYPE_CODE};
static void hist(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], Stream& stream)
{
CV_Assert( levels[0].type() == LEVEL_TYPE_CODE && levels[0].rows == 1 );
CV_Assert( levels[1].type() == LEVEL_TYPE_CODE && levels[1].rows == 1 );
CV_Assert( levels[2].type() == LEVEL_TYPE_CODE && levels[2].rows == 1 );
CV_Assert( levels[3].type() == LEVEL_TYPE_CODE && levels[3].rows == 1 );
hist[0].create(1, levels[0].cols - 1, CV_32S);
hist[1].create(1, levels[1].cols - 1, CV_32S);
hist[2].create(1, levels[2].cols - 1, CV_32S);
hist[3].create(1, levels[3].cols - 1, CV_32S);
Npp32s* pHist[] = {hist[0].ptr<Npp32s>(), hist[1].ptr<Npp32s>(), hist[2].ptr<Npp32s>(), hist[3].ptr<Npp32s>()};
int nLevels[] = {levels[0].cols, levels[1].cols, levels[2].cols, levels[3].cols};
const level_t* pLevels[] = {levels[0].ptr<level_t>(), levels[1].ptr<level_t>(), levels[2].ptr<level_t>(), levels[3].ptr<level_t>()};
NppiSize sz;
sz.width = src.cols;
sz.height = src.rows;
NppStreamHandler h(stream);
#if (NPP_VERSION >= 12205)
size_t buf_size;
get_buf_size(sz, nLevels, &buf_size, h);
#else
int buf_size;
get_buf_size(sz, nLevels, &buf_size);
#endif
BufferPool pool(stream);
CV_Assert(buf_size <= std::numeric_limits<int>::max());
GpuMat buf = pool.getBuffer(1, static_cast<int>(buf_size), CV_8UC1);
#if USE_NPP_STREAM_CTX
nppSafeCall(func(src.ptr<src_t>(), static_cast<int>(src.step), sz, pHist, pLevels, nLevels, buf.ptr<Npp8u>(), h));
#else
nppSafeCall( func(src.ptr<src_t>(), static_cast<int>(src.step), sz, pHist, pLevels, nLevels, buf.ptr<Npp8u>()) );
#endif
if (stream == 0)
cudaSafeCall( cudaDeviceSynchronize() );
}
};
}
void cv::cuda::evenLevels(OutputArray _levels, int nLevels, int lowerLevel, int upperLevel, Stream& stream)
{
const int kind = _levels.kind();
_levels.create(1, nLevels, CV_32SC1);
Mat host_levels;
if (kind == _InputArray::CUDA_GPU_MAT)
host_levels.create(1, nLevels, CV_32SC1);
else
host_levels = _levels.getMat();
nppSafeCall( nppiEvenLevelsHost_32s(host_levels.ptr<Npp32s>(), nLevels, lowerLevel, upperLevel) );
if (kind == _InputArray::CUDA_GPU_MAT)
_levels.getGpuMatRef().upload(host_levels, stream);
}
namespace hist
{
void histEven8u(PtrStepSzb src, int* hist, int binCount, int lowerLevel, int upperLevel, const int offsetX, cudaStream_t stream);
}
namespace
{
void histEven8u(const GpuMat& src, GpuMat& hist, int histSize, int lowerLevel, int upperLevel, cudaStream_t stream)
{
Point ofs; Size wholeSize;
src.locateROI(wholeSize, ofs);
hist.create(1, histSize, CV_32S);
cudaSafeCall( cudaMemsetAsync(hist.data, 0, histSize * sizeof(int), stream) );
hist::histEven8u(src, hist.ptr<int>(), histSize, lowerLevel, upperLevel, ofs.x, stream);
}
}
void cv::cuda::histEven(InputArray _src, OutputArray hist, int histSize, int lowerLevel, int upperLevel, Stream& stream)
{
typedef void (*hist_t)(const GpuMat& src, OutputArray hist, int levels, int lowerLevel, int upperLevel, Stream& stream);
static const hist_t hist_callers[] =
{
#if USE_NPP_STREAM_CTX
NppHistogramEvenC1<CV_8U , nppiHistogramEven_8u_C1R_Ctx , nppiHistogramEvenGetBufferSize_8u_C1R_Ctx >::hist,
0,
NppHistogramEvenC1<CV_16U, nppiHistogramEven_16u_C1R_Ctx, nppiHistogramEvenGetBufferSize_16u_C1R_Ctx>::hist,
NppHistogramEvenC1<CV_16S, nppiHistogramEven_16s_C1R_Ctx, nppiHistogramEvenGetBufferSize_16s_C1R_Ctx>::hist
#else
NppHistogramEvenC1<CV_8U , nppiHistogramEven_8u_C1R , nppiHistogramEvenGetBufferSize_8u_C1R >::hist,
0,
NppHistogramEvenC1<CV_16U, nppiHistogramEven_16u_C1R, nppiHistogramEvenGetBufferSize_16u_C1R>::hist,
NppHistogramEvenC1<CV_16S, nppiHistogramEven_16s_C1R, nppiHistogramEvenGetBufferSize_16s_C1R>::hist
#endif
};
GpuMat src = _src.getGpuMat();
if (src.depth() == CV_8U && deviceSupports(FEATURE_SET_COMPUTE_30))
{
histEven8u(src, hist.getGpuMatRef(), histSize, lowerLevel, upperLevel, StreamAccessor::getStream(stream));
return;
}
CV_Assert( src.type() == CV_8UC1 || src.type() == CV_16UC1 || src.type() == CV_16SC1 );
hist_callers[src.depth()](src, hist, histSize, lowerLevel, upperLevel, stream);
}
void cv::cuda::histEven(InputArray _src, GpuMat hist[4], int histSize[4], int lowerLevel[4], int upperLevel[4], Stream& stream)
{
typedef void (*hist_t)(const GpuMat& src, GpuMat hist[4], int levels[4], int lowerLevel[4], int upperLevel[4], Stream& stream);
static const hist_t hist_callers[] =
{
#if USE_NPP_STREAM_CTX
NppHistogramEvenC4<CV_8U , nppiHistogramEven_8u_C4R_Ctx , nppiHistogramEvenGetBufferSize_8u_C4R_Ctx >::hist,
0,
NppHistogramEvenC4<CV_16U, nppiHistogramEven_16u_C4R_Ctx, nppiHistogramEvenGetBufferSize_16u_C4R_Ctx>::hist,
NppHistogramEvenC4<CV_16S, nppiHistogramEven_16s_C4R_Ctx, nppiHistogramEvenGetBufferSize_16s_C4R_Ctx>::hist
#else
NppHistogramEvenC4<CV_8U , nppiHistogramEven_8u_C4R , nppiHistogramEvenGetBufferSize_8u_C4R >::hist,
0,
NppHistogramEvenC4<CV_16U, nppiHistogramEven_16u_C4R, nppiHistogramEvenGetBufferSize_16u_C4R>::hist,
NppHistogramEvenC4<CV_16S, nppiHistogramEven_16s_C4R, nppiHistogramEvenGetBufferSize_16s_C4R>::hist
#endif
};
GpuMat src = _src.getGpuMat();
CV_Assert( src.type() == CV_8UC4 || src.type() == CV_16UC4 || src.type() == CV_16SC4 );
hist_callers[src.depth()](src, hist, histSize, lowerLevel, upperLevel, stream);
}
void cv::cuda::histRange(InputArray _src, OutputArray hist, InputArray _levels, Stream& stream)
{
typedef void (*hist_t)(const GpuMat& src, OutputArray hist, const GpuMat& levels, Stream& stream);
static const hist_t hist_callers[] =
{
#if USE_NPP_STREAM_CTX
NppHistogramRangeC1<CV_8U , nppiHistogramRange_8u_C1R_Ctx , nppiHistogramRangeGetBufferSize_8u_C1R_Ctx >::hist,
0,
NppHistogramRangeC1<CV_16U, nppiHistogramRange_16u_C1R_Ctx, nppiHistogramRangeGetBufferSize_16u_C1R_Ctx>::hist,
NppHistogramRangeC1<CV_16S, nppiHistogramRange_16s_C1R_Ctx, nppiHistogramRangeGetBufferSize_16s_C1R_Ctx>::hist,
0,
NppHistogramRangeC1<CV_32F, nppiHistogramRange_32f_C1R_Ctx, nppiHistogramRangeGetBufferSize_32f_C1R_Ctx>::hist
#else
NppHistogramRangeC1<CV_8U , nppiHistogramRange_8u_C1R , nppiHistogramRangeGetBufferSize_8u_C1R >::hist,
0,
NppHistogramRangeC1<CV_16U, nppiHistogramRange_16u_C1R, nppiHistogramRangeGetBufferSize_16u_C1R>::hist,
NppHistogramRangeC1<CV_16S, nppiHistogramRange_16s_C1R, nppiHistogramRangeGetBufferSize_16s_C1R>::hist,
0,
NppHistogramRangeC1<CV_32F, nppiHistogramRange_32f_C1R, nppiHistogramRangeGetBufferSize_32f_C1R>::hist
#endif
};
GpuMat src = _src.getGpuMat();
GpuMat levels = _levels.getGpuMat();
CV_Assert( src.type() == CV_8UC1 || src.type() == CV_16UC1 || src.type() == CV_16SC1 || src.type() == CV_32FC1 );
hist_callers[src.depth()](src, hist, levels, stream);
}
void cv::cuda::histRange(InputArray _src, GpuMat hist[4], const GpuMat levels[4], Stream& stream)
{
typedef void (*hist_t)(const GpuMat& src, GpuMat hist[4], const GpuMat levels[4], Stream& stream);
static const hist_t hist_callers[] =
{
#if USE_NPP_STREAM_CTX
NppHistogramRangeC4<CV_8U , nppiHistogramRange_8u_C4R_Ctx , nppiHistogramRangeGetBufferSize_8u_C4R_Ctx >::hist,
0,
NppHistogramRangeC4<CV_16U, nppiHistogramRange_16u_C4R_Ctx, nppiHistogramRangeGetBufferSize_16u_C4R_Ctx>::hist,
NppHistogramRangeC4<CV_16S, nppiHistogramRange_16s_C4R_Ctx, nppiHistogramRangeGetBufferSize_16s_C4R_Ctx>::hist,
0,
NppHistogramRangeC4<CV_32F, nppiHistogramRange_32f_C4R_Ctx, nppiHistogramRangeGetBufferSize_32f_C4R_Ctx>::hist
#else
NppHistogramRangeC4<CV_8U , nppiHistogramRange_8u_C4R , nppiHistogramRangeGetBufferSize_8u_C4R >::hist,
0,
NppHistogramRangeC4<CV_16U, nppiHistogramRange_16u_C4R, nppiHistogramRangeGetBufferSize_16u_C4R>::hist,
NppHistogramRangeC4<CV_16S, nppiHistogramRange_16s_C4R, nppiHistogramRangeGetBufferSize_16s_C4R>::hist,
0,
NppHistogramRangeC4<CV_32F, nppiHistogramRange_32f_C4R, nppiHistogramRangeGetBufferSize_32f_C4R>::hist
#endif
};
GpuMat src = _src.getGpuMat();
CV_Assert( src.type() == CV_8UC4 || src.type() == CV_16UC4 || src.type() == CV_16SC4 || src.type() == CV_32FC4 );
hist_callers[src.depth()](src, hist, levels, stream);
}
#endif /* !defined (HAVE_CUDA) */
+329
View File
@@ -0,0 +1,329 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || !defined(HAVE_OPENCV_CUDAFILTERS)
Ptr<cuda::HoughCirclesDetector> cv::cuda::createHoughCirclesDetector(float, float, int, int, int, int, int) { throw_no_cuda(); return Ptr<HoughCirclesDetector>(); }
#else /* !defined (HAVE_CUDA) */
namespace cv { namespace cuda { namespace device
{
namespace hough
{
int buildPointList_gpu(PtrStepSzb src, unsigned int* list, int* counterPtr, cudaStream_t stream);
}
namespace hough_circles
{
void circlesAccumCenters_gpu(const unsigned int* list, int count, PtrStepi dx, PtrStepi dy, PtrStepSzi accum, int minRadius, int maxRadius, float idp, cudaStream_t stream);
int buildCentersList_gpu(PtrStepSzi accum, unsigned int* centers, int threshold, int* counterPtr, cudaStream_t stream);
int circlesAccumRadius_gpu(const unsigned int* centers, int centersCount, const unsigned int* list, int count,
float3* circles, int maxCircles, float dp, int minRadius, int maxRadius, int threshold, bool has20, int* counterPtr, cudaStream_t stream);
}
}}}
namespace
{
class HoughCirclesDetectorImpl : public HoughCirclesDetector
{
public:
HoughCirclesDetectorImpl(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles);
~HoughCirclesDetectorImpl();
void detect(InputArray src, OutputArray circles, Stream& stream);
void setDp(float dp) { dp_ = dp; }
float getDp() const { return dp_; }
void setMinDist(float minDist) { minDist_ = minDist; }
float getMinDist() const { return minDist_; }
void setCannyThreshold(int cannyThreshold) { cannyThreshold_ = cannyThreshold; }
int getCannyThreshold() const { return cannyThreshold_; }
void setVotesThreshold(int votesThreshold) { votesThreshold_ = votesThreshold; }
int getVotesThreshold() const { return votesThreshold_; }
void setMinRadius(int minRadius) { minRadius_ = minRadius; }
int getMinRadius() const { return minRadius_; }
void setMaxRadius(int maxRadius) { maxRadius_ = maxRadius; }
int getMaxRadius() const { return maxRadius_; }
void setMaxCircles(int maxCircles) { maxCircles_ = maxCircles; }
int getMaxCircles() const { return maxCircles_; }
void write(FileStorage& fs) const
{
writeFormat(fs);
fs << "name" << "HoughCirclesDetector_CUDA"
<< "dp" << dp_
<< "minDist" << minDist_
<< "cannyThreshold" << cannyThreshold_
<< "votesThreshold" << votesThreshold_
<< "minRadius" << minRadius_
<< "maxRadius" << maxRadius_
<< "maxCircles" << maxCircles_;
}
void read(const FileNode& fn)
{
CV_Assert( String(fn["name"]) == "HoughCirclesDetector_CUDA" );
dp_ = (float)fn["dp"];
minDist_ = (float)fn["minDist"];
cannyThreshold_ = (int)fn["cannyThreshold"];
votesThreshold_ = (int)fn["votesThreshold"];
minRadius_ = (int)fn["minRadius"];
maxRadius_ = (int)fn["maxRadius"];
maxCircles_ = (int)fn["maxCircles"];
}
private:
float dp_;
float minDist_;
int cannyThreshold_;
int votesThreshold_;
int minRadius_;
int maxRadius_;
int maxCircles_;
GpuMat dx_, dy_;
GpuMat edges_;
GpuMat accum_;
Mat tt; //CPU copy of accum_
GpuMat list_;
GpuMat result_;
Ptr<cuda::Filter> filterDx_;
Ptr<cuda::Filter> filterDy_;
Ptr<cuda::CannyEdgeDetector> canny_;
int* counterPtr_;
};
bool centersCompare(Vec3f a, Vec3f b) {return (a[2] > b[2]);}
HoughCirclesDetectorImpl::HoughCirclesDetectorImpl(float dp, float minDist, int cannyThreshold, int votesThreshold,
int minRadius, int maxRadius, int maxCircles) :
dp_(dp), minDist_(minDist), cannyThreshold_(cannyThreshold), votesThreshold_(votesThreshold),
minRadius_(minRadius), maxRadius_(maxRadius), maxCircles_(maxCircles)
{
canny_ = cuda::createCannyEdgeDetector(std::max(cannyThreshold_ / 2, 1), cannyThreshold_);
filterDx_ = cuda::createSobelFilter(CV_8UC1, CV_32S, 1, 0);
filterDy_ = cuda::createSobelFilter(CV_8UC1, CV_32S, 0, 1);
cudaSafeCall(cudaMalloc(&counterPtr_, sizeof(int)));
}
HoughCirclesDetectorImpl::~HoughCirclesDetectorImpl()
{
cudaSafeCall(cudaFree(counterPtr_));
}
void HoughCirclesDetectorImpl::detect(InputArray _src, OutputArray circles, Stream& stream)
{
using namespace cv::cuda::device::hough;
using namespace cv::cuda::device::hough_circles;
auto cudaStream = StreamAccessor::getStream(stream);
GpuMat src = _src.getGpuMat();
CV_Assert( src.type() == CV_8UC1 );
CV_Assert( src.cols < std::numeric_limits<unsigned short>::max() );
CV_Assert( src.rows < std::numeric_limits<unsigned short>::max() );
CV_Assert( dp_ > 0 );
CV_Assert( minRadius_ > 0 && maxRadius_ > minRadius_ );
CV_Assert( cannyThreshold_ > 0 );
CV_Assert( votesThreshold_ > 0 );
CV_Assert( maxCircles_ > 0 );
const float idp = 1.0f / dp_;
filterDx_->apply(src, dx_);
filterDy_->apply(src, dy_);
canny_->setLowThreshold(std::max(cannyThreshold_ / 2, 1));
canny_->setHighThreshold(cannyThreshold_);
canny_->detect(dx_, dy_, edges_, stream);
ensureSizeIsEnough(2, src.size().area(), CV_32SC1, list_);
unsigned int* srcPoints = list_.ptr<unsigned int>(0);
unsigned int* centers = list_.ptr<unsigned int>(1);
const int pointsCount = buildPointList_gpu(edges_, srcPoints, counterPtr_, cudaStream);
if (pointsCount == 0)
{
circles.release();
return;
}
ensureSizeIsEnough(cvCeil(src.rows * idp) + 2, cvCeil(src.cols * idp) + 2, CV_32SC1, accum_);
accum_.setTo(Scalar::all(0), stream);
circlesAccumCenters_gpu(srcPoints, pointsCount, dx_, dy_, accum_, minRadius_, maxRadius_, idp, cudaStream);
accum_.download(tt, stream);
int centersCount = buildCentersList_gpu(accum_, centers, votesThreshold_, counterPtr_, cudaStream);
if (centersCount == 0)
{
circles.release();
return;
}
if (minDist_ > 1)
{
AutoBuffer<ushort2> oldBuf_(centersCount);
AutoBuffer<ushort2> newBuf_(centersCount);
int newCount = 0;
ushort2* oldBuf = oldBuf_.data();
ushort2* newBuf = newBuf_.data();
cudaSafeCall( cudaMemcpyAsync(oldBuf, centers, centersCount * sizeof(ushort2), cudaMemcpyDeviceToHost, cudaStream) );
cudaSafeCall( cudaStreamSynchronize(cudaStream) );
const int cellSize = cvRound(minDist_);
const int gridWidth = (src.cols + cellSize - 1) / cellSize;
const int gridHeight = (src.rows + cellSize - 1) / cellSize;
std::vector< std::vector<ushort2> > grid(gridWidth * gridHeight);
const float minDist2 = minDist_ * minDist_;
std::vector<Vec3f> sortBuf;
for(int i=0; i<centersCount; i++){
Vec3f temp;
temp[0] = oldBuf[i].x;
temp[1] = oldBuf[i].y;
temp[2] = tt.at<int>(temp[1]+1, temp[0]+1);
sortBuf.push_back(temp);
}
std::sort(sortBuf.begin(), sortBuf.end(), centersCompare);
for (int i = 0; i < centersCount; ++i)
{
ushort2 p;
p.x = sortBuf[i][0];
p.y = sortBuf[i][1];
bool good = true;
int xCell = static_cast<int>(p.x / cellSize);
int yCell = static_cast<int>(p.y / cellSize);
int x1 = xCell - 1;
int y1 = yCell - 1;
int x2 = xCell + 1;
int y2 = yCell + 1;
// boundary check
x1 = std::max(0, x1);
y1 = std::max(0, y1);
x2 = std::min(gridWidth - 1, x2);
y2 = std::min(gridHeight - 1, y2);
for (int yy = y1; yy <= y2; ++yy)
{
for (int xx = x1; xx <= x2; ++xx)
{
std::vector<ushort2>& m = grid[yy * gridWidth + xx];
for(size_t j = 0; j < m.size(); ++j)
{
float dx = (float)(p.x - m[j].x);
float dy = (float)(p.y - m[j].y);
if (dx * dx + dy * dy < minDist2)
{
good = false;
goto break_out;
}
}
}
}
break_out:
if(good)
{
grid[yCell * gridWidth + xCell].push_back(p);
newBuf[newCount++] = p;
}
}
cudaSafeCall( cudaMemcpyAsync(centers, newBuf, newCount * sizeof(unsigned int), cudaMemcpyHostToDevice, cudaStream) );
centersCount = newCount;
}
ensureSizeIsEnough(1, maxCircles_, CV_32FC3, result_);
int circlesCount = circlesAccumRadius_gpu(centers, centersCount, srcPoints, pointsCount, result_.ptr<float3>(), maxCircles_,
dp_, minRadius_, maxRadius_, votesThreshold_, deviceSupports(FEATURE_SET_COMPUTE_20),
counterPtr_, cudaStream);
if (circlesCount == 0)
{
circles.release();
return;
}
result_.cols = circlesCount;
result_.copyTo(circles, stream);
}
}
Ptr<HoughCirclesDetector> cv::cuda::createHoughCirclesDetector(float dp, float minDist, int cannyThreshold, int votesThreshold, int minRadius, int maxRadius, int maxCircles)
{
return makePtr<HoughCirclesDetectorImpl>(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius, maxCircles);
}
#endif /* !defined (HAVE_CUDA) */
+221
View File
@@ -0,0 +1,221 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
Ptr<cuda::HoughLinesDetector> cv::cuda::createHoughLinesDetector(float, float, int, bool, int) { throw_no_cuda(); return Ptr<HoughLinesDetector>(); }
#else /* !defined (HAVE_CUDA) */
namespace cv { namespace cuda { namespace device
{
namespace hough
{
int buildPointList_gpu(PtrStepSzb src, unsigned int* list, int* counterPtr, cudaStream_t stream);
}
namespace hough_lines
{
void linesAccum_gpu(const unsigned int* list, int count, PtrStepSzi accum, float rho, float theta, size_t sharedMemPerBlock, bool has20, cudaStream_t stream);
int linesGetResult_gpu(PtrStepSzi accum, float2* out, int* votes, int maxSize, float rho, float theta, int threshold, bool doSort, int* counterPtr, cudaStream_t stream);
}
}}}
namespace
{
class HoughLinesDetectorImpl : public HoughLinesDetector
{
public:
HoughLinesDetectorImpl(float rho, float theta, int threshold, bool doSort, int maxLines);
~HoughLinesDetectorImpl();
void detect(InputArray src, OutputArray lines, Stream& stream);
void downloadResults(InputArray d_lines, OutputArray h_lines, OutputArray h_votes, Stream& stream);
void setRho(float rho) { rho_ = rho; }
float getRho() const { return rho_; }
void setTheta(float theta) { theta_ = theta; }
float getTheta() const { return theta_; }
void setThreshold(int threshold) { threshold_ = threshold; }
int getThreshold() const { return threshold_; }
void setDoSort(bool doSort) { doSort_ = doSort; }
bool getDoSort() const { return doSort_; }
void setMaxLines(int maxLines) { maxLines_ = maxLines; }
int getMaxLines() const { return maxLines_; }
void write(FileStorage& fs) const
{
writeFormat(fs);
fs << "name" << "HoughLinesDetector_CUDA"
<< "rho" << rho_
<< "theta" << theta_
<< "threshold" << threshold_
<< "doSort" << doSort_
<< "maxLines" << maxLines_;
}
void read(const FileNode& fn)
{
CV_Assert( String(fn["name"]) == "HoughLinesDetector_CUDA" );
rho_ = (float)fn["rho"];
theta_ = (float)fn["theta"];
threshold_ = (int)fn["threshold"];
doSort_ = (int)fn["doSort"] != 0;
maxLines_ = (int)fn["maxLines"];
}
private:
float rho_;
float theta_;
int threshold_;
bool doSort_;
int maxLines_;
GpuMat accum_;
GpuMat list_;
GpuMat result_;
int* counterPtr_;
};
HoughLinesDetectorImpl::HoughLinesDetectorImpl(float rho, float theta, int threshold, bool doSort, int maxLines) :
rho_(rho), theta_(theta), threshold_(threshold), doSort_(doSort), maxLines_(maxLines)
{
cudaSafeCall(cudaMalloc(&counterPtr_, sizeof(int)));
}
HoughLinesDetectorImpl::~HoughLinesDetectorImpl()
{
cudaSafeCall(cudaFree(counterPtr_));
}
void HoughLinesDetectorImpl::detect(InputArray _src, OutputArray lines, Stream& stream)
{
using namespace cv::cuda::device::hough;
using namespace cv::cuda::device::hough_lines;
auto cudaStream = StreamAccessor::getStream(stream);
GpuMat src = _src.getGpuMat();
CV_Assert( src.type() == CV_8UC1 );
CV_Assert( src.cols < std::numeric_limits<unsigned short>::max() );
CV_Assert( src.rows < std::numeric_limits<unsigned short>::max() );
ensureSizeIsEnough(1, src.size().area(), CV_32SC1, list_);
unsigned int* srcPoints = list_.ptr<unsigned int>();
const int pointsCount = buildPointList_gpu(src, srcPoints, counterPtr_, cudaStream);
if (pointsCount == 0)
{
lines.release();
return;
}
const int numangle = cvRound(CV_PI / theta_);
const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho_);
CV_Assert( numangle > 0 && numrho > 0 );
ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum_);
accum_.setTo(Scalar::all(0), stream);
DeviceInfo devInfo;
linesAccum_gpu(srcPoints, pointsCount, accum_, rho_, theta_, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20), cudaStream);
ensureSizeIsEnough(2, maxLines_, CV_32FC2, result_);
int linesCount = linesGetResult_gpu(accum_, result_.ptr<float2>(0), result_.ptr<int>(1), maxLines_, rho_, theta_, threshold_, doSort_, counterPtr_, cudaStream);
if (linesCount == 0)
{
lines.release();
return;
}
result_.cols = linesCount;
result_.copyTo(lines, stream);
}
void HoughLinesDetectorImpl::downloadResults(InputArray _d_lines, OutputArray h_lines, OutputArray h_votes, Stream& stream)
{
GpuMat d_lines = _d_lines.getGpuMat();
if (d_lines.empty())
{
h_lines.release();
if (h_votes.needed())
h_votes.release();
return;
}
CV_Assert( d_lines.rows == 2 && d_lines.type() == CV_32FC2 );
if (stream)
d_lines.row(0).download(h_lines, stream);
else
d_lines.row(0).download(h_lines);
if (h_votes.needed())
{
GpuMat d_votes(1, d_lines.cols, CV_32SC1, d_lines.ptr<int>(1));
if (stream)
d_votes.download(h_votes, stream);
else
d_votes.download(h_votes);
}
}
}
Ptr<HoughLinesDetector> cv::cuda::createHoughLinesDetector(float rho, float theta, int threshold, bool doSort, int maxLines)
{
return makePtr<HoughLinesDetectorImpl>(rho, theta, threshold, doSort, maxLines);
}
#endif /* !defined (HAVE_CUDA) */
+205
View File
@@ -0,0 +1,205 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
Ptr<cuda::HoughSegmentDetector> cv::cuda::createHoughSegmentDetector(float, float, int, int, int, int) { throw_no_cuda(); return Ptr<HoughSegmentDetector>(); }
#else /* !defined (HAVE_CUDA) */
namespace cv { namespace cuda { namespace device
{
namespace hough
{
int buildPointList_gpu(PtrStepSzb src, unsigned int* list, int* counterPtr, cudaStream_t stream);
}
namespace hough_lines
{
void linesAccum_gpu(const unsigned int* list, int count, PtrStepSzi accum, float rho, float theta, size_t sharedMemPerBlock, bool has20, cudaStream_t stream);
}
namespace hough_segments
{
int houghLinesProbabilistic_gpu(GpuMat &mask, PtrStepSzi accum, int4* out, int maxSize, float rho, float theta, int lineGap, int lineLength, int threshold, int* counterPtr, cudaStream_t stream);
}
}}}
namespace
{
class HoughSegmentDetectorImpl : public HoughSegmentDetector
{
public:
HoughSegmentDetectorImpl(float rho, float theta, int minLineLength, int maxLineGap, int maxLines, int threshold);
~HoughSegmentDetectorImpl();
void detect(InputArray src, OutputArray lines, Stream& stream);
void setRho(float rho) { rho_ = rho; }
float getRho() const { return rho_; }
void setTheta(float theta) { theta_ = theta; }
float getTheta() const { return theta_; }
void setMinLineLength(int minLineLength) { minLineLength_ = minLineLength; }
int getMinLineLength() const { return minLineLength_; }
void setMaxLineGap(int maxLineGap) { maxLineGap_ = maxLineGap; }
int getMaxLineGap() const { return maxLineGap_; }
void setMaxLines(int maxLines) { maxLines_ = maxLines; }
int getMaxLines() const { return maxLines_; }
void setThreshold(int threshold) { threshold_ = threshold; }
int getThreshold() const { return threshold_; }
void write(FileStorage& fs) const
{
writeFormat(fs);
fs << "name" << "PHoughLinesDetector_CUDA"
<< "rho" << rho_
<< "theta" << theta_
<< "minLineLength" << minLineLength_
<< "maxLineGap" << maxLineGap_
<< "maxLines" << maxLines_
<< "threshold" << threshold_;
}
void read(const FileNode& fn)
{
CV_Assert( String(fn["name"]) == "PHoughLinesDetector_CUDA" );
rho_ = (float)fn["rho"];
theta_ = (float)fn["theta"];
minLineLength_ = (int)fn["minLineLength"];
maxLineGap_ = (int)fn["maxLineGap"];
maxLines_ = (int)fn["maxLines"];
threshold_ = (int)fn["threshold"];
}
private:
float rho_;
float theta_;
int minLineLength_;
int maxLineGap_;
int maxLines_;
int threshold_;
GpuMat accum_;
GpuMat list_;
GpuMat result_;
int* counterPtr_;
};
HoughSegmentDetectorImpl::HoughSegmentDetectorImpl(float rho, float theta, int minLineLength, int maxLineGap, int maxLines, int threshold) :
rho_(rho), theta_(theta), minLineLength_(minLineLength), maxLineGap_(maxLineGap), maxLines_(maxLines), threshold_(threshold)
{
cudaSafeCall(cudaMalloc(&counterPtr_, sizeof(int)));
}
HoughSegmentDetectorImpl::~HoughSegmentDetectorImpl()
{
cudaSafeCall(cudaFree(counterPtr_));
}
void HoughSegmentDetectorImpl::detect(InputArray _src, OutputArray lines, Stream& stream)
{
// TODO : implement async version
CV_UNUSED(stream);
using namespace cv::cuda::device::hough;
using namespace cv::cuda::device::hough_lines;
using namespace cv::cuda::device::hough_segments;
auto cudaStream = StreamAccessor::getStream(stream);
GpuMat src = _src.getGpuMat();
CV_Assert( src.type() == CV_8UC1 );
CV_Assert( src.cols < std::numeric_limits<unsigned short>::max() );
CV_Assert( src.rows < std::numeric_limits<unsigned short>::max() );
ensureSizeIsEnough(1, src.size().area(), CV_32SC1, list_);
unsigned int* srcPoints = list_.ptr<unsigned int>();
const int pointsCount = buildPointList_gpu(src, srcPoints, counterPtr_, cudaStream);
if (pointsCount == 0)
{
lines.release();
return;
}
const int numangle = cvRound(CV_PI / theta_);
const int numrho = cvRound(((src.cols + src.rows) * 2 + 1) / rho_);
CV_Assert( numangle > 0 && numrho > 0 );
ensureSizeIsEnough(numangle + 2, numrho + 2, CV_32SC1, accum_);
accum_.setTo(Scalar::all(0), stream);
DeviceInfo devInfo;
linesAccum_gpu(srcPoints, pointsCount, accum_, rho_, theta_, devInfo.sharedMemPerBlock(), devInfo.supports(FEATURE_SET_COMPUTE_20), cudaStream);
ensureSizeIsEnough(1, maxLines_, CV_32SC4, result_);
int linesCount = houghLinesProbabilistic_gpu(src, accum_, result_.ptr<int4>(), maxLines_, rho_, theta_, maxLineGap_, minLineLength_, threshold_, counterPtr_, cudaStream);
if (linesCount == 0)
{
lines.release();
return;
}
result_.cols = linesCount;
result_.copyTo(lines, stream);
}
}
Ptr<HoughSegmentDetector> cv::cuda::createHoughSegmentDetector(float rho, float theta, int minLineLength, int maxLineGap, int maxLines, int threshold)
{
return makePtr<HoughSegmentDetectorImpl>(rho, theta, minLineLength, maxLineGap, maxLines, threshold);
}
#endif /* !defined (HAVE_CUDA) */
+644
View File
@@ -0,0 +1,644 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || !defined (HAVE_OPENCV_CUDAARITHM) || defined (CUDA_DISABLER)
Ptr<cuda::TemplateMatching> cv::cuda::createTemplateMatching(int, int, Size) { throw_no_cuda(); return Ptr<cuda::TemplateMatching>(); }
#else
namespace cv { namespace cuda { namespace device
{
namespace match_template
{
void matchTemplateNaive_CCORR_8U(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, int cn, cudaStream_t stream);
void matchTemplateNaive_CCORR_32F(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, int cn, cudaStream_t stream);
void matchTemplateNaive_SQDIFF_8U(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, int cn, cudaStream_t stream);
void matchTemplateNaive_SQDIFF_32F(const PtrStepSzb image, const PtrStepSzb templ, PtrStepSzf result, int cn, cudaStream_t stream);
void matchTemplatePrepared_SQDIFF_8U(int w, int h, const PtrStepSz<double> image_sqsum, double templ_sqsum, PtrStepSzf result,
int cn, cudaStream_t stream);
void matchTemplatePrepared_SQDIFF_NORMED_8U(int w, int h, const PtrStepSz<double> image_sqsum, double templ_sqsum, PtrStepSzf result,
int cn, cudaStream_t stream);
void matchTemplatePrepared_CCOFF_8U(int w, int h, const PtrStepSz<int> image_sum, int templ_sum, PtrStepSzf result, cudaStream_t stream);
void matchTemplatePrepared_CCOFF_8UC2(
int w, int h,
const PtrStepSz<int> image_sum_r,
const PtrStepSz<int> image_sum_g,
int templ_sum_r,
int templ_sum_g,
PtrStepSzf result, cudaStream_t stream);
void matchTemplatePrepared_CCOFF_8UC3(
int w, int h,
const PtrStepSz<int> image_sum_r,
const PtrStepSz<int> image_sum_g,
const PtrStepSz<int> image_sum_b,
int templ_sum_r,
int templ_sum_g,
int templ_sum_b,
PtrStepSzf result, cudaStream_t stream);
void matchTemplatePrepared_CCOFF_8UC4(
int w, int h,
const PtrStepSz<int> image_sum_r,
const PtrStepSz<int> image_sum_g,
const PtrStepSz<int> image_sum_b,
const PtrStepSz<int> image_sum_a,
int templ_sum_r,
int templ_sum_g,
int templ_sum_b,
int templ_sum_a,
PtrStepSzf result, cudaStream_t stream);
void matchTemplatePrepared_CCOFF_NORMED_8U(
int w, int h, const PtrStepSz<int> image_sum,
const PtrStepSz<double> image_sqsum,
int templ_sum, double templ_sqsum,
PtrStepSzf result, cudaStream_t stream);
void matchTemplatePrepared_CCOFF_NORMED_8UC2(
int w, int h,
const PtrStepSz<int> image_sum_r, const PtrStepSz<double> image_sqsum_r,
const PtrStepSz<int> image_sum_g, const PtrStepSz<double> image_sqsum_g,
int templ_sum_r, double templ_sqsum_r,
int templ_sum_g, double templ_sqsum_g,
PtrStepSzf result, cudaStream_t stream);
void matchTemplatePrepared_CCOFF_NORMED_8UC3(
int w, int h,
const PtrStepSz<int> image_sum_r, const PtrStepSz<double> image_sqsum_r,
const PtrStepSz<int> image_sum_g, const PtrStepSz<double> image_sqsum_g,
const PtrStepSz<int> image_sum_b, const PtrStepSz<double> image_sqsum_b,
int templ_sum_r, double templ_sqsum_r,
int templ_sum_g, double templ_sqsum_g,
int templ_sum_b, double templ_sqsum_b,
PtrStepSzf result, cudaStream_t stream);
void matchTemplatePrepared_CCOFF_NORMED_8UC4(
int w, int h,
const PtrStepSz<int> image_sum_r, const PtrStepSz<double> image_sqsum_r,
const PtrStepSz<int> image_sum_g, const PtrStepSz<double> image_sqsum_g,
const PtrStepSz<int> image_sum_b, const PtrStepSz<double> image_sqsum_b,
const PtrStepSz<int> image_sum_a, const PtrStepSz<double> image_sqsum_a,
int templ_sum_r, double templ_sqsum_r,
int templ_sum_g, double templ_sqsum_g,
int templ_sum_b, double templ_sqsum_b,
int templ_sum_a, double templ_sqsum_a,
PtrStepSzf result, cudaStream_t stream);
void normalize_8U(int w, int h, const PtrStepSz<double> image_sqsum,
double templ_sqsum, PtrStepSzf result, int cn, cudaStream_t stream);
void extractFirstChannel_32F(const PtrStepSzb image, PtrStepSzf result, int cn, cudaStream_t stream);
}
}}}
namespace
{
// Evaluates optimal template's area threshold. If
// template's area is less than the threshold, we use naive match
// template version, otherwise FFT-based (if available)
int getTemplateThreshold(int method, int depth)
{
switch (method)
{
case TM_CCORR:
if (depth == CV_32F) return 250;
if (depth == CV_8U) return 300;
break;
case TM_SQDIFF:
if (depth == CV_8U) return 300;
break;
}
CV_Error(Error::StsBadArg, "unsupported match template mode");
return 0;
}
///////////////////////////////////////////////////////////////
// CCORR_32F
class Match_CCORR_32F : public TemplateMatching
{
public:
explicit Match_CCORR_32F(Size user_block_size);
void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null());
private:
Ptr<cuda::Convolution> conv_;
GpuMat result_;
};
Match_CCORR_32F::Match_CCORR_32F(Size user_block_size)
{
conv_ = cuda::createConvolution(user_block_size);
}
void Match_CCORR_32F::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& _stream)
{
using namespace cv::cuda::device::match_template;
GpuMat image = _image.getGpuMat();
GpuMat templ = _templ.getGpuMat();
CV_Assert( image.depth() == CV_32F );
CV_Assert( image.type() == templ.type() );
CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows );
cudaStream_t stream = StreamAccessor::getStream(_stream);
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1);
GpuMat result = _result.getGpuMat();
if (templ.size().area() < getTemplateThreshold(TM_CCORR, CV_32F))
{
matchTemplateNaive_CCORR_32F(image, templ, result, image.channels(), stream);
return;
}
if (image.channels() == 1)
{
conv_->convolve(image.reshape(1), templ.reshape(1), result, true, _stream);
}
else
{
conv_->convolve(image.reshape(1), templ.reshape(1), result_, true, _stream);
extractFirstChannel_32F(result_, result, image.channels(), stream);
}
}
///////////////////////////////////////////////////////////////
// CCORR_8U
class Match_CCORR_8U : public TemplateMatching
{
public:
explicit Match_CCORR_8U(Size user_block_size) : match32F_(user_block_size)
{
}
void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null());
private:
GpuMat imagef_, templf_;
Match_CCORR_32F match32F_;
};
void Match_CCORR_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream)
{
using namespace cv::cuda::device::match_template;
GpuMat image = _image.getGpuMat();
GpuMat templ = _templ.getGpuMat();
CV_Assert( image.depth() == CV_8U );
CV_Assert( image.type() == templ.type() );
CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows );
if (templ.size().area() < getTemplateThreshold(TM_CCORR, CV_8U))
{
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1);
GpuMat result = _result.getGpuMat();
matchTemplateNaive_CCORR_8U(image, templ, result, image.channels(), StreamAccessor::getStream(stream));
return;
}
image.convertTo(imagef_, CV_32F, stream);
templ.convertTo(templf_, CV_32F, stream);
match32F_.match(imagef_, templf_, _result, stream);
}
///////////////////////////////////////////////////////////////
// CCORR_NORMED_8U
class Match_CCORR_NORMED_8U : public TemplateMatching
{
public:
explicit Match_CCORR_NORMED_8U(Size user_block_size) : match_CCORR_(user_block_size)
{
}
void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null());
private:
Match_CCORR_8U match_CCORR_;
GpuMat image_sqsums_;
};
void Match_CCORR_NORMED_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream)
{
using namespace cv::cuda::device::match_template;
GpuMat image = _image.getGpuMat();
GpuMat templ = _templ.getGpuMat();
CV_Assert( image.depth() == CV_8U );
CV_Assert( image.type() == templ.type() );
CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows );
match_CCORR_.match(image, templ, _result, stream);
GpuMat result = _result.getGpuMat();
cuda::sqrIntegral(image.reshape(1), image_sqsums_, stream);
double templ_sqsum = cuda::sqrSum(templ.reshape(1))[0];
normalize_8U(templ.cols, templ.rows, image_sqsums_, templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream));
}
///////////////////////////////////////////////////////////////
// SQDIFF_32F
class Match_SQDIFF_32F : public TemplateMatching
{
public:
void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null());
};
void Match_SQDIFF_32F::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream)
{
using namespace cv::cuda::device::match_template;
GpuMat image = _image.getGpuMat();
GpuMat templ = _templ.getGpuMat();
CV_Assert( image.depth() == CV_32F );
CV_Assert( image.type() == templ.type() );
CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows );
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1);
GpuMat result = _result.getGpuMat();
matchTemplateNaive_SQDIFF_32F(image, templ, result, image.channels(), StreamAccessor::getStream(stream));
}
///////////////////////////////////////////////////////////////
// SQDIFF_8U
class Match_SQDIFF_8U : public TemplateMatching
{
public:
explicit Match_SQDIFF_8U(Size user_block_size) : match_CCORR_(user_block_size)
{
}
void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null());
private:
GpuMat image_sqsums_;
Match_CCORR_8U match_CCORR_;
};
void Match_SQDIFF_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream)
{
using namespace cv::cuda::device::match_template;
GpuMat image = _image.getGpuMat();
GpuMat templ = _templ.getGpuMat();
CV_Assert( image.depth() == CV_8U );
CV_Assert( image.type() == templ.type() );
CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows );
if (templ.size().area() < getTemplateThreshold(TM_SQDIFF, CV_8U))
{
_result.create(image.rows - templ.rows + 1, image.cols - templ.cols + 1, CV_32FC1);
GpuMat result = _result.getGpuMat();
matchTemplateNaive_SQDIFF_8U(image, templ, result, image.channels(), StreamAccessor::getStream(stream));
return;
}
cuda::sqrIntegral(image.reshape(1), image_sqsums_, stream);
double templ_sqsum = cuda::sqrSum(templ.reshape(1))[0];
match_CCORR_.match(image, templ, _result, stream);
GpuMat result = _result.getGpuMat();
matchTemplatePrepared_SQDIFF_8U(templ.cols, templ.rows, image_sqsums_, templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream));
}
///////////////////////////////////////////////////////////////
// SQDIFF_NORMED_8U
class Match_SQDIFF_NORMED_8U : public TemplateMatching
{
public:
explicit Match_SQDIFF_NORMED_8U(Size user_block_size) : match_CCORR_(user_block_size)
{
}
void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null());
private:
GpuMat image_sqsums_;
Match_CCORR_8U match_CCORR_;
};
void Match_SQDIFF_NORMED_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream)
{
using namespace cv::cuda::device::match_template;
GpuMat image = _image.getGpuMat();
GpuMat templ = _templ.getGpuMat();
CV_Assert( image.depth() == CV_8U );
CV_Assert( image.type() == templ.type() );
CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows );
cuda::sqrIntegral(image.reshape(1), image_sqsums_, stream);
double templ_sqsum = cuda::sqrSum(templ.reshape(1))[0];
match_CCORR_.match(image, templ, _result, stream);
GpuMat result = _result.getGpuMat();
matchTemplatePrepared_SQDIFF_NORMED_8U(templ.cols, templ.rows, image_sqsums_, templ_sqsum, result, image.channels(), StreamAccessor::getStream(stream));
}
///////////////////////////////////////////////////////////////
// CCOFF_8U
class Match_CCOEFF_8U : public TemplateMatching
{
public:
explicit Match_CCOEFF_8U(Size user_block_size) : match_CCORR_(user_block_size)
{
}
void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null());
private:
std::vector<GpuMat> images_;
std::vector<GpuMat> image_sums_;
Match_CCORR_8U match_CCORR_;
};
void Match_CCOEFF_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream)
{
using namespace cv::cuda::device::match_template;
GpuMat image = _image.getGpuMat();
GpuMat templ = _templ.getGpuMat();
CV_Assert( image.depth() == CV_8U );
CV_Assert( image.type() == templ.type() );
CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows );
match_CCORR_.match(image, templ, _result, stream);
GpuMat result = _result.getGpuMat();
if (image.channels() == 1)
{
image_sums_.resize(1);
cuda::integral(image, image_sums_[0], stream);
int templ_sum = (int) cuda::sum(templ)[0];
matchTemplatePrepared_CCOFF_8U(templ.cols, templ.rows, image_sums_[0], templ_sum, result, StreamAccessor::getStream(stream));
}
else
{
cuda::split(image, images_);
image_sums_.resize(images_.size());
for (int i = 0; i < image.channels(); ++i)
cuda::integral(images_[i], image_sums_[i], stream);
Scalar templ_sum = cuda::sum(templ);
switch (image.channels())
{
case 2:
matchTemplatePrepared_CCOFF_8UC2(
templ.cols, templ.rows, image_sums_[0], image_sums_[1],
(int) templ_sum[0], (int) templ_sum[1],
result, StreamAccessor::getStream(stream));
break;
case 3:
matchTemplatePrepared_CCOFF_8UC3(
templ.cols, templ.rows, image_sums_[0], image_sums_[1], image_sums_[2],
(int) templ_sum[0], (int) templ_sum[1], (int) templ_sum[2],
result, StreamAccessor::getStream(stream));
break;
case 4:
matchTemplatePrepared_CCOFF_8UC4(
templ.cols, templ.rows, image_sums_[0], image_sums_[1], image_sums_[2], image_sums_[3],
(int) templ_sum[0], (int) templ_sum[1], (int) templ_sum[2], (int) templ_sum[3],
result, StreamAccessor::getStream(stream));
break;
default:
CV_Error(Error::StsBadArg, "unsupported number of channels");
}
}
}
///////////////////////////////////////////////////////////////
// CCOFF_NORMED_8U
class Match_CCOEFF_NORMED_8U : public TemplateMatching
{
public:
explicit Match_CCOEFF_NORMED_8U(Size user_block_size) : match_CCORR_32F_(user_block_size)
{
}
void match(InputArray image, InputArray templ, OutputArray result, Stream& stream = Stream::Null());
private:
GpuMat imagef_, templf_;
Match_CCORR_32F match_CCORR_32F_;
std::vector<GpuMat> images_;
std::vector<GpuMat> image_sums_;
std::vector<GpuMat> image_sqsums_;
};
void Match_CCOEFF_NORMED_8U::match(InputArray _image, InputArray _templ, OutputArray _result, Stream& stream)
{
using namespace cv::cuda::device::match_template;
GpuMat image = _image.getGpuMat();
GpuMat templ = _templ.getGpuMat();
CV_Assert( image.depth() == CV_8U );
CV_Assert( image.type() == templ.type() );
CV_Assert( image.cols >= templ.cols && image.rows >= templ.rows );
image.convertTo(imagef_, CV_32F, stream);
templ.convertTo(templf_, CV_32F, stream);
match_CCORR_32F_.match(imagef_, templf_, _result, stream);
GpuMat result = _result.getGpuMat();
if (image.channels() == 1)
{
image_sums_.resize(1);
cuda::integral(image, image_sums_[0], stream);
image_sqsums_.resize(1);
cuda::sqrIntegral(image, image_sqsums_[0], stream);
int templ_sum = (int) cuda::sum(templ)[0];
double templ_sqsum = cuda::sqrSum(templ)[0];
matchTemplatePrepared_CCOFF_NORMED_8U(
templ.cols, templ.rows, image_sums_[0], image_sqsums_[0],
templ_sum, templ_sqsum, result, StreamAccessor::getStream(stream));
}
else
{
cuda::split(image, images_);
image_sums_.resize(images_.size());
image_sqsums_.resize(images_.size());
for (int i = 0; i < image.channels(); ++i)
{
cuda::integral(images_[i], image_sums_[i], stream);
cuda::sqrIntegral(images_[i], image_sqsums_[i], stream);
}
Scalar templ_sum = cuda::sum(templ);
Scalar templ_sqsum = cuda::sqrSum(templ);
switch (image.channels())
{
case 2:
matchTemplatePrepared_CCOFF_NORMED_8UC2(
templ.cols, templ.rows,
image_sums_[0], image_sqsums_[0],
image_sums_[1], image_sqsums_[1],
(int)templ_sum[0], templ_sqsum[0],
(int)templ_sum[1], templ_sqsum[1],
result, StreamAccessor::getStream(stream));
break;
case 3:
matchTemplatePrepared_CCOFF_NORMED_8UC3(
templ.cols, templ.rows,
image_sums_[0], image_sqsums_[0],
image_sums_[1], image_sqsums_[1],
image_sums_[2], image_sqsums_[2],
(int)templ_sum[0], templ_sqsum[0],
(int)templ_sum[1], templ_sqsum[1],
(int)templ_sum[2], templ_sqsum[2],
result, StreamAccessor::getStream(stream));
break;
case 4:
matchTemplatePrepared_CCOFF_NORMED_8UC4(
templ.cols, templ.rows,
image_sums_[0], image_sqsums_[0],
image_sums_[1], image_sqsums_[1],
image_sums_[2], image_sqsums_[2],
image_sums_[3], image_sqsums_[3],
(int)templ_sum[0], templ_sqsum[0],
(int)templ_sum[1], templ_sqsum[1],
(int)templ_sum[2], templ_sqsum[2],
(int)templ_sum[3], templ_sqsum[3],
result, StreamAccessor::getStream(stream));
break;
default:
CV_Error(Error::StsBadArg, "unsupported number of channels");
}
}
}
}
Ptr<cuda::TemplateMatching> cv::cuda::createTemplateMatching(int srcType, int method, Size user_block_size)
{
const int sdepth = CV_MAT_DEPTH(srcType);
CV_Assert( sdepth == CV_8U || sdepth == CV_32F );
if (sdepth == CV_32F)
{
switch (method)
{
case TM_SQDIFF:
return makePtr<Match_SQDIFF_32F>();
case TM_CCORR:
return makePtr<Match_CCORR_32F>(user_block_size);
default:
CV_Error( Error::StsBadFlag, "Unsopported method" );
return Ptr<cuda::TemplateMatching>();
}
}
else
{
switch (method)
{
case TM_SQDIFF:
return makePtr<Match_SQDIFF_8U>(user_block_size);
case TM_SQDIFF_NORMED:
return makePtr<Match_SQDIFF_NORMED_8U>(user_block_size);
case TM_CCORR:
return makePtr<Match_CCORR_8U>(user_block_size);
case TM_CCORR_NORMED:
return makePtr<Match_CCORR_NORMED_8U>(user_block_size);
case TM_CCOEFF:
return makePtr<Match_CCOEFF_8U>(user_block_size);
case TM_CCOEFF_NORMED:
return makePtr<Match_CCOEFF_NORMED_8U>(user_block_size);
default:
CV_Error( Error::StsBadFlag, "Unsopported method" );
return Ptr<cuda::TemplateMatching>();
}
}
}
#endif
+128
View File
@@ -0,0 +1,128 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
void cv::cuda::meanShiftFiltering(InputArray, OutputArray, int, int, TermCriteria, Stream&) { throw_no_cuda(); }
void cv::cuda::meanShiftProc(InputArray, OutputArray, OutputArray, int, int, TermCriteria, Stream&) { throw_no_cuda(); }
#else /* !defined (HAVE_CUDA) */
////////////////////////////////////////////////////////////////////////
// meanShiftFiltering
namespace cv { namespace cuda { namespace device
{
namespace imgproc
{
void meanShiftFiltering_gpu(const PtrStepSzb& src, PtrStepSzb dst, int sp, int sr, int maxIter, float eps, cudaStream_t stream);
}
}}}
void cv::cuda::meanShiftFiltering(InputArray _src, OutputArray _dst, int sp, int sr, TermCriteria criteria, Stream& stream)
{
using namespace ::cv::cuda::device::imgproc;
GpuMat src = _src.getGpuMat();
CV_Assert( src.type() == CV_8UC4 );
_dst.create(src.size(), CV_8UC4);
GpuMat dst = _dst.getGpuMat();
if (!(criteria.type & TermCriteria::MAX_ITER))
criteria.maxCount = 5;
int maxIter = std::min(std::max(criteria.maxCount, 1), 100);
if (!(criteria.type & TermCriteria::EPS))
criteria.epsilon = 1.f;
float eps = (float) std::max(criteria.epsilon, 0.0);
meanShiftFiltering_gpu(src, dst, sp, sr, maxIter, eps, StreamAccessor::getStream(stream));
}
////////////////////////////////////////////////////////////////////////
// meanShiftProc_CUDA
namespace cv { namespace cuda { namespace device
{
namespace imgproc
{
void meanShiftProc_gpu(const PtrStepSzb& src, PtrStepSzb dstr, PtrStepSzb dstsp, int sp, int sr, int maxIter, float eps, cudaStream_t stream);
}
}}}
void cv::cuda::meanShiftProc(InputArray _src, OutputArray _dstr, OutputArray _dstsp, int sp, int sr, TermCriteria criteria, Stream& stream)
{
using namespace ::cv::cuda::device::imgproc;
GpuMat src = _src.getGpuMat();
CV_Assert( src.type() == CV_8UC4 );
_dstr.create(src.size(), CV_8UC4);
_dstsp.create(src.size(), CV_16SC2);
GpuMat dstr = _dstr.getGpuMat();
GpuMat dstsp = _dstsp.getGpuMat();
if (!(criteria.type & TermCriteria::MAX_ITER))
criteria.maxCount = 5;
int maxIter = std::min(std::max(criteria.maxCount, 1), 100);
if (!(criteria.type & TermCriteria::EPS))
criteria.epsilon = 1.f;
float eps = (float) std::max(criteria.epsilon, 0.0);
meanShiftProc_gpu(src, dstr, dstsp, sp, sr, maxIter, eps, StreamAccessor::getStream(stream));
}
#endif /* !defined (HAVE_CUDA) */
+85
View File
@@ -0,0 +1,85 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
using namespace cv;
using namespace cv::cuda;
template<typename T>
cv::Moments convertSpatialMomentsT(Mat spatialMoments, const MomentsOrder order) {
switch (order) {
case MomentsOrder::FIRST_ORDER_MOMENTS:
return Moments(spatialMoments.at<T>(0), spatialMoments.at<T>(1), spatialMoments.at<T>(2), 0, 0, 0, 0, 0, 0, 0);
case MomentsOrder::SECOND_ORDER_MOMENTS:
return Moments(spatialMoments.at<T>(0), spatialMoments.at<T>(1), spatialMoments.at<T>(2), spatialMoments.at<T>(3), spatialMoments.at<T>(4), spatialMoments.at<T>(5), 0, 0, 0, 0);
default:
return Moments(spatialMoments.at<T>(0), spatialMoments.at<T>(1), spatialMoments.at<T>(2), spatialMoments.at<T>(3), spatialMoments.at<T>(4), spatialMoments.at<T>(5), spatialMoments.at<T>(6), spatialMoments.at<T>(7), spatialMoments.at<T>(8), spatialMoments.at<T>(9));
}
}
cv::Moments cv::cuda::convertSpatialMoments(Mat spatialMoments, const MomentsOrder order, const int momentsType) {
if (momentsType == CV_32F)
return convertSpatialMomentsT<float>(spatialMoments, order);
else
return convertSpatialMomentsT<double>(spatialMoments, order);
}
#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
int cv::cuda::numMoments(MomentsOrder) { throw_no_cuda(); return 0; }
Moments cv::cuda::moments(InputArray src, const bool binary, const MomentsOrder order, const int momentsType) { throw_no_cuda(); }
void cv::cuda::spatialMoments(InputArray src, OutputArray moments, const bool binary, const MomentsOrder order, const int momentsType, Stream& stream) { throw_no_cuda(); }
#else /* !defined (HAVE_CUDA) */
#include "cuda/moments.cuh"
int cv::cuda::numMoments(const MomentsOrder order) {
return order == MomentsOrder::FIRST_ORDER_MOMENTS ? device::imgproc::n1 : order == MomentsOrder::SECOND_ORDER_MOMENTS ? device::imgproc::n12 : device::imgproc::n123;
}
namespace cv { namespace cuda { namespace device { namespace imgproc {
template <typename TSrc, typename TMoments>
void moments(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
}}}}
void cv::cuda::spatialMoments(InputArray src, OutputArray moments, const bool binary, const MomentsOrder order, const int momentsType, Stream& stream) {
CV_Assert(src.depth() <= CV_64F);
const GpuMat srcDevice = getInputMat(src, stream);
CV_Assert(momentsType == CV_32F || momentsType == CV_64F);
const int nMoments = numMoments(order);
const int momentsCols = nMoments < moments.cols() ? moments.cols() : nMoments;
GpuMat momentsDevice = getOutputMat(moments, 1, momentsCols, momentsType, stream);
momentsDevice.setTo(0);
Point ofs; Size wholeSize;
srcDevice.locateROI(wholeSize, ofs);
typedef void (*func_t)(const PtrStepSzb src, PtrStepSzb moments, const bool binary, const int order, const int offsetX, const cudaStream_t stream);
static const func_t funcs[7][2] =
{
{device::imgproc::moments<uchar, float>, device::imgproc::moments<uchar, double> },
{device::imgproc::moments<schar, float>, device::imgproc::moments<schar, double> },
{device::imgproc::moments<ushort, float>, device::imgproc::moments<ushort, double>},
{device::imgproc::moments<short, float>, device::imgproc::moments<short, double> },
{device::imgproc::moments<int, float>, device::imgproc::moments<int, double> },
{device::imgproc::moments<float, float>, device::imgproc::moments<float, double> },
{device::imgproc::moments<double, float>, device::imgproc::moments<double, double> }
};
const func_t func = funcs[srcDevice.depth()][momentsType == CV_64F];
func(srcDevice, momentsDevice, binary, static_cast<int>(order), ofs.x, StreamAccessor::getStream(stream));
syncOutput(momentsDevice, moments, stream);
}
Moments cv::cuda::moments(InputArray src, const bool binary, const MomentsOrder order, const int momentsType) {
Stream stream;
HostMem dst;
spatialMoments(src, dst, binary, order, momentsType, stream);
stream.waitForCompletion();
Mat moments = dst.createMatHeader();
return convertSpatialMoments(moments, order, momentsType);
}
#endif /* !defined (HAVE_CUDA) */
+402
View File
@@ -0,0 +1,402 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
#if !defined HAVE_CUDA || defined(CUDA_DISABLER)
void cv::cuda::meanShiftSegmentation(InputArray, OutputArray, int, int, int, TermCriteria, Stream&) { throw_no_cuda(); }
#else
// Auxiliray stuff
namespace
{
//
// Declarations
//
class DjSets
{
public:
DjSets(int n);
int find(int elem);
int merge(int set1, int set2);
std::vector<int> parent;
std::vector<int> rank;
std::vector<int> size;
private:
DjSets(const DjSets&);
void operator =(const DjSets&);
};
template <typename T>
struct GraphEdge
{
GraphEdge() {}
GraphEdge(int to_, int next_, const T& val_) : to(to_), next(next_), val(val_) {}
int to;
int next;
T val;
};
template <typename T>
class Graph
{
public:
typedef GraphEdge<T> Edge;
Graph(int numv, int nume_max);
void addEdge(int from, int to, const T& val=T());
std::vector<int> start;
std::vector<Edge> edges;
int numv;
int nume_max;
int nume;
private:
Graph(const Graph&);
void operator =(const Graph&);
};
struct SegmLinkVal
{
SegmLinkVal() {}
SegmLinkVal(int dr_, int dsp_) : dr(dr_), dsp(dsp_) {}
bool operator <(const SegmLinkVal& other) const
{
return dr + dsp < other.dr + other.dsp;
}
int dr;
int dsp;
};
struct SegmLink
{
SegmLink() {}
SegmLink(int from_, int to_, const SegmLinkVal& val_)
: from(from_), to(to_), val(val_) {}
bool operator <(const SegmLink& other) const
{
return val < other.val;
}
int from;
int to;
SegmLinkVal val;
};
//
// Implementation
//
DjSets::DjSets(int n) : parent(n), rank(n, 0), size(n, 1)
{
for (int i = 0; i < n; ++i)
parent[i] = i;
}
inline int DjSets::find(int elem)
{
int set = elem;
while (set != parent[set])
set = parent[set];
while (elem != parent[elem])
{
int next = parent[elem];
parent[elem] = set;
elem = next;
}
return set;
}
inline int DjSets::merge(int set1, int set2)
{
if (rank[set1] < rank[set2])
{
parent[set1] = set2;
size[set2] += size[set1];
return set2;
}
if (rank[set2] < rank[set1])
{
parent[set2] = set1;
size[set1] += size[set2];
return set1;
}
parent[set1] = set2;
rank[set2]++;
size[set2] += size[set1];
return set2;
}
template <typename T>
Graph<T>::Graph(int numv_, int nume_max_) : start(numv_, -1), edges(nume_max_)
{
this->numv = numv_;
this->nume_max = nume_max_;
nume = 0;
}
template <typename T>
inline void Graph<T>::addEdge(int from, int to, const T& val)
{
edges[nume] = Edge(to, start[from], val);
start[from] = nume;
nume++;
}
inline int pix(int y, int x, int ncols)
{
return y * ncols + x;
}
inline int sqr(int x)
{
return x * x;
}
inline int dist2(const cv::Vec4b& lhs, const cv::Vec4b& rhs)
{
return sqr(lhs[0] - rhs[0]) + sqr(lhs[1] - rhs[1]) + sqr(lhs[2] - rhs[2]);
}
inline int dist2(const cv::Vec2s& lhs, const cv::Vec2s& rhs)
{
return sqr(lhs[0] - rhs[0]) + sqr(lhs[1] - rhs[1]);
}
} // anonymous namespace
void cv::cuda::meanShiftSegmentation(InputArray _src, OutputArray _dst, int sp, int sr, int minsize, TermCriteria criteria, Stream& stream)
{
GpuMat src = _src.getGpuMat();
CV_Assert( src.type() == CV_8UC4 );
const int nrows = src.rows;
const int ncols = src.cols;
const int hr = sr;
const int hsp = sp;
// Perform mean shift procedure and obtain region and spatial maps
GpuMat d_rmap, d_spmap;
cuda::meanShiftProc(src, d_rmap, d_spmap, sp, sr, criteria, stream);
stream.waitForCompletion();
Mat rmap(d_rmap);
Mat spmap(d_spmap);
Graph<SegmLinkVal> g(nrows * ncols, 4 * (nrows - 1) * (ncols - 1)
+ (nrows - 1) + (ncols - 1));
// Make region adjacent graph from image
Vec4b r1;
Vec4b r2[4];
Vec2s sp1;
Vec2s sp2[4];
int dr[4];
int dsp[4];
for (int y = 0; y < nrows - 1; ++y)
{
Vec4b* ry = rmap.ptr<Vec4b>(y);
Vec4b* ryp = rmap.ptr<Vec4b>(y + 1);
Vec2s* spy = spmap.ptr<Vec2s>(y);
Vec2s* spyp = spmap.ptr<Vec2s>(y + 1);
for (int x = 0; x < ncols - 1; ++x)
{
r1 = ry[x];
sp1 = spy[x];
r2[0] = ry[x + 1];
r2[1] = ryp[x];
r2[2] = ryp[x + 1];
r2[3] = ryp[x];
sp2[0] = spy[x + 1];
sp2[1] = spyp[x];
sp2[2] = spyp[x + 1];
sp2[3] = spyp[x];
dr[0] = dist2(r1, r2[0]);
dr[1] = dist2(r1, r2[1]);
dr[2] = dist2(r1, r2[2]);
dsp[0] = dist2(sp1, sp2[0]);
dsp[1] = dist2(sp1, sp2[1]);
dsp[2] = dist2(sp1, sp2[2]);
r1 = ry[x + 1];
sp1 = spy[x + 1];
dr[3] = dist2(r1, r2[3]);
dsp[3] = dist2(sp1, sp2[3]);
g.addEdge(pix(y, x, ncols), pix(y, x + 1, ncols), SegmLinkVal(dr[0], dsp[0]));
g.addEdge(pix(y, x, ncols), pix(y + 1, x, ncols), SegmLinkVal(dr[1], dsp[1]));
g.addEdge(pix(y, x, ncols), pix(y + 1, x + 1, ncols), SegmLinkVal(dr[2], dsp[2]));
g.addEdge(pix(y, x + 1, ncols), pix(y + 1, x, ncols), SegmLinkVal(dr[3], dsp[3]));
}
}
for (int y = 0; y < nrows - 1; ++y)
{
r1 = rmap.at<Vec4b>(y, ncols - 1);
r2[0] = rmap.at<Vec4b>(y + 1, ncols - 1);
sp1 = spmap.at<Vec2s>(y, ncols - 1);
sp2[0] = spmap.at<Vec2s>(y + 1, ncols - 1);
dr[0] = dist2(r1, r2[0]);
dsp[0] = dist2(sp1, sp2[0]);
g.addEdge(pix(y, ncols - 1, ncols), pix(y + 1, ncols - 1, ncols), SegmLinkVal(dr[0], dsp[0]));
}
for (int x = 0; x < ncols - 1; ++x)
{
r1 = rmap.at<Vec4b>(nrows - 1, x);
r2[0] = rmap.at<Vec4b>(nrows - 1, x + 1);
sp1 = spmap.at<Vec2s>(nrows - 1, x);
sp2[0] = spmap.at<Vec2s>(nrows - 1, x + 1);
dr[0] = dist2(r1, r2[0]);
dsp[0] = dist2(sp1, sp2[0]);
g.addEdge(pix(nrows - 1, x, ncols), pix(nrows - 1, x + 1, ncols), SegmLinkVal(dr[0], dsp[0]));
}
DjSets comps(g.numv);
// Find adjacent components
for (int v = 0; v < g.numv; ++v)
{
for (int e_it = g.start[v]; e_it != -1; e_it = g.edges[e_it].next)
{
int c1 = comps.find(v);
int c2 = comps.find(g.edges[e_it].to);
if (c1 != c2 && g.edges[e_it].val.dr < hr && g.edges[e_it].val.dsp < hsp)
comps.merge(c1, c2);
}
}
std::vector<SegmLink> edges;
edges.reserve(g.numv);
// Prepare edges connecting different components
for (int v = 0; v < g.numv; ++v)
{
int c1 = comps.find(v);
for (int e_it = g.start[v]; e_it != -1; e_it = g.edges[e_it].next)
{
int c2 = comps.find(g.edges[e_it].to);
if (c1 != c2)
edges.push_back(SegmLink(c1, c2, g.edges[e_it].val));
}
}
// Sort all graph's edges connecting different components (in ascending order)
std::sort(edges.begin(), edges.end());
// Exclude small components (starting from the nearest couple)
for (size_t i = 0; i < edges.size(); ++i)
{
int c1 = comps.find(edges[i].from);
int c2 = comps.find(edges[i].to);
if (c1 != c2 && (comps.size[c1] < minsize || comps.size[c2] < minsize))
comps.merge(c1, c2);
}
// Compute sum of the pixel's colors which are in the same segment
Mat h_src(src);
std::vector<Vec4i> sumcols(nrows * ncols, Vec4i(0, 0, 0, 0));
for (int y = 0; y < nrows; ++y)
{
Vec4b* h_srcy = h_src.ptr<Vec4b>(y);
for (int x = 0; x < ncols; ++x)
{
int parent = comps.find(pix(y, x, ncols));
Vec4b col = h_srcy[x];
Vec4i& sumcol = sumcols[parent];
sumcol[0] += col[0];
sumcol[1] += col[1];
sumcol[2] += col[2];
}
}
// Create final image, color of each segment is the average color of its pixels
Mat dst(src.size(), src.type());
for (int y = 0; y < nrows; ++y)
{
Vec4b* dsty = dst.ptr<Vec4b>(y);
for (int x = 0; x < ncols; ++x)
{
int parent = comps.find(pix(y, x, ncols));
const Vec4i& sumcol = sumcols[parent];
Vec4b& dstcol = dsty[x];
dstcol[0] = static_cast<uchar>(sumcol[0] / comps.size[parent]);
dstcol[1] = static_cast<uchar>(sumcol[1] / comps.size[parent]);
dstcol[2] = static_cast<uchar>(sumcol[2] / comps.size[parent]);
dstcol[3] = 255;
}
}
if (_dst.kind() == _InputArray::CUDA_GPU_MAT)
{
GpuMat dstGpuMat = getOutputMat(_dst, src.size(), src.type(), stream);
dstGpuMat.upload(dst, stream);
}
else {
dst.copyTo(_dst);
}
}
#endif // #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
+65
View File
@@ -0,0 +1,65 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __OPENCV_PRECOMP_H__
#define __OPENCV_PRECOMP_H__
#include "opencv2/cudaimgproc.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/core/private.hpp"
#include "opencv2/core/private.cuda.hpp"
#include "opencv2/opencv_modules.hpp"
#ifdef HAVE_OPENCV_CUDAARITHM
# include "opencv2/cudaarithm.hpp"
#endif
#ifdef HAVE_OPENCV_CUDAFILTERS
# include "opencv2/cudafilters.hpp"
#endif
#include <limits>
#include <algorithm>
#endif /* __OPENCV_PRECOMP_H__ */
@@ -0,0 +1,98 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#ifdef HAVE_CUDA
namespace opencv_test { namespace {
////////////////////////////////////////////////////////
// BilateralFilter
PARAM_TEST_CASE(BilateralFilter, cv::cuda::DeviceInfo, cv::Size, MatType)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
int type;
int kernel_size;
float sigma_color;
float sigma_spatial;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = GET_PARAM(1);
type = GET_PARAM(2);
kernel_size = 5;
sigma_color = 10.f;
sigma_spatial = 3.5f;
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(BilateralFilter, Accuracy)
{
cv::Mat src = randomMat(size, type);
src.convertTo(src, type);
cv::cuda::GpuMat dst;
cv::cuda::bilateralFilter(loadMat(src), dst, kernel_size, sigma_color, sigma_spatial);
cv::Mat dst_gold;
cv::bilateralFilter(src, dst_gold, kernel_size, sigma_color, sigma_spatial);
EXPECT_MAT_NEAR(dst_gold, dst, src.depth() == CV_32F ? 1e-3 : 1.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, BilateralFilter, testing::Combine(
ALL_DEVICES,
testing::Values(cv::Size(128, 128), cv::Size(113, 113), cv::Size(639, 481)),
testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_32FC1), MatType(CV_32FC3))
));
}} // namespace
#endif // HAVE_CUDA
+126
View File
@@ -0,0 +1,126 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#ifdef HAVE_CUDA
namespace opencv_test { namespace {
////////////////////////////////////////////////////////////////////////////
// Blend
namespace
{
template <typename T>
void blendLinearGold(const cv::Mat& img1, const cv::Mat& img2, const cv::Mat& weights1, const cv::Mat& weights2, cv::Mat& result_gold)
{
result_gold.create(img1.size(), img1.type());
int cn = img1.channels();
for (int y = 0; y < img1.rows; ++y)
{
const float* weights1_row = weights1.ptr<float>(y);
const float* weights2_row = weights2.ptr<float>(y);
const T* img1_row = img1.ptr<T>(y);
const T* img2_row = img2.ptr<T>(y);
T* result_gold_row = result_gold.ptr<T>(y);
for (int x = 0; x < img1.cols * cn; ++x)
{
float w1 = weights1_row[x / cn];
float w2 = weights2_row[x / cn];
result_gold_row[x] = static_cast<T>((img1_row[x] * w1 + img2_row[x] * w2) / (w1 + w2 + 1e-5f));
}
}
}
}
PARAM_TEST_CASE(Blend, cv::cuda::DeviceInfo, cv::Size, MatType, UseRoi)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
int type;
bool useRoi;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = GET_PARAM(1);
type = GET_PARAM(2);
useRoi = GET_PARAM(3);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(Blend, Accuracy)
{
int depth = CV_MAT_DEPTH(type);
cv::Mat img1 = randomMat(size, type, 0.0, depth == CV_8U ? 255.0 : 1.0);
cv::Mat img2 = randomMat(size, type, 0.0, depth == CV_8U ? 255.0 : 1.0);
cv::Mat weights1 = randomMat(size, CV_32F, 0, 1);
cv::Mat weights2 = randomMat(size, CV_32F, 0, 1);
cv::cuda::GpuMat result;
cv::cuda::blendLinear(loadMat(img1, useRoi), loadMat(img2, useRoi), loadMat(weights1, useRoi), loadMat(weights2, useRoi), result);
cv::Mat result_gold;
if (depth == CV_8U)
blendLinearGold<uchar>(img1, img2, weights1, weights2, result_gold);
else
blendLinearGold<float>(img1, img2, weights1, weights2, result_gold);
EXPECT_MAT_NEAR(result_gold, result, CV_MAT_DEPTH(type) == CV_8U ? 1.0 : 1e-5);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, Blend, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES,
testing::Values(MatType(CV_8UC1), MatType(CV_8UC3), MatType(CV_8UC4), MatType(CV_32FC1), MatType(CV_32FC3), MatType(CV_32FC4)),
WHOLE_SUBMAT));
}} // namespace
#endif // HAVE_CUDA
+160
View File
@@ -0,0 +1,160 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#ifdef HAVE_CUDA
namespace opencv_test { namespace {
////////////////////////////////////////////////////////
// Canny
namespace
{
IMPLEMENT_PARAM_CLASS(AppertureSize, int)
IMPLEMENT_PARAM_CLASS(L2gradient, bool)
}
PARAM_TEST_CASE(Canny, cv::cuda::DeviceInfo, AppertureSize, L2gradient, UseRoi)
{
cv::cuda::DeviceInfo devInfo;
int apperture_size;
bool useL2gradient;
bool useRoi;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
apperture_size = GET_PARAM(1);
useL2gradient = GET_PARAM(2);
useRoi = GET_PARAM(3);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(Canny, Accuracy)
{
cv::Mat img = readImage("stereobm/aloe-L.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(img.empty());
double low_thresh = 50.0;
double high_thresh = 100.0;
cv::Ptr<cv::cuda::CannyEdgeDetector> canny = cv::cuda::createCannyEdgeDetector(low_thresh, high_thresh, apperture_size, useL2gradient);
cv::cuda::GpuMat edges;
canny->detect(loadMat(img, useRoi), edges);
cv::Mat edges_gold;
cv::Canny(img, edges_gold, low_thresh, high_thresh, apperture_size, useL2gradient);
EXPECT_MAT_SIMILAR(edges_gold, edges, 2e-2);
}
class CannyAsyncParallelLoopBody : public cv::ParallelLoopBody
{
public:
CannyAsyncParallelLoopBody(const cv::cuda::GpuMat& d_img_, cv::cuda::GpuMat* edges_, double low_thresh_, double high_thresh_, int apperture_size_, bool useL2gradient_)
: d_img(d_img_), edges(edges_), low_thresh(low_thresh_), high_thresh(high_thresh_), apperture_size(apperture_size_), useL2gradient(useL2gradient_) {}
~CannyAsyncParallelLoopBody() {};
void operator()(const cv::Range& r) const
{
for (int i = r.start; i < r.end; i++) {
cv::cuda::Stream stream;
cv::Ptr<cv::cuda::CannyEdgeDetector> canny = cv::cuda::createCannyEdgeDetector(low_thresh, high_thresh, apperture_size, useL2gradient);
canny->detect(d_img, edges[i], stream);
stream.waitForCompletion();
}
}
protected:
const cv::cuda::GpuMat& d_img;
cv::cuda::GpuMat* edges;
double low_thresh;
double high_thresh;
int apperture_size;
bool useL2gradient;
};
#define NUM_STREAMS 128
CUDA_TEST_P(Canny, Async)
{
if (!supportFeature(devInfo, cv::cuda::FEATURE_SET_COMPUTE_30))
{
throw SkipTestException("CUDA device doesn't support texture objects");
}
else
{
const cv::Mat img = readImage("stereobm/aloe-L.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(img.empty());
const cv::cuda::GpuMat d_img_roi = loadMat(img, useRoi);
double low_thresh = 50.0;
double high_thresh = 100.0;
// Synchronous call
cv::Ptr<cv::cuda::CannyEdgeDetector> canny = cv::cuda::createCannyEdgeDetector(low_thresh, high_thresh, apperture_size, useL2gradient);
cv::cuda::GpuMat edges_gold;
canny->detect(d_img_roi, edges_gold);
// Asynchronous call
cv::cuda::GpuMat edges[NUM_STREAMS];
cv::parallel_for_(cv::Range(0, NUM_STREAMS), CannyAsyncParallelLoopBody(d_img_roi, edges, low_thresh, high_thresh, apperture_size, useL2gradient));
// Compare the results of synchronous call and asynchronous call
for (int i = 0; i < NUM_STREAMS; i++)
EXPECT_MAT_NEAR(edges_gold, edges[i], 0.0);
}
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, Canny, testing::Combine(
ALL_DEVICES,
testing::Values(AppertureSize(3), AppertureSize(5), AppertureSize(7)),
testing::Values(L2gradient(false), L2gradient(true)),
WHOLE_SUBMAT));
}} // namespace
#endif // HAVE_CUDA
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,479 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#ifdef HAVE_CUDA
namespace opencv_test {
namespace {
// This function force a row major order for the labels
template <typename LabelT>
void normalize_labels_impl(Mat& labels) {
std::map<LabelT, LabelT> map_new_labels;
LabelT i_max_new_label = 0;
for (int r = 0; r < labels.rows; ++r) {
LabelT* const mat_row = labels.ptr<LabelT>(r);
for (int c = 0; c < labels.cols; ++c) {
LabelT iCurLabel = mat_row[c];
if (iCurLabel > 0) {
if (map_new_labels.find(iCurLabel) == map_new_labels.end()) {
map_new_labels[iCurLabel] = ++i_max_new_label;
}
mat_row[c] = map_new_labels.at(iCurLabel);
}
}
}
}
void normalize_labels(Mat& labels) {
int type = labels.type();
int depth = type & CV_MAT_DEPTH_MASK;
int chans = 1 + (type >> CV_CN_SHIFT);
CV_Assert(chans == 1);
CV_Assert(depth == CV_16U || depth == CV_16S || depth == CV_32S);
switch (depth) {
case CV_16U: normalize_labels_impl<ushort>(labels); break;
case CV_16S: normalize_labels_impl<short>(labels); break;
case CV_32S: normalize_labels_impl<int>(labels); break;
default: CV_Assert(0);
}
}
////////////////////////////////////////////////////////
// ConnectedComponents
PARAM_TEST_CASE(ConnectedComponents, cv::cuda::DeviceInfo, int, int, cv::cuda::ConnectedComponentsAlgorithmsTypes)
{
cv::cuda::DeviceInfo devInfo;
int connectivity;
int ltype;
cv::cuda::ConnectedComponentsAlgorithmsTypes algo;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
connectivity = GET_PARAM(1);
ltype = GET_PARAM(2);
algo = GET_PARAM(3);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(ConnectedComponents, Chessboard_Even)
{
std::initializer_list<int> sizes{ 16, 16 };
cv::Mat1b input;
cv::Mat1i correct_output_int;
cv::Mat correct_output;
// Chessboard image with even number of rows and cols
// Note that this is the maximum number of labels for 4-way connectivity
{
input = cv::Mat1b(sizes, {
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
if (connectivity == 8) {
correct_output_int = cv::Mat1i(sizes, {
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
}
else {
correct_output_int = cv::Mat1i(sizes, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0,
0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16,
17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0,
0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32,
33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0,
0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48,
49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56, 0,
0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64,
65, 0, 66, 0, 67, 0, 68, 0, 69, 0, 70, 0, 71, 0, 72, 0,
0, 73, 0, 74, 0, 75, 0, 76, 0, 77, 0, 78, 0, 79, 0, 80,
81, 0, 82, 0, 83, 0, 84, 0, 85, 0, 86, 0, 87, 0, 88, 0,
0, 89, 0, 90, 0, 91, 0, 92, 0, 93, 0, 94, 0, 95, 0, 96,
97, 0, 98, 0, 99, 0, 100, 0, 101, 0, 102, 0, 103, 0, 104, 0,
0, 105, 0, 106, 0, 107, 0, 108, 0, 109, 0, 110, 0, 111, 0, 112,
113, 0, 114, 0, 115, 0, 116, 0, 117, 0, 118, 0, 119, 0, 120, 0,
0, 121, 0, 122, 0, 123, 0, 124, 0, 125, 0, 126, 0, 127, 0, 128
});
}
}
correct_output_int.convertTo(correct_output, CV_MAT_DEPTH(ltype));
cv::Mat labels;
cv::Mat diff;
cv::cuda::GpuMat d_input;
cv::cuda::GpuMat d_labels;
d_input.upload(input);
EXPECT_NO_THROW(cv::cuda::connectedComponents(d_input, d_labels, connectivity, ltype, algo));
d_labels.download(labels);
normalize_labels(labels);
diff = labels != correct_output;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
CUDA_TEST_P(ConnectedComponents, Chessboard_Odd)
{
std::initializer_list<int> sizes{ 15, 15 };
cv::Mat1b input;
cv::Mat1i correct_output_int;
cv::Mat correct_output;
// Chessboard image with even number of rows and cols
// Note that this is the maximum number of labels for 4-way connectivity
{
input = Mat1b(sizes, {
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
if (connectivity == 8) {
correct_output_int = Mat1i(sizes, {
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
}
else {
correct_output_int = Mat1i(sizes, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0,
16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23,
0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0,
31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38,
0, 39, 0, 40, 0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0,
46, 0, 47, 0, 48, 0, 49, 0, 50, 0, 51, 0, 52, 0, 53,
0, 54, 0, 55, 0, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0,
61, 0, 62, 0, 63, 0, 64, 0, 65, 0, 66, 0, 67, 0, 68,
0, 69, 0, 70, 0, 71, 0, 72, 0, 73, 0, 74, 0, 75, 0,
76, 0, 77, 0, 78, 0, 79, 0, 80, 0, 81, 0, 82, 0, 83,
0, 84, 0, 85, 0, 86, 0, 87, 0, 88, 0, 89, 0, 90, 0,
91, 0, 92, 0, 93, 0, 94, 0, 95, 0, 96, 0, 97, 0, 98,
0, 99, 0, 100, 0, 101, 0, 102, 0, 103, 0, 104, 0, 105, 0,
106, 0, 107, 0, 108, 0, 109, 0, 110, 0, 111, 0, 112, 0, 113
});
}
}
correct_output_int.convertTo(correct_output, CV_MAT_DEPTH(ltype));
cv::Mat labels;
cv::Mat diff;
cv::cuda::GpuMat d_input;
cv::cuda::GpuMat d_labels;
d_input.upload(input);
EXPECT_NO_THROW(cv::cuda::connectedComponents(d_input, d_labels, connectivity, ltype, algo));
d_labels.download(labels);
normalize_labels(labels);
diff = labels != correct_output;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
CUDA_TEST_P(ConnectedComponents, Maxlabels_8conn_Even)
{
std::initializer_list<int> sizes{ 16, 16 };
cv::Mat1b input;
cv::Mat1i correct_output_int;
cv::Mat correct_output;
// Chessboard image with even number of rows and cols
// Note that this is the maximum number of labels for 4-way connectivity
{
input = Mat1b(sizes, {
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
});
correct_output_int = Mat1i(sizes, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
});
}
correct_output_int.convertTo(correct_output, CV_MAT_DEPTH(ltype));
cv::Mat labels;
cv::Mat diff;
cv::cuda::GpuMat d_input;
cv::cuda::GpuMat d_labels;
d_input.upload(input);
EXPECT_NO_THROW(cv::cuda::connectedComponents(d_input, d_labels, connectivity, ltype, algo));
d_labels.download(labels);
normalize_labels(labels);
diff = labels != correct_output;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
CUDA_TEST_P(ConnectedComponents, Maxlabels_8conn_Odd)
{
std::initializer_list<int> sizes{ 15, 15 };
cv::Mat1b input;
cv::Mat1i correct_output_int;
cv::Mat correct_output;
// Chessboard image with even number of rows and cols
// Note that this is the maximum number of labels for 4-way connectivity
{
input = Mat1b(sizes, {
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1
});
correct_output_int = Mat1i(sizes, {
1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64
});
}
correct_output_int.convertTo(correct_output, CV_MAT_DEPTH(ltype));
cv::Mat labels;
cv::Mat diff;
cv::cuda::GpuMat d_input;
cv::cuda::GpuMat d_labels;
d_input.upload(input);
EXPECT_NO_THROW(cv::cuda::connectedComponents(d_input, d_labels, connectivity, ltype, algo));
d_labels.download(labels);
normalize_labels(labels);
diff = labels != correct_output;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
CUDA_TEST_P(ConnectedComponents, Single_Row)
{
std::initializer_list<int> sizes{ 1, 15 };
cv::Mat1b input;
cv::Mat1i correct_output_int;
cv::Mat correct_output;
// Chessboard image with even number of rows and cols
// Note that this is the maximum number of labels for 4-way connectivity
{
input = Mat1b(sizes, { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 });
correct_output_int = Mat1i(sizes, { 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8 });
}
correct_output_int.convertTo(correct_output, CV_MAT_DEPTH(ltype));
cv::Mat labels;
cv::Mat diff;
cv::cuda::GpuMat d_input;
cv::cuda::GpuMat d_labels;
d_input.upload(input);
EXPECT_NO_THROW(cv::cuda::connectedComponents(d_input, d_labels, connectivity, ltype, algo));
d_labels.download(labels);
normalize_labels(labels);
diff = labels != correct_output;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
CUDA_TEST_P(ConnectedComponents, Single_Column)
{
std::initializer_list<int> sizes{ 15, 1 };
cv::Mat1b input;
cv::Mat1i correct_output_int;
cv::Mat correct_output;
// Chessboard image with even number of rows and cols
// Note that this is the maximum number of labels for 4-way connectivity
{
input = Mat1b(sizes, { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 });
correct_output_int = Mat1i(sizes, { 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8 });
}
correct_output_int.convertTo(correct_output, CV_MAT_DEPTH(ltype));
cv::Mat labels;
cv::Mat diff;
cv::cuda::GpuMat d_input;
cv::cuda::GpuMat d_labels;
d_input.upload(input);
EXPECT_NO_THROW(cv::cuda::connectedComponents(d_input, d_labels, connectivity, ltype, algo));
d_labels.download(labels);
normalize_labels(labels);
diff = labels != correct_output;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
CUDA_TEST_P(ConnectedComponents, Concentric_Circles)
{
string img_path = cvtest::TS::ptr()->get_data_path() + "connectedcomponents/concentric_circles.png";
string exp_path = cvtest::TS::ptr()->get_data_path() + "connectedcomponents/ccomp_exp.png";
Mat img = imread(img_path, 0);
EXPECT_FALSE(img.empty());
Mat exp = imread(exp_path, 0);
EXPECT_FALSE(exp.empty());
Mat labels;
exp.convertTo(exp, ltype);
GpuMat d_img;
GpuMat d_labels;
d_img.upload(img);
EXPECT_NO_THROW(cv::cuda::connectedComponents(d_img, d_labels, connectivity, ltype, algo));
d_labels.download(labels);
normalize_labels(labels);
Mat diff = labels != exp;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, ConnectedComponents, testing::Combine(
ALL_DEVICES,
testing::Values(8),
testing::Values(CV_32S),
testing::Values(cv::cuda::CCL_DEFAULT, cv::cuda::CCL_BKE)
));
}
} // namespace
#endif // HAVE_CUDA
+397
View File
@@ -0,0 +1,397 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#ifdef HAVE_CUDA
namespace opencv_test { namespace {
///////////////////////////////////////////////////////////////////////////////////////////////////////
// HistEven
typedef tuple<Size, int> hist_size_to_roi_offset_params_t;
const hist_size_to_roi_offset_params_t hist_size_to_roi_offset_params[] =
{
// uchar reads only
hist_size_to_roi_offset_params_t(Size(1,32), 0),
hist_size_to_roi_offset_params_t(Size(2,32), 0),
hist_size_to_roi_offset_params_t(Size(2,32), 1),
hist_size_to_roi_offset_params_t(Size(3,32), 0),
hist_size_to_roi_offset_params_t(Size(3,32), 1),
hist_size_to_roi_offset_params_t(Size(3,32), 2),
hist_size_to_roi_offset_params_t(Size(4,32), 0),
hist_size_to_roi_offset_params_t(Size(4,32), 1),
hist_size_to_roi_offset_params_t(Size(4,32), 2),
hist_size_to_roi_offset_params_t(Size(4,32), 3),
// uchar and int reads
hist_size_to_roi_offset_params_t(Size(129,32), 0),
hist_size_to_roi_offset_params_t(Size(129,32), 1),
hist_size_to_roi_offset_params_t(Size(129,32), 2),
hist_size_to_roi_offset_params_t(Size(129,32), 3),
// int reads only
hist_size_to_roi_offset_params_t(Size(128,32), 0)
};
PARAM_TEST_CASE(HistEven, cv::cuda::DeviceInfo, hist_size_to_roi_offset_params_t)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
int roiOffsetX;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = get<0>(GET_PARAM(1));
roiOffsetX = get<1>(GET_PARAM(1));
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(HistEven, Accuracy)
{
cv::Mat src = randomMat(size, CV_8UC1);
const Rect roi = Rect(roiOffsetX, 0, src.cols - roiOffsetX, src.rows);
int hbins = 30;
float hranges[] = {50.0f, 200.0f};
cv::cuda::GpuMat hist;
cv::cuda::GpuMat srcDevice = loadMat(src);
cv::cuda::histEven(srcDevice(roi), hist, hbins, (int)hranges[0], (int)hranges[1]);
cv::Mat hist_gold;
int histSize[] = {hbins};
const float* ranges[] = {hranges};
int channels[] = {0};
Mat srcRoi = src(roi);
cv::calcHist(&srcRoi, 1, channels, cv::Mat(), hist_gold, 1, histSize, ranges);
hist_gold.convertTo(hist_gold, CV_32S);
EXPECT_MAT_NEAR(hist_gold, hist, 0.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, HistEven, testing::Combine(
ALL_DEVICES, testing::ValuesIn(hist_size_to_roi_offset_params)));
///////////////////////////////////////////////////////////////////////////////////////////////////////
// CalcHist
PARAM_TEST_CASE(CalcHist, cv::cuda::DeviceInfo, hist_size_to_roi_offset_params_t)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
int roiOffsetX;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = get<0>(GET_PARAM(1));
roiOffsetX = get<1>(GET_PARAM(1));
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(CalcHist, Accuracy)
{
cv::Mat src = randomMat(size, CV_8UC1);
const Rect roi = Rect(roiOffsetX, 0, src.cols - roiOffsetX, src.rows);
cv::cuda::GpuMat hist;
GpuMat srcDevice = loadMat(src);
cv::cuda::calcHist(srcDevice(roi), hist);
cv::Mat hist_gold;
const int hbins = 256;
const float hranges[] = {0.0f, 256.0f};
const int histSize[] = {hbins};
const float* ranges[] = {hranges};
const int channels[] = {0};
const Mat srcRoi = src(roi);
cv::calcHist(&srcRoi, 1, channels, cv::Mat(), hist_gold, 1, histSize, ranges);
hist_gold = hist_gold.reshape(1, 1);
hist_gold.convertTo(hist_gold, CV_32S);
EXPECT_MAT_NEAR(hist_gold, hist, 0.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, CalcHist, testing::Combine(
ALL_DEVICES, testing::ValuesIn(hist_size_to_roi_offset_params)));
PARAM_TEST_CASE(CalcHistWithMask, cv::cuda::DeviceInfo, hist_size_to_roi_offset_params_t)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
int roiOffsetX;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = get<0>(GET_PARAM(1));
roiOffsetX = get<1>(GET_PARAM(1));
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(CalcHistWithMask, Accuracy)
{
cv::Mat src = randomMat(size, CV_8UC1);
const Rect roi = Rect(roiOffsetX, 0, src.cols - roiOffsetX, src.rows);
cv::Mat mask = randomMat(size, CV_8UC1);
cv::Mat(mask, cv::Rect(0, 0, size.width / 2, size.height / 2)).setTo(0);
cv::cuda::GpuMat hist;
GpuMat srcDevice = loadMat(src);
GpuMat maskDevice = loadMat(mask);
cv::cuda::calcHist(srcDevice(roi), maskDevice(roi), hist);
cv::Mat hist_gold;
const int hbins = 256;
const float hranges[] = {0.0f, 256.0f};
const int histSize[] = {hbins};
const float* ranges[] = {hranges};
const int channels[] = {0};
const Mat srcRoi = src(roi);
cv::calcHist(&srcRoi, 1, channels, mask(roi), hist_gold, 1, histSize, ranges);
hist_gold = hist_gold.reshape(1, 1);
hist_gold.convertTo(hist_gold, CV_32S);
EXPECT_MAT_NEAR(hist_gold, hist, 0.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, CalcHistWithMask, testing::Combine(
ALL_DEVICES, testing::ValuesIn(hist_size_to_roi_offset_params)));
///////////////////////////////////////////////////////////////////////////////////////////////////////
// EqualizeHist
PARAM_TEST_CASE(EqualizeHist, cv::cuda::DeviceInfo, cv::Size)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = GET_PARAM(1);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(EqualizeHist, Async)
{
cv::Mat src = randomMat(size, CV_8UC1);
cv::cuda::Stream stream;
cv::cuda::GpuMat dst;
cv::cuda::equalizeHist(loadMat(src), dst, stream);
stream.waitForCompletion();
cv::Mat dst_gold;
cv::equalizeHist(src, dst_gold);
EXPECT_MAT_NEAR(dst_gold, dst, 0.0);
}
CUDA_TEST_P(EqualizeHist, Accuracy)
{
cv::Mat src = randomMat(size, CV_8UC1);
cv::cuda::GpuMat dst;
cv::cuda::equalizeHist(loadMat(src), dst);
cv::Mat dst_gold;
cv::equalizeHist(src, dst_gold);
EXPECT_MAT_NEAR(dst_gold, dst, 0.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, EqualizeHist, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES));
TEST(EqualizeHistIssue, Issue18035)
{
std::vector<std::string> imgPaths;
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/3MP.png");
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/5MP.png");
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/airplane.png");
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/baboon.png");
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/box.png");
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/box_in_scene.png");
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/fruits.png");
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/fruits_ecc.png");
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/graffiti.png");
imgPaths.push_back(std::string(cvtest::TS::ptr()->get_data_path()) + "../cv/shared/lena.png");
for (size_t i = 0; i < imgPaths.size(); ++i)
{
std::string imgPath = imgPaths[i];
cv::Mat src = cv::imread(imgPath, cv::IMREAD_GRAYSCALE);
src = src / 30;
cv::cuda::GpuMat d_src, dst;
d_src.upload(src);
cv::cuda::equalizeHist(d_src, dst);
cv::Mat dst_gold;
cv::equalizeHist(src, dst_gold);
EXPECT_MAT_NEAR(dst_gold, dst, 0.0);
}
}
PARAM_TEST_CASE(EqualizeHistExtreme, cv::cuda::DeviceInfo, cv::Size, int)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
int val;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = GET_PARAM(1);
val = GET_PARAM(2);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(EqualizeHistExtreme, Case1)
{
cv::Mat src(size, CV_8UC1, val);
cv::cuda::GpuMat dst;
cv::cuda::equalizeHist(loadMat(src), dst);
cv::Mat dst_gold;
cv::equalizeHist(src, dst_gold);
EXPECT_MAT_NEAR(dst_gold, dst, 0.0);
}
CUDA_TEST_P(EqualizeHistExtreme, Case2)
{
cv::Mat src = randomMat(size, CV_8UC1, val);
cv::cuda::GpuMat dst;
cv::cuda::equalizeHist(loadMat(src), dst);
cv::Mat dst_gold;
cv::equalizeHist(src, dst_gold);
EXPECT_MAT_NEAR(dst_gold, dst, 0.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, EqualizeHistExtreme, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES,
testing::Range(0, 256)));
///////////////////////////////////////////////////////////////////////////////////////////////////////
// CLAHE
namespace
{
IMPLEMENT_PARAM_CLASS(ClipLimit, double)
}
PARAM_TEST_CASE(CLAHE, cv::cuda::DeviceInfo, cv::Size, ClipLimit, MatType)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
double clipLimit;
int type;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = GET_PARAM(1);
clipLimit = GET_PARAM(2);
type = GET_PARAM(3);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(CLAHE, Accuracy)
{
cv::Mat src;
if (type == CV_8UC1)
src = randomMat(size, type);
else if (type == CV_16UC1)
src = randomMat(size, type, 0, 65535);
cv::Ptr<cv::cuda::CLAHE> clahe = cv::cuda::createCLAHE(clipLimit);
cv::cuda::GpuMat dst;
clahe->apply(loadMat(src), dst);
cv::Ptr<cv::CLAHE> clahe_gold = cv::createCLAHE(clipLimit);
cv::Mat dst_gold;
clahe_gold->apply(src, dst_gold);
ASSERT_MAT_NEAR(dst_gold, dst, 1.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, CLAHE, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES,
testing::Values(0.0, 5.0, 10.0, 20.0, 40.0),
testing::Values(MatType(CV_8UC1), MatType(CV_16UC1))));
}} // namespace
#endif // HAVE_CUDA
+373
View File
@@ -0,0 +1,373 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#ifdef HAVE_CUDA
namespace opencv_test { namespace {
///////////////////////////////////////////////////////////////////////////////////////////////////////
// HoughLines
PARAM_TEST_CASE(HoughLines, cv::cuda::DeviceInfo, cv::Size, UseRoi)
{
static void generateLines(cv::Mat& img)
{
img.setTo(cv::Scalar::all(0));
cv::line(img, cv::Point(20, 0), cv::Point(20, img.rows), cv::Scalar::all(255));
cv::line(img, cv::Point(0, 50), cv::Point(img.cols, 50), cv::Scalar::all(255));
cv::line(img, cv::Point(0, 0), cv::Point(img.cols, img.rows), cv::Scalar::all(255));
cv::line(img, cv::Point(img.cols, 0), cv::Point(0, img.rows), cv::Scalar::all(255));
}
static void drawLines(cv::Mat& dst, const std::vector<cv::Vec2f>& lines)
{
dst.setTo(cv::Scalar::all(0));
for (size_t i = 0; i < lines.size(); ++i)
{
float rho = lines[i][0], theta = lines[i][1];
cv::Point pt1, pt2;
double a = std::cos(theta), b = std::sin(theta);
double x0 = a*rho, y0 = b*rho;
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
cv::line(dst, pt1, pt2, cv::Scalar::all(255));
}
}
};
CUDA_TEST_P(HoughLines, Accuracy)
{
const cv::cuda::DeviceInfo devInfo = GET_PARAM(0);
cv::cuda::setDevice(devInfo.deviceID());
const cv::Size size = GET_PARAM(1);
const bool useRoi = GET_PARAM(2);
const float rho = 1.0f;
const float theta = (float) (1.5 * CV_PI / 180.0);
const int threshold = 100;
cv::Mat src(size, CV_8UC1);
generateLines(src);
cv::Ptr<cv::cuda::HoughLinesDetector> hough = cv::cuda::createHoughLinesDetector(rho, theta, threshold);
cv::cuda::GpuMat d_lines;
hough->detect(loadMat(src, useRoi), d_lines);
std::vector<cv::Vec2f> lines;
hough->downloadResults(d_lines, lines);
cv::Mat dst(size, CV_8UC1);
drawLines(dst, lines);
ASSERT_MAT_NEAR(src, dst, 0.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, HoughLines, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES,
WHOLE_SUBMAT));
///////////////////////////////////////////////////////////////////////////////////////////////////////
// HoughLines Probabilistic
PARAM_TEST_CASE(HoughLinesProbabilistic, DeviceInfo, Size, UseRoi)
{
cv::cuda::DeviceInfo devInfo;
bool useRoi;
Size size;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = GET_PARAM(1);
useRoi = GET_PARAM(2);
cv::cuda::setDevice(devInfo.deviceID());
}
static void generateLines(cv::Mat& img)
{
img.setTo(cv::Scalar::all(0));
cv::line(img, cv::Point(10, 0), cv::Point(10, 20), cv::Scalar::all(255));
cv::line(img, cv::Point(20, 50), cv::Point(40, 50), cv::Scalar::all(255));
}
static void drawLines(cv::Mat& dst, const std::vector<cv::Vec4i>& linesSegment)
{
dst.setTo(cv::Scalar::all(0));
for (size_t i = 0; i < linesSegment.size(); ++i)
{
Vec4i l = linesSegment[i];
cv::line(dst, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar::all(255));
}
}
};
CUDA_TEST_P(HoughLinesProbabilistic, Accuracy)
{
const float rho = 1.0f;
const float theta = (float) (1.0 * CV_PI / 180.0);
const int minLineLength = 15;
const int maxLineGap = 8;
cv::Mat src(size, CV_8UC1);
generateLines(src);
Ptr<cv::cuda::HoughSegmentDetector> hough = cv::cuda::createHoughSegmentDetector(rho, theta, minLineLength, maxLineGap);
cv::cuda::GpuMat d_lines;
hough->detect(loadMat(src, useRoi), d_lines);
std::vector<cv::Vec4i> linesSegment;
std::vector<cv::Vec2f> lines;
d_lines.download(linesSegment);
cv::Mat dst(size, CV_8UC1);
drawLines(dst, linesSegment);
ASSERT_MAT_NEAR(src, dst, 0.0);
}
void HoughLinesProbabilisticThread(const Ptr<HoughSegmentDetector> detector, const GpuMat& imgIn, const std::vector<GpuMat>& linesOut, Stream& stream) {
for (auto& lines : linesOut)
detector->detect(imgIn, lines, stream);
stream.waitForCompletion();
}
CUDA_TEST_P(HoughLinesProbabilistic, Async)
{
constexpr int nThreads = 5;
constexpr int nIters = 5;
vector<Stream> streams(nThreads); // async test only
vector<GpuMat> imgsIn;
vector<Ptr<HoughSegmentDetector>> detectors;
vector<vector<GpuMat>> linesOut(nThreads);
const float rho = 1.0f;
const float theta = (float)(1.0 * CV_PI / 180.0);
const int minLineLength = 15;
const int maxLineGap = 8;
cv::Mat src(size, CV_8UC1);
generateLines(src);
for (int i = 0; i < nThreads; i++) {
imgsIn.push_back(loadMat(src, useRoi));
detectors.push_back(createHoughSegmentDetector(rho, theta, minLineLength, maxLineGap));
linesOut.push_back(vector<GpuMat>(nIters));
}
vector<std::thread> thread(nThreads);
for (int i = 0; i < nThreads; i++) thread.at(i) = std::thread(HoughLinesProbabilisticThread, detectors.at(i), std::ref(imgsIn.at(i)), std::ref(linesOut.at(i)), std::ref(streams.at(i)));
for (int i = 0; i < nThreads; i++) thread.at(i).join();
for (int i = 0; i < nThreads; i++) {
std::vector<cv::Vec4i> linesSegment;
std::vector<cv::Vec2f> lines;
for (const auto& line : linesOut.at(i)) {
line.download(linesSegment);
cv::Mat dst(size, CV_8UC1);
drawLines(dst, linesSegment);
ASSERT_MAT_NEAR(src, dst, 0.0);
}
}
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, HoughLinesProbabilistic, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES,
WHOLE_SUBMAT));
///////////////////////////////////////////////////////////////////////////////////////////////////////
// HoughCircles
PARAM_TEST_CASE(HoughCircles, cv::cuda::DeviceInfo, cv::Size, UseRoi)
{
static void drawCircles(cv::Mat& dst, const std::vector<cv::Vec3f>& circles, bool fill)
{
dst.setTo(cv::Scalar::all(0));
for (size_t i = 0; i < circles.size(); ++i)
cv::circle(dst, cv::Point2f(circles[i][0], circles[i][1]), (int)circles[i][2], cv::Scalar::all(255), fill ? -1 : 1);
}
};
CUDA_TEST_P(HoughCircles, Accuracy)
{
const cv::cuda::DeviceInfo devInfo = GET_PARAM(0);
cv::cuda::setDevice(devInfo.deviceID());
const cv::Size size = GET_PARAM(1);
const bool useRoi = GET_PARAM(2);
const float dp = 2.0f;
const float minDist = 0.0f;
const int minRadius = 10;
const int maxRadius = 20;
const int cannyThreshold = 100;
const int votesThreshold = 20;
std::vector<cv::Vec3f> circles_gold(4);
circles_gold[0] = cv::Vec3i(20, 20, minRadius);
circles_gold[1] = cv::Vec3i(90, 87, minRadius + 3);
circles_gold[2] = cv::Vec3i(30, 70, minRadius + 8);
circles_gold[3] = cv::Vec3i(80, 10, maxRadius);
cv::Mat src(size, CV_8UC1);
drawCircles(src, circles_gold, true);
cv::Ptr<cv::cuda::HoughCirclesDetector> houghCircles = cv::cuda::createHoughCirclesDetector(dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius);
cv::cuda::GpuMat d_circles;
houghCircles->detect(loadMat(src, useRoi), d_circles);
std::vector<cv::Vec3f> circles;
d_circles.download(circles);
ASSERT_FALSE(circles.empty());
for (size_t i = 0; i < circles.size(); ++i)
{
cv::Vec3f cur = circles[i];
bool found = false;
for (size_t j = 0; j < circles_gold.size(); ++j)
{
cv::Vec3f gold = circles_gold[j];
if (std::fabs(cur[0] - gold[0]) < 5 && std::fabs(cur[1] - gold[1]) < 5 && std::fabs(cur[2] - gold[2]) < 5)
{
found = true;
break;
}
}
ASSERT_TRUE(found);
}
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, HoughCircles, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES,
WHOLE_SUBMAT));
///////////////////////////////////////////////////////////////////////////////////////////////////////
// GeneralizedHough
PARAM_TEST_CASE(GeneralizedHough, cv::cuda::DeviceInfo, UseRoi)
{
};
CUDA_TEST_P(GeneralizedHough, Ballard)
{
const cv::cuda::DeviceInfo devInfo = GET_PARAM(0);
cv::cuda::setDevice(devInfo.deviceID());
const bool useRoi = GET_PARAM(1);
cv::Mat templ = readImage("../cv/shared/templ.png", cv::IMREAD_GRAYSCALE);
ASSERT_FALSE(templ.empty());
cv::Point templCenter(templ.cols / 2, templ.rows / 2);
const size_t gold_count = 3;
cv::Point pos_gold[gold_count];
pos_gold[0] = cv::Point(templCenter.x + 10, templCenter.y + 10);
pos_gold[1] = cv::Point(2 * templCenter.x + 40, templCenter.y + 10);
pos_gold[2] = cv::Point(2 * templCenter.x + 40, 2 * templCenter.y + 40);
cv::Mat image(templ.rows * 3, templ.cols * 3, CV_8UC1, cv::Scalar::all(0));
for (size_t i = 0; i < gold_count; ++i)
{
cv::Rect rec(pos_gold[i].x - templCenter.x, pos_gold[i].y - templCenter.y, templ.cols, templ.rows);
cv::Mat imageROI = image(rec);
templ.copyTo(imageROI);
}
cv::Ptr<cv::GeneralizedHoughBallard> alg = cv::cuda::createGeneralizedHoughBallard();
alg->setVotesThreshold(200);
alg->setTemplate(loadMat(templ, useRoi));
cv::cuda::GpuMat d_pos;
alg->detect(loadMat(image, useRoi), d_pos);
std::vector<cv::Vec4f> pos;
d_pos.download(pos);
ASSERT_EQ(gold_count, pos.size());
for (size_t i = 0; i < gold_count; ++i)
{
cv::Point gold = pos_gold[i];
bool found = false;
for (size_t j = 0; j < pos.size(); ++j)
{
cv::Point2f p(pos[j][0], pos[j][1]);
if (::fabs(p.x - gold.x) < 2 && ::fabs(p.y - gold.y) < 2)
{
found = true;
break;
}
}
ASSERT_TRUE(found);
}
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, GeneralizedHough, testing::Combine(
ALL_DEVICES,
WHOLE_SUBMAT));
}} // namespace
#endif // HAVE_CUDA
+45
View File
@@ -0,0 +1,45 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
CV_CUDA_TEST_MAIN("gpu")
@@ -0,0 +1,341 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#ifdef HAVE_CUDA
namespace opencv_test { namespace {
////////////////////////////////////////////////////////////////////////////////
// MatchTemplate8U
CV_ENUM(TemplateMethod, cv::TM_SQDIFF, cv::TM_SQDIFF_NORMED, cv::TM_CCORR, cv::TM_CCORR_NORMED, cv::TM_CCOEFF, cv::TM_CCOEFF_NORMED)
#define ALL_TEMPLATE_METHODS testing::Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_SQDIFF_NORMED), TemplateMethod(cv::TM_CCORR), TemplateMethod(cv::TM_CCORR_NORMED), TemplateMethod(cv::TM_CCOEFF), TemplateMethod(cv::TM_CCOEFF_NORMED))
namespace
{
IMPLEMENT_PARAM_CLASS(TemplateSize, cv::Size);
}
PARAM_TEST_CASE(MatchTemplate8U, cv::cuda::DeviceInfo, cv::Size, TemplateSize, Channels, TemplateMethod)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
cv::Size templ_size;
int cn;
int method;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = GET_PARAM(1);
templ_size = GET_PARAM(2);
cn = GET_PARAM(3);
method = GET_PARAM(4);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(MatchTemplate8U, Accuracy)
{
cv::Mat image = randomMat(size, CV_MAKETYPE(CV_8U, cn));
cv::Mat templ = randomMat(templ_size, CV_MAKETYPE(CV_8U, cn));
cv::Ptr<cv::cuda::TemplateMatching> alg = cv::cuda::createTemplateMatching(image.type(), method);
cv::cuda::GpuMat dst;
alg->match(loadMat(image), loadMat(templ), dst);
cv::Mat dst_gold;
cv::matchTemplate(image, templ, dst_gold, method);
cv::Mat h_dst(dst);
ASSERT_EQ(dst_gold.size(), h_dst.size());
ASSERT_EQ(dst_gold.type(), h_dst.type());
for (int y = 0; y < h_dst.rows; ++y)
{
for (int x = 0; x < h_dst.cols; ++x)
{
float gold_val = dst_gold.at<float>(y, x);
float actual_val = dst_gold.at<float>(y, x);
ASSERT_FLOAT_EQ(gold_val, actual_val) << y << ", " << x;
}
}
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, MatchTemplate8U, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES,
testing::Values(TemplateSize(cv::Size(5, 5)), TemplateSize(cv::Size(16, 16)), TemplateSize(cv::Size(30, 30))),
testing::Values(Channels(1), Channels(3), Channels(4)),
ALL_TEMPLATE_METHODS));
////////////////////////////////////////////////////////////////////////////////
// MatchTemplate32F
PARAM_TEST_CASE(MatchTemplate32F, cv::cuda::DeviceInfo, cv::Size, TemplateSize, Channels, TemplateMethod)
{
cv::cuda::DeviceInfo devInfo;
cv::Size size;
cv::Size templ_size;
int cn;
int method;
int n, m, h, w;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = GET_PARAM(1);
templ_size = GET_PARAM(2);
cn = GET_PARAM(3);
method = GET_PARAM(4);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(MatchTemplate32F, Regression)
{
cv::Mat image = randomMat(size, CV_MAKETYPE(CV_32F, cn));
cv::Mat templ = randomMat(templ_size, CV_MAKETYPE(CV_32F, cn));
cv::Ptr<cv::cuda::TemplateMatching> alg = cv::cuda::createTemplateMatching(image.type(), method);
cv::cuda::GpuMat dst;
alg->match(loadMat(image), loadMat(templ), dst);
cv::Mat dst_gold;
cv::matchTemplate(image, templ, dst_gold, method);
cv::Mat h_dst(dst);
ASSERT_EQ(dst_gold.size(), h_dst.size());
ASSERT_EQ(dst_gold.type(), h_dst.type());
for (int y = 0; y < h_dst.rows; ++y)
{
for (int x = 0; x < h_dst.cols; ++x)
{
float gold_val = dst_gold.at<float>(y, x);
float actual_val = dst_gold.at<float>(y, x);
ASSERT_FLOAT_EQ(gold_val, actual_val) << y << ", " << x;
}
}
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, MatchTemplate32F, testing::Combine(
ALL_DEVICES,
DIFFERENT_SIZES,
testing::Values(TemplateSize(cv::Size(5, 5)), TemplateSize(cv::Size(16, 16)), TemplateSize(cv::Size(30, 30))),
testing::Values(Channels(1), Channels(3), Channels(4)),
testing::Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_CCORR))));
////////////////////////////////////////////////////////////////////////////////
// MatchTemplateBlackSource
PARAM_TEST_CASE(MatchTemplateBlackSource, cv::cuda::DeviceInfo, TemplateMethod)
{
cv::cuda::DeviceInfo devInfo;
int method;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
method = GET_PARAM(1);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(MatchTemplateBlackSource, Accuracy)
{
cv::Mat image = readImage("matchtemplate/black.png");
ASSERT_FALSE(image.empty());
cv::Mat pattern = readImage("matchtemplate/cat.png");
ASSERT_FALSE(pattern.empty());
cv::Ptr<cv::cuda::TemplateMatching> alg = cv::cuda::createTemplateMatching(image.type(), method);
cv::cuda::GpuMat d_dst;
alg->match(loadMat(image), loadMat(pattern), d_dst);
cv::Mat dst(d_dst);
double maxValue;
cv::Point maxLoc;
cv::minMaxLoc(dst, NULL, &maxValue, NULL, &maxLoc);
cv::Point maxLocGold = cv::Point(284, 12);
ASSERT_EQ(maxLocGold, maxLoc);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, MatchTemplateBlackSource, testing::Combine(
ALL_DEVICES,
testing::Values(TemplateMethod(cv::TM_CCOEFF_NORMED), TemplateMethod(cv::TM_CCORR_NORMED))));
////////////////////////////////////////////////////////////////////////////////
// MatchTemplate_CCOEF_NORMED
PARAM_TEST_CASE(MatchTemplate_CCOEF_NORMED, cv::cuda::DeviceInfo, std::pair<std::string, std::string>)
{
cv::cuda::DeviceInfo devInfo;
std::string imageName;
std::string patternName;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
imageName = GET_PARAM(1).first;
patternName = GET_PARAM(1).second;
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(MatchTemplate_CCOEF_NORMED, Accuracy)
{
cv::Mat image = readImage(imageName);
ASSERT_FALSE(image.empty());
cv::Mat pattern = readImage(patternName);
ASSERT_FALSE(pattern.empty());
cv::Ptr<cv::cuda::TemplateMatching> alg = cv::cuda::createTemplateMatching(image.type(), cv::TM_CCOEFF_NORMED);
cv::cuda::GpuMat d_dst;
alg->match(loadMat(image), loadMat(pattern), d_dst);
cv::Mat dst(d_dst);
cv::Point minLoc, maxLoc;
double minVal, maxVal;
cv::minMaxLoc(dst, &minVal, &maxVal, &minLoc, &maxLoc);
cv::Mat dstGold;
cv::matchTemplate(image, pattern, dstGold, cv::TM_CCOEFF_NORMED);
double minValGold, maxValGold;
cv::Point minLocGold, maxLocGold;
cv::minMaxLoc(dstGold, &minValGold, &maxValGold, &minLocGold, &maxLocGold);
ASSERT_EQ(minLocGold, minLoc);
ASSERT_EQ(maxLocGold, maxLoc);
ASSERT_LE(maxVal, 1.0);
ASSERT_GE(minVal, -1.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, MatchTemplate_CCOEF_NORMED, testing::Combine(
ALL_DEVICES,
testing::Values(std::make_pair(std::string("matchtemplate/source-0.png"), std::string("matchtemplate/target-0.png")))));
////////////////////////////////////////////////////////////////////////////////
// MatchTemplate_CanFindBigTemplate
struct MatchTemplate_CanFindBigTemplate : testing::TestWithParam<cv::cuda::DeviceInfo>
{
cv::cuda::DeviceInfo devInfo;
virtual void SetUp()
{
devInfo = GetParam();
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(MatchTemplate_CanFindBigTemplate, SQDIFF_NORMED)
{
cv::Mat scene = readImage("matchtemplate/scene.png");
ASSERT_FALSE(scene.empty());
cv::Mat templ = readImage("matchtemplate/template.png");
ASSERT_FALSE(templ.empty());
cv::Ptr<cv::cuda::TemplateMatching> alg = cv::cuda::createTemplateMatching(scene.type(), cv::TM_SQDIFF_NORMED);
cv::cuda::GpuMat d_result;
alg->match(loadMat(scene), loadMat(templ), d_result);
cv::Mat result(d_result);
double minVal;
cv::Point minLoc;
cv::minMaxLoc(result, &minVal, 0, &minLoc, 0);
ASSERT_GE(minVal, 0);
ASSERT_LT(minVal, 1e-3);
ASSERT_EQ(344, minLoc.x);
ASSERT_EQ(0, minLoc.y);
}
CUDA_TEST_P(MatchTemplate_CanFindBigTemplate, SQDIFF)
{
cv::Mat scene = readImage("matchtemplate/scene.png");
ASSERT_FALSE(scene.empty());
cv::Mat templ = readImage("matchtemplate/template.png");
ASSERT_FALSE(templ.empty());
cv::Ptr<cv::cuda::TemplateMatching> alg = cv::cuda::createTemplateMatching(scene.type(), cv::TM_SQDIFF);
cv::cuda::GpuMat d_result;
alg->match(loadMat(scene), loadMat(templ), d_result);
cv::Mat result(d_result);
double minVal;
cv::Point minLoc;
cv::minMaxLoc(result, &minVal, 0, &minLoc, 0);
ASSERT_GE(minVal, 0);
ASSERT_EQ(344, minLoc.x);
ASSERT_EQ(0, minLoc.y);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, MatchTemplate_CanFindBigTemplate, ALL_DEVICES);
}} // namespace
#endif // HAVE_CUDA
@@ -0,0 +1,176 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#ifdef HAVE_CUDA
namespace opencv_test { namespace {
////////////////////////////////////////////////////////////////////////////////
// MeanShift
struct MeanShift : testing::TestWithParam<cv::cuda::DeviceInfo>
{
cv::cuda::DeviceInfo devInfo;
cv::Mat img;
int spatialRad;
int colorRad;
virtual void SetUp()
{
devInfo = GetParam();
cv::cuda::setDevice(devInfo.deviceID());
img = readImageType("meanshift/cones.png", CV_8UC4);
ASSERT_FALSE(img.empty());
spatialRad = 30;
colorRad = 30;
}
};
CUDA_TEST_P(MeanShift, Filtering)
{
cv::Mat img_template;
if (supportFeature(devInfo, cv::cuda::FEATURE_SET_COMPUTE_20))
img_template = readImage("meanshift/con_result.png");
else
img_template = readImage("meanshift/con_result_CC1X.png");
ASSERT_FALSE(img_template.empty());
cv::cuda::GpuMat d_dst;
cv::cuda::meanShiftFiltering(loadMat(img), d_dst, spatialRad, colorRad);
ASSERT_EQ(CV_8UC4, d_dst.type());
cv::Mat dst(d_dst);
cv::Mat result;
cv::cvtColor(dst, result, cv::COLOR_BGRA2BGR);
EXPECT_MAT_NEAR(img_template, result, 0.0);
}
CUDA_TEST_P(MeanShift, Proc)
{
cv::FileStorage fs;
if (supportFeature(devInfo, cv::cuda::FEATURE_SET_COMPUTE_20))
fs.open(std::string(cvtest::TS::ptr()->get_data_path()) + "meanshift/spmap.yaml", cv::FileStorage::READ);
else
fs.open(std::string(cvtest::TS::ptr()->get_data_path()) + "meanshift/spmap_CC1X.yaml", cv::FileStorage::READ);
ASSERT_TRUE(fs.isOpened());
cv::Mat spmap_template;
fs["spmap"] >> spmap_template;
ASSERT_FALSE(spmap_template.empty());
cv::cuda::GpuMat rmap_filtered;
cv::cuda::meanShiftFiltering(loadMat(img), rmap_filtered, spatialRad, colorRad);
cv::cuda::GpuMat rmap;
cv::cuda::GpuMat spmap;
cv::cuda::meanShiftProc(loadMat(img), rmap, spmap, spatialRad, colorRad);
ASSERT_EQ(CV_8UC4, rmap.type());
EXPECT_MAT_NEAR(rmap_filtered, rmap, 0.0);
EXPECT_MAT_NEAR(spmap_template, spmap, 0.0);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, MeanShift, ALL_DEVICES);
////////////////////////////////////////////////////////////////////////////////
// MeanShiftSegmentation
namespace
{
IMPLEMENT_PARAM_CLASS(MinSize, int);
}
PARAM_TEST_CASE(MeanShiftSegmentation, cv::cuda::DeviceInfo, MinSize)
{
cv::cuda::DeviceInfo devInfo;
int minsize;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
minsize = GET_PARAM(1);
cv::cuda::setDevice(devInfo.deviceID());
}
};
CUDA_TEST_P(MeanShiftSegmentation, Regression)
{
cv::Mat img = readImageType("meanshift/cones.png", CV_8UC4);
ASSERT_FALSE(img.empty());
std::ostringstream path;
path << "meanshift/cones_segmented_sp10_sr10_minsize" << minsize;
if (supportFeature(devInfo, cv::cuda::FEATURE_SET_COMPUTE_20))
path << ".png";
else
path << "_CC1X.png";
cv::Mat dst_gold = readImage(path.str());
ASSERT_FALSE(dst_gold.empty());
cv::Mat dst;
cv::cuda::meanShiftSegmentation(loadMat(img), dst, 10, 10, minsize);
cv::Mat dst_rgb;
cv::cvtColor(dst, dst_rgb, cv::COLOR_BGRA2BGR);
EXPECT_MAT_SIMILAR(dst_gold, dst_rgb, 1e-3);
}
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, MeanShiftSegmentation, testing::Combine(
ALL_DEVICES,
testing::Values(MinSize(0), MinSize(4), MinSize(20), MinSize(84), MinSize(340), MinSize(1364))));
}} // namespace
#endif // HAVE_CUDA
+121
View File
@@ -0,0 +1,121 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#ifdef HAVE_CUDA
namespace opencv_test { namespace {
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Moments
CV_ENUM(MaxMomentsOrder, MomentsOrder::FIRST_ORDER_MOMENTS, MomentsOrder::SECOND_ORDER_MOMENTS, MomentsOrder::THIRD_ORDER_MOMENTS)
PARAM_TEST_CASE(Moments, cv::cuda::DeviceInfo, cv::Size, bool, MatDepth, MatDepth, UseRoi, MaxMomentsOrder)
{
DeviceInfo devInfo;
Size size;
bool isBinary;
float pcWidth = 0.6f;
int momentsType;
int imgType;
bool useRoi;
MomentsOrder order;
virtual void SetUp()
{
devInfo = GET_PARAM(0);
size = GET_PARAM(1);
isBinary = GET_PARAM(2);
momentsType = GET_PARAM(3);
imgType = GET_PARAM(4);
useRoi = GET_PARAM(5);
order = static_cast<MomentsOrder>(static_cast<int>(GET_PARAM(6)));
cv::cuda::setDevice(devInfo.deviceID());
}
static void drawCircle(cv::Mat& dst, const cv::Vec3i& circle, bool fill)
{
dst.setTo(Scalar::all(0));
cv::circle(dst, Point2i(circle[0], circle[1]), circle[2], Scalar::all(255), fill ? -1 : 1, cv::LINE_AA);
}
};
bool Equal(const double m0, const double m1, const double absPcErr) {
if (absPcErr == 0) return m0 == m1;
if (m0 == 0) {
if (m1 < absPcErr) return true;
else return false;
}
const double pcDiff = abs(m0 - m1) / m1;
return pcDiff < absPcErr;
}
void CheckMoments(const cv::Moments m0, const cv::Moments m1, const MomentsOrder order, const int momentsType) {
double absPcErr = momentsType == CV_64F ? 0 : 5e-7;
ASSERT_TRUE(Equal(m0.m00, m1.m00, absPcErr)) << "m0.m00: " << m0.m00 << ", m1.m00: " << m1.m00 << ", absPcErr: " << absPcErr;
ASSERT_TRUE(Equal(m0.m10, m1.m10, absPcErr)) << "m0.m10: " << m0.m10 << ", m1.m10: " << m1.m10 << ", absPcErr: " << absPcErr;
ASSERT_TRUE(Equal(m0.m01, m1.m01, absPcErr)) << "m0.m01: " << m0.m01 << ", m1.m01: " << m1.m01 << ", absPcErr: " << absPcErr;
if (static_cast<int>(order) >= static_cast<int>(MomentsOrder::SECOND_ORDER_MOMENTS)) {
ASSERT_TRUE(Equal(m0.m20, m1.m20, absPcErr)) << "m0.m20: " << m0.m20 << ", m1.m20: " << m1.m20 << ", absPcErr: " << absPcErr;
ASSERT_TRUE(Equal(m0.m11, m1.m11, absPcErr)) << "m0.m11: " << m0.m11 << ", m1.m11: " << m1.m11 << ", absPcErr: " << absPcErr;
ASSERT_TRUE(Equal(m0.m02, m1.m02, absPcErr)) << "m0.m02: " << m0.m02 << ", m1.m02: " << m1.m02 << ", absPcErr: " << absPcErr;
}
if (static_cast<int>(order) >= static_cast<int>(MomentsOrder::THIRD_ORDER_MOMENTS)) {
ASSERT_TRUE(Equal(m0.m30, m1.m30, absPcErr)) << "m0.m30: " << m0.m30 << ", m1.m30: " << m1.m30 << ", absPcErr: " << absPcErr;
ASSERT_TRUE(Equal(m0.m21, m1.m21, absPcErr)) << "m0.m21: " << m0.m21 << ", m1.m21: " << m1.m21 << ", absPcErr: " << absPcErr;
ASSERT_TRUE(Equal(m0.m12, m1.m12, absPcErr)) << "m0.m12: " << m0.m12 << ", m1.m12: " << m1.m12 << ", absPcErr: " << absPcErr;
ASSERT_TRUE(Equal(m0.m03, m1.m03, absPcErr)) << "m0.m03: " << m0.m03 << ", m1.m03: " << m1.m03 << ", absPcErr: " << absPcErr;
}
}
CUDA_TEST_P(Moments, Accuracy)
{
Mat imgHost(size, imgType);
const Rect roi = useRoi ? Rect(1, 0, imgHost.cols - 2, imgHost.rows) : Rect(0, 0, imgHost.cols, imgHost.rows);
const Vec3i circle(size.width / 2, size.height / 2, static_cast<int>(static_cast<float>(size.width/2) * pcWidth));
drawCircle(imgHost, circle, true);
const GpuMat imgDevice(imgHost);
const int nMoments = numMoments(order);
setBufferPoolUsage(true);
setBufferPoolConfig(getDevice(), nMoments * ((momentsType == CV_64F) ? sizeof(double) : sizeof(float)), 1);
const cv::Moments moments = cuda::moments(imgDevice(roi), isBinary, order, momentsType);
Mat imgHostFloat; imgHost(roi).convertTo(imgHostFloat, CV_32F);
const cv::Moments momentsGs = cv::moments(imgHostFloat, isBinary);
CheckMoments(momentsGs, moments, order, momentsType);
}
CUDA_TEST_P(Moments, Async)
{
Stream stream;
const int nMoments = numMoments(order);
GpuMat momentsDevice(1, nMoments, momentsType);
Mat imgHost(size, imgType);
const Rect roi = useRoi ? Rect(1, 0, imgHost.cols - 2, imgHost.rows) : Rect(0, 0, imgHost.cols, imgHost.rows);
const Vec3i circle(size.width / 2, size.height / 2, static_cast<int>(static_cast<float>(size.width/2) * pcWidth));
drawCircle(imgHost, circle, true);
const GpuMat imgDevice(imgHost);
cuda::spatialMoments(imgDevice(roi), momentsDevice, isBinary, order, momentsType, stream);
HostMem momentsHost(1, nMoments, momentsType);
momentsDevice.download(momentsHost, stream);
stream.waitForCompletion();
const cv::Moments moments = convertSpatialMoments(momentsHost.createMatHeader(), order, momentsType);
Mat imgHostAdjustedType = imgHost(roi);
if (imgType != CV_8U && imgType != CV_32F)
imgHost(roi).convertTo(imgHostAdjustedType, CV_32F);
const cv::Moments momentsGs = cv::moments(imgHostAdjustedType, isBinary);
CheckMoments(momentsGs, moments, order, momentsType);
}
#define SIZES DIFFERENT_SIZES
#define GRAYSCALE_BINARY testing::Bool()
#define MOMENTS_TYPE testing::Values(MatDepth(CV_32F), MatDepth(CV_64F))
#define IMG_TYPE ALL_DEPTH
#define USE_ROI WHOLE_SUBMAT
#define MOMENTS_ORDER testing::Values(MaxMomentsOrder(MomentsOrder::FIRST_ORDER_MOMENTS), MaxMomentsOrder(MomentsOrder::SECOND_ORDER_MOMENTS), MaxMomentsOrder(MomentsOrder::THIRD_ORDER_MOMENTS))
INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, Moments, testing::Combine(ALL_DEVICES, SIZES, GRAYSCALE_BINARY, MOMENTS_TYPE, IMG_TYPE, USE_ROI, MOMENTS_ORDER));
}} // namespace
#endif // HAVE_CUDA
+54
View File
@@ -0,0 +1,54 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __OPENCV_TEST_PRECOMP_HPP__
#define __OPENCV_TEST_PRECOMP_HPP__
#include "opencv2/ts.hpp"
#include "opencv2/ts/cuda_test.hpp"
#include "opencv2/cudaimgproc.hpp"
#include "opencv2/geometry.hpp"
#include "cvconfig.h"
#include <thread>
#endif