Skip to content

Commit e196d06

Browse files
committed
Merge branch '4.x' into coordinate
1 parent e90a281 commit e196d06

File tree

6 files changed

+146
-20
lines changed

6 files changed

+146
-20
lines changed

.github/PULL_REQUEST_TEMPLATE.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
44

5-
- [ ] I agree to contribute to the project under Apache 2 License.
6-
- [ ] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
5+
- [x] I agree to contribute to the project under Apache 2 License.
6+
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
77
- [ ] The PR is proposed to the proper branch
88
- [ ] There is a reference to the original bug report and related work
99
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable

modules/cudaarithm/CMakeLists.txt

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4127 /wd4324 /wd4512 -Wundef -Wmissing-d
99
set(extra_dependencies "")
1010
set(optional_dependencies "")
1111
if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE)
12+
if(UNIX AND NOT BUILD_SHARED_LIBS AND CUDA_VERSION_STRING VERSION_GREATER_EQUAL 9.2 AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.23)
13+
set(CUDA_FFT_LIB_EXT "_static_nocallback")
14+
endif()
1215
list(APPEND extra_dependencies CUDA::cudart_static CUDA::nppial${CUDA_LIB_EXT} CUDA::nppc${CUDA_LIB_EXT} CUDA::nppitc${CUDA_LIB_EXT} CUDA::nppig${CUDA_LIB_EXT} CUDA::nppist${CUDA_LIB_EXT} CUDA::nppidei${CUDA_LIB_EXT})
1316
if(HAVE_CUBLAS)
1417
list(APPEND optional_dependencies CUDA::cublas${CUDA_LIB_EXT})
@@ -18,7 +21,8 @@ if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE)
1821
endif()
1922
if(HAVE_CUFFT)
2023
# static version requires seperable compilation which is incompatible with opencv's current library structure
21-
list(APPEND optional_dependencies CUDA::cufft)
24+
# the cufft_static_nocallback variant does not requires seperable compilation. callbacks are currently not used.
25+
list(APPEND optional_dependencies CUDA::cufft${CUDA_FFT_LIB_EXT})
2226
endif()
2327
else()
2428
if(HAVE_CUBLAS)

