From 8edff1065a859b20aa315a1a31bd5f7477d53962 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 11 Oct 2018 09:07:22 +0000 Subject: [PATCH 01/17] add .editorconfig https://editorconfig.org/ --- .editorconfig | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..7aca75262b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,31 @@ +# https://editorconfig.org/ + +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 + +[{CMakeLists.*,*.cmake}] +indent_style = space +indent_size = 2 + +[Makefile] +indent_style = tab + +[*.{bat,cmd,cmd.*}] +end_of_line = crlf +indent_style = space +indent_size = 2 + +[*.{ps1,ps1.*}] +end_of_line = crlf +indent_style = space +indent_size = 4 + +[*.{md,markdown}] +indent_size = 2 From 237b8677217744068441aff8388ffc7412a6ace9 Mon Sep 17 00:00:00 2001 From: Karpushin Vladislav Date: Thu, 18 Oct 2018 11:41:59 +0700 Subject: [PATCH 02/17] doc: add new tutorial periodic noise removing filter --- .../images/period_filter.jpg | Bin 0 -> 8508 bytes .../images/period_input.jpg | Bin 0 -> 69636 bytes .../images/period_output.jpg | Bin 0 -> 53512 bytes .../images/period_psd.jpg | Bin 0 -> 6634 bytes .../periodic_noise_removing_filter.markdown | 61 ++++++++ .../imgproc/table_of_content_imgproc.markdown | 10 ++ .../periodic_noise_removing_filter.cpp | 148 ++++++++++++++++++ 7 files changed, 219 insertions(+) create mode 100755 doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_filter.jpg create mode 100755 doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_input.jpg create mode 100755 doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_output.jpg create mode 100755 doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_psd.jpg create mode 100755 doc/tutorials/imgproc/periodic_noise_removing_filter/periodic_noise_removing_filter.markdown create mode 100755 samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp diff --git a/doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_filter.jpg b/doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_filter.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1efd2cb183c862626b214ec90ddf2ab4f8d5f8a6 GIT binary patch literal 8508 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 literal 0 HcmV?d00001 diff --git a/doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_input.jpg b/doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_input.jpg new file mode 100755 index 0000000000000000000000000000000000000000..78f97e94ce2e903d189bce14d31ea48f0b01913c GIT binary patch literal 69636 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