modules/cudafilters/include/opencv2/cudafilters.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,14 @@ CV_EXPORTS_W Ptr<Filter> createLaplacianFilter(int srcType, int dstType, int ksi
142142
////////////////////////////////////////////////////////////////////////////////////////////////////
143143
// Separable Linear Filter
144144

145-
/** @brief Creates a separable linear filter.
145+
/** @brief Creates a separable linear filter. In-place processing is supported.
146146
147147
@param srcType Source array type.
148148
@param dstType Destination array type.
149149
@param rowKernel Horizontal filter coefficients. Support kernels with size \<= 32 .
150+
noArray() is supported to ignore the row filtering.
150151
@param columnKernel Vertical filter coefficients. Support kernels with size \<= 32 .
152+
noArray() is supported to ignore the column filtering.
151153
@param anchor Anchor position within the kernel. Negative values mean that anchor is positioned at
152154
the aperture center.
153155
@param rowBorderMode Pixel extrapolation method in the vertical direction For details, see

modules/cudafilters/src/filtering.cpp

+55-15
Original file line numberDiff line numberDiff line change
@@ -386,28 +386,38 @@ namespace
386386
const int cn = CV_MAT_CN(srcType);
387387
const int ddepth = CV_MAT_DEPTH(dstType);
388388

389-
Mat rowKernel = _rowKernel.getMat();
390-
Mat columnKernel = _columnKernel.getMat();
389+
CV_Assert( _rowKernel.empty() || _rowKernel.isMat() );
390+
CV_Assert( _columnKernel.empty() || _columnKernel.isMat() );
391+
Mat rowKernel = _rowKernel.empty() ? cv::Mat() : _rowKernel.getMat();
392+
Mat columnKernel = _columnKernel.empty() ? cv::Mat() : _columnKernel.getMat();
391393

392394
CV_Assert( sdepth <= CV_64F && cn <= 4 );
393-
CV_Assert( rowKernel.channels() == 1 );
394-
CV_Assert( columnKernel.channels() == 1 );
395+
CV_Assert( rowKernel.empty() || rowKernel.channels() == 1 );
396+
CV_Assert( columnKernel.empty() || columnKernel.channels() == 1 );
395397
CV_Assert( rowBorderMode == BORDER_REFLECT101 || rowBorderMode == BORDER_REPLICATE || rowBorderMode == BORDER_CONSTANT || rowBorderMode == BORDER_REFLECT || rowBorderMode == BORDER_WRAP );
396398
CV_Assert( columnBorderMode == BORDER_REFLECT101 || columnBorderMode == BORDER_REPLICATE || columnBorderMode == BORDER_CONSTANT || columnBorderMode == BORDER_REFLECT || columnBorderMode == BORDER_WRAP );
397399

398400
Mat kernel32F;
399401

400-
rowKernel.convertTo(kernel32F, CV_32F);
401-
rowKernel_.upload(kernel32F.reshape(1, 1));
402+
if (!rowKernel.empty())
403+
{
404+
rowKernel.convertTo(kernel32F, CV_32F);
405+
rowKernel_.upload(kernel32F.reshape(1, 1));
406+
}
402407

403-
columnKernel.convertTo(kernel32F, CV_32F);
404-
columnKernel_.upload(kernel32F.reshape(1, 1));
408+
if (!columnKernel.empty())
409+
{
410+
columnKernel.convertTo(kernel32F, CV_32F);
411+
columnKernel_.upload(kernel32F.reshape(1, 1));
412+
}
405413

406-
CV_Assert( rowKernel_.cols > 0 && rowKernel_.cols <= 32 );
407-
CV_Assert( columnKernel_.cols > 0 && columnKernel_.cols <= 32 );
414+
CV_Assert( rowKernel_.empty() || (rowKernel_.cols > 0 && rowKernel_.cols <= 32 ));
415+
CV_Assert( columnKernel_.empty() || (columnKernel_.cols > 0 && columnKernel_.cols <= 32 ));
408416

409-
normalizeAnchor(anchor_.x, rowKernel_.cols);
410-
normalizeAnchor(anchor_.y, columnKernel_.cols);
417+
if (!rowKernel_.empty())
418+
normalizeAnchor(anchor_.x, rowKernel_.cols);
419+
if (!columnKernel_.empty())
420+
normalizeAnchor(anchor_.y, columnKernel_.cols);
411421

412422
bufType_ = CV_MAKE_TYPE(CV_32F, cn);
413423

@@ -426,15 +436,45 @@ namespace
426436
_dst.create(src.size(), dstType_);
427437
GpuMat dst = _dst.getGpuMat();
428438

429-
ensureSizeIsEnough(src.size(), bufType_, buf_);
439+
const bool isInPlace = (src.data == dst.data);
440+
const bool hasRowKernel = !rowKernel_.empty();
441+
const bool hasColKernel = !columnKernel_.empty();
442+
const bool hasSingleKernel = (hasRowKernel ^ hasColKernel);
443+
const bool needsSrcAdaptation = !hasRowKernel && hasColKernel && (srcType_ != bufType_);
444+
const bool needsDstAdaptation = hasRowKernel && !hasColKernel && (dstType_ != bufType_);
445+
const bool needsBufForIntermediateStorage = (hasRowKernel && hasColKernel) || (hasSingleKernel && isInPlace);
446+
const bool needsBuf = needsSrcAdaptation || needsDstAdaptation || needsBufForIntermediateStorage;
447+
if (needsBuf)
448+
ensureSizeIsEnough(src.size(), bufType_, buf_);
449+
450+
if (needsSrcAdaptation)
451+
src.convertTo(buf_, bufType_, _stream);
452+
GpuMat& srcAdapted = needsSrcAdaptation ? buf_ : src;
430453

431454
DeviceInfo devInfo;
432455
const int cc = devInfo.majorVersion() * 10 + devInfo.minorVersion();
433456

434457
cudaStream_t stream = StreamAccessor::getStream(_stream);
435458

436-
rowFilter_(src, buf_, rowKernel_.ptr<float>(), rowKernel_.cols, anchor_.x, rowBorderMode_, cc, stream);
437-
columnFilter_(buf_, dst, columnKernel_.ptr<float>(), columnKernel_.cols, anchor_.y, columnBorderMode_, cc, stream);
459+
if (!hasRowKernel && !hasColKernel && !isInPlace)
460+
srcAdapted.convertTo(dst, dstType_, _stream);
461+
else if (hasRowKernel || hasColKernel)
462+
{
463+
GpuMat& rowFilterSrc = srcAdapted;
464+
GpuMat& rowFilterDst = !hasRowKernel ? srcAdapted : needsBuf ? buf_ : dst;
465+
GpuMat& colFilterSrc = hasColKernel && needsBuf ? buf_ : srcAdapted;
466+
GpuMat& colFilterTo = dst;
467+
468+
if (hasRowKernel)
469+
rowFilter_(rowFilterSrc, rowFilterDst, rowKernel_.ptr<float>(), rowKernel_.cols, anchor_.x, rowBorderMode_, cc, stream);
470+
else if (hasColKernel && (needsBufForIntermediateStorage && !needsSrcAdaptation))
471+
rowFilterSrc.convertTo(buf_, bufType_, _stream);
472+
473+
if (hasColKernel)
474+
columnFilter_(colFilterSrc, colFilterTo, columnKernel_.ptr<float>(), columnKernel_.cols, anchor_.y, columnBorderMode_, cc, stream);
475+
else if (needsBuf)
476+
buf_.convertTo(dst, dstType_, _stream);
477+
}
438478
}
439479
}
440480

modules/cudafilters/test/test_filters.cpp

+80
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,86 @@ INSTANTIATE_TEST_CASE_P(CUDA_Filters, SeparableLinearFilter, testing::Combine(
281281
BorderType(cv::BORDER_REFLECT)),
282282
WHOLE_SUBMAT));
283283

284+
PARAM_TEST_CASE(SeparableLinearFilterWithEmptyKernels, cv::cuda::DeviceInfo, MatDepth, Channels, MatDepth, bool, bool, bool)
285+
{
286+
cv::cuda::DeviceInfo devInfo;
287+
bool inPlace;
288+
bool useRowKernel;
289+
bool useColKernel;
290+
291+
cv::Size size;
292+
int srcDepth;
293+
int cn;
294+
int dstDepth;
295+
cv::Size ksize;
296+
cv::Point anchor;
297+
int borderType;
298+
int srcType;
299+
int dstType;
300+
301+
virtual void SetUp()
302+
{
303+
devInfo = GET_PARAM(0);
304+
srcDepth = GET_PARAM(1);
305+
cn = GET_PARAM(2);
306+
dstDepth = GET_PARAM(3);
307+
inPlace = GET_PARAM(4);
308+
useRowKernel = GET_PARAM(5);
309+
useColKernel = GET_PARAM(6);
310+
311+
size = cv::Size(640, 480);
312+
ksize = cv::Size(3, 1);
313+
anchor = cv::Point(-1, -1);
314+
borderType = cv::BORDER_REPLICATE;
315+
316+
cv::cuda::setDevice(devInfo.deviceID());
317+
318+
srcType = CV_MAKE_TYPE(srcDepth, cn);
319+
dstType = CV_MAKE_TYPE(dstDepth, cn);
320+
}
321+
};
322+
323+
CUDA_TEST_P(SeparableLinearFilterWithEmptyKernels, Accuracy)
324+
{
325+
cv::Mat src = randomMat(size, srcType);
326+
cv::Mat rowKernel = (cv::Mat_<float>(ksize) << -1, 0, 1);
327+
cv::Mat colKernel = rowKernel.t();
328+
cv::Mat oneKernel = cv::Mat::ones(cv::Size(1, 1), CV_32FC1);
329+
cv::Mat noKernel = cv::Mat();
330+
331+
cv::Ptr<cv::cuda::Filter> sepFilterDummyKernels =
332+
cv::cuda::createSeparableLinearFilter(srcType, dstType,
333+
useRowKernel ? rowKernel : oneKernel,
334+
useColKernel ? colKernel : oneKernel,
335+
cv::Point(-1, -1), cv::BORDER_REPLICATE, cv::BORDER_REPLICATE);
336+
337+
cv::Ptr<cv::cuda::Filter> sepFilterEmptyKernels =
338+
cv::cuda::createSeparableLinearFilter(srcType, dstType,
339+
useRowKernel ? rowKernel : noKernel,
340+
useColKernel ? colKernel : noKernel,
341+
cv::Point(-1, -1), cv::BORDER_REPLICATE, cv::BORDER_REPLICATE);
342+
343+
cv::cuda::GpuMat src_sep_dummyK = loadMat(src);
344+
cv::cuda::GpuMat dst_sep_dummyK = inPlace ? src_sep_dummyK : cv::cuda::GpuMat();
345+
cv::cuda::GpuMat src_sep_emptyK = loadMat(src);
346+
cv::cuda::GpuMat dst_sep_emptyK = inPlace ? src_sep_emptyK : cv::cuda::GpuMat();
347+
348+
sepFilterDummyKernels->apply(src_sep_dummyK, dst_sep_dummyK);
349+
sepFilterEmptyKernels->apply(src_sep_emptyK, dst_sep_emptyK);
350+
351+
EXPECT_MAT_NEAR(dst_sep_dummyK, dst_sep_emptyK, src.depth() < CV_32F ? 1.0 : 1e-2);
352+
}
353+
354+
INSTANTIATE_TEST_CASE_P(CUDA_Filters, SeparableLinearFilterWithEmptyKernels, testing::Combine(
355+
ALL_DEVICES,
356+
testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_16S), MatDepth(CV_32F)),
357+
IMAGE_CHANNELS,
358+
testing::Values(MatDepth(CV_8U), MatDepth(CV_16U), MatDepth(CV_16S), MatDepth(CV_32F)),
359+
testing::Values(false, true),//in-place
360+
testing::Values(false, true),//use row kernel
361+
testing::Values(false, true)//use col kernel
362+
));
363+
284364
/////////////////////////////////////////////////////////////////////////////////////////////////
285365
// Sobel
286366

modules/wechat_qrcode/samples/qrcode.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
except:
2323
print("---------------------------------------------------------------")
2424
print("Failed to initialize WeChatQRCode.")
25-
print("Please, download 'detector.*' and 'sr.*' from")
25+
print("Please, download 'detect.*' and 'sr.*' from")
2626
print("https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode")
2727
print("and put them into the current directory.")
2828
print("---------------------------------------------------------------")

0 commit comments

Comments
 (0)