=~>zaM9!c{V0fCy8J^Y2um z$t=ZWa0)I%W7dR8-dsZEQ)NgF22Zc}tgyCg_h_Y!(5MiGq|Uz?tWohR)@reLbp>N2XmPI^?APWKMi zZc!Q_rwY6r98;p4+&tGNG*F5(g%}@|QuFt?l ptEBzl=q_Z)QZt;=qmymL(F*=N=p&4p5an4W1xW|JiuO`Og3V literal 0 HcmV?d00001 diff --git a/doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_output.jpg b/doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_output.jpg new file mode 100755 index 0000000000000000000000000000000000000000..fd37288f668603b1fdd50eeda7f41da93c4d2873 GIT binary patch literal 53512 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

  • U(fNtSH$Y-&22|)=BE5 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 literal 0 HcmV?d00001 diff --git a/doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_psd.jpg b/doc/tutorials/imgproc/periodic_noise_removing_filter/images/period_psd.jpg new file mode 100755 index 0000000000000000000000000000000000000000..75e83c691e36226054c65f0b0c6a6c2b96167027 GIT binary patch literal 6634 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 literal 0 HcmV?d00001 diff --git a/doc/tutorials/imgproc/periodic_noise_removing_filter/periodic_noise_removing_filter.markdown b/doc/tutorials/imgproc/periodic_noise_removing_filter/periodic_noise_removing_filter.markdown new file mode 100755 index 0000000000..ca0ffbf02b --- /dev/null +++ b/doc/tutorials/imgproc/periodic_noise_removing_filter/periodic_noise_removing_filter.markdown @@ -0,0 +1,61 @@ +Periodic Noise Removing Filter {#tutorial_periodic_noise_removing_filter} +========================== + +Goal +---- + +In this tutorial you will learn: + +- how to remove periodic noise in the Fourier domain + +Theory +------ + +@note The explanation is based on the book @cite gonzalez. The image on this page is a real world image. + +Periodic noise produces spikes in the Fourier domain that can often be detected by visual analysis. + +### How to remove periodic noise in the Fourier domain? + +Periodic noise can be reduced significantly via frequency domain filtering. On this page we use a notch reject filter with an appropriate radius to completely enclose the noise spikes in the Fourier domain. The notch filter rejects frequencies in predefined neighborhoods around a center frequency. The number of notch filters is arbitrary. The shape of the notch areas can also be arbitrary (e.g. rectangular or circular). On this page we use three circular shape notch reject filters. Power spectrum densify of an image is used for the noise spike’s visual detection. + +Source code +----------- + +You can find source code in the `samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp` of the OpenCV source code library. + +@include samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp + +Explanation +----------- + +Periodic noise reduction by frequency domain filtering consists of power spectrum density calculation (for the noise spikes visual detection), notch reject filter synthesis and frequency filtering: +@snippet samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp main + +A function calcPSD() calculates power spectrum density of an image: +@snippet samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp calcPSD + +A function synthesizeFilterH() forms a transfer function of an ideal circular shape notch reject filter according to a center frequency and a radius: +@snippet samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp synthesizeFilterH + +A function filter2DFreq() filters an image in the frequency domain. The functions fftshift() and filter2DFreq() are copied from the tutorial @ref tutorial_out_of_focus_deblur_filter "Out-of-focus Deblur Filter". + +Result +------ + +The figure below shows an image heavily corrupted by periodical noise of various frequencies. +![Image corrupted by periodic noise](images/period_input.jpg) + +The noise components are easily seen as bright dots (spikes) in the Power spectrum density shown in the figure below. +![Power spectrum density showing periodic noise](images/period_psd.jpg) + +The figure below shows a notch reject filter with an appropriate radius to completely enclose the noise spikes. +![Notch reject filter](images/period_filter.jpg) + +The result of processing the image with the notch reject filter is shown below. +![Result of filtering](images/period_output.jpg) + +The improvement is quite evident. This image contains significantly less visible periodic noise than the original image. + +You can also find a quick video demonstration of this filtering idea on [YouTube](https://youtu.be/Qne51TcWwAc). +@youtube{Qne51TcWwAc} diff --git a/doc/tutorials/imgproc/table_of_content_imgproc.markdown b/doc/tutorials/imgproc/table_of_content_imgproc.markdown index badc30d095..bd04b57717 100644 --- a/doc/tutorials/imgproc/table_of_content_imgproc.markdown +++ b/doc/tutorials/imgproc/table_of_content_imgproc.markdown @@ -340,3 +340,13 @@ In this section you will learn about the image processing (manipulation) functio *Author:* Karpushin Vladislav You will learn how to segment an anisotropic image with a single local orientation by a gradient structure tensor. + +- @subpage tutorial_periodic_noise_removing_filter + + *Languages:* C++ + + *Compatibility:* \> OpenCV 2.0 + + *Author:* Karpushin Vladislav + + You will learn how to remove periodic noise in the Fourier domain. diff --git a/samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp b/samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp new file mode 100755 index 0000000000..0f49b698d5 --- /dev/null +++ b/samples/cpp/tutorial_code/ImgProc/periodic_noise_removing_filter/periodic_noise_removing_filter.cpp @@ -0,0 +1,148 @@ +/** +* @brief You will learn how to remove periodic noise in the Fourier domain +* @author Karpushin Vladislav, karpushin@ngs.ru, https://github.com/VladKarpushin +*/ +#include +#include +#include + +using namespace cv; +using namespace std; + +void fftshift(const Mat& inputImg, Mat& outputImg); +void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H); +void synthesizeFilterH(Mat& inputOutput_H, Point center, int radius); +void calcPSD(const Mat& inputImg, Mat& outputImg, int flag = 0); + +int main() +{ + Mat imgIn = imread("input.jpg", IMREAD_GRAYSCALE); + if (imgIn.empty()) //check whether the image is loaded or not + { + cout << "ERROR : Image cannot be loaded..!!" << endl; + return -1; + } + + imgIn.convertTo(imgIn, CV_32F); + +//! [main] + // it needs to process even image only + Rect roi = Rect(0, 0, imgIn.cols & -2, imgIn.rows & -2); + imgIn = imgIn(roi); + + // PSD calculation (start) + Mat imgPSD; + calcPSD(imgIn, imgPSD); + fftshift(imgPSD, imgPSD); + normalize(imgPSD, imgPSD, 0, 255, NORM_MINMAX); + // PSD calculation (stop) + + //H calculation (start) + Mat H = Mat(roi.size(), CV_32F, Scalar(1)); + const int r = 21; + synthesizeFilterH(H, Point(705, 458), r); + synthesizeFilterH(H, Point(850, 391), r); + synthesizeFilterH(H, Point(993, 325), r); + //H calculation (stop) + // filtering (start) + Mat imgOut; + fftshift(H, H); + filter2DFreq(imgIn, imgOut, H); + // filtering (stop) +//! [main] + + imgOut.convertTo(imgOut, CV_8U); + normalize(imgOut, imgOut, 0, 255, NORM_MINMAX); + imwrite("result.jpg", imgOut); + imwrite("PSD.jpg", imgPSD); + fftshift(H, H); + normalize(H, H, 0, 255, NORM_MINMAX); + imwrite("filter.jpg", H); + return 0; +} + +//! [fftshift] +void fftshift(const Mat& inputImg, Mat& outputImg) +{ + outputImg = inputImg.clone(); + int cx = outputImg.cols / 2; + int cy = outputImg.rows / 2; + Mat q0(outputImg, Rect(0, 0, cx, cy)); + Mat q1(outputImg, Rect(cx, 0, cx, cy)); + Mat q2(outputImg, Rect(0, cy, cx, cy)); + Mat q3(outputImg, Rect(cx, cy, cx, cy)); + Mat tmp; + q0.copyTo(tmp); + q3.copyTo(q0); + tmp.copyTo(q3); + q1.copyTo(tmp); + q2.copyTo(q1); + tmp.copyTo(q2); +} +//! [fftshift] + +//! [filter2DFreq] +void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H) +{ + Mat planes[2] = { Mat_(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) }; + Mat complexI; + merge(planes, 2, complexI); + dft(complexI, complexI, DFT_SCALE); + + Mat planesH[2] = { Mat_(H.clone()), Mat::zeros(H.size(), CV_32F) }; + Mat complexH; + merge(planesH, 2, complexH); + Mat complexIH; + mulSpectrums(complexI, complexH, complexIH, 0); + + idft(complexIH, complexIH); + split(complexIH, planes); + outputImg = planes[0]; +} +//! [filter2DFreq] + +//! [synthesizeFilterH] +void synthesizeFilterH(Mat& inputOutput_H, Point center, int radius) +{ + Point c2 = center, c3 = center, c4 = center; + c2.y = inputOutput_H.rows - center.y; + c3.x = inputOutput_H.cols - center.x; + c4 = Point(c3.x,c2.y); + circle(inputOutput_H, center, radius, 0, -1, 8); + circle(inputOutput_H, c2, radius, 0, -1, 8); + circle(inputOutput_H, c3, radius, 0, -1, 8); + circle(inputOutput_H, c4, radius, 0, -1, 8); +} +//! [synthesizeFilterH] + +// Function calculates PSD(Power spectrum density) by fft with two flags +// flag = 0 means to return PSD +// flag = 1 means to return log(PSD) +//! [calcPSD] +void calcPSD(const Mat& inputImg, Mat& outputImg, int flag) +{ + Mat planes[2] = { Mat_(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) }; + Mat complexI; + merge(planes, 2, complexI); + dft(complexI, complexI); + split(complexI, planes); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I)) + + planes[0].at(0) = 0; + planes[1].at(0) = 0; + + // compute the PSD = sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)^2 + Mat imgPSD; + magnitude(planes[0], planes[1], imgPSD); //imgPSD = sqrt(Power spectrum density) + pow(imgPSD, 2, imgPSD); //it needs ^2 in order to get PSD + outputImg = imgPSD; + + // logPSD = log(1 + PSD) + if (flag) + { + Mat imglogPSD; + imglogPSD = imgPSD + Scalar::all(1); + log(imglogPSD, imglogPSD); + outputImg = imglogPSD; + } +} +//! [calcPSD] From 6974fce183cda32bfb289a0a59378195489e0b90 Mon Sep 17 00:00:00 2001 From: Mansoo Kim Date: Sun, 21 Oct 2018 15:13:43 +0000 Subject: [PATCH 03/17] cmake: fix objdetect QR decoder link_libraries --- modules/objdetect/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/objdetect/CMakeLists.txt b/modules/objdetect/CMakeLists.txt index a51740c280..414e578099 100644 --- a/modules/objdetect/CMakeLists.txt +++ b/modules/objdetect/CMakeLists.txt @@ -4,5 +4,5 @@ ocv_define_module(objdetect opencv_core opencv_imgproc opencv_calib3d WRAP java if(HAVE_QUIRC) get_property(QUIRC_INCLUDE GLOBAL PROPERTY QUIRC_INCLUDE_DIR) ocv_include_directories(${QUIRC_INCLUDE}) - ocv_target_link_libraries(${PROJECT_NAME} quirc) + ocv_target_link_libraries(${the_module} quirc) endif() From 1fbaa48cecc632ce9a6db3f427a382576b0c568f Mon Sep 17 00:00:00 2001 From: huangqinjin Date: Sat, 20 Oct 2018 21:43:39 +0800 Subject: [PATCH 04/17] ORB: compute default norm by wta_k --- modules/features2d/src/orb.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/features2d/src/orb.cpp b/modules/features2d/src/orb.cpp index e3468af60b..0a328576c0 100644 --- a/modules/features2d/src/orb.cpp +++ b/modules/features2d/src/orb.cpp @@ -724,7 +724,16 @@ int ORB_Impl::descriptorType() const int ORB_Impl::defaultNorm() const { - return NORM_HAMMING; + switch (wta_k) + { + case 2: + return NORM_HAMMING; + case 3: + case 4: + return NORM_HAMMING2; + default: + return -1; + } } #ifdef HAVE_OPENCL From d3f75df0a6f1148fc112c2aa4b88e363237813dd Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Wed, 24 Oct 2018 09:35:02 +0900 Subject: [PATCH 05/17] objdetect: fix test failure of QR code on Aarch64 * use boundingRect instead of manual loop --- modules/objdetect/src/qrcode.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/modules/objdetect/src/qrcode.cpp b/modules/objdetect/src/qrcode.cpp index aa269d9e4a..ac0a142134 100644 --- a/modules/objdetect/src/qrcode.cpp +++ b/modules/objdetect/src/qrcode.cpp @@ -862,6 +862,20 @@ bool QRDecode::updatePerspective() return true; } +inline Point computeOffset(const vector& v) +{ + // compute the width/height of convex hull + Rect areaBox = boundingRect(v); + + // compute the good offset + // the box is consisted by 7 steps + // to pick the middle of the stripe, it needs to be 1/14 of the size + const int cStep = 7 * 2; + Point offset = Point(areaBox.width, areaBox.height); + offset /= cStep; + return offset; +} + bool QRDecode::versionDefinition() { LineIterator line_iter(intermediate, Point2f(0, 0), Point2f(test_perspective_size, test_perspective_size)); @@ -879,17 +893,18 @@ bool QRDecode::versionDefinition() Mat mask_roi = mask(Range(1, intermediate.rows - 1), Range(1, intermediate.cols - 1)); findNonZero(mask_roi, non_zero_elem); convexHull(Mat(non_zero_elem), locations); + Point offset = computeOffset(locations); Point temp_remote = locations[0], remote_point; - const Point delta_diff = Point(4, 4); + const Point delta_diff = offset; for (size_t i = 0; i < locations.size(); i++) { - if (norm(black_point - temp_remote) < norm(black_point - locations[i])) + if (norm(black_point - temp_remote) <= norm(black_point - locations[i])) { const uint8_t value = intermediate.at(temp_remote - delta_diff); - if (value == 0) { remote_point = temp_remote - delta_diff; } - else { remote_point = temp_remote; } temp_remote = locations[i]; + if (value == 0) { remote_point = temp_remote - delta_diff; } + else { remote_point = temp_remote - (delta_diff / 2); } } } From 0f07edded65e0e78fa7acda98e75d32cf525b952 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 24 Oct 2018 03:54:31 +0000 Subject: [PATCH 06/17] cmake: don't change baseline compiler flags in 'detection' mode --- cmake/OpenCVCompilerOptimizations.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/OpenCVCompilerOptimizations.cmake b/cmake/OpenCVCompilerOptimizations.cmake index 377eb98a65..72a5ebd1b2 100644 --- a/cmake/OpenCVCompilerOptimizations.cmake +++ b/cmake/OpenCVCompilerOptimizations.cmake @@ -448,7 +448,9 @@ foreach(OPT ${CPU_KNOWN_OPTIMIZATIONS}) if(NOT ";${CPU_BASELINE_FINAL};" MATCHES ";${OPT};") list(APPEND CPU_BASELINE_FINAL ${OPT}) endif() - ocv_append_optimization_flag(CPU_BASELINE_FLAGS ${OPT}) + if(NOT CPU_BASELINE_DETECT) # Don't change compiler flags in 'detection' mode + ocv_append_optimization_flag(CPU_BASELINE_FLAGS ${OPT}) + endif() endif() endif() endforeach() From 9a76322ef989c62e96d3eb79e1d2aa7716a8890a Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 24 Oct 2018 04:37:31 +0000 Subject: [PATCH 07/17] ios: update build script - IPHONEOS_DEPLOYMENT_TARGET=8.0 by default (minimal for XCode 10) --- CMakeLists.txt | 2 ++ platforms/ios/build_framework.py | 20 ++++++++++++++----- .../Toolchains/common-ios-toolchain.cmake | 13 +++++++++--- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index de27a744d8..f6e2b84447 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,8 +324,10 @@ OCV_OPTION(ENABLE_OMIT_FRAME_POINTER "Enable -fomit-frame-pointer for GCC" OCV_OPTION(ENABLE_POWERPC "Enable PowerPC for GCC" ON IF (CV_GCC AND CMAKE_SYSTEM_PROCESSOR MATCHES powerpc.*) ) OCV_OPTION(ENABLE_VSX "Enable POWER8 and above VSX (64-bit little-endian)" ON IF ((CV_GCC OR CV_CLANG) AND PPC64LE) ) OCV_OPTION(ENABLE_FAST_MATH "Enable -ffast-math (not recommended for GCC 4.6.x)" OFF IF (CV_GCC AND (X86 OR X86_64)) ) +if(NOT IOS) # Use CPU_BASELINE instead OCV_OPTION(ENABLE_NEON "Enable NEON instructions" (NEON OR ANDROID_ARM_NEON OR AARCH64) IF (CV_GCC OR CV_CLANG) AND (ARM OR AARCH64 OR IOS) ) OCV_OPTION(ENABLE_VFPV3 "Enable VFPv3-D32 instructions" OFF IF (CV_GCC OR CV_CLANG) AND (ARM OR AARCH64 OR IOS) ) +endif() OCV_OPTION(ENABLE_NOISY_WARNINGS "Show all warnings even if they are too noisy" OFF ) OCV_OPTION(OPENCV_WARNINGS_ARE_ERRORS "Treat warnings as errors" OFF ) OCV_OPTION(ANDROID_EXAMPLES_WITH_LIBS "Build binaries of Android examples with native libraries" OFF IF ANDROID ) diff --git a/platforms/ios/build_framework.py b/platforms/ios/build_framework.py index f546c6af5d..8b828fa267 100755 --- a/platforms/ios/build_framework.py +++ b/platforms/ios/build_framework.py @@ -31,8 +31,11 @@ from __future__ import print_function import glob, re, os, os.path, shutil, string, sys, argparse, traceback, multiprocessing from subprocess import check_call, check_output, CalledProcessError +IPHONEOS_DEPLOYMENT_TARGET='8.0' # default, can be changed via command line options or environemnt variable + def execute(cmd, cwd = None): print("Executing: %s in %s" % (cmd, cwd), file=sys.stderr) + print('Executing: ' + ' '.join(cmd)) retcode = check_call(cmd, cwd = cwd) if retcode != 0: raise Exception("Child returned:", retcode) @@ -149,7 +152,7 @@ class Builder: if self.dynamic: buildcmd += [ - "IPHONEOS_DEPLOYMENT_TARGET=8.0", + "IPHONEOS_DEPLOYMENT_TARGET=" + os.environ['IPHONEOS_DEPLOYMENT_TARGET'], "ONLY_ACTIVE_ARCH=NO", ] @@ -162,7 +165,7 @@ class Builder: else: arch = ";".join(archs) buildcmd += [ - "IPHONEOS_DEPLOYMENT_TARGET=6.0", + "IPHONEOS_DEPLOYMENT_TARGET=" + os.environ['IPHONEOS_DEPLOYMENT_TARGET'], "ARCHS=%s" % arch, ] @@ -184,7 +187,7 @@ class Builder: cmakecmd = self.getCMakeArgs(arch, target) + \ (["-DCMAKE_TOOLCHAIN_FILE=%s" % toolchain] if toolchain is not None else []) if target.lower().startswith("iphoneos"): - cmakecmd.append("-DCPU_BASELINE=NEON;FP16") + cmakecmd.append("-DCPU_BASELINE=DETECT") cmakecmd.append(self.opencv) cmakecmd.extend(cmakeargs) execute(cmakecmd, cwd = builddir) @@ -278,14 +281,21 @@ if __name__ == "__main__": parser.add_argument('--without', metavar='MODULE', default=[], action='append', help='OpenCV modules to exclude from the framework') parser.add_argument('--dynamic', default=False, action='store_true', help='build dynamic framework (default is "False" - builds static framework)') parser.add_argument('--disable-bitcode', default=False, dest='bitcodedisabled', action='store_true', help='disable bitcode (enabled by default)') + parser.add_argument('--iphoneos_deployment_target', default=os.environ.get('IPHONEOS_DEPLOYMENT_TARGET', IPHONEOS_DEPLOYMENT_TARGET), help='specify IPHONEOS_DEPLOYMENT_TARGET') + parser.add_argument('--iphoneos_archs', default='armv7,armv7s,arm64', help='select iPhoneOS target ARCHS') args = parser.parse_args() + os.environ['IPHONEOS_DEPLOYMENT_TARGET'] = args.iphoneos_deployment_target + print('Using IPHONEOS_DEPLOYMENT_TARGET=' + os.environ['IPHONEOS_DEPLOYMENT_TARGET']) + iphoneos_archs = args.iphoneos_archs.split(',') + print('Using iPhoneOS ARCHS=' + str(iphoneos_archs)) + b = iOSBuilder(args.opencv, args.contrib, args.dynamic, args.bitcodedisabled, args.without, [ - (["armv7s", "arm64"], "iPhoneOS"), + (iphoneos_archs, "iPhoneOS"), ] if os.environ.get('BUILD_PRECOMMIT', None) else [ - (["armv7", "armv7s", "arm64"], "iPhoneOS"), + (iphoneos_archs, "iPhoneOS"), (["i386", "x86_64"], "iPhoneSimulator"), ]) b.build(args.out) diff --git a/platforms/ios/cmake/Toolchains/common-ios-toolchain.cmake b/platforms/ios/cmake/Toolchains/common-ios-toolchain.cmake index 3eeb29199a..cec30f77b6 100644 --- a/platforms/ios/cmake/Toolchains/common-ios-toolchain.cmake +++ b/platforms/ios/cmake/Toolchains/common-ios-toolchain.cmake @@ -90,6 +90,13 @@ if(APPLE_FRAMEWORK AND NOT BUILD_SHARED_LIBS) set(CMAKE_OSX_ARCHITECTURES "${IOS_ARCH}" CACHE INTERNAL "Build architecture for iOS" FORCE) endif() +if(NOT DEFINED IPHONEOS_DEPLOYMENT_TARGET) + if(NOT DEFINED ENV{IPHONEOS_DEPLOYMENT_TARGET}) + message(FATAL_ERROR "IPHONEOS_DEPLOYMENT_TARGET is not specified") + endif() + set(IPHONEOS_DEPLOYMENT_TARGET "$ENV{IPHONEOS_DEPLOYMENT_TARGET}") +endif() + if(NOT __IN_TRY_COMPILE) set(_xcodebuild_wrapper "${CMAKE_BINARY_DIR}/xcodebuild_wrapper") if(NOT DEFINED CMAKE_MAKE_PROGRAM) # empty since CMake 3.10 @@ -103,14 +110,14 @@ if(NOT __IN_TRY_COMPILE) if(APPLE_FRAMEWORK AND BUILD_SHARED_LIBS) set(_xcodebuild_wrapper_tmp "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/xcodebuild_wrapper") file(WRITE "${_xcodebuild_wrapper_tmp}" "#!/bin/sh -${CMAKE_MAKE_PROGRAM} IPHONEOS_DEPLOYMENT_TARGET=8.0 -sdk ${CMAKE_OSX_SYSROOT} \$*") +${CMAKE_MAKE_PROGRAM} IPHONEOS_DEPLOYMENT_TARGET=${IPHONEOS_DEPLOYMENT_TARGET} -sdk ${CMAKE_OSX_SYSROOT} \$*") # Make executable file(COPY "${_xcodebuild_wrapper_tmp}" DESTINATION ${CMAKE_BINARY_DIR} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) set(CMAKE_MAKE_PROGRAM "${_xcodebuild_wrapper}" CACHE INTERNAL "" FORCE) else() set(_xcodebuild_wrapper_tmp "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/xcodebuild_wrapper") file(WRITE "${_xcodebuild_wrapper_tmp}" "#!/bin/sh -${CMAKE_MAKE_PROGRAM} IPHONEOS_DEPLOYMENT_TARGET=6.0 ARCHS=${IOS_ARCH} -sdk ${CMAKE_OSX_SYSROOT} \$*") +${CMAKE_MAKE_PROGRAM} IPHONEOS_DEPLOYMENT_TARGET=${IPHONEOS_DEPLOYMENT_TARGET} ARCHS=${IOS_ARCH} -sdk ${CMAKE_OSX_SYSROOT} \$*") # Make executable file(COPY "${_xcodebuild_wrapper_tmp}" DESTINATION ${CMAKE_BINARY_DIR} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) set(CMAKE_MAKE_PROGRAM "${_xcodebuild_wrapper}" CACHE INTERNAL "" FORCE) @@ -162,4 +169,4 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -toolchain_save_config(IOS_ARCH) \ No newline at end of file +toolchain_save_config(IOS_ARCH IPHONEOS_DEPLOYMENT_TARGET) From 8b26906d6d06874edf460dca7a9eaafdbdbae237 Mon Sep 17 00:00:00 2001 From: Sayed Adel Date: Wed, 24 Oct 2018 04:33:08 +0000 Subject: [PATCH 08/17] core:vsx change behavior of v_round to rounding to nearest even --- modules/core/include/opencv2/core/hal/intrin_vsx.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/core/include/opencv2/core/hal/intrin_vsx.hpp b/modules/core/include/opencv2/core/hal/intrin_vsx.hpp index fb81986f6c..72ac45c3eb 100644 --- a/modules/core/include/opencv2/core/hal/intrin_vsx.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_vsx.hpp @@ -832,10 +832,10 @@ OPENCV_HAL_IMPL_VSX_BIN_FUNC2(v_int64x2, v_uint64x2, vec_udword2_c, v_absdiff, v /** Rounding **/ inline v_int32x4 v_round(const v_float32x4& a) -{ return v_int32x4(vec_cts(vec_round(a.val))); } +{ return v_int32x4(vec_cts(vec_rint(a.val))); } inline v_int32x4 v_round(const v_float64x2& a) -{ return v_int32x4(vec_mergesqo(vec_ctso(vec_round(a.val)), vec_int4_z)); } +{ return v_int32x4(vec_mergesqo(vec_ctso(vec_rint(a.val)), vec_int4_z)); } inline v_int32x4 v_floor(const v_float32x4& a) { return v_int32x4(vec_cts(vec_floor(a.val))); } From 7a3cb2280bb9d8a2679b677dafe880a90d7c8f45 Mon Sep 17 00:00:00 2001 From: Antonio Borondo Date: Tue, 23 Oct 2018 20:17:22 +0100 Subject: [PATCH 09/17] Recognize ConvolutionDepthwise as Convolution --- modules/dnn/src/caffe/caffe_importer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/dnn/src/caffe/caffe_importer.cpp b/modules/dnn/src/caffe/caffe_importer.cpp index f31966022e..3c3119bb79 100644 --- a/modules/dnn/src/caffe/caffe_importer.cpp +++ b/modules/dnn/src/caffe/caffe_importer.cpp @@ -379,6 +379,10 @@ public: layerParams.blobs[1].setTo(1); // std } } + else if ("ConvolutionDepthwise" == type) + { + type = "Convolution"; + } int id = dstNet.addLayer(name, type, layerParams); From ad356e3239635db5304fd81bda6ffca94634666f Mon Sep 17 00:00:00 2001 From: berak Date: Wed, 24 Oct 2018 12:37:01 +0200 Subject: [PATCH 10/17] dnn/samples: handle not set env vars gracefully --- samples/dnn/common.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/dnn/common.hpp b/samples/dnn/common.hpp index a0ca012645..fce7f9fbb9 100644 --- a/samples/dnn/common.hpp +++ b/samples/dnn/common.hpp @@ -58,10 +58,12 @@ std::string findFile(const std::string& filename) if (filename.empty() || utils::fs::exists(filename)) return filename; - std::string extraPaths[] = {getenv("OPENCV_DNN_TEST_DATA_PATH"), + const char* extraPaths[] = {getenv("OPENCV_DNN_TEST_DATA_PATH"), getenv("OPENCV_TEST_DATA_PATH")}; for (int i = 0; i < 2; ++i) { + if (extraPaths[i] == NULL) + continue; std::string absPath = utils::fs::join(extraPaths[i], utils::fs::join("dnn", filename)); if (utils::fs::exists(absPath)) return absPath; From e397434cb689723eeee4ab0dffe4e8cebd0a710b Mon Sep 17 00:00:00 2001 From: maver1 Date: Wed, 24 Oct 2018 15:02:53 +0300 Subject: [PATCH 11/17] Merge pull request #12877 from maver1:3.4 * Updated ICV packages and IPP integration * core(test): minMaxIdx IPP regression test * core(ipp): workaround minMaxIdx problem * core(ipp): workaround meanStdDev() CV_32FC3 buffer overrun * Returned semicolon after CV_INSTRUMENT_REGION_IPP() --- 3rdparty/ippicv/ippicv.cmake | 26 +- cmake/OpenCVFindIPP.cmake | 7 +- cmake/OpenCVFindIPPIW.cmake | 115 ++++---- cmake/templates/cvconfig.h.in | 1 + modules/core/include/opencv2/core/base.hpp | 6 +- modules/core/include/opencv2/core/private.hpp | 4 +- modules/core/src/channels.cpp | 4 +- modules/core/src/copy.cpp | 6 +- modules/core/src/mean.cpp | 5 + modules/core/src/merge.cpp | 2 +- modules/core/src/minmax.cpp | 6 + modules/core/src/split.cpp | 2 +- modules/core/src/system.cpp | 25 +- modules/core/test/test_arithm.cpp | 26 ++ modules/imgproc/src/filter.cpp | 2 +- modules/imgproc/src/resize.cpp | 2 +- modules/objdetect/src/haar.cpp | 259 ++++-------------- 17 files changed, 201 insertions(+), 297 deletions(-) diff --git a/3rdparty/ippicv/ippicv.cmake b/3rdparty/ippicv/ippicv.cmake index a54d8f11ae..ae8748c283 100644 --- a/3rdparty/ippicv/ippicv.cmake +++ b/3rdparty/ippicv/ippicv.cmake @@ -2,37 +2,37 @@ function(download_ippicv root_var) set(${root_var} "" PARENT_SCOPE) # Commit SHA in the opencv_3rdparty repo - set(IPPICV_COMMIT "bdb7bb85f34a8cb0d35e40a81f58da431aa1557a") + set(IPPICV_COMMIT "32e315a5b106a7b89dbed51c28f8120a48b368b4") # Define actual ICV versions if(APPLE) set(OPENCV_ICV_PLATFORM "macosx") set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_mac") if(X86_64) - set(OPENCV_ICV_NAME "ippicv_2017u3_mac_intel64_general_20180518.tgz") - set(OPENCV_ICV_HASH "3ae52b9be0fe73dd45bc5e9429cd3732") + set(OPENCV_ICV_NAME "ippicv_2019_mac_intel64_general_20180723.tgz") + set(OPENCV_ICV_HASH "fe6b2bb75ae0e3f19ad3ae1a31dfa4a2") else() - set(OPENCV_ICV_NAME "ippicv_2017u3_mac_ia32_general_20180518.tgz") - set(OPENCV_ICV_HASH "698660b975b62bee3ef6c5af51e97544") + set(OPENCV_ICV_NAME "ippicv_2019_mac_ia32_general_20180723.tgz") + set(OPENCV_ICV_HASH "b5dfa78c87eb75c64470cbe5ec876f4f") endif() elseif((UNIX AND NOT ANDROID) OR (UNIX AND ANDROID_ABI MATCHES "x86")) set(OPENCV_ICV_PLATFORM "linux") set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_lnx") if(X86_64) - set(OPENCV_ICV_NAME "ippicv_2017u3_lnx_intel64_general_20180518.tgz") - set(OPENCV_ICV_HASH "b7cc351267db2d34b9efa1cd22ff0572") + set(OPENCV_ICV_NAME "ippicv_2019_lnx_intel64_general_20180723.tgz") + set(OPENCV_ICV_HASH "c0bd78adb4156bbf552c1dfe90599607") else() - set(OPENCV_ICV_NAME "ippicv_2017u3_lnx_ia32_general_20180518.tgz") - set(OPENCV_ICV_HASH "ea72de74dae3c604eb6348395366e78e") + set(OPENCV_ICV_NAME "ippicv_2019_lnx_ia32_general_20180723.tgz") + set(OPENCV_ICV_HASH "4f38432c30bfd6423164b7a24bbc98a0") endif() elseif(WIN32 AND NOT ARM) set(OPENCV_ICV_PLATFORM "windows") set(OPENCV_ICV_PACKAGE_SUBDIR "ippicv_win") if(X86_64) - set(OPENCV_ICV_NAME "ippicv_2017u3_win_intel64_general_20180518.zip") - set(OPENCV_ICV_HASH "915ff92958089ede8ea532d3c4fe7187") + set(OPENCV_ICV_NAME "ippicv_2019_win_intel64_20180723_general.zip") + set(OPENCV_ICV_HASH "1d222685246896fe089f88b8858e4b2f") else() - set(OPENCV_ICV_NAME "ippicv_2017u3_win_ia32_general_20180518.zip") - set(OPENCV_ICV_HASH "928168c2d99ab284047dfcfb7a821d91") + set(OPENCV_ICV_NAME "ippicv_2019_win_ia32_20180723_general.zip") + set(OPENCV_ICV_HASH "0157251a2eb9cd63a3ebc7eed0f3e59e") endif() else() return() diff --git a/cmake/OpenCVFindIPP.cmake b/cmake/OpenCVFindIPP.cmake index 52c8d50638..403d0494b5 100644 --- a/cmake/OpenCVFindIPP.cmake +++ b/cmake/OpenCVFindIPP.cmake @@ -240,11 +240,12 @@ endif() if(NOT DEFINED IPPROOT) include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/ippicv.cmake") - download_ippicv(IPPROOT) - if(NOT IPPROOT) + download_ippicv(ICV_PACKAGE_ROOT) + if(NOT ICV_PACKAGE_ROOT) return() endif() - ocv_install_3rdparty_licenses(ippicv "${IPPROOT}/readme.htm" "${IPPROOT}/license/ippEULA.txt") + set(IPPROOT "${ICV_PACKAGE_ROOT}/icv") + ocv_install_3rdparty_licenses(ippicv "${IPPROOT}/readme.htm" "${ICV_PACKAGE_ROOT}/EULA.txt") endif() file(TO_CMAKE_PATH "${IPPROOT}" __IPPROOT) diff --git a/cmake/OpenCVFindIPPIW.cmake b/cmake/OpenCVFindIPPIW.cmake index 3b63aa1a0d..79a9fb21be 100644 --- a/cmake/OpenCVFindIPPIW.cmake +++ b/cmake/OpenCVFindIPPIW.cmake @@ -1,17 +1,19 @@ # -# The script to detect Intel(R) Integrated Performance Primitives Integration Wrappers (IPP IW) +# The script to detect Intel(R) Integrated Performance Primitives Integration Wrappers (IPP Integration Wrappers) # installation/package # # # On return this will define: # -# HAVE_IPP_IW - True if Intel IPP found -# IPP_IW_PATH - Root of Intel IPP IW directory -# IPP_IW_LIBRARIES - Intel IPP IW libraries -# IPP_IW_INCLUDES - Intel IPP IW include folder +# HAVE_IPP_IW - True if Intel IPP Integration Wrappers found +# HAVE_IPP_IW_LL - True if Intel IPP Integration Wrappers found with Low Level API header +# IPP_IW_PATH - Root of Intel IPP Integration Wrappers directory +# IPP_IW_LIBRARIES - Intel IPP Integration Wrappers libraries +# IPP_IW_INCLUDES - Intel IPP Integration Wrappers include folder # unset(HAVE_IPP_IW CACHE) +unset(HAVE_IPP_IW_LL CACHE) unset(IPP_IW_PATH) unset(IPP_IW_LIBRARIES) unset(IPP_IW_INCLUDES) @@ -29,13 +31,16 @@ macro(ippiw_debugmsg MESSAGE) endmacro() file(TO_CMAKE_PATH "${IPPROOT}" IPPROOT) -# This function detects Intel IPP IW version by analyzing .h file +# This function detects Intel IPP Integration Wrappers version by analyzing .h file macro(ippiw_setup PATH BUILD) - set(FILE "${PATH}/include/iw/iw_ll.h") # check if Intel IPP IW is OpenCV specific - ippiw_debugmsg("Checking path: ${PATH}") + set(FILE "${PATH}/include/iw/iw_version.h") + if(${BUILD}) + ippiw_debugmsg("Checking sources: ${PATH}") + else() + ippiw_debugmsg("Checking binaries: ${PATH}") + endif() if(EXISTS "${FILE}") - set(FILE "${PATH}/include/iw/iw_version.h") - ippiw_debugmsg("vfile\tok") + ippiw_debugmsg("vfile\tfound") file(STRINGS "${FILE}" IW_VERSION_MAJOR REGEX "IW_VERSION_MAJOR") file(STRINGS "${FILE}" IW_VERSION_MINOR REGEX "IW_VERSION_MINOR") file(STRINGS "${FILE}" IW_VERSION_UPDATE REGEX "IW_VERSION_UPDATE") @@ -56,13 +61,13 @@ macro(ippiw_setup PATH BUILD) math(EXPR IW_MIN_COMPATIBLE_IPP_EXP "${IW_MIN_COMPATIBLE_IPP_MAJOR}*10000 + ${IW_MIN_COMPATIBLE_IPP_MINOR}*100 + ${IW_MIN_COMPATIBLE_IPP_UPDATE}") if((IPP_VERSION_EXP GREATER IW_MIN_COMPATIBLE_IPP_EXP) OR (IPP_VERSION_EXP EQUAL IW_MIN_COMPATIBLE_IPP_EXP)) - ippiw_debugmsg("version\tok") + ippiw_debugmsg("vcheck\tpassed") if(${BUILD}) # check sources if(EXISTS "${PATH}/src/iw_core.c") - ippiw_debugmsg("sources\tok") + ippiw_debugmsg("sources\tyes") set(IPP_IW_PATH "${PATH}") - message(STATUS "found Intel IPP IW sources: ${IW_VERSION_MAJOR}.${IW_VERSION_MINOR}.${IW_VERSION_UPDATE}") + message(STATUS "found Intel IPP Integration Wrappers sources: ${IW_VERSION_MAJOR}.${IW_VERSION_MINOR}.${IW_VERSION_UPDATE}") message(STATUS "at: ${IPP_IW_PATH}") set(IPP_IW_LIBRARY ippiw) @@ -72,7 +77,13 @@ macro(ippiw_setup PATH BUILD) add_subdirectory("${IPP_IW_PATH}/" ${OpenCV_BINARY_DIR}/3rdparty/ippiw) set(HAVE_IPP_IW 1) + set(FILE "${PATH}/include/iw/iw_ll.h") # check if Intel IPP Integration Wrappers is OpenCV specific + if(EXISTS "${FILE}") + set(HAVE_IPP_IW_LL 1) + endif() return() + else() + ippiw_debugmsg("sources\tno") endif() else() # check binaries @@ -82,9 +93,9 @@ macro(ippiw_setup PATH BUILD) set(FILE "${PATH}/lib/ia32/${CMAKE_STATIC_LIBRARY_PREFIX}ipp_iw${CMAKE_STATIC_LIBRARY_SUFFIX}") endif() if(EXISTS ${FILE}) - ippiw_debugmsg("binaries\tok (64=${IPP_X64})") + ippiw_debugmsg("binaries\tyes (64=${IPP_X64})") set(IPP_IW_PATH "${PATH}") - message(STATUS "found Intel IPP IW binaries: ${IW_VERSION_MAJOR}.${IW_VERSION_MINOR}.${IW_VERSION_UPDATE}") + message(STATUS "found Intel IPP Integration Wrappers binaries: ${IW_VERSION_MAJOR}.${IW_VERSION_MINOR}.${IW_VERSION_UPDATE}") message(STATUS "at: ${IPP_IW_PATH}") add_library(ippiw STATIC IMPORTED) @@ -105,81 +116,77 @@ macro(ippiw_setup PATH BUILD) set(HAVE_IPP_IW 1) set(BUILD_IPP_IW 0) + set(FILE "${PATH}/include/iw/iw_ll.h") # check if Intel IPP Integration Wrappers is OpenCV specific + if(EXISTS "${FILE}") + set(HAVE_IPP_IW_LL 1) + endif() return() + else() + ippiw_debugmsg("binaries\tno") endif() endif() + else() + ippiw_debugmsg("vcheck\tfailed") endif() + else() + ippiw_debugmsg("vfile\tnot found") endif() set(HAVE_IPP_IW 0) + set(HAVE_IPP_IW_LL 0) endmacro() -# check os and architecture -if(APPLE) - set(IW_PACKAGE_SUBDIR "ippiw_mac") -elseif((UNIX AND NOT ANDROID) OR (UNIX AND ANDROID_ABI MATCHES "x86")) - set(IW_PACKAGE_SUBDIR "ippiw_lnx") -elseif(WIN32 AND NOT ARM) - set(IW_PACKAGE_SUBDIR "ippiw_win") -else() - message(SEND_ERROR "Improper system for Intel IPP Integrations Wrappers. This message shouldn't appear. Check Intel IPP configurations steps") - return() -endif() - # check build options first if(BUILD_IPP_IW) # custom path if(DEFINED IPPIWROOT) ippiw_setup("${IPPIWROOT}/" 1) - message(STATUS "Can't find Intel IPP IW sources at: ${IPPIWROOT}") + message(STATUS "Can't find Intel IPP Integration Wrappers sources at: ${IPPIWROOT}") endif() # local sources ippiw_setup("${OpenCV_SOURCE_DIR}/3rdparty/ippiw" 1) - set(IPPIW_ROOT "${IPPROOT}/../${IW_PACKAGE_SUBDIR}") + set(IPPIW_ROOT "${IPPROOT}/../iw") ocv_install_3rdparty_licenses(ippiw - "${IPPIW_ROOT}/EULA.txt" - "${IPPIW_ROOT}/redist.txt" - "${IPPIW_ROOT}/support.txt" - "${IPPIW_ROOT}/third-party-programs.txt") + "${IPPIW_ROOT}/../EULA.txt" + "${IPPIW_ROOT}/../support.txt" + "${IPPIW_ROOT}/../third-party-programs.txt") # Package sources - get_filename_component(__PATH "${IPPROOT}/../${IW_PACKAGE_SUBDIR}/" ABSOLUTE) + get_filename_component(__PATH "${IPPROOT}/../iw/" ABSOLUTE) ippiw_setup("${__PATH}" 1) + + # take Intel IPP Integration Wrappers from ICV package + if(NOT HAVE_IPP_ICV) + message(STATUS "Cannot find Intel IPP Integration Wrappers. Checking \"Intel IPP for OpenCV\" package") + set(TEMP_ROOT 0) + include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/ippicv.cmake") + download_ippicv(TEMP_ROOT) + set(IPPIW_ROOT "${TEMP_ROOT}/iw/") + ocv_install_3rdparty_licenses(ippiw + "${IPPIW_ROOT}/../EULA.txt" + "${IPPIW_ROOT}/../support.txt" + "${IPPIW_ROOT}/../third-party-programs.txt") + + ippiw_setup("${IPPIW_ROOT}" 1) + endif() endif() # custom binaries if(DEFINED IPPIWROOT) ippiw_setup("${IPPIWROOT}/" 0) - message(STATUS "Can't find Intel IPP IW sources at: ${IPPIWROOT}") + message(STATUS "Can't find Intel IPP Integration Wrappers binaries at: ${IPPIWROOT}") endif() # check binaries in IPP folder ippiw_setup("${IPPROOT}/" 0) # check binaries near IPP folder -ippiw_setup("${IPPROOT}/../${IW_PACKAGE_SUBDIR}/" 0) - - -# take Intel IPP IW from ICV package -if(NOT HAVE_IPP_ICV AND BUILD_IPP_IW) - message(STATUS "Cannot find Intel IPP IW. Checking \"Intel IPP for OpenCV\" package") - set(TEMP_ROOT 0) - include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/ippicv.cmake") - download_ippicv(TEMP_ROOT) - set(IPPIW_ROOT "${TEMP_ROOT}/../${IW_PACKAGE_SUBDIR}") - ocv_install_3rdparty_licenses(ippiw - "${IPPIW_ROOT}/EULA.txt" - "${IPPIW_ROOT}/redist.txt" - "${IPPIW_ROOT}/support.txt" - "${IPPIW_ROOT}/third-party-programs.txt") - - # Package sources. Only sources are compatible with regular Intel IPP - ippiw_setup("${IPPIW_ROOT}" 1) -endif() +ippiw_setup("${IPPROOT}/../iw/" 0) set(HAVE_IPP_IW 0) +set(HAVE_IPP_IW_LL 0) message(STATUS "Cannot find Intel IPP Integration Wrappers, optimizations will be limited. Use IPPIWROOT to set custom location") return() diff --git a/cmake/templates/cvconfig.h.in b/cmake/templates/cvconfig.h.in index 8ffac75862..0fcbeaa2fc 100644 --- a/cmake/templates/cvconfig.h.in +++ b/cmake/templates/cvconfig.h.in @@ -105,6 +105,7 @@ #cmakedefine HAVE_IPP #cmakedefine HAVE_IPP_ICV #cmakedefine HAVE_IPP_IW +#cmakedefine HAVE_IPP_IW_LL /* JPEG-2000 codec */ #cmakedefine HAVE_JASPER diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp index 98683a2023..a68dca7d56 100644 --- a/modules/core/include/opencv2/core/base.hpp +++ b/modules/core/include/opencv2/core/base.hpp @@ -767,9 +767,13 @@ CV_EXPORTS_W void setUseIPP(bool flag); CV_EXPORTS_W String getIppVersion(); // IPP Not-Exact mode. This function may force use of IPP then both IPP and OpenCV provide proper results -// but have internal accuracy differences which have to much direct or indirect impact on accuracy tests. +// but have internal accuracy differences which have too much direct or indirect impact on accuracy tests. +CV_EXPORTS_W bool useIPP_NotExact(); +CV_EXPORTS_W void setUseIPP_NotExact(bool flag); +#if OPENCV_ABI_COMPATIBILITY < 400 CV_EXPORTS_W bool useIPP_NE(); CV_EXPORTS_W void setUseIPP_NE(bool flag); +#endif } // ipp diff --git a/modules/core/include/opencv2/core/private.hpp b/modules/core/include/opencv2/core/private.hpp index 869b34d8a7..26611f04ae 100644 --- a/modules/core/include/opencv2/core/private.hpp +++ b/modules/core/include/opencv2/core/private.hpp @@ -194,8 +194,8 @@ T* allocSingleton(size_t count = 1) { return static_cast(allocSingletonBuffe #define IPP_DISABLE_LAB_RGB 1 // breaks OCL accuracy tests #define IPP_DISABLE_RGB_XYZ 1 // big accuracy difference #define IPP_DISABLE_XYZ_RGB 1 // big accuracy difference -#define IPP_DISABLE_HAAR 1 // improper integration/results #define IPP_DISABLE_HOUGH 1 // improper integration/results +#define IPP_DISABLE_FILTER2D_BIG_MASK 1 // different results on masks > 7x7 #define IPP_DISABLE_GAUSSIANBLUR_PARALLEL 1 // not supported (2017u2 / 2017u3) @@ -229,7 +229,9 @@ T* allocSingleton(size_t count = 1) { return static_cast(allocSingletonBuffe # pragma GCC diagnostic ignored "-Wsuggest-override" # endif #include "iw++/iw.hpp" +# ifdef HAVE_IPP_IW_LL #include "iw/iw_ll.h" +# endif # if defined(__OPENCV_BUILD) && defined(__GNUC__) && __GNUC__ >= 5 # pragma GCC diagnostic pop # endif diff --git a/modules/core/src/channels.cpp b/modules/core/src/channels.cpp index 4e464d910c..87d38a5dd5 100644 --- a/modules/core/src/channels.cpp +++ b/modules/core/src/channels.cpp @@ -341,7 +341,7 @@ namespace cv { static bool ipp_extractChannel(const Mat &src, Mat &dst, int channel) { -#ifdef HAVE_IPP_IW +#ifdef HAVE_IPP_IW_LL CV_INSTRUMENT_REGION_IPP(); int srcChannels = src.channels(); @@ -379,7 +379,7 @@ static bool ipp_extractChannel(const Mat &src, Mat &dst, int channel) static bool ipp_insertChannel(const Mat &src, Mat &dst, int channel) { -#ifdef HAVE_IPP_IW +#ifdef HAVE_IPP_IW_LL CV_INSTRUMENT_REGION_IPP(); int srcChannels = src.channels(); diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index 7fb850ee38..fc4f363c7b 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -328,7 +328,7 @@ void Mat::copyTo( OutputArray _dst ) const #ifdef HAVE_IPP static bool ipp_copyTo(const Mat &src, Mat &dst, const Mat &mask) { -#ifdef HAVE_IPP_IW +#ifdef HAVE_IPP_IW_LL CV_INSTRUMENT_REGION_IPP(); if(mask.channels() > 1 || mask.depth() != CV_8U) @@ -463,7 +463,7 @@ Mat& Mat::operator = (const Scalar& s) #ifdef HAVE_IPP static bool ipp_Mat_setTo_Mat(Mat &dst, Mat &_val, Mat &mask) { -#ifdef HAVE_IPP_IW +#ifdef HAVE_IPP_IW_LL CV_INSTRUMENT_REGION_IPP(); if(mask.empty()) @@ -1152,7 +1152,7 @@ namespace cv { static bool ipp_copyMakeBorder( Mat &_src, Mat &_dst, int top, int bottom, int left, int right, int _borderType, const Scalar& value ) { -#if defined HAVE_IPP_IW && !IPP_DISABLE_PERF_COPYMAKE +#if defined HAVE_IPP_IW_LL && !IPP_DISABLE_PERF_COPYMAKE CV_INSTRUMENT_REGION_IPP(); ::ipp::IwiBorderSize borderSize(left, top, right, bottom); diff --git a/modules/core/src/mean.cpp b/modules/core/src/mean.cpp index 8542381d49..b488ee230a 100644 --- a/modules/core/src/mean.cpp +++ b/modules/core/src/mean.cpp @@ -674,6 +674,11 @@ static bool ipp_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& m if (cn > 1) return false; #endif +#if IPP_VERSION_X100 < 201901 + // IPP_DISABLE: 32f C3C functions can read outside of allocated memory + if (cn > 1 && src.depth() == CV_32F) + return false; +#endif size_t total_size = src.total(); int rows = src.size[0], cols = rows ? (int)(total_size/rows) : 0; diff --git a/modules/core/src/merge.cpp b/modules/core/src/merge.cpp index c701fd4658..b460d212d1 100644 --- a/modules/core/src/merge.cpp +++ b/modules/core/src/merge.cpp @@ -228,7 +228,7 @@ static MergeFunc getMergeFunc(int depth) namespace cv { static bool ipp_merge(const Mat* mv, Mat& dst, int channels) { -#ifdef HAVE_IPP_IW +#ifdef HAVE_IPP_IW_LL CV_INSTRUMENT_REGION_IPP(); if(channels != 3 && channels != 4) diff --git a/modules/core/src/minmax.cpp b/modules/core/src/minmax.cpp index 7c5b318398..daad21038d 100644 --- a/modules/core/src/minmax.cpp +++ b/modules/core/src/minmax.cpp @@ -8,6 +8,8 @@ #include "opencv2/core/openvx/ovx_defs.hpp" #include "stat.hpp" +#define IPP_DISABLE_MINMAXIDX_MANY_ROWS 1 // see Core_MinMaxIdx.rows_overflow test + /****************************************************************************************\ * minMaxLoc * \****************************************************************************************/ @@ -624,6 +626,10 @@ static bool ipp_minMaxIdx(Mat &src, double* _minVal, double* _maxVal, int* _minI if(src.dims <= 2) { IppiSize size = ippiSize(src.size()); +#if defined(_WIN32) && !defined(_WIN64) && IPP_VERSION_X100 == 201900 && IPP_DISABLE_MINMAXIDX_MANY_ROWS + if (size.height > 65536) + return false; // test: Core_MinMaxIdx.rows_overflow +#endif size.width *= src.channels(); status = ippMinMaxFun(src.ptr(), (int)src.step, size, dataType, pMinVal, pMaxVal, pMinIdx, pMaxIdx, (Ipp8u*)mask.ptr(), (int)mask.step); diff --git a/modules/core/src/split.cpp b/modules/core/src/split.cpp index 5b56fa0c5a..ac1b7217bb 100644 --- a/modules/core/src/split.cpp +++ b/modules/core/src/split.cpp @@ -236,7 +236,7 @@ static SplitFunc getSplitFunc(int depth) namespace cv { static bool ipp_split(const Mat& src, Mat* mv, int channels) { -#ifdef HAVE_IPP_IW +#ifdef HAVE_IPP_IW_LL CV_INSTRUMENT_REGION_IPP(); if(channels != 3 && channels != 4) diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index eb987f87a2..ad5a4e3cc0 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -2078,7 +2078,12 @@ public: cv::String env = pIppEnv; if(env.size()) { -#if IPP_VERSION_X100 >= 201703 +#if IPP_VERSION_X100 >= 201900 + const Ipp64u minorFeatures = ippCPUID_MOVBE|ippCPUID_AES|ippCPUID_CLMUL|ippCPUID_ABR|ippCPUID_RDRAND|ippCPUID_F16C| + ippCPUID_ADCOX|ippCPUID_RDSEED|ippCPUID_PREFETCHW|ippCPUID_SHA|ippCPUID_MPX|ippCPUID_AVX512CD|ippCPUID_AVX512ER| + ippCPUID_AVX512PF|ippCPUID_AVX512BW|ippCPUID_AVX512DQ|ippCPUID_AVX512VL|ippCPUID_AVX512VBMI|ippCPUID_AVX512_4FMADDPS| + ippCPUID_AVX512_4VNNIW|ippCPUID_AVX512IFMA; +#elif IPP_VERSION_X100 >= 201703 const Ipp64u minorFeatures = ippCPUID_MOVBE|ippCPUID_AES|ippCPUID_CLMUL|ippCPUID_ABR|ippCPUID_RDRAND|ippCPUID_F16C| ippCPUID_ADCOX|ippCPUID_RDSEED|ippCPUID_PREFETCHW|ippCPUID_SHA|ippCPUID_MPX|ippCPUID_AVX512CD|ippCPUID_AVX512ER| ippCPUID_AVX512PF|ippCPUID_AVX512BW|ippCPUID_AVX512DQ|ippCPUID_AVX512VL|ippCPUID_AVX512VBMI; @@ -2279,7 +2284,7 @@ void setUseIPP(bool flag) #endif } -bool useIPP_NE() +bool useIPP_NotExact() { #ifdef HAVE_IPP CoreTLSData* data = getCoreTlsData().get(); @@ -2293,17 +2298,29 @@ bool useIPP_NE() #endif } -void setUseIPP_NE(bool flag) +void setUseIPP_NotExact(bool flag) { CoreTLSData* data = getCoreTlsData().get(); #ifdef HAVE_IPP - data->useIPP_NE = (getIPPSingleton().useIPP_NE)?flag:false; + data->useIPP_NE = flag; #else CV_UNUSED(flag); data->useIPP_NE = false; #endif } +#if OPENCV_ABI_COMPATIBILITY < 400 +bool useIPP_NE() +{ + return useIPP_NotExact(); +} + +void setUseIPP_NE(bool flag) +{ + setUseIPP_NotExact(flag); +} +#endif + } // namespace ipp } // namespace cv diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp index 256493c54b..0eb2318c76 100644 --- a/modules/core/test/test_arithm.cpp +++ b/modules/core/test/test_arithm.cpp @@ -2298,4 +2298,30 @@ TEST(UMat_Core_DivideRules, type_32f) { testDivide(); } TEST(Core_DivideRules, type_64f) { testDivide(); } TEST(UMat_Core_DivideRules, type_64f) { testDivide(); } + +TEST(Core_MinMaxIdx, rows_overflow) +{ + const int N = 65536 + 1; + const int M = 1; + { + setRNGSeed(123); + Mat m(N, M, CV_32FC1); + randu(m, -100, 100); + double minVal = 0, maxVal = 0; + int minIdx[CV_MAX_DIM] = { 0 }, maxIdx[CV_MAX_DIM] = { 0 }; + cv::minMaxIdx(m, &minVal, &maxVal, minIdx, maxIdx); + + double minVal0 = 0, maxVal0 = 0; + int minIdx0[CV_MAX_DIM] = { 0 }, maxIdx0[CV_MAX_DIM] = { 0 }; + cv::ipp::setUseIPP(false); + cv::minMaxIdx(m, &minVal0, &maxVal0, minIdx0, maxIdx0); + cv::ipp::setUseIPP(true); + + EXPECT_FALSE(fabs(minVal0 - minVal) > 1e-6 || fabs(maxVal0 - maxVal) > 1e-6) << "NxM=" << N << "x" << M << + " min=" << minVal0 << " vs " << minVal << + " max=" << maxVal0 << " vs " << maxVal; + } +} + + }} // namespace diff --git a/modules/imgproc/src/filter.cpp b/modules/imgproc/src/filter.cpp index 5fd3f3eb95..da2370e5a7 100644 --- a/modules/imgproc/src/filter.cpp +++ b/modules/imgproc/src/filter.cpp @@ -4585,7 +4585,7 @@ static bool ippFilter2D(int stype, int dtype, int kernel_type, return false; #endif -#if IPP_VERSION_X100 < 201801 +#if IPP_DISABLE_FILTER2D_BIG_MASK // Too big difference compared to OpenCV FFT-based convolution if(kernel_type == CV_32FC1 && (type == ipp16s || type == ipp16u) && (kernel_width > 7 || kernel_height > 7)) return false; diff --git a/modules/imgproc/src/resize.cpp b/modules/imgproc/src/resize.cpp index 7eeefc7098..123ad4fd72 100644 --- a/modules/imgproc/src/resize.cpp +++ b/modules/imgproc/src/resize.cpp @@ -3321,7 +3321,7 @@ static bool ipp_resize(const uchar * src_data, size_t src_step, int src_width, i return false; // Resize which doesn't match OpenCV exactly - if (!cv::ipp::useIPP_NE()) + if (!cv::ipp::useIPP_NotExact()) { if (ippInter == ippNearest || ippInter == ippSuper || (ippDataType == ipp8u && ippInter == ippLinear)) return false; diff --git a/modules/objdetect/src/haar.cpp b/modules/objdetect/src/haar.cpp index 588ea2b46f..9e20111f43 100644 --- a/modules/objdetect/src/haar.cpp +++ b/modules/objdetect/src/haar.cpp @@ -94,7 +94,6 @@ typedef struct CvHidHaarClassifierCascade sqsumtype *pq0, *pq1, *pq2, *pq3; sumtype *p0, *p1, *p2, *p3; - void** ipp_stages; bool is_tree; bool isStumpBased; } CvHidHaarClassifierCascade; @@ -128,23 +127,6 @@ icvReleaseHidHaarClassifierCascade( CvHidHaarClassifierCascade** _cascade ) { if( _cascade && *_cascade ) { -#ifdef HAVE_IPP - CvHidHaarClassifierCascade* cascade = *_cascade; - if( CV_IPP_CHECK_COND && cascade->ipp_stages ) - { - int i; - for( i = 0; i < cascade->count; i++ ) - { - if( cascade->ipp_stages[i] ) -#if IPP_VERSION_X100 < 900 && !IPP_DISABLE_HAAR - ippiHaarClassifierFree_32f( (IppiHaarClassifier_32f*)cascade->ipp_stages[i] ); -#else - cvFree(&cascade->ipp_stages[i]); -#endif - } - } - cvFree( &cascade->ipp_stages ); -#endif cvFree( _cascade ); } } @@ -153,10 +135,6 @@ icvReleaseHidHaarClassifierCascade( CvHidHaarClassifierCascade** _cascade ) static CvHidHaarClassifierCascade* icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade ) { - CvRect* ipp_features = 0; - float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0; - int* ipp_counts = 0; - CvHidHaarClassifierCascade* out = 0; int i, j, k, l; @@ -312,72 +290,9 @@ icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade ) } } -#if defined HAVE_IPP && !IPP_DISABLE_HAAR - int can_use_ipp = CV_IPP_CHECK_COND && (!out->has_tilted_features && !out->is_tree && out->isStumpBased); - - if( can_use_ipp ) - { - int ipp_datasize = cascade->count*sizeof(out->ipp_stages[0]); - float ipp_weight_scale=(float)(1./((orig_window_size.width-icv_object_win_border*2)* - (orig_window_size.height-icv_object_win_border*2))); - - out->ipp_stages = (void**)cvAlloc( ipp_datasize ); - memset( out->ipp_stages, 0, ipp_datasize ); - - ipp_features = (CvRect*)cvAlloc( max_count*3*sizeof(ipp_features[0]) ); - ipp_weights = (float*)cvAlloc( max_count*3*sizeof(ipp_weights[0]) ); - ipp_thresholds = (float*)cvAlloc( max_count*sizeof(ipp_thresholds[0]) ); - ipp_val1 = (float*)cvAlloc( max_count*sizeof(ipp_val1[0]) ); - ipp_val2 = (float*)cvAlloc( max_count*sizeof(ipp_val2[0]) ); - ipp_counts = (int*)cvAlloc( max_count*sizeof(ipp_counts[0]) ); - - for( i = 0; i < cascade->count; i++ ) - { - CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i; - for( j = 0, k = 0; j < stage_classifier->count; j++ ) - { - CvHaarClassifier* classifier = stage_classifier->classifier + j; - int rect_count = 2 + (classifier->haar_feature->rect[2].r.width != 0); - - ipp_thresholds[j] = classifier->threshold[0]; - ipp_val1[j] = classifier->alpha[0]; - ipp_val2[j] = classifier->alpha[1]; - ipp_counts[j] = rect_count; - - for( l = 0; l < rect_count; l++, k++ ) - { - ipp_features[k] = classifier->haar_feature->rect[l].r; - //ipp_features[k].y = orig_window_size.height - ipp_features[k].y - ipp_features[k].height; - ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale; - } - } - - if( ippiHaarClassifierInitAlloc_32f( (IppiHaarClassifier_32f**)&out->ipp_stages[i], - (const IppiRect*)ipp_features, ipp_weights, ipp_thresholds, - ipp_val1, ipp_val2, ipp_counts, stage_classifier->count ) < 0 ) - break; - } - - if( i < cascade->count ) - { - for( j = 0; j < i; j++ ) - if( out->ipp_stages[i] ) - ippiHaarClassifierFree_32f( (IppiHaarClassifier_32f*)out->ipp_stages[i] ); - cvFree( &out->ipp_stages ); - } - } -#endif - cascade->hid_cascade = out; assert( (char*)haar_node_ptr - (char*)out <= datasize ); - cvFree( &ipp_features ); - cvFree( &ipp_weights ); - cvFree( &ipp_thresholds ); - cvFree( &ipp_val1 ); - cvFree( &ipp_val2 ); - cvFree( &ipp_counts ); - return out; } @@ -975,120 +890,54 @@ public: std::vector rejectLevelsLocal; std::vector levelWeightsLocal; -#ifdef HAVE_IPP - if(CV_IPP_CHECK_COND && cascade->hid_cascade->ipp_stages ) - { - IppiRect iequRect = {equRect.x, equRect.y, equRect.width, equRect.height}; - CV_INSTRUMENT_FUN_IPP(ippiRectStdDev_32f_C1R, sum1.ptr(y1), (int)sum1.step, - sqsum1.ptr(y1), (int)sqsum1.step, - norm1->ptr(y1), (int)norm1->step, - ippiSize(ssz.width, ssz.height), iequRect); - - int positive = (ssz.width/ystep)*((ssz.height + ystep-1)/ystep); - - if( ystep == 1 ) - (*mask1) = Scalar::all(1); - else - for( y = y1; y < y2; y++ ) - { - uchar* mask1row = mask1->ptr(y); - memset( mask1row, 0, ssz.width ); - - if( y % ystep == 0 ) - for( x = 0; x < ssz.width; x += ystep ) - mask1row[x] = (uchar)1; - } - - for( int j = 0; j < cascade->count; j++ ) + for( y = y1; y < y2; y += ystep ) + for( x = 0; x < ssz.width; x += ystep ) { - if (CV_INSTRUMENT_FUN_IPP(ippiApplyHaarClassifier_32f_C1R, - sum1.ptr(y1), (int)sum1.step, - norm1->ptr(y1), (int)norm1->step, - mask1->ptr(y1), (int)mask1->step, - ippiSize(ssz.width, ssz.height), &positive, - cascade->hid_cascade->stage_classifier[j].threshold, - (IppiHaarClassifier_32f*)cascade->hid_cascade->ipp_stages[j]) < 0 ) - positive = 0; - if( positive <= 0 ) - break; + double gypWeight; + int result = cvRunHaarClassifierCascadeSum( cascade, cvPoint(x,y), gypWeight, 0 ); + if( rejectLevels ) + { + if( result == 1 ) + result = -1*cascade->count; + if( cascade->count + result < 4 ) + { + vecLocal.push_back(Rect(cvRound(x*factor), cvRound(y*factor), + winSize.width, winSize.height)); + rejectLevelsLocal.push_back(-result); + levelWeightsLocal.push_back(gypWeight); + + if (vecLocal.size() >= PARALLEL_LOOP_BATCH_SIZE) + { + mtx->lock(); + vec->insert(vec->end(), vecLocal.begin(), vecLocal.end()); + rejectLevels->insert(rejectLevels->end(), rejectLevelsLocal.begin(), rejectLevelsLocal.end()); + levelWeights->insert(levelWeights->end(), levelWeightsLocal.begin(), levelWeightsLocal.end()); + mtx->unlock(); + + vecLocal.clear(); + rejectLevelsLocal.clear(); + levelWeightsLocal.clear(); + } + } + } + else + { + if( result > 0 ) + { + vecLocal.push_back(Rect(cvRound(x*factor), cvRound(y*factor), + winSize.width, winSize.height)); + + if (vecLocal.size() >= PARALLEL_LOOP_BATCH_SIZE) + { + mtx->lock(); + vec->insert(vec->end(), vecLocal.begin(), vecLocal.end()); + mtx->unlock(); + + vecLocal.clear(); + } + } + } } - CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT); - - if( positive > 0 ) - for( y = y1; y < y2; y += ystep ) - { - uchar* mask1row = mask1->ptr(y); - for( x = 0; x < ssz.width; x += ystep ) - if( mask1row[x] != 0 ) - { - vecLocal.push_back(Rect(cvRound(x*factor), cvRound(y*factor), - winSize.width, winSize.height)); - - if (vecLocal.size() >= PARALLEL_LOOP_BATCH_SIZE) - { - mtx->lock(); - vec->insert(vec->end(), vecLocal.begin(), vecLocal.end()); - mtx->unlock(); - - vecLocal.clear(); - } - if( --positive == 0 ) - break; - } - if( positive == 0 ) - break; - } - } - else -#endif // IPP - for( y = y1; y < y2; y += ystep ) - for( x = 0; x < ssz.width; x += ystep ) - { - double gypWeight; - int result = cvRunHaarClassifierCascadeSum( cascade, cvPoint(x,y), gypWeight, 0 ); - if( rejectLevels ) - { - if( result == 1 ) - result = -1*cascade->count; - if( cascade->count + result < 4 ) - { - vecLocal.push_back(Rect(cvRound(x*factor), cvRound(y*factor), - winSize.width, winSize.height)); - rejectLevelsLocal.push_back(-result); - levelWeightsLocal.push_back(gypWeight); - - if (vecLocal.size() >= PARALLEL_LOOP_BATCH_SIZE) - { - mtx->lock(); - vec->insert(vec->end(), vecLocal.begin(), vecLocal.end()); - rejectLevels->insert(rejectLevels->end(), rejectLevelsLocal.begin(), rejectLevelsLocal.end()); - levelWeights->insert(levelWeights->end(), levelWeightsLocal.begin(), levelWeightsLocal.end()); - mtx->unlock(); - - vecLocal.clear(); - rejectLevelsLocal.clear(); - levelWeightsLocal.clear(); - } - } - } - else - { - if( result > 0 ) - { - vecLocal.push_back(Rect(cvRound(x*factor), cvRound(y*factor), - winSize.width, winSize.height)); - - if (vecLocal.size() >= PARALLEL_LOOP_BATCH_SIZE) - { - mtx->lock(); - vec->insert(vec->end(), vecLocal.begin(), vecLocal.end()); - mtx->unlock(); - - vecLocal.clear(); - } - } - } - } if (rejectLevelsLocal.size()) { @@ -1283,12 +1132,6 @@ cvHaarDetectObjectsForROC( const CvArr* _img, if( flags & CV_HAAR_SCALE_IMAGE ) { CvSize winSize0 = cascade->orig_window_size; -#ifdef HAVE_IPP - int use_ipp = CV_IPP_CHECK_COND && (cascade->hid_cascade->ipp_stages != 0); - - if( use_ipp ) - normImg.reset(cvCreateMat( img->rows, img->cols, CV_32FC1)); -#endif imgSmall.reset(cvCreateMat( img->rows + 1, img->cols + 1, CV_8UC1 )); for( factor = 1; ; factor *= scaleFactor ) @@ -1330,15 +1173,7 @@ cvHaarDetectObjectsForROC( const CvArr* _img, int stripCount = ((sz1.width/ystep)*(sz1.height + ystep-1)/ystep + LOCS_PER_THREAD/2)/LOCS_PER_THREAD; stripCount = std::min(std::max(stripCount, 1), 100); -#ifdef HAVE_IPP - if( use_ipp ) - { - cv::Mat fsum(sum1.rows, sum1.cols, CV_32F, sum1.data.ptr, sum1.step); - cv::cvarrToMat(&sum1).convertTo(fsum, CV_32F, 1, -(1<<24)); - } - else -#endif - cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, _tilted, 1. ); + cvSetImagesForHaarClassifierCascade( cascade, &sum1, &sqsum1, _tilted, 1. ); cv::Mat _norm1 = cv::cvarrToMat(&norm1), _mask1 = cv::cvarrToMat(&mask1); cv::parallel_for_(cv::Range(0, stripCount), From a1bd39441f45e1044a2a8b774d04806e144b0a6f Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 24 Oct 2018 19:12:35 +0300 Subject: [PATCH 12/17] videoio: fix typo --- modules/videoio/include/opencv2/videoio.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp index cfa27740c7..281d51eded 100644 --- a/modules/videoio/include/opencv2/videoio.hpp +++ b/modules/videoio/include/opencv2/videoio.hpp @@ -738,7 +738,7 @@ public: @note In @ref videoio_c "C API", functions cvRetrieveFrame() and cv.RetrieveFrame() return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using - :ocvcvCloneImage and then do whatever you want with the copy. + cvCloneImage and then do whatever you want with the copy. */ CV_WRAP virtual bool retrieve(OutputArray image, int flag = 0); @@ -764,7 +764,7 @@ public: @note In @ref videoio_c "C API", functions cvRetrieveFrame() and cv.RetrieveFrame() return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using - :ocvcvCloneImage and then do whatever you want with the copy. + cvCloneImage and then do whatever you want with the copy. */ CV_WRAP virtual bool read(OutputArray image); From d305fd4fca77a941b6b9de3876882ce78cb9831c Mon Sep 17 00:00:00 2001 From: Alexander Nesterov Date: Tue, 16 Oct 2018 12:27:37 +0000 Subject: [PATCH 13/17] Added perf tests with sanity check --- .../objdetect/perf/perf_qrcode_pipeline.cpp | 106 ++++++++++++++++++ modules/objdetect/test/test_qrcode.cpp | 3 +- 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 modules/objdetect/perf/perf_qrcode_pipeline.cpp diff --git a/modules/objdetect/perf/perf_qrcode_pipeline.cpp b/modules/objdetect/perf/perf_qrcode_pipeline.cpp new file mode 100644 index 0000000000..09139a2df4 --- /dev/null +++ b/modules/objdetect/perf/perf_qrcode_pipeline.cpp @@ -0,0 +1,106 @@ +// 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 +{ + +typedef ::perf::TestBaseWithParam< std::string > Perf_Objdetect_QRCode; + +PERF_TEST_P_(Perf_Objdetect_QRCode, detect) +{ + const std::string name_current_image = GetParam(); + const std::string root = "cv/qrcode/"; + + std::string image_path = findDataFile(root + name_current_image); + Mat src = imread(image_path, IMREAD_GRAYSCALE), straight_barcode; + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + + std::vector< Point > corners; + TEST_CYCLE() ASSERT_TRUE(detectQRCode(src, corners)); + SANITY_CHECK(corners); +} + +#ifdef HAVE_QUIRC +PERF_TEST_P_(Perf_Objdetect_QRCode, decode) +{ + const std::string name_current_image = GetParam(); + const std::string root = "cv/qrcode/"; + + std::string image_path = findDataFile(root + name_current_image); + Mat src = imread(image_path, IMREAD_GRAYSCALE), straight_barcode; + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; + + std::vector< Point > corners; + std::string decoded_info; + ASSERT_TRUE(detectQRCode(src, corners)); + TEST_CYCLE() ASSERT_TRUE(decodeQRCode(src, corners, decoded_info, straight_barcode)); + + std::vector decoded_info_uint8_t(decoded_info.begin(), decoded_info.end()); + SANITY_CHECK(decoded_info_uint8_t); + SANITY_CHECK(straight_barcode); + +} +#endif + +INSTANTIATE_TEST_CASE_P(/*nothing*/, Perf_Objdetect_QRCode, + ::testing::Values( + "version_1_down.jpg", "version_1_left.jpg", "version_1_right.jpg", "version_1_up.jpg", "version_1_top.jpg", + "version_5_down.jpg", "version_5_left.jpg", "version_5_right.jpg", "version_5_up.jpg", "version_5_top.jpg", + "russian.jpg", "kanji.jpg", "link_github_ocv.jpg", "link_ocv.jpg", "link_wiki_cv.jpg" + ) +); + +typedef ::perf::TestBaseWithParam< tuple< std::string, Size > > Perf_Objdetect_Not_QRCode; + +PERF_TEST_P_(Perf_Objdetect_Not_QRCode, detect) +{ + std::vector corners; + std::string type_gen = get<0>(GetParam()); + Size resolution = get<1>(GetParam()); + Mat not_qr_code(resolution, CV_8UC1, Scalar(0)); + if (type_gen == "random") + { + RNG rng; + rng.fill(not_qr_code, RNG::UNIFORM, Scalar(0), Scalar(1)); + } + + TEST_CYCLE() ASSERT_FALSE(detectQRCode(not_qr_code, corners)); + SANITY_CHECK_NOTHING(); +} + +#ifdef HAVE_QUIRC +PERF_TEST_P_(Perf_Objdetect_Not_QRCode, decode) +{ + Mat straight_barcode; + std::string decoded_info; + std::vector< Point > corners; + corners.push_back(Point( 0, 0)); corners.push_back(Point( 0, 5)); + corners.push_back(Point(10, 0)); corners.push_back(Point(15, 15)); + + std::string type_gen = get<0>(GetParam()); + Size resolution = get<1>(GetParam()); + Mat not_qr_code(resolution, CV_8UC1, Scalar(0)); + if (type_gen == "random") + { + RNG rng; + rng.fill(not_qr_code, RNG::UNIFORM, Scalar(0), Scalar(1)); + } + + TEST_CYCLE() ASSERT_FALSE(decodeQRCode(not_qr_code, corners, decoded_info, straight_barcode)); + SANITY_CHECK_NOTHING(); +} +#endif + +INSTANTIATE_TEST_CASE_P(/*nothing*/, Perf_Objdetect_Not_QRCode, + ::testing::Combine( + ::testing::Values("zero", "random"), + ::testing::Values(Size(640, 480), Size(1280, 720), Size(1920, 1080)) + )); + +} +} // namespace diff --git a/modules/objdetect/test/test_qrcode.cpp b/modules/objdetect/test/test_qrcode.cpp index 8ede46860d..5019127b3f 100644 --- a/modules/objdetect/test/test_qrcode.cpp +++ b/modules/objdetect/test/test_qrcode.cpp @@ -115,7 +115,8 @@ INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode, testing::ValuesIn(qrcode_images_ TEST(Objdetect_QRCode_basic, not_found_qrcode) { - std::vector corners, straight_barcode; + std::vector corners; + Mat straight_barcode; std::string decoded_info; Mat zero_image = Mat::zeros(256, 256, CV_8UC1); EXPECT_FALSE(detectQRCode(zero_image, corners)); From 28a14df26c883c6c6b4d01222fe2f01caafe6893 Mon Sep 17 00:00:00 2001 From: Ali Yasin Eser Date: Wed, 24 Oct 2018 19:29:27 +0200 Subject: [PATCH 14/17] Update depth map for pytho-opencv --- .../py_calib3d/py_depthmap/py_depthmap.markdown | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.markdown b/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.markdown index b1a143ea72..f0ea83122b 100644 --- a/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.markdown +++ b/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.markdown @@ -55,10 +55,18 @@ you can get a better result. ![image](images/disparity_map.jpg) -@note More details to be added +There are some parameters when you get familiar with StereoBM, and you may need to fine tune the parameters to get better and smooth results. Parameters: +- texture_threshold: filters out areas that don't have enough texture for reliable matching +- Speckle range and size: Block-based matchers often produce "speckles" near the boundaries of objects, where the matching window catches the foreground on one side and the background on the other. In this scene it appears that the matcher is also finding small spurious matches in the projected texture on the table. To get rid of these artifacts we post-process the disparity image with a speckle filter controlled by the speckle_size and speckle_range parameters. speckle_size is the number of pixels below which a disparity blob is dismissed as "speckle." speckle_range controls how close in value disparities must be to be considered part of the same blob. +- Number of disparities: How many pixels to slide the window over. The larger it is, the larger the range of visible depths, but more computation is required. +- min_disparity: the offset from the x-position of the left pixel at which to begin searching. +- uniqueness_ratio: Another post-filtering step. If the best matching disparity is not sufficiently better than every other disparity in the search range, the pixel is filtered out. You can try tweaking this if texture_threshold and the speckle filtering are still letting through spurious matches. +- prefilter_size and prefilter_cap: The pre-filtering phase, which normalizes image brightness and enhances texture in preparation for block matching. Normally you should not need to adjust these. + Additional Resources -------------------- +- [Ros stereo img processing wiki page](http://wiki.ros.org/stereo_image_proc/Tutorials/ChoosingGoodStereoParameters) Exercises --------- From 7f608db244df7b9909db11b7db268221606e5231 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 25 Oct 2018 03:02:01 +0000 Subject: [PATCH 15/17] core: move compiler defines from base.hpp into cvdef.h --- modules/core/include/opencv2/core/base.hpp | 86 ---------------------- modules/core/include/opencv2/core/cvdef.h | 86 ++++++++++++++++++++++ 2 files changed, 86 insertions(+), 86 deletions(-) diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp index a68dca7d56..b688a39638 100644 --- a/modules/core/include/opencv2/core/base.hpp +++ b/modules/core/include/opencv2/core/base.hpp @@ -283,84 +283,6 @@ enum BorderTypes { //! @addtogroup core_utils //! @{ -//! @cond IGNORED - -//////////////// static assert ///////////////// -#define CVAUX_CONCAT_EXP(a, b) a##b -#define CVAUX_CONCAT(a, b) CVAUX_CONCAT_EXP(a,b) - -#if defined(__clang__) -# ifndef __has_extension -# define __has_extension __has_feature /* compatibility, for older versions of clang */ -# endif -# if __has_extension(cxx_static_assert) -# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) -# elif __has_extension(c_static_assert) -# define CV_StaticAssert(condition, reason) _Static_assert((condition), reason " " #condition) -# endif -#elif defined(__GNUC__) -# if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) -# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) -# endif -#elif defined(_MSC_VER) -# if _MSC_VER >= 1600 /* MSVC 10 */ -# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) -# endif -#endif -#ifndef CV_StaticAssert -# if !defined(__clang__) && defined(__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__ > 302) -# define CV_StaticAssert(condition, reason) ({ extern int __attribute__((error("CV_StaticAssert: " reason " " #condition))) CV_StaticAssert(); ((condition) ? 0 : CV_StaticAssert()); }) -# else - template struct CV_StaticAssert_failed; - template <> struct CV_StaticAssert_failed { enum { val = 1 }; }; - template struct CV_StaticAssert_test {}; -# define CV_StaticAssert(condition, reason)\ - typedef cv::CV_StaticAssert_test< sizeof(cv::CV_StaticAssert_failed< static_cast(condition) >) > CVAUX_CONCAT(CV_StaticAssert_failed_at_, __LINE__) -# endif -#endif - -// Suppress warning "-Wdeprecated-declarations" / C4996 -#if defined(_MSC_VER) - #define CV_DO_PRAGMA(x) __pragma(x) -#elif defined(__GNUC__) - #define CV_DO_PRAGMA(x) _Pragma (#x) -#else - #define CV_DO_PRAGMA(x) -#endif - -#ifdef _MSC_VER -#define CV_SUPPRESS_DEPRECATED_START \ - CV_DO_PRAGMA(warning(push)) \ - CV_DO_PRAGMA(warning(disable: 4996)) -#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(warning(pop)) -#elif defined (__clang__) || ((__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__ > 405)) -#define CV_SUPPRESS_DEPRECATED_START \ - CV_DO_PRAGMA(GCC diagnostic push) \ - CV_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations") -#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(GCC diagnostic pop) -#else -#define CV_SUPPRESS_DEPRECATED_START -#define CV_SUPPRESS_DEPRECATED_END -#endif - -#define CV_UNUSED(name) (void)name - -#if defined __GNUC__ && !defined __EXCEPTIONS -#define CV_TRY -#define CV_CATCH(A, B) for (A B; false; ) -#define CV_CATCH_ALL if (false) -#define CV_THROW(A) abort() -#define CV_RETHROW() abort() -#else -#define CV_TRY try -#define CV_CATCH(A, B) catch(const A & B) -#define CV_CATCH_ALL catch(...) -#define CV_THROW(A) throw A -#define CV_RETHROW() throw -#endif - -//! @endcond - /*! @brief Signals an error and raises the exception. By default the function prints information about the error to stderr, @@ -400,14 +322,6 @@ CV_INLINE CV_NORETURN void errorNoReturn(int _code, const String& _err, const ch # endif #endif -#if defined __GNUC__ -#define CV_Func __func__ -#elif defined _MSC_VER -#define CV_Func __FUNCTION__ -#else -#define CV_Func "" -#endif - #ifdef CV_STATIC_ANALYSIS // In practice, some macro are not processed correctly (noreturn is not detected). diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h index b9e5bce222..05e74dddb2 100644 --- a/modules/core/include/opencv2/core/cvdef.h +++ b/modules/core/include/opencv2/core/cvdef.h @@ -82,6 +82,92 @@ namespace cv { namespace debug_build_guard { } using namespace debug_build_guard #define __CV_VA_NUM_ARGS_HELPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define __CV_VA_NUM_ARGS(...) __CV_VA_NUM_ARGS_HELPER(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#if defined __GNUC__ +#define CV_Func __func__ +#elif defined _MSC_VER +#define CV_Func __FUNCTION__ +#else +#define CV_Func "" +#endif + +//! @cond IGNORED + +//////////////// static assert ///////////////// +#define CVAUX_CONCAT_EXP(a, b) a##b +#define CVAUX_CONCAT(a, b) CVAUX_CONCAT_EXP(a,b) + +#if defined(__clang__) +# ifndef __has_extension +# define __has_extension __has_feature /* compatibility, for older versions of clang */ +# endif +# if __has_extension(cxx_static_assert) +# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) +# elif __has_extension(c_static_assert) +# define CV_StaticAssert(condition, reason) _Static_assert((condition), reason " " #condition) +# endif +#elif defined(__GNUC__) +# if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) +# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) +# endif +#elif defined(_MSC_VER) +# if _MSC_VER >= 1600 /* MSVC 10 */ +# define CV_StaticAssert(condition, reason) static_assert((condition), reason " " #condition) +# endif +#endif +#ifndef CV_StaticAssert +# if !defined(__clang__) && defined(__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__ > 302) +# define CV_StaticAssert(condition, reason) ({ extern int __attribute__((error("CV_StaticAssert: " reason " " #condition))) CV_StaticAssert(); ((condition) ? 0 : CV_StaticAssert()); }) +# else + template struct CV_StaticAssert_failed; + template <> struct CV_StaticAssert_failed { enum { val = 1 }; }; + template struct CV_StaticAssert_test {}; +# define CV_StaticAssert(condition, reason)\ + typedef cv::CV_StaticAssert_test< sizeof(cv::CV_StaticAssert_failed< static_cast(condition) >) > CVAUX_CONCAT(CV_StaticAssert_failed_at_, __LINE__) +# endif +#endif + +// Suppress warning "-Wdeprecated-declarations" / C4996 +#if defined(_MSC_VER) + #define CV_DO_PRAGMA(x) __pragma(x) +#elif defined(__GNUC__) + #define CV_DO_PRAGMA(x) _Pragma (#x) +#else + #define CV_DO_PRAGMA(x) +#endif + +#ifdef _MSC_VER +#define CV_SUPPRESS_DEPRECATED_START \ + CV_DO_PRAGMA(warning(push)) \ + CV_DO_PRAGMA(warning(disable: 4996)) +#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(warning(pop)) +#elif defined (__clang__) || ((__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__ > 405)) +#define CV_SUPPRESS_DEPRECATED_START \ + CV_DO_PRAGMA(GCC diagnostic push) \ + CV_DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations") +#define CV_SUPPRESS_DEPRECATED_END CV_DO_PRAGMA(GCC diagnostic pop) +#else +#define CV_SUPPRESS_DEPRECATED_START +#define CV_SUPPRESS_DEPRECATED_END +#endif + +#define CV_UNUSED(name) (void)name + +#if defined __GNUC__ && !defined __EXCEPTIONS +#define CV_TRY +#define CV_CATCH(A, B) for (A B; false; ) +#define CV_CATCH_ALL if (false) +#define CV_THROW(A) abort() +#define CV_RETHROW() abort() +#else +#define CV_TRY try +#define CV_CATCH(A, B) catch(const A & B) +#define CV_CATCH_ALL catch(...) +#define CV_THROW(A) throw A +#define CV_RETHROW() throw +#endif + +//! @endcond + // undef problematic defines sometimes defined by system headers (windows.h in particular) #undef small #undef min From aa6e2962360ecff5066dacab99e9b81fb910a69f Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 25 Oct 2018 03:47:59 +0000 Subject: [PATCH 16/17] python: eliminate DeprecationWarning: SO -> EXT_SUFFIX - https://python.readthedocs.io/en/stable/whatsnew/3.4.html - The `sysconfig` key `SO` is deprecated, it has been replaced by `EXT_SUFFIX` --- modules/python/common.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/python/common.cmake b/modules/python/common.cmake index cbb79b8c44..4300abecc9 100644 --- a/modules/python/common.cmake +++ b/modules/python/common.cmake @@ -43,7 +43,11 @@ ocv_target_link_libraries(${the_module} LINK_PRIVATE ${deps}) if(DEFINED ${PYTHON}_CVPY_SUFFIX) set(CVPY_SUFFIX "${${PYTHON}_CVPY_SUFFIX}") else() - execute_process(COMMAND ${${PYTHON}_EXECUTABLE} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('SO'))" + set(__python_ext_suffix_var "EXT_SUFFIX") + if("${${PYTHON}_VERSION_MAJOR}" STREQUAL "2") + set(__python_ext_suffix_var "SO") + endif() + execute_process(COMMAND ${${PYTHON}_EXECUTABLE} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('${__python_ext_suffix_var}'))" RESULT_VARIABLE PYTHON_CVPY_PROCESS OUTPUT_VARIABLE CVPY_SUFFIX OUTPUT_STRIP_TRAILING_WHITESPACE) From 3e0c72ea84f8612f3d2a5e63724926d9f4318acc Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Fri, 26 Oct 2018 14:57:20 +0300 Subject: [PATCH 17/17] core(ipp): disable SSE4.2 meanStdDev() optimization for CV_32F --- modules/core/src/mean.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/core/src/mean.cpp b/modules/core/src/mean.cpp index b488ee230a..aed5f76ac5 100644 --- a/modules/core/src/mean.cpp +++ b/modules/core/src/mean.cpp @@ -674,10 +674,23 @@ static bool ipp_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& m if (cn > 1) return false; #endif -#if IPP_VERSION_X100 < 201901 +#if IPP_VERSION_X100 >= 201900 && IPP_VERSION_X100 < 201901 // IPP_DISABLE: 32f C3C functions can read outside of allocated memory if (cn > 1 && src.depth() == CV_32F) return false; + + // SSE4.2 buffer overrun +#if defined(_WIN32) && !defined(_WIN64) + // IPPICV doesn't have AVX2 in 32-bit builds + // However cv::ipp::getIppTopFeatures() may return AVX2 value on AVX2 capable H/W + // details #12959 +#else + if (cv::ipp::getIppTopFeatures() == ippCPUID_SSE42) // Linux x64 + OPENCV_IPP=SSE42 is affected too +#endif + { + if (src.depth() == CV_32F && src.dims > 1 && src.size[src.dims - 1] == 6) + return false; + } #endif size_t total_size = src.total();