mirror of
https://github.com/opencv/opencv.git
synced 2026-07-21 19:33:03 +04:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 837f715eec | |||
| 6eb0dc97f5 | |||
| 3def56d25a | |||
| 62bcd12f9c | |||
| 6a2d8d24da | |||
| d878b04c6b | |||
| 4208a89b3e | |||
| 41d48d6eeb | |||
| 0a4d6a849a | |||
| 017a5138d1 | |||
| afbfa275d8 | |||
| 6df9732c81 | |||
| 40d6727ea2 | |||
| cfb3a8bbb7 | |||
| 194db6f5cb | |||
| 5aad95cb1d | |||
| 86433eac87 | |||
| 2906d4d73a | |||
| 96a71a8d83 | |||
| 19ec7ea28b | |||
| 12eaf9bd4c | |||
| cadcb7e4e0 | |||
| fa55ed2837 | |||
| 4dee742731 | |||
| a77474f3b1 | |||
| 590d8f6439 | |||
| aed41fdabe | |||
| f80d02e1c7 | |||
| ffa38e1b74 | |||
| 1780a86075 | |||
| 48b8099214 | |||
| 3d02d863f9 | |||
| 3d55d2fcef | |||
| d10138fa1c | |||
| 9780b3b329 | |||
| 63b59865d3 | |||
| b9a38df0e6 | |||
| fe61ae0e41 | |||
| 6f29af625b | |||
| 0397596e17 | |||
| 2a70226181 | |||
| 21356eed2b | |||
| 11b0bd15cf | |||
| c936dcaef7 | |||
| ab1aaa75aa | |||
| d9f89b028b | |||
| 517710fe56 | |||
| a99141acd7 | |||
| 1b047868dd | |||
| a7bb1d1e1e | |||
| aee03ffbb2 | |||
| b723ddd72b |
-3
@@ -136,9 +136,6 @@ endif()
|
||||
|
||||
set(JPEG_LIB_VERSION 70)
|
||||
|
||||
# OpenCV
|
||||
set(JPEG_LIB_VERSION "${VERSION}-${JPEG_LIB_VERSION}" PARENT_SCOPE)
|
||||
|
||||
set(THREAD_LOCAL "") # WITH_TURBOJPEG is not used
|
||||
|
||||
add_definitions(-DNO_GETENV -DNO_PUTENV)
|
||||
|
||||
@@ -102,8 +102,23 @@ if(WITH_JPEG)
|
||||
macro(ocv_detect_jpeg_version header_file)
|
||||
if(NOT DEFINED JPEG_LIB_VERSION AND EXISTS "${header_file}")
|
||||
ocv_parse_header("${header_file}" JPEG_VERSION_LINES JPEG_LIB_VERSION)
|
||||
|
||||
if(DEFINED JPEG_LIB_VERSION)
|
||||
# Extract libjpeg-turbo version from the header file if JPEG_LIB_VERSION is found.
|
||||
file(STRINGS "${header_file}" JPEG_TURBO_VERSION_LINE REGEX "^#define[\t ]+LIBJPEG_TURBO_VERSION[\t ]")
|
||||
|
||||
if(JPEG_TURBO_VERSION_LINE)
|
||||
# Support both raw values (e.g., 3.1.2) and quoted strings (e.g., "3.1.2").
|
||||
string(REGEX REPLACE "^#define[\t ]+LIBJPEG_TURBO_VERSION[\t ]+\"?([^\"]+)\"?.*" "\\1" JPEG_TURBO_VERSION_STRING "${JPEG_TURBO_VERSION_LINE}")
|
||||
if(JPEG_TURBO_VERSION_STRING)
|
||||
string(STRIP "${JPEG_TURBO_VERSION_STRING}" JPEG_TURBO_VERSION_STRING)
|
||||
set(JPEG_LIB_VERSION "${JPEG_TURBO_VERSION_STRING}-${JPEG_LIB_VERSION}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
ocv_detect_jpeg_version("${JPEG_INCLUDE_DIR}/jpeglib.h")
|
||||
if(DEFINED CMAKE_CXX_LIBRARY_ARCHITECTURE)
|
||||
ocv_detect_jpeg_version("${JPEG_INCLUDE_DIR}/${CMAKE_CXX_LIBRARY_ARCHITECTURE}/jconfig.h")
|
||||
|
||||
@@ -105,7 +105,7 @@ let mat = new cv.Mat();
|
||||
let matVec = new cv.MatVector();
|
||||
// Push a Mat back into MatVector
|
||||
matVec.push_back(mat);
|
||||
// Get a Mat fom MatVector
|
||||
// Get a Mat from MatVector
|
||||
let cnt = matVec.get(0);
|
||||
mat.delete(); matVec.delete(); cnt.delete();
|
||||
@endcode
|
||||
|
||||
@@ -27,7 +27,7 @@ foreground object (Always try to keep foreground in white). So what it does? The
|
||||
through the image (as in 2D convolution). A pixel in the original image (either 1 or 0) will be
|
||||
considered 1 only if all the pixels under the kernel is 1, otherwise it is eroded (made to zero).
|
||||
|
||||
So what happends is that, all the pixels near boundary will be discarded depending upon the size of
|
||||
So what happens is that, all the pixels near boundary will be discarded depending upon the size of
|
||||
kernel. So the thickness or size of the foreground object decreases or simply white region decreases
|
||||
in the image. It is useful for removing small white noises (as we have seen in colorspace chapter),
|
||||
detach two connected objects etc.
|
||||
@@ -174,4 +174,4 @@ Try it
|
||||
<iframe src="../../js_morphological_ops_getStructuringElement.html" width="100%"
|
||||
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
|
||||
</iframe>
|
||||
\endhtmlonly
|
||||
\endhtmlonly
|
||||
|
||||
@@ -103,4 +103,4 @@ int main(void)
|
||||
|
||||
Limitation/Known problem
|
||||
------------------------
|
||||
- cv::moveWindow() is not implementated. ( See. https://github.com/opencv/opencv/issues/25478 )
|
||||
- cv::moveWindow() is not implemented. ( See. https://github.com/opencv/opencv/issues/25478 )
|
||||
|
||||
@@ -72,8 +72,8 @@ In order to use the Astra camera's depth sensor with OpenCV you should do the fo
|
||||
|
||||
@note The last tried version `2.3.0.86_202210111154_4c8f5aa4_beta6` does not work correctly with
|
||||
modern Linux, even after libusb rebuild as recommended by the instruction. The last know good
|
||||
configuration is version 2.3.0.63 (tested with Ubuntu 18.04 amd64). It's not provided officialy
|
||||
with the downloading page, but published by Orbbec technical suport on Orbbec community forum
|
||||
configuration is version 2.3.0.63 (tested with Ubuntu 18.04 amd64). It's not provided officially
|
||||
with the downloading page, but published by Orbbec technical support on Orbbec community forum
|
||||
[here](https://3dclub.orbbec3d.com/t/universal-download-thread-for-astra-series-cameras/622).
|
||||
|
||||
-# Now you can configure OpenCV with OpenNI support enabled by setting the `WITH_OPENNI2` flag in CMake.
|
||||
|
||||
+2
-2
@@ -63,7 +63,7 @@ Example code to generate features coordinates for calibration with symmetric gri
|
||||
}
|
||||
}
|
||||
```
|
||||
Example code to generate features corrdinates for calibration with asymmetic grid (object points):
|
||||
Example code to generate features coordinates for calibration with asymmetric grid (object points):
|
||||
```
|
||||
std::vector<cv::Point3f> objectPoints;
|
||||
for (int i = 0; i < boardSize.height; i++) {
|
||||
@@ -84,7 +84,7 @@ about ArUco pairs. In opposite to the previous pattern partially occluded board
|
||||
corners are labeled. The board is rotation invariant, but set of ArUco markers and their order
|
||||
should be known to detector apriori. It cannot detect ChAruco board with predefined size and random
|
||||
set of markers.
|
||||
Example code to generate features corrdinates for calibration (object points) for board size in units:
|
||||
Example code to generate features coordinates for calibration (object points) for board size in units:
|
||||
```
|
||||
std::vector<cv::Point3f> objectPoints;
|
||||
for (int i = 0; i < boardSize.height-1; ++i) {
|
||||
|
||||
@@ -64,25 +64,25 @@ We encourage you to add new algorithms to these APIs.
|
||||
|
||||
```
|
||||
crnn.onnx:
|
||||
url: https://drive.google.com/uc?export=dowload&id=1ooaLR-rkTl8jdpGy1DoQs0-X0lQsB6Fj
|
||||
url: https://drive.google.com/uc?export=download&id=1ooaLR-rkTl8jdpGy1DoQs0-X0lQsB6Fj
|
||||
sha: 270d92c9ccb670ada2459a25977e8deeaf8380d3,
|
||||
alphabet_36.txt: https://drive.google.com/uc?export=dowload&id=1oPOYx5rQRp8L6XQciUwmwhMCfX0KyO4b
|
||||
alphabet_36.txt: https://drive.google.com/uc?export=download&id=1oPOYx5rQRp8L6XQciUwmwhMCfX0KyO4b
|
||||
parameter setting: -rgb=0;
|
||||
description: The classification number of this model is 36 (0~9 + a~z).
|
||||
The training dataset is MJSynth.
|
||||
|
||||
crnn_cs.onnx:
|
||||
url: https://drive.google.com/uc?export=dowload&id=12diBsVJrS9ZEl6BNUiRp9s0xPALBS7kt
|
||||
url: https://drive.google.com/uc?export=download&id=12diBsVJrS9ZEl6BNUiRp9s0xPALBS7kt
|
||||
sha: a641e9c57a5147546f7a2dbea4fd322b47197cd5
|
||||
alphabet_94.txt: https://drive.google.com/uc?export=dowload&id=1oKXxXKusquimp7XY1mFvj9nwLzldVgBR
|
||||
alphabet_94.txt: https://drive.google.com/uc?export=download&id=1oKXxXKusquimp7XY1mFvj9nwLzldVgBR
|
||||
parameter setting: -rgb=1;
|
||||
description: The classification number of this model is 94 (0~9 + a~z + A~Z + punctuations).
|
||||
The training datasets are MJsynth and SynthText.
|
||||
|
||||
crnn_cs_CN.onnx:
|
||||
url: https://drive.google.com/uc?export=dowload&id=1is4eYEUKH7HR7Gl37Sw4WPXx6Ir8oQEG
|
||||
url: https://drive.google.com/uc?export=download&id=1is4eYEUKH7HR7Gl37Sw4WPXx6Ir8oQEG
|
||||
sha: 3940942b85761c7f240494cf662dcbf05dc00d14
|
||||
alphabet_3944.txt: https://drive.google.com/uc?export=dowload&id=18IZUUdNzJ44heWTndDO6NNfIpJMmN-ul
|
||||
alphabet_3944.txt: https://drive.google.com/uc?export=download&id=18IZUUdNzJ44heWTndDO6NNfIpJMmN-ul
|
||||
parameter setting: -rgb=1;
|
||||
description: The classification number of this model is 3944 (0~9 + a~z + A~Z + Chinese characters + special characters).
|
||||
The training dataset is ReCTS (https://rrc.cvc.uab.es/?ch=12).
|
||||
@@ -96,25 +96,25 @@ You can train more models by [CRNN](https://github.com/meijieru/crnn.pytorch), a
|
||||
|
||||
```
|
||||
- DB_IC15_resnet50.onnx:
|
||||
url: https://drive.google.com/uc?export=dowload&id=17_ABp79PlFt9yPCxSaarVc_DKTmrSGGf
|
||||
url: https://drive.google.com/uc?export=download&id=17_ABp79PlFt9yPCxSaarVc_DKTmrSGGf
|
||||
sha: bef233c28947ef6ec8c663d20a2b326302421fa3
|
||||
recommended parameter setting: -inputHeight=736, -inputWidth=1280;
|
||||
description: This model is trained on ICDAR2015, so it can only detect English text instances.
|
||||
|
||||
- DB_IC15_resnet18.onnx:
|
||||
url: https://drive.google.com/uc?export=dowload&id=1vY_KsDZZZb_svd5RT6pjyI8BS1nPbBSX
|
||||
url: https://drive.google.com/uc?export=download&id=1vY_KsDZZZb_svd5RT6pjyI8BS1nPbBSX
|
||||
sha: 19543ce09b2efd35f49705c235cc46d0e22df30b
|
||||
recommended parameter setting: -inputHeight=736, -inputWidth=1280;
|
||||
description: This model is trained on ICDAR2015, so it can only detect English text instances.
|
||||
|
||||
- DB_TD500_resnet50.onnx:
|
||||
url: https://drive.google.com/uc?export=dowload&id=19YWhArrNccaoSza0CfkXlA8im4-lAGsR
|
||||
url: https://drive.google.com/uc?export=download&id=19YWhArrNccaoSza0CfkXlA8im4-lAGsR
|
||||
sha: 1b4dd21a6baa5e3523156776970895bd3db6960a
|
||||
recommended parameter setting: -inputHeight=736, -inputWidth=736;
|
||||
description: This model is trained on MSRA-TD500, so it can detect both English and Chinese text instances.
|
||||
|
||||
- DB_TD500_resnet18.onnx:
|
||||
url: https://drive.google.com/uc?export=dowload&id=1sZszH3pEt8hliyBlTmB-iulxHP1dCQWV
|
||||
url: https://drive.google.com/uc?export=download&id=1sZszH3pEt8hliyBlTmB-iulxHP1dCQWV
|
||||
sha: 8a3700bdc13e00336a815fc7afff5dcc1ce08546
|
||||
recommended parameter setting: -inputHeight=736, -inputWidth=736;
|
||||
description: This model is trained on MSRA-TD500, so it can detect both English and Chinese text instances.
|
||||
@@ -133,11 +133,11 @@ This model is based on https://github.com/argman/EAST
|
||||
|
||||
```
|
||||
Text Recognition:
|
||||
url: https://drive.google.com/uc?export=dowload&id=1nMcEy68zDNpIlqAn6xCk_kYcUTIeSOtN
|
||||
url: https://drive.google.com/uc?export=download&id=1nMcEy68zDNpIlqAn6xCk_kYcUTIeSOtN
|
||||
sha: 89205612ce8dd2251effa16609342b69bff67ca3
|
||||
|
||||
Text Detection:
|
||||
url: https://drive.google.com/uc?export=dowload&id=149tAhIcvfCYeyufRoZ9tmc2mZDKE_XrF
|
||||
url: https://drive.google.com/uc?export=download&id=149tAhIcvfCYeyufRoZ9tmc2mZDKE_XrF
|
||||
sha: ced3c03fb7f8d9608169a913acf7e7b93e07109b
|
||||
```
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ than YOLOX) in case it is needed. However, usually each YOLO repository has pred
|
||||
|
||||
#### Exporting YOLOv10 model
|
||||
|
||||
In oder to run YOLOv10 one needs to cut off postporcessing with dynamic shapes from torch and then convert it to ONNX. If someone is looking for on how to cut off the postprocessing, there is this [forked branch](https://github.com/Abdurrahheem/yolov10/tree/ash/opencv-export) from official YOLOv10. The forked branch cuts of the postprocessing by [returning output](https://github.com/Abdurrahheem/yolov10/blob/4fdaafd912c8891642bfbe85751ea66ec20f05ad/ultralytics/nn/modules/head.py#L522) of the model before postprocessing procedure itself. To convert torch model to ONNX follow this proceduce.
|
||||
In order to run YOLOv10 one needs to cut off postprocessing with dynamic shapes from torch and then convert it to ONNX. If someone is looking for on how to cut off the postprocessing, there is this [forked branch](https://github.com/Abdurrahheem/yolov10/tree/ash/opencv-export) from official YOLOv10. The forked branch cuts off the postprocessing by [returning output](https://github.com/Abdurrahheem/yolov10/blob/4fdaafd912c8891642bfbe85751ea66ec20f05ad/ultralytics/nn/modules/head.py#L522) of the model before postprocessing procedure itself. To convert torch model to ONNX follow this procedure.
|
||||
|
||||
@code{.bash}
|
||||
git clone git@github.com:Abdurrahheem/yolov10.git
|
||||
|
||||
@@ -167,7 +167,7 @@ for `cv::aruco::Dictionary`. The data member of board classes are public and can
|
||||
To do so, you will need to use an external rendering engine library, such as OpenGL. The aruco module
|
||||
only provides the functionality to obtain the camera pose, i.e. the rotation and translation vectors,
|
||||
which is necessary to create the augmented reality effect. However, you will need to adapt the rotation
|
||||
and traslation vectors from the OpenCV format to the format accepted by your 3d rendering library.
|
||||
and translation vectors from the OpenCV format to the format accepted by your 3d rendering library.
|
||||
The original ArUco library contains examples of how to do it for OpenGL and Ogre3D.
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ It is similar to a ChArUco board in appearance, however they are conceptually di
|
||||
In both, ChArUco board and Diamond markers, their detection is based on the previous detected ArUco
|
||||
markers. In the ChArUco case, the used markers are selected by directly looking their identifiers. This means
|
||||
that if a marker (included in the board) is found on a image, it will be automatically assumed to belong to the board. Furthermore,
|
||||
if a marker board is found more than once in the image, it will produce an ambiguity since the system wont
|
||||
if a marker board is found more than once in the image, it will produce an ambiguity since the system won't
|
||||
be able to know which one should be used for the Board.
|
||||
|
||||
On the other hand, the detection of Diamond marker is not based on the identifiers. Instead, their detection
|
||||
|
||||
@@ -2285,7 +2285,7 @@ namespace CAROTENE_NS {
|
||||
f64 alpha, f64 beta);
|
||||
|
||||
/*
|
||||
Reduce matrix to a vector by calculatin given operation for each column
|
||||
Reduce matrix to a vector by calculating given operation for each column
|
||||
*/
|
||||
void reduceColSum(const Size2D &size,
|
||||
const u8 * srcBase, ptrdiff_t srcStride,
|
||||
|
||||
@@ -231,7 +231,7 @@ void accumulateSquare(const Size2D &size,
|
||||
internal::assertSupportedConfiguration();
|
||||
|
||||
#ifdef CAROTENE_NEON
|
||||
// this ugly contruction is needed to avoid:
|
||||
// this ugly construction is needed to avoid:
|
||||
// /usr/lib/gcc/arm-linux-gnueabihf/4.8/include/arm_neon.h:3581:59: error: argument must be a constant
|
||||
// return (int16x8_t)__builtin_neon_vshr_nv8hi (__a, __b, 1);
|
||||
|
||||
|
||||
@@ -524,7 +524,7 @@ inline void Canny3x3(const Size2D &size, s32 cn,
|
||||
|
||||
//i == 0
|
||||
normEstimator.firstRow(size, cn, srcBase, srcStride, dxBase, dxStride, dyBase, dyStride, mag_buf);
|
||||
// calculate magnitude and angle of gradient, perform non-maxima supression.
|
||||
// calculate magnitude and angle of gradient, perform non-maxima suppression.
|
||||
// fill the map with one of the following values:
|
||||
// 0 - the pixel might belong to an edge
|
||||
// 1 - the pixel can not belong to an edge
|
||||
|
||||
@@ -66,7 +66,7 @@ inline float32x2_t vrecp_f32(float32x2_t val)
|
||||
return reciprocal;
|
||||
}
|
||||
|
||||
// caclulate sqrt value
|
||||
// calculate sqrt value
|
||||
|
||||
inline float32x4_t vrsqrtq_f32(float32x4_t val)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ set(IPP_HAL_HEADERS
|
||||
CACHE INTERNAL "")
|
||||
|
||||
add_library(ipphal STATIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/math_ipp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/mean_ipp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/minmax_ipp.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/norm_ipp.cpp"
|
||||
|
||||
@@ -74,6 +74,33 @@ int ipp_hal_transpose2d(const uchar* src_data, size_t src_step, uchar* dst_data,
|
||||
#undef cv_hal_transpose2d
|
||||
#define cv_hal_transpose2d ipp_hal_transpose2d
|
||||
|
||||
int ipp_hal_invSqrt32f(const float* src, float* dst, int len);
|
||||
int ipp_hal_invSqrt64f(const double* src, double* dst, int len);
|
||||
|
||||
#undef cv_hal_invSqrt32f
|
||||
#define cv_hal_invSqrt32f ipp_hal_invSqrt32f
|
||||
|
||||
#undef cv_hal_invSqrt64f
|
||||
#define cv_hal_invSqrt64f ipp_hal_invSqrt64f
|
||||
|
||||
int ipp_hal_exp32f(const float* src, float* dst, int len);
|
||||
int ipp_hal_exp64f(const double* src, double* dst, int len);
|
||||
|
||||
#undef cv_hal_exp32f
|
||||
#define cv_hal_exp32f ipp_hal_exp32f
|
||||
|
||||
#undef cv_hal_exp64f
|
||||
#define cv_hal_exp64f ipp_hal_exp64f
|
||||
|
||||
int ipp_hal_log32f(const float* src, float* dst, int len);
|
||||
int ipp_hal_log64f(const double* src, double* dst, int len);
|
||||
|
||||
#undef cv_hal_log32f
|
||||
#define cv_hal_log32f ipp_hal_log32f
|
||||
|
||||
#undef cv_hal_log64f
|
||||
#define cv_hal_log64f ipp_hal_log64f
|
||||
|
||||
//! @endcond
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// 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 "ipp_hal_core.hpp"
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/core/base.hpp>
|
||||
|
||||
int ipp_hal_invSqrt32f(const float* src, float* dst, int len)
|
||||
{
|
||||
CV_HAL_CHECK_USE_IPP();
|
||||
IppStatus status = CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_32f_A21, src, dst, len);
|
||||
if (status >= 0)
|
||||
{
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int ipp_hal_invSqrt64f(const double* src, double* dst, int len)
|
||||
{
|
||||
CV_HAL_CHECK_USE_IPP();
|
||||
IppStatus status = CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_64f_A50, src, dst, len);
|
||||
if (status >= 0)
|
||||
{
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int ipp_hal_exp32f(const float* src, float* dst, int len)
|
||||
{
|
||||
CV_HAL_CHECK_USE_IPP();
|
||||
IppStatus status = CV_INSTRUMENT_FUN_IPP(ippsExp_32f_A21, src, dst, len);
|
||||
if (status >= 0)
|
||||
{
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int ipp_hal_exp64f(const double* src, double* dst, int len)
|
||||
{
|
||||
CV_HAL_CHECK_USE_IPP();
|
||||
IppStatus status = CV_INSTRUMENT_FUN_IPP(ippsExp_64f_A50, src, dst, len);
|
||||
if (status >= 0)
|
||||
{
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int ipp_hal_log32f(const float* src, float* dst, int len)
|
||||
{
|
||||
CV_HAL_CHECK_USE_IPP();
|
||||
IppStatus status = CV_INSTRUMENT_FUN_IPP(ippsLn_32f_A21, src, dst, len);
|
||||
if (status >= 0)
|
||||
{
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int ipp_hal_log64f(const double* src, double* dst, int len)
|
||||
{
|
||||
CV_HAL_CHECK_USE_IPP();
|
||||
IppStatus status = CV_INSTRUMENT_FUN_IPP(ippsLn_64f_A50, src, dst, len);
|
||||
if (status >= 0)
|
||||
{
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
@@ -56,32 +56,35 @@ inline int fast_16(const uchar* src_data, size_t src_step,
|
||||
size_t vl;
|
||||
for (; j < width - 3; j += vl, ptr += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e16m1(width - 3 - j);
|
||||
/* u8mf2 pre-screen: same VL as i16m1, defer vzext until needed */
|
||||
vl = __riscv_vsetvl_e8mf2(width - 3 - j);
|
||||
vuint8mf2_t vcen_8 = __riscv_vle8_v_u8mf2(ptr, vl);
|
||||
vuint8mf2_t vlo_8 = __riscv_vssubu_vx_u8mf2(vcen_8, (uint8_t)threshold, vl);
|
||||
vuint8mf2_t vhi_8 = __riscv_vsaddu_vx_u8mf2(vcen_8, (uint8_t)threshold, vl);
|
||||
vuint8mf2_t vk0_8 = __riscv_vle8_v_u8mf2(ptr + pixel[0], vl);
|
||||
vuint8mf2_t vk4_8 = __riscv_vle8_v_u8mf2(ptr + pixel[4], vl);
|
||||
vuint8mf2_t vk8_8 = __riscv_vle8_v_u8mf2(ptr + pixel[8], vl);
|
||||
vuint8mf2_t vk12_8 = __riscv_vle8_v_u8mf2(ptr + pixel[12], vl);
|
||||
|
||||
/* Load center pixel and widen to int16 */
|
||||
vint16m1_t vcen = __riscv_vreinterpret_v_u16m1_i16m1(
|
||||
__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr, vl), vl));
|
||||
vint16m1_t vlo = __riscv_vsub_vx_i16m1(vcen, threshold, vl);
|
||||
vint16m1_t vhi = __riscv_vadd_vx_i16m1(vcen, threshold, vl);
|
||||
|
||||
/* 4-direction quick reject */
|
||||
vint16m1_t vk0 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[0], vl), vl));
|
||||
vint16m1_t vk4 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[4], vl), vl));
|
||||
vint16m1_t vk8 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[8], vl), vl));
|
||||
vint16m1_t vk12 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[12], vl), vl));
|
||||
|
||||
vbool16_t bright = __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vk0, vhi, vl), __riscv_vmsgt_vv_i16m1_b16(vk4, vhi, vl), vl);
|
||||
vbool16_t dark = __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vlo, vk0, vl), __riscv_vmsgt_vv_i16m1_b16(vlo, vk4, vl), vl);
|
||||
bright = __riscv_vmor_mm_b16(bright, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vk4, vhi, vl), __riscv_vmsgt_vv_i16m1_b16(vk8, vhi, vl), vl), vl);
|
||||
dark = __riscv_vmor_mm_b16(dark, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vlo, vk4, vl), __riscv_vmsgt_vv_i16m1_b16(vlo, vk8, vl), vl), vl);
|
||||
bright = __riscv_vmor_mm_b16(bright, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vk8, vhi, vl), __riscv_vmsgt_vv_i16m1_b16(vk12, vhi, vl), vl), vl);
|
||||
dark = __riscv_vmor_mm_b16(dark, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vlo, vk8, vl), __riscv_vmsgt_vv_i16m1_b16(vlo, vk12, vl), vl), vl);
|
||||
bright = __riscv_vmor_mm_b16(bright, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vk12, vhi, vl), __riscv_vmsgt_vv_i16m1_b16(vk0, vhi, vl), vl), vl);
|
||||
dark = __riscv_vmor_mm_b16(dark, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vlo, vk12, vl), __riscv_vmsgt_vv_i16m1_b16(vlo, vk0, vl), vl), vl);
|
||||
vbool16_t bright = __riscv_vmand_mm_b16(__riscv_vmsgtu_vv_u8mf2_b16(vk0_8, vhi_8, vl), __riscv_vmsgtu_vv_u8mf2_b16(vk4_8, vhi_8, vl), vl);
|
||||
vbool16_t dark = __riscv_vmand_mm_b16(__riscv_vmsgtu_vv_u8mf2_b16(vlo_8, vk0_8, vl), __riscv_vmsgtu_vv_u8mf2_b16(vlo_8, vk4_8, vl), vl);
|
||||
bright = __riscv_vmor_mm_b16(bright, __riscv_vmand_mm_b16(__riscv_vmsgtu_vv_u8mf2_b16(vk4_8, vhi_8, vl), __riscv_vmsgtu_vv_u8mf2_b16(vk8_8, vhi_8, vl), vl), vl);
|
||||
dark = __riscv_vmor_mm_b16(dark, __riscv_vmand_mm_b16(__riscv_vmsgtu_vv_u8mf2_b16(vlo_8, vk4_8, vl), __riscv_vmsgtu_vv_u8mf2_b16(vlo_8, vk8_8, vl), vl), vl);
|
||||
bright = __riscv_vmor_mm_b16(bright, __riscv_vmand_mm_b16(__riscv_vmsgtu_vv_u8mf2_b16(vk8_8, vhi_8, vl), __riscv_vmsgtu_vv_u8mf2_b16(vk12_8, vhi_8, vl), vl), vl);
|
||||
dark = __riscv_vmor_mm_b16(dark, __riscv_vmand_mm_b16(__riscv_vmsgtu_vv_u8mf2_b16(vlo_8, vk8_8, vl), __riscv_vmsgtu_vv_u8mf2_b16(vlo_8, vk12_8, vl), vl), vl);
|
||||
bright = __riscv_vmor_mm_b16(bright, __riscv_vmand_mm_b16(__riscv_vmsgtu_vv_u8mf2_b16(vk12_8, vhi_8, vl), __riscv_vmsgtu_vv_u8mf2_b16(vk0_8, vhi_8, vl), vl), vl);
|
||||
dark = __riscv_vmor_mm_b16(dark, __riscv_vmand_mm_b16(__riscv_vmsgtu_vv_u8mf2_b16(vlo_8, vk12_8, vl), __riscv_vmsgtu_vv_u8mf2_b16(vlo_8, vk0_8, vl), vl), vl);
|
||||
|
||||
if (__riscv_vfirst_m_b16(__riscv_vmor_mm_b16(bright, dark, vl), vl) < 0)
|
||||
continue;
|
||||
|
||||
/* Widen pre-loaded u8mf2 to i16m1 for score computation */
|
||||
vint16m1_t vcen = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(vcen_8, vl));
|
||||
vint16m1_t vk0 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(vk0_8, vl));
|
||||
vint16m1_t vk4 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(vk4_8, vl));
|
||||
vint16m1_t vk8 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(vk8_8, vl));
|
||||
vint16m1_t vk12 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(vk12_8, vl));
|
||||
|
||||
/* Load remaining 12 neighbors */
|
||||
vint16m1_t vk1 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[1], vl), vl));
|
||||
vint16m1_t vk2 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[2], vl), vl));
|
||||
|
||||
@@ -39,4 +39,35 @@ PERF_TEST_P(String_Size, asymm_circles_grid, testing::Values(
|
||||
SANITY_CHECK(ptvec, 2);
|
||||
}
|
||||
|
||||
// Perf test using synthetic keypoints (no image I/O). Exercises the RNG and
|
||||
// findLongestPath code paths directly with a pre-detected point set.
|
||||
typedef perf::TestBaseWithParam<cv::Size> CirclesGrid_RNG_Size;
|
||||
|
||||
PERF_TEST_P(CirclesGrid_RNG_Size, detect_keypoints_symmetric,
|
||||
testing::Values(cv::Size(6, 5), cv::Size(8, 6), cv::Size(10, 8), cv::Size(15, 12), cv::Size(20, 15)))
|
||||
{
|
||||
const cv::Size patternSize = GetParam();
|
||||
const float spacing = 30.f;
|
||||
|
||||
std::vector<cv::Point2f> pts;
|
||||
pts.reserve(patternSize.area());
|
||||
for (int r = 0; r < patternSize.height; r++)
|
||||
for (int c = 0; c < patternSize.width; c++)
|
||||
pts.push_back(cv::Point2f(c * spacing, r * spacing));
|
||||
|
||||
// Shuffle so the detector works from an unordered set, same as real use.
|
||||
cv::RNG& rng = cv::theRNG();
|
||||
for (int k = (int)pts.size() - 1; k > 0; k--)
|
||||
std::swap(pts[k], pts[rng.uniform(0, k + 1)]);
|
||||
|
||||
std::vector<cv::Point2f> centers;
|
||||
centers.resize(patternSize.area());
|
||||
declare.in(cv::Mat(pts)).out(centers);
|
||||
|
||||
TEST_CYCLE() ASSERT_TRUE(findCirclesGrid(cv::Mat(pts), patternSize, centers,
|
||||
CALIB_CB_SYMMETRIC_GRID, cv::Ptr<cv::FeatureDetector>()));
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "precomp.hpp"
|
||||
#include "opencv2/flann.hpp"
|
||||
#include "chessboard.hpp"
|
||||
#include "math.h"
|
||||
#include <math.h>
|
||||
|
||||
//#define CV_DETECTORS_CHESSBOARD_DEBUG
|
||||
#ifdef CV_DETECTORS_CHESSBOARD_DEBUG
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "precomp.hpp"
|
||||
#include "circlesgrid.hpp"
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
|
||||
// Requires CMake flag: DEBUG_opencv_calib3d=ON
|
||||
//#define DEBUG_CIRCLES
|
||||
@@ -569,8 +570,6 @@ CirclesGridFinder::Segment::Segment(cv::Point2f _s, cv::Point2f _e) :
|
||||
{
|
||||
}
|
||||
|
||||
void computeShortestPath(Mat &predecessorMatrix, int v1, int v2, std::vector<int> &path);
|
||||
void computePredecessorMatrix(const Mat &dm, int verticesCount, Mat &predecessorMatrix);
|
||||
|
||||
CirclesGridFinderParameters::CirclesGridFinderParameters()
|
||||
{
|
||||
@@ -1204,79 +1203,91 @@ void CirclesGridFinder::computeRNG(Graph &rng, std::vector<cv::Point2f> &vectors
|
||||
rng = Graph(keypoints.size());
|
||||
vectors.clear();
|
||||
|
||||
//TODO: use more fast algorithm instead of naive N^3
|
||||
for (size_t i = 0; i < keypoints.size(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < keypoints.size(); j++)
|
||||
{
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
Point2f vec = keypoints[i] - keypoints[j];
|
||||
double dist = norm(vec);
|
||||
|
||||
bool isNeighbors = true;
|
||||
for (size_t k = 0; k < keypoints.size(); k++)
|
||||
{
|
||||
if (k == i || k == j)
|
||||
continue;
|
||||
|
||||
double dist1 = norm(keypoints[i] - keypoints[k]);
|
||||
double dist2 = norm(keypoints[j] - keypoints[k]);
|
||||
if (dist1 < dist && dist2 < dist)
|
||||
{
|
||||
isNeighbors = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNeighbors)
|
||||
{
|
||||
rng.addEdge(i, j);
|
||||
vectors.push_back(keypoints[i] - keypoints[j]);
|
||||
if (drawImage != 0)
|
||||
{
|
||||
line(*drawImage, keypoints[i], keypoints[j], Scalar(255, 0, 0), 2);
|
||||
circle(*drawImage, keypoints[i], 3, Scalar(0, 0, 255), -1);
|
||||
circle(*drawImage, keypoints[j], 3, Scalar(0, 0, 255), -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void computePredecessorMatrix(const Mat &dm, int verticesCount, Mat &predecessorMatrix)
|
||||
{
|
||||
CV_Assert( dm.type() == CV_32SC1 );
|
||||
predecessorMatrix.create(verticesCount, verticesCount, CV_32SC1);
|
||||
predecessorMatrix = -1;
|
||||
for (int i = 0; i < predecessorMatrix.rows; i++)
|
||||
{
|
||||
for (int j = 0; j < predecessorMatrix.cols; j++)
|
||||
{
|
||||
int dist = dm.at<int> (i, j);
|
||||
for (int k = 0; k < verticesCount; k++)
|
||||
{
|
||||
if (dm.at<int> (i, k) == dist - 1 && dm.at<int> (k, j) == 1)
|
||||
{
|
||||
predecessorMatrix.at<int> (i, j) = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void computeShortestPath(Mat &predecessorMatrix, size_t v1, size_t v2, std::vector<size_t> &path)
|
||||
{
|
||||
if (predecessorMatrix.at<int> ((int)v1, (int)v2) < 0)
|
||||
{
|
||||
path.push_back(v1);
|
||||
const size_t n = keypoints.size();
|
||||
if (n < 2)
|
||||
return;
|
||||
|
||||
// RNG is a subgraph of the Delaunay triangulation, so we only need to test
|
||||
// Delaunay edges as candidates. This brings the complexity from O(N^3) down
|
||||
// to O(N^2) in the worst case, and much better in practice for regular grids
|
||||
// where Delaunay edges (~3N) are almost all RNG edges anyway.
|
||||
|
||||
float minX = keypoints[0].x, minY = keypoints[0].y;
|
||||
float maxX = minX, maxY = minY;
|
||||
for (size_t i = 1; i < n; i++)
|
||||
{
|
||||
minX = std::min(minX, keypoints[i].x);
|
||||
minY = std::min(minY, keypoints[i].y);
|
||||
maxX = std::max(maxX, keypoints[i].x);
|
||||
maxY = std::max(maxY, keypoints[i].y);
|
||||
}
|
||||
|
||||
computeShortestPath(predecessorMatrix, v1, predecessorMatrix.at<int> ((int)v1, (int)v2), path);
|
||||
path.push_back(v2);
|
||||
// Subdiv2D requires a rect that strictly contains all points.
|
||||
const float margin = 1.f;
|
||||
Rect2f rect(minX - margin, minY - margin,
|
||||
(maxX - minX) + 2*margin,
|
||||
(maxY - minY) + 2*margin);
|
||||
Subdiv2D subdiv(rect);
|
||||
subdiv.insert(std::vector<Point2f>(keypoints.begin(), keypoints.end()));
|
||||
|
||||
// Map coordinates back to keypoint indices. Subdiv2D stores and returns the
|
||||
// exact float values we inserted, so direct comparison is safe here.
|
||||
std::map<std::pair<float, float>, size_t> ptToIdx;
|
||||
for (size_t i = 0; i < n; i++)
|
||||
ptToIdx[{keypoints[i].x, keypoints[i].y}] = i;
|
||||
|
||||
std::vector<Vec4f> edgeList;
|
||||
subdiv.getEdgeList(edgeList);
|
||||
|
||||
for (const Vec4f& e : edgeList)
|
||||
{
|
||||
auto it1 = ptToIdx.find({e[0], e[1]});
|
||||
auto it2 = ptToIdx.find({e[2], e[3]});
|
||||
// Edges involving the virtual bounding-rect vertices won't be in ptToIdx.
|
||||
if (it1 == ptToIdx.end() || it2 == ptToIdx.end())
|
||||
continue;
|
||||
|
||||
size_t i = it1->second;
|
||||
size_t j = it2->second;
|
||||
if (i == j)
|
||||
continue;
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
|
||||
Point2f vec = keypoints[i] - keypoints[j];
|
||||
double distSq = (double)vec.x*vec.x + (double)vec.y*vec.y;
|
||||
|
||||
bool isRNG = true;
|
||||
for (size_t k = 0; k < n; k++)
|
||||
{
|
||||
if (k == i || k == j)
|
||||
continue;
|
||||
Point2f d1 = keypoints[i] - keypoints[k];
|
||||
Point2f d2 = keypoints[j] - keypoints[k];
|
||||
double d1Sq = (double)d1.x*d1.x + (double)d1.y*d1.y;
|
||||
double d2Sq = (double)d2.x*d2.x + (double)d2.y*d2.y;
|
||||
if (d1Sq < distSq && d2Sq < distSq)
|
||||
{
|
||||
isRNG = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isRNG)
|
||||
{
|
||||
rng.addEdge(i, j);
|
||||
// Push both directions; findBasis needs the full set to cluster into
|
||||
// the 4 groups (two grid axes and their negatives) via k-means.
|
||||
vectors.push_back(keypoints[i] - keypoints[j]);
|
||||
vectors.push_back(keypoints[j] - keypoints[i]);
|
||||
if (drawImage != 0)
|
||||
{
|
||||
line(*drawImage, keypoints[i], keypoints[j], Scalar(255, 0, 0), 2);
|
||||
circle(*drawImage, keypoints[i], 3, Scalar(0, 0, 255), -1);
|
||||
circle(*drawImage, keypoints[j], 3, Scalar(0, 0, 255), -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t CirclesGridFinder::findLongestPath(std::vector<Graph> &basisGraphs, Path &bestPath)
|
||||
@@ -1285,45 +1296,93 @@ size_t CirclesGridFinder::findLongestPath(std::vector<Graph> &basisGraphs, Path
|
||||
std::vector<int> confidences;
|
||||
|
||||
size_t bestGraphIdx = 0;
|
||||
const int infinity = -1;
|
||||
for (size_t graphIdx = 0; graphIdx < basisGraphs.size(); graphIdx++)
|
||||
{
|
||||
const Graph &g = basisGraphs[graphIdx];
|
||||
Mat distanceMatrix;
|
||||
g.floydWarshall(distanceMatrix, infinity);
|
||||
Mat predecessorMatrix;
|
||||
computePredecessorMatrix(distanceMatrix, (int)g.getVerticesCount(), predecessorMatrix);
|
||||
const int n = (int)g.getVerticesCount();
|
||||
|
||||
double maxVal;
|
||||
Point maxLoc;
|
||||
minMaxLoc(distanceMatrix, 0, &maxVal, 0, &maxLoc);
|
||||
// BFS from every vertex to find the diameter (longest shortest path).
|
||||
// basisGraphs are sparse -- each vertex connects only to grid neighbors in
|
||||
// one direction -- so this is O(N^2) vs Floyd-Warshall's O(N^3).
|
||||
std::vector<int> dist(n);
|
||||
std::queue<int> q;
|
||||
|
||||
if (maxVal > longestPaths[0].length)
|
||||
int maxDist = 0;
|
||||
int srcBest = 0, dstBest = 0;
|
||||
|
||||
for (int src = 0; src < n; src++)
|
||||
{
|
||||
std::fill(dist.begin(), dist.end(), -1);
|
||||
dist[src] = 0;
|
||||
q.push(src);
|
||||
while (!q.empty())
|
||||
{
|
||||
int v = q.front(); q.pop();
|
||||
for (size_t nb : g.getNeighbors((size_t)v))
|
||||
{
|
||||
int u = (int)nb;
|
||||
if (dist[u] < 0)
|
||||
{
|
||||
dist[u] = dist[v] + 1;
|
||||
q.push(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dst = 0; dst < n; dst++)
|
||||
{
|
||||
if (dist[dst] > maxDist)
|
||||
{
|
||||
maxDist = dist[dst];
|
||||
srcBest = src;
|
||||
dstBest = dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxDist > longestPaths[0].length)
|
||||
{
|
||||
longestPaths.clear();
|
||||
confidences.clear();
|
||||
bestGraphIdx = graphIdx;
|
||||
}
|
||||
if (longestPaths.empty() || (maxVal == longestPaths[0].length && graphIdx == bestGraphIdx))
|
||||
if (longestPaths.empty() || (maxDist == longestPaths[0].length && graphIdx == bestGraphIdx))
|
||||
{
|
||||
Path path = Path(maxLoc.x, maxLoc.y, cvRound(maxVal));
|
||||
CV_Assert(maxLoc.x >= 0 && maxLoc.y >= 0)
|
||||
;
|
||||
size_t id1 = static_cast<size_t> (maxLoc.x);
|
||||
size_t id2 = static_cast<size_t> (maxLoc.y);
|
||||
computeShortestPath(predecessorMatrix, id1, id2, path.vertices);
|
||||
Path path = Path(srcBest, dstBest, maxDist);
|
||||
|
||||
// BFS again from srcBest to reconstruct the path to dstBest
|
||||
std::vector<int> pred(n, -1);
|
||||
std::fill(dist.begin(), dist.end(), -1);
|
||||
dist[srcBest] = 0;
|
||||
q.push(srcBest);
|
||||
while (!q.empty())
|
||||
{
|
||||
int v = q.front(); q.pop();
|
||||
for (size_t nb : g.getNeighbors((size_t)v))
|
||||
{
|
||||
int u = (int)nb;
|
||||
if (dist[u] < 0)
|
||||
{
|
||||
dist[u] = dist[v] + 1;
|
||||
pred[u] = v;
|
||||
q.push(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<size_t> pathVertices;
|
||||
for (int cur = dstBest; cur != srcBest; cur = pred[cur])
|
||||
pathVertices.push_back((size_t)cur);
|
||||
pathVertices.push_back((size_t)srcBest);
|
||||
std::reverse(pathVertices.begin(), pathVertices.end());
|
||||
path.vertices = pathVertices;
|
||||
|
||||
longestPaths.push_back(path);
|
||||
|
||||
int conf = 0;
|
||||
for (int v2 = 0; v2 < (int)path.vertices.size(); v2++)
|
||||
{
|
||||
conf += (int)basisGraphs[1 - (int)graphIdx].getDegree(v2);
|
||||
}
|
||||
conf += (int)basisGraphs[1 - (int)graphIdx].getDegree(path.vertices[v2]);
|
||||
confidences.push_back(conf);
|
||||
}
|
||||
}
|
||||
//if( bestGraphIdx != 0 )
|
||||
//CV_Error( 0, "" );
|
||||
|
||||
int maxConf = -1;
|
||||
int bestPathIdx = -1;
|
||||
@@ -1336,7 +1395,6 @@ size_t CirclesGridFinder::findLongestPath(std::vector<Graph> &basisGraphs, Path
|
||||
}
|
||||
}
|
||||
|
||||
//int bestPathIdx = rand() % longestPaths.size();
|
||||
bestPath = longestPaths.at(bestPathIdx);
|
||||
bool needReverse = (bestGraphIdx == 0 && keypoints[bestPath.lastVertex].x < keypoints[bestPath.firstVertex].x)
|
||||
|| (bestGraphIdx == 1 && keypoints[bestPath.lastVertex].y < keypoints[bestPath.firstVertex].y);
|
||||
|
||||
@@ -517,7 +517,7 @@ void filterHomographyDecompByVisibleRefpoints(InputArrayOfArrays _rotations,
|
||||
CV_Assert(pointsMask.empty() || pointsMask.checkVector(1, CV_8U) == npoints);
|
||||
const uchar* pointsMaskPtr = pointsMask.data;
|
||||
|
||||
std::vector<uchar> solutionMask(nsolutions, (uchar)1);
|
||||
AutoBuffer<uchar> solutionMask(nsolutions, (uchar)1);
|
||||
std::vector<Mat> normals(nsolutions);
|
||||
std::vector<Mat> rotnorm(nsolutions);
|
||||
Mat R;
|
||||
@@ -559,7 +559,8 @@ void filterHomographyDecompByVisibleRefpoints(InputArrayOfArrays _rotations,
|
||||
if( solutionMask[i] )
|
||||
possibleSolutions.push_back(i);
|
||||
|
||||
Mat(possibleSolutions).copyTo(_possibleSolutions);
|
||||
constexpr int cvType = traits::Type<decltype(possibleSolutions)::value_type>::value;
|
||||
Mat(static_cast<int>(possibleSolutions.size()), 1, cvType, possibleSolutions.data()).copyTo(_possibleSolutions);
|
||||
}
|
||||
|
||||
} //namespace cv
|
||||
|
||||
@@ -849,6 +849,97 @@ TEST(Calib3d_RotatedCirclesPatternDetector, issue_24964)
|
||||
EXPECT_LE(error, precise_success_error_level);
|
||||
}
|
||||
|
||||
// Generate a perfect W x H symmetric circle grid at the given spacing.
|
||||
// Points are returned in shuffled order so the detector can't rely on input ordering.
|
||||
static std::vector<Point2f> makeSyntheticSymmetricGrid(int cols, int rows, float spacing)
|
||||
{
|
||||
std::vector<Point2f> pts;
|
||||
pts.reserve(cols * rows);
|
||||
for (int r = 0; r < rows; r++)
|
||||
for (int c = 0; c < cols; c++)
|
||||
pts.push_back(Point2f(c * spacing, r * spacing));
|
||||
|
||||
cv::RNG& rng = cv::theRNG();
|
||||
for (int k = (int)pts.size() - 1; k > 0; k--)
|
||||
std::swap(pts[k], pts[rng.uniform(0, k + 1)]);
|
||||
|
||||
return pts;
|
||||
}
|
||||
|
||||
// Generate an asymmetric circle grid. Even rows start at x=0, odd rows are offset by spacing/2.
|
||||
static std::vector<Point2f> makeSyntheticAsymmetricGrid(int cols, int rows, float spacing)
|
||||
{
|
||||
std::vector<Point2f> pts;
|
||||
pts.reserve(cols * rows);
|
||||
for (int r = 0; r < rows; r++)
|
||||
for (int c = 0; c < cols; c++)
|
||||
pts.push_back(Point2f(c * spacing + (r % 2) * spacing * 0.5f, r * spacing * 0.5f));
|
||||
|
||||
cv::RNG& rng = cv::theRNG();
|
||||
for (int k = (int)pts.size() - 1; k > 0; k--)
|
||||
std::swap(pts[k], pts[rng.uniform(0, k + 1)]);
|
||||
|
||||
return pts;
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<Size> Calib3d_CirclesGrid_RNG_Symmetric;
|
||||
|
||||
TEST_P(Calib3d_CirclesGrid_RNG_Symmetric, synthetic)
|
||||
{
|
||||
// Verify that findCirclesGrid correctly detects synthetic perfect symmetric grids of
|
||||
// various sizes. This exercises the computeRNG path (Delaunay-based) end-to-end.
|
||||
const float spacing = 30.f;
|
||||
const Size gridSize = GetParam();
|
||||
|
||||
std::vector<Point2f> pts = makeSyntheticSymmetricGrid(gridSize.width, gridSize.height, spacing);
|
||||
|
||||
std::vector<Point2f> centers;
|
||||
bool found = findCirclesGrid(Mat(pts), gridSize, centers,
|
||||
CALIB_CB_SYMMETRIC_GRID, Ptr<FeatureDetector>());
|
||||
|
||||
ASSERT_TRUE(found) << "Symmetric grid " << gridSize.width << "x" << gridSize.height << " not detected";
|
||||
ASSERT_EQ((int)centers.size(), gridSize.area());
|
||||
for (const Point2f& c : centers)
|
||||
{
|
||||
bool matched = false;
|
||||
for (const Point2f& p : pts)
|
||||
if (cv::norm(c - p) < 1.f) { matched = true; break; }
|
||||
EXPECT_TRUE(matched) << "Detected center " << c << " does not match any input point "
|
||||
<< "for grid " << gridSize.width << "x" << gridSize.height;
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Calib3d_CirclesGrid_RNG_Symmetric,
|
||||
testing::Values(Size(4, 4), Size(6, 5), Size(8, 6), Size(10, 8)));
|
||||
|
||||
typedef testing::TestWithParam<Size> Calib3d_CirclesGrid_RNG_Asymmetric;
|
||||
|
||||
TEST_P(Calib3d_CirclesGrid_RNG_Asymmetric, synthetic)
|
||||
{
|
||||
const float spacing = 30.f;
|
||||
const Size gridSize = GetParam();
|
||||
|
||||
std::vector<Point2f> pts = makeSyntheticAsymmetricGrid(gridSize.width, gridSize.height, spacing);
|
||||
|
||||
std::vector<Point2f> centers;
|
||||
bool found = findCirclesGrid(Mat(pts), gridSize, centers,
|
||||
CALIB_CB_ASYMMETRIC_GRID, Ptr<FeatureDetector>());
|
||||
|
||||
ASSERT_TRUE(found) << "Asymmetric grid " << gridSize.width << "x" << gridSize.height << " not detected";
|
||||
ASSERT_EQ((int)centers.size(), gridSize.area());
|
||||
for (const Point2f& c : centers)
|
||||
{
|
||||
bool matched = false;
|
||||
for (const Point2f& p : pts)
|
||||
if (cv::norm(c - p) < 1.f) { matched = true; break; }
|
||||
EXPECT_TRUE(matched) << "Detected center " << c << " does not match any input point "
|
||||
<< "for grid " << gridSize.width << "x" << gridSize.height;
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Calib3d_CirclesGrid_RNG_Asymmetric,
|
||||
testing::Values(Size(4, 6), Size(5, 8)));
|
||||
|
||||
TEST(Calib3d_CornerOrdering, issue_26830) {
|
||||
const cv::String dataDir = string(TS::ptr()->get_data_path()) + "cv/cameracalibration/";
|
||||
const cv::Mat image = cv::imread(dataDir + "checkerboard_marker_white.png");
|
||||
|
||||
@@ -3060,39 +3060,25 @@ inline v_float64x2 v_cvt_f64(const v_int64x2& v)
|
||||
|
||||
inline v_int8x16 v_lut(const schar* tab, const int* idx)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return v_int8x16(_mm_setr_epi8(tab[idx[0]], tab[idx[1]], tab[idx[ 2]], tab[idx[ 3]], tab[idx[ 4]], tab[idx[ 5]], tab[idx[ 6]], tab[idx[ 7]],
|
||||
tab[idx[8]], tab[idx[9]], tab[idx[10]], tab[idx[11]], tab[idx[12]], tab[idx[13]], tab[idx[14]], tab[idx[15]]));
|
||||
#else
|
||||
return v_int8x16(_mm_setr_epi64(
|
||||
_mm_setr_pi8(tab[idx[0]], tab[idx[1]], tab[idx[ 2]], tab[idx[ 3]], tab[idx[ 4]], tab[idx[ 5]], tab[idx[ 6]], tab[idx[ 7]]),
|
||||
_mm_setr_pi8(tab[idx[8]], tab[idx[9]], tab[idx[10]], tab[idx[11]], tab[idx[12]], tab[idx[13]], tab[idx[14]], tab[idx[15]])
|
||||
));
|
||||
#endif
|
||||
return v_int8x16(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]],
|
||||
tab[idx[4]], tab[idx[5]], tab[idx[6]], tab[idx[7]],
|
||||
tab[idx[8]], tab[idx[9]], tab[idx[10]], tab[idx[11]],
|
||||
tab[idx[12]], tab[idx[13]], tab[idx[14]], tab[idx[15]]);
|
||||
}
|
||||
inline v_int8x16 v_lut_pairs(const schar* tab, const int* idx)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return v_int8x16(_mm_setr_epi16(*(const short*)(tab + idx[0]), *(const short*)(tab + idx[1]), *(const short*)(tab + idx[2]), *(const short*)(tab + idx[3]),
|
||||
*(const short*)(tab + idx[4]), *(const short*)(tab + idx[5]), *(const short*)(tab + idx[6]), *(const short*)(tab + idx[7])));
|
||||
#else
|
||||
return v_int8x16(_mm_setr_epi64(
|
||||
_mm_setr_pi16(*(const short*)(tab + idx[0]), *(const short*)(tab + idx[1]), *(const short*)(tab + idx[2]), *(const short*)(tab + idx[3])),
|
||||
_mm_setr_pi16(*(const short*)(tab + idx[4]), *(const short*)(tab + idx[5]), *(const short*)(tab + idx[6]), *(const short*)(tab + idx[7]))
|
||||
));
|
||||
#endif
|
||||
return v_int8x16(tab[idx[0]], tab[idx[0] + 1], tab[idx[1]], tab[idx[1] + 1],
|
||||
tab[idx[2]], tab[idx[2] + 1], tab[idx[3]], tab[idx[3] + 1],
|
||||
tab[idx[4]], tab[idx[4] + 1], tab[idx[5]], tab[idx[5] + 1],
|
||||
tab[idx[6]], tab[idx[6] + 1], tab[idx[7]], tab[idx[7] + 1]);
|
||||
}
|
||||
inline v_int8x16 v_lut_quads(const schar* tab, const int* idx)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return v_int8x16(_mm_setr_epi32(*(const int*)(tab + idx[0]), *(const int*)(tab + idx[1]),
|
||||
*(const int*)(tab + idx[2]), *(const int*)(tab + idx[3])));
|
||||
#else
|
||||
return v_int8x16(_mm_setr_epi64(
|
||||
_mm_setr_pi32(*(const int*)(tab + idx[0]), *(const int*)(tab + idx[1])),
|
||||
_mm_setr_pi32(*(const int*)(tab + idx[2]), *(const int*)(tab + idx[3]))
|
||||
));
|
||||
#endif
|
||||
return v_int8x16(
|
||||
tab[idx[0]], tab[idx[0] + 1], tab[idx[0] + 2], tab[idx[0] + 3],
|
||||
tab[idx[1]], tab[idx[1] + 1], tab[idx[1] + 2], tab[idx[1] + 3],
|
||||
tab[idx[2]], tab[idx[2] + 1], tab[idx[2] + 2], tab[idx[2] + 3],
|
||||
tab[idx[3]], tab[idx[3] + 1], tab[idx[3] + 2], tab[idx[3] + 3]);
|
||||
}
|
||||
inline v_uint8x16 v_lut(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut((const schar *)tab, idx)); }
|
||||
inline v_uint8x16 v_lut_pairs(const uchar* tab, const int* idx) { return v_reinterpret_as_u8(v_lut_pairs((const schar *)tab, idx)); }
|
||||
@@ -3100,31 +3086,19 @@ inline v_uint8x16 v_lut_quads(const uchar* tab, const int* idx) { return v_reint
|
||||
|
||||
inline v_int16x8 v_lut(const short* tab, const int* idx)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return v_int16x8(_mm_setr_epi16(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]],
|
||||
tab[idx[4]], tab[idx[5]], tab[idx[6]], tab[idx[7]]));
|
||||
#else
|
||||
return v_int16x8(_mm_setr_epi64(
|
||||
_mm_setr_pi16(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]),
|
||||
_mm_setr_pi16(tab[idx[4]], tab[idx[5]], tab[idx[6]], tab[idx[7]])
|
||||
));
|
||||
#endif
|
||||
return v_int16x8(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]],
|
||||
tab[idx[4]], tab[idx[5]], tab[idx[6]], tab[idx[7]]);
|
||||
}
|
||||
inline v_int16x8 v_lut_pairs(const short* tab, const int* idx)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return v_int16x8(_mm_setr_epi32(*(const int*)(tab + idx[0]), *(const int*)(tab + idx[1]),
|
||||
*(const int*)(tab + idx[2]), *(const int*)(tab + idx[3])));
|
||||
#else
|
||||
return v_int16x8(_mm_setr_epi64(
|
||||
_mm_setr_pi32(*(const int*)(tab + idx[0]), *(const int*)(tab + idx[1])),
|
||||
_mm_setr_pi32(*(const int*)(tab + idx[2]), *(const int*)(tab + idx[3]))
|
||||
));
|
||||
#endif
|
||||
return v_int16x8(tab[idx[0]], tab[idx[0] + 1], tab[idx[1]], tab[idx[1] + 1],
|
||||
tab[idx[2]], tab[idx[2] + 1], tab[idx[3]], tab[idx[3] + 1]);
|
||||
}
|
||||
inline v_int16x8 v_lut_quads(const short* tab, const int* idx)
|
||||
{
|
||||
return v_int16x8(_mm_set_epi64x(*(const int64_t*)(tab + idx[1]), *(const int64_t*)(tab + idx[0])));
|
||||
return v_int16x8(tab[idx[0]], tab[idx[0] + 1], tab[idx[0] + 2],
|
||||
tab[idx[0] + 3], tab[idx[1]], tab[idx[1] + 1],
|
||||
tab[idx[1] + 2], tab[idx[1] + 3]);
|
||||
}
|
||||
inline v_uint16x8 v_lut(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut((const short *)tab, idx)); }
|
||||
inline v_uint16x8 v_lut_pairs(const ushort* tab, const int* idx) { return v_reinterpret_as_u16(v_lut_pairs((const short *)tab, idx)); }
|
||||
@@ -3132,15 +3106,7 @@ inline v_uint16x8 v_lut_quads(const ushort* tab, const int* idx) { return v_rein
|
||||
|
||||
inline v_int32x4 v_lut(const int* tab, const int* idx)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return v_int32x4(_mm_setr_epi32(tab[idx[0]], tab[idx[1]],
|
||||
tab[idx[2]], tab[idx[3]]));
|
||||
#else
|
||||
return v_int32x4(_mm_setr_epi64(
|
||||
_mm_setr_pi32(tab[idx[0]], tab[idx[1]]),
|
||||
_mm_setr_pi32(tab[idx[2]], tab[idx[3]])
|
||||
));
|
||||
#endif
|
||||
return v_int32x4(tab[idx[0]], tab[idx[1]], tab[idx[2]], tab[idx[3]]);
|
||||
}
|
||||
inline v_int32x4 v_lut_pairs(const int* tab, const int* idx)
|
||||
{
|
||||
|
||||
@@ -555,6 +555,7 @@ public:
|
||||
Mat_<uchar> m2({2, 3}, {1, 2, 3, 4, 5, 6}); // 2x3 Mat
|
||||
|
||||
Mat_<double> R({2, 2}, {a, -b, b, a}); // from example
|
||||
\endcode
|
||||
*/
|
||||
template<typename _Tp> class MatCommaInitializer_
|
||||
{
|
||||
|
||||
@@ -2660,7 +2660,7 @@ cvReshapeMatND( const CvArr* arr,
|
||||
mat = &stub;
|
||||
}
|
||||
|
||||
if( CV_IS_MAT_CONT( mat->type ))
|
||||
if( !CV_IS_MAT_CONT( mat->type ))
|
||||
CV_Error( cv::Error::StsBadArg, "Non-continuous nD arrays are not supported" );
|
||||
|
||||
size1 = mat->dim[0].size;
|
||||
|
||||
@@ -107,7 +107,6 @@ void invSqrt32f(const float* src, float* dst, int len)
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CALL_HAL(invSqrt32f, cv_hal_invSqrt32f, src, dst, len);
|
||||
CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_32f_A21, src, dst, len) >= 0);
|
||||
|
||||
CV_CPU_DISPATCH(invSqrt32f, (src, dst, len),
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
@@ -119,7 +118,6 @@ void invSqrt64f(const double* src, double* dst, int len)
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CALL_HAL(invSqrt64f, cv_hal_invSqrt64f, src, dst, len);
|
||||
CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_64f_A50, src, dst, len) >= 0);
|
||||
|
||||
CV_CPU_DISPATCH(invSqrt64f, (src, dst, len),
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
@@ -152,7 +150,6 @@ void exp32f(const float *src, float *dst, int n)
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CALL_HAL(exp32f, cv_hal_exp32f, src, dst, n);
|
||||
CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_32f_A21, src, dst, n) >= 0);
|
||||
|
||||
CV_CPU_DISPATCH(exp32f, (src, dst, n),
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
@@ -163,7 +160,6 @@ void exp64f(const double *src, double *dst, int n)
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CALL_HAL(exp64f, cv_hal_exp64f, src, dst, n);
|
||||
CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_64f_A50, src, dst, n) >= 0);
|
||||
|
||||
CV_CPU_DISPATCH(exp64f, (src, dst, n),
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
@@ -174,7 +170,6 @@ void log32f(const float *src, float *dst, int n)
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CALL_HAL(log32f, cv_hal_log32f, src, dst, n);
|
||||
CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_32f_A21, src, dst, n) >= 0);
|
||||
|
||||
CV_CPU_DISPATCH(log32f, (src, dst, n),
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
@@ -185,7 +180,6 @@ void log64f(const double *src, double *dst, int n)
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CALL_HAL(log64f, cv_hal_log64f, src, dst, n);
|
||||
CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_64f_A50, src, dst, n) >= 0);
|
||||
|
||||
CV_CPU_DISPATCH(log64f, (src, dst, n),
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
|
||||
@@ -595,7 +595,7 @@ void sqrt64f(const double* src, double* dst, int len)
|
||||
// Workaround for ICE in MSVS 2015 update 3 (issue #7795)
|
||||
// CV_AVX is not used here, because generated code is faster in non-AVX mode.
|
||||
// (tested with disabled IPP on i5-6300U)
|
||||
#if (defined _MSC_VER && _MSC_VER >= 1900) || defined(__EMSCRIPTEN__)
|
||||
#if (defined _MSC_VER && _MSC_VER >= 1900 && (defined(_M_IX86) || defined(_M_X64))) || defined(__EMSCRIPTEN__)
|
||||
void exp32f(const float *src, float *dst, int n)
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
@@ -558,7 +558,7 @@ void transposeND(InputArray src_, const std::vector<int>& order, OutputArray dst
|
||||
CV_CheckEQ(static_cast<size_t>(order_[i]), i, "New order should be a valid permutation of the old one");
|
||||
}
|
||||
|
||||
std::vector<int> newShape(order.size());
|
||||
AutoBuffer<int> newShape(order.size());
|
||||
for (size_t i = 0; i < order.size(); ++i)
|
||||
{
|
||||
newShape[i] = inp.size[order[i]];
|
||||
@@ -582,7 +582,7 @@ void transposeND(InputArray src_, const std::vector<int>& order, OutputArray dst
|
||||
size_t continuous_size = continuous_idx == 0 ? out.total() : out.step1(continuous_idx - 1);
|
||||
size_t outer_size = out.total() / continuous_size;
|
||||
|
||||
std::vector<size_t> steps(order.size());
|
||||
AutoBuffer<size_t> steps(order.size());
|
||||
for (int i = 0; i < static_cast<int>(steps.size()); ++i)
|
||||
{
|
||||
steps[i] = inp.step1(order[i]);
|
||||
@@ -1229,7 +1229,7 @@ void broadcast(InputArray _src, InputArray _shape, OutputArray _dst) {
|
||||
// impl
|
||||
_dst.create(dims_shape, shape.ptr<int>(), src.type());
|
||||
Mat dst = _dst.getMat();
|
||||
std::vector<int> is_same_shape(dims_shape, 0);
|
||||
AutoBuffer<int> is_same_shape(dims_shape, 0);
|
||||
for (int i = 0; i < static_cast<int>(shape_src.size()); ++i) {
|
||||
if (shape_src[i] == ptr_shape[i]) {
|
||||
is_same_shape[i] = 1;
|
||||
@@ -1328,7 +1328,7 @@ void broadcast(InputArray _src, InputArray _shape, OutputArray _dst) {
|
||||
std::memcpy(p_dst + dst_offset, p_src + src_offset, dst.elemSize());
|
||||
}
|
||||
// broadcast copy (dst inplace)
|
||||
std::vector<int> cumulative_shape(dims_shape, 1);
|
||||
AutoBuffer<int> cumulative_shape(dims_shape, 1);
|
||||
int total = static_cast<int>(dst.total());
|
||||
for (int i = dims_shape - 1; i >= 0; --i) {
|
||||
cumulative_shape[i] = static_cast<int>(total / ptr_shape[i]);
|
||||
|
||||
@@ -1330,7 +1330,7 @@ static void reduceMinMax(cv::InputArray src, cv::OutputArray dst, ReduceMode mod
|
||||
axis = (axis + srcMat.dims) % srcMat.dims;
|
||||
CV_Assert(srcMat.channels() == 1 && axis >= 0 && axis < srcMat.dims);
|
||||
|
||||
std::vector<int> sizes(srcMat.dims);
|
||||
cv::AutoBuffer<int> sizes(srcMat.dims);
|
||||
std::copy(srcMat.size.p, srcMat.size.p + srcMat.dims, sizes.begin());
|
||||
sizes[axis] = 1;
|
||||
|
||||
|
||||
@@ -1682,27 +1682,12 @@ Context& initializeContextFromGL()
|
||||
|
||||
if(extensionSize > 0)
|
||||
{
|
||||
char* extensions = nullptr;
|
||||
|
||||
try {
|
||||
extensions = new char[extensionSize];
|
||||
|
||||
status = clGetDeviceInfo(devices[j], CL_DEVICE_EXTENSIONS, extensionSize, extensions, &extensionSize);
|
||||
if (status != CL_SUCCESS)
|
||||
continue;
|
||||
} catch(...) {
|
||||
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Exception thrown during device extensions gathering");
|
||||
}
|
||||
|
||||
std::string devString;
|
||||
|
||||
if(extensions != nullptr) {
|
||||
devString = extensions;
|
||||
delete[] extensions;
|
||||
}
|
||||
else {
|
||||
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Unexpected error during device extensions gathering");
|
||||
}
|
||||
std::string devString(extensionSize, '\0');
|
||||
status = clGetDeviceInfo(devices[j], CL_DEVICE_EXTENSIONS, devString.size(), &devString[0], &extensionSize);
|
||||
if (status != CL_SUCCESS)
|
||||
continue;
|
||||
if (extensionSize > 0 && devString.size() >= extensionSize)
|
||||
devString.resize(extensionSize - 1);
|
||||
|
||||
size_t oldPos = 0;
|
||||
size_t spacePos = devString.find(' ', oldPos); // extensions string is space delimited
|
||||
|
||||
@@ -65,15 +65,15 @@ public:
|
||||
/*
|
||||
* a convertor must provide :
|
||||
* - `operator >> (uchar * & dst)` for writing current binary data to `dst` and moving to next data.
|
||||
* - `operator bool` for checking if current loaction is valid and not the end.
|
||||
* - `operator bool` for checking if current location is valid and not the end.
|
||||
*/
|
||||
template<typename _to_binary_convertor_t> inline
|
||||
Base64ContextEmitter & write(_to_binary_convertor_t & convertor)
|
||||
{
|
||||
static const size_t BUFFER_MAX_LEN = 1024U;
|
||||
constexpr size_t BUFFER_MAX_LEN = 1024U;
|
||||
|
||||
std::vector<uchar> buffer(BUFFER_MAX_LEN);
|
||||
uchar * beg = buffer.data();
|
||||
uchar buffer[BUFFER_MAX_LEN];
|
||||
uchar * beg = buffer;
|
||||
uchar * end = beg;
|
||||
|
||||
while (convertor) {
|
||||
|
||||
@@ -75,7 +75,7 @@ void write( FileStorage& fs, const String& name, const SparseMat& m )
|
||||
fs << "data" << "[:";
|
||||
|
||||
size_t i = 0, n = m.nzcount();
|
||||
std::vector<const SparseMat::Node*> elems(n);
|
||||
AutoBuffer<const SparseMat::Node*> elems(n);
|
||||
SparseMatConstIterator it = m.begin(), it_end = m.end();
|
||||
|
||||
for( ; it != it_end; ++it )
|
||||
@@ -142,6 +142,7 @@ void read(const FileNode& node, Mat& m, const Mat& default_mat)
|
||||
CV_Assert( !sizes_node.empty() );
|
||||
|
||||
dims = (int)sizes_node.size();
|
||||
CV_Assert( dims > 0 && dims <= CV_MAX_DIM );
|
||||
sizes_node.readRaw("i", sizes, dims*sizeof(sizes[0]));
|
||||
|
||||
m.create(dims, sizes, elem_type);
|
||||
@@ -180,6 +181,7 @@ void read( const FileNode& node, SparseMat& m, const SparseMat& default_mat )
|
||||
CV_Assert( !sizes_node.empty() );
|
||||
|
||||
int dims = (int)sizes_node.size();
|
||||
CV_Assert( dims > 0 && dims <= CV_MAX_DIM );
|
||||
sizes_node.readRaw("i", sizes, dims*sizeof(sizes[0]));
|
||||
|
||||
m.create(dims, sizes, elem_type);
|
||||
|
||||
@@ -807,6 +807,35 @@ TEST(Core_InputOutput, filestorage_heap_overflow)
|
||||
EXPECT_EQ(0, remove(name.c_str()));
|
||||
}
|
||||
|
||||
TEST(Core_InputOutput, filestorage_nd_matrix_too_many_dims)
|
||||
{
|
||||
// A declared dimension count above CV_MAX_DIM used to write the sizes list
|
||||
// past the fixed-size sizes[CV_MAX_DIM] stack buffer in cv::read().
|
||||
std::string sizes;
|
||||
for (int i = 0; i < CV_MAX_DIM + 8; i++)
|
||||
sizes += "2, ";
|
||||
sizes += "2";
|
||||
|
||||
const std::string content =
|
||||
"%YAML:1.0\n---\n"
|
||||
"m: !!opencv-nd-matrix\n"
|
||||
" sizes: [ " + sizes + " ]\n"
|
||||
" dt: f\n"
|
||||
" data: [ 0., 0. ]\n"
|
||||
"sm: !!opencv-sparse-matrix\n"
|
||||
" sizes: [ " + sizes + " ]\n"
|
||||
" dt: f\n"
|
||||
" data: [ ]\n";
|
||||
|
||||
FileStorage fs(content, FileStorage::READ | FileStorage::MEMORY);
|
||||
|
||||
Mat m;
|
||||
EXPECT_ANY_THROW(fs["m"] >> m);
|
||||
|
||||
SparseMat sm;
|
||||
EXPECT_ANY_THROW(fs["sm"] >> sm);
|
||||
}
|
||||
|
||||
TEST(Core_InputOutput, filestorage_base64_valid_call)
|
||||
{
|
||||
const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info();
|
||||
|
||||
@@ -2626,6 +2626,24 @@ TEST(Mat1D, DISABLED_basic)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Mat, regression_cvReshapeMatND_continuous)
|
||||
{
|
||||
int sizes[] = {2, 3, 4};
|
||||
Mat mat(3, sizes, CV_32SC1);
|
||||
CvMatND src = cvMatND(mat);
|
||||
CvMatND reshaped;
|
||||
int new_sizes[] = {4, 3, 2};
|
||||
CvArr* result = 0;
|
||||
|
||||
ASSERT_NO_THROW(result = cvReshapeMatND(&src, sizeof(reshaped), &reshaped, 0, 3, new_sizes));
|
||||
ASSERT_NE((CvArr*)0, result);
|
||||
EXPECT_EQ(3, reshaped.dims);
|
||||
EXPECT_EQ(new_sizes[0], reshaped.dim[0].size);
|
||||
EXPECT_EQ(new_sizes[1], reshaped.dim[1].size);
|
||||
EXPECT_EQ(new_sizes[2], reshaped.dim[2].size);
|
||||
EXPECT_EQ(src.data.ptr, reshaped.data.ptr);
|
||||
}
|
||||
|
||||
TEST(Mat, ptrVecni_20044)
|
||||
{
|
||||
Mat_<int> m(3,4); m << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12;
|
||||
|
||||
@@ -63,4 +63,343 @@ INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImages,
|
||||
std::vector<int>{16, 2048, 2048})
|
||||
);
|
||||
|
||||
// NCHW, 8U->32F, C3, mean+scale+swapRB at 640x640
|
||||
using Utils_blobFromImage_8U_NCHW = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImage_8U_NCHW, MeanScale_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImage(input, 1.0/255.0, Size(), Scalar(104, 117, 123), true, false, CV_32F);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImage_8U_NCHW,
|
||||
Values(std::vector<int>{ 640, 640})
|
||||
);
|
||||
|
||||
// NHWC, 8U->32F, C3
|
||||
using Utils_blobFromImage_8U_NHWC = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImage_8U_NHWC, SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
|
||||
Image2BlobParams params;
|
||||
params.scalefactor = Scalar::all(1.0);
|
||||
params.swapRB = true;
|
||||
params.datalayout = DNN_LAYOUT_NHWC;
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImageWithParams(input, params);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(Utils_blobFromImage_8U_NHWC, MeanScale_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
|
||||
Image2BlobParams params;
|
||||
params.scalefactor = Scalar::all(1.0/255.0);
|
||||
params.mean = Scalar(104, 117, 123);
|
||||
params.swapRB = true;
|
||||
params.datalayout = DNN_LAYOUT_NHWC;
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImageWithParams(input, params);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImage_8U_NHWC,
|
||||
Values(std::vector<int>{ 224, 224},
|
||||
std::vector<int>{ 640, 640})
|
||||
);
|
||||
|
||||
// NHWC, 32F->32F, C3
|
||||
using Utils_blobFromImage_32F_NHWC = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImage_32F_NHWC, SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_32FC3);
|
||||
randu(input, 0.0f, 1.0f);
|
||||
|
||||
Image2BlobParams params;
|
||||
params.scalefactor = Scalar::all(1.0);
|
||||
params.swapRB = true;
|
||||
params.datalayout = DNN_LAYOUT_NHWC;
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImageWithParams(input, params);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(Utils_blobFromImage_32F_NHWC, MeanScale_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_32FC3);
|
||||
randu(input, 0.0f, 1.0f);
|
||||
|
||||
Image2BlobParams params;
|
||||
params.scalefactor = Scalar::all(1.0/0.226);
|
||||
params.mean = Scalar(0.485, 0.456, 0.406);
|
||||
params.swapRB = true;
|
||||
params.datalayout = DNN_LAYOUT_NHWC;
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImageWithParams(input, params);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImage_32F_NHWC,
|
||||
Values(std::vector<int>{ 224, 224},
|
||||
std::vector<int>{ 640, 640})
|
||||
);
|
||||
|
||||
// Resize+crop, 8U->32F, C3, mean+scale+swapRB to 640x640
|
||||
using Utils_blobFromImage_8U_Resize = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImage_8U_Resize, NHWC_Crop_MeanScale_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
|
||||
Image2BlobParams params;
|
||||
params.scalefactor = Scalar::all(1.0/255.0);
|
||||
params.size = Size(640, 640);
|
||||
params.mean = Scalar(104, 117, 123);
|
||||
params.swapRB = true;
|
||||
params.datalayout = DNN_LAYOUT_NHWC;
|
||||
params.paddingmode = DNN_PMODE_CROP_CENTER;
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImageWithParams(input, params);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(Utils_blobFromImage_8U_Resize, NCHW_Crop_MeanScale_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImage(input, 1.0/255.0, Size(640, 640), Scalar(104, 117, 123), true, true, CV_32F);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImage_8U_Resize,
|
||||
Values(std::vector<int>{ 720, 1280},
|
||||
std::vector<int>{ 1080, 1920},
|
||||
std::vector<int>{ 2160, 3840})
|
||||
);
|
||||
|
||||
// Resize+crop, NCHW, 32F->32F, C3, mean+scale+swapRB to 300x300
|
||||
using Utils_blobFromImage_32F_NCHW_Resize = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImage_32F_NCHW_Resize, Crop_MeanScale_SwapRB_To300) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_32FC3);
|
||||
randu(input, 0.0f, 1.0f);
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImage(input, 1.0/0.226, Size(300, 300), Scalar(0.485, 0.456, 0.406), true, true, CV_32F);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImage_32F_NCHW_Resize,
|
||||
Values(std::vector<int>{ 720, 1280},
|
||||
std::vector<int>{ 1080, 1920})
|
||||
);
|
||||
|
||||
// Resize+crop, NCHW, 8U->8U, C3
|
||||
using Utils_blobFromImage_8U_to_8U_Crop = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImage_8U_to_8U_Crop, NCHW_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImage(input, 1.0, Size(640, 640), Scalar(), true, true, CV_8U);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(Utils_blobFromImage_8U_to_8U_Crop, NCHW) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImage(input, 1.0, Size(640, 640), Scalar(), false, true, CV_8U);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImage_8U_to_8U_Crop,
|
||||
Values(std::vector<int>{ 1080, 1920},
|
||||
std::vector<int>{ 2160, 3840})
|
||||
);
|
||||
|
||||
// Resize, NCHW, 8U->8U, C3
|
||||
using Utils_blobFromImage_8U_to_8U_Resize = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImage_8U_to_8U_Resize, NCHW_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImage(input, 1.0, Size(640, 640), Scalar(), true, false, CV_8U);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImage_8U_to_8U_Resize,
|
||||
Values(std::vector<int>{ 1080, 1920},
|
||||
std::vector<int>{ 2160, 3840})
|
||||
);
|
||||
|
||||
// Resize+crop, NCHW, 32F->32F, C1, mean
|
||||
using Utils_blobFromImage_32F_NCHW_C1 = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImage_32F_NCHW_C1, Crop_MeanScale_To224) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_32FC1);
|
||||
randu(input, 0.0f, 1.0f);
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImage(input, 1.0/0.226, Size(224, 224), Scalar(0.5), false, true, CV_32F);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(Utils_blobFromImage_32F_NCHW_C1, Crop_MeanScale_To640) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
|
||||
Mat input(input_shape, CV_32FC1);
|
||||
randu(input, 0.0f, 1.0f);
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImage(input, 1.0/0.226, Size(640, 640), Scalar(0.5), false, true, CV_32F);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImage_32F_NCHW_C1,
|
||||
Values(std::vector<int>{ 1080, 1920},
|
||||
std::vector<int>{ 2160, 3840})
|
||||
);
|
||||
|
||||
// Batch=8, NHWC, 8U->32F, C3, mean+scale+swapRB
|
||||
using Utils_blobFromImages_NoResize = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImages_NoResize, NHWC_MeanScale_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
int batch = input_shape.front();
|
||||
std::vector<int> input_shape_no_batch(input_shape.begin()+1, input_shape.end());
|
||||
|
||||
std::vector<Mat> inputs;
|
||||
for (int i = 0; i < batch; i++) {
|
||||
Mat input(input_shape_no_batch, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
inputs.push_back(input);
|
||||
}
|
||||
|
||||
Image2BlobParams params;
|
||||
params.scalefactor = Scalar::all(1.0/255.0);
|
||||
params.mean = Scalar(104, 117, 123);
|
||||
params.swapRB = true;
|
||||
params.datalayout = DNN_LAYOUT_NHWC;
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImagesWithParams(inputs, params);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImages_NoResize,
|
||||
Values(std::vector<int>{8, 640, 640})
|
||||
);
|
||||
|
||||
// Batch=8, resize+crop to 640x640, 8U->32F, C3, mean+scale+swapRB
|
||||
using Utils_blobFromImages_Resize = TestBaseWithParam<std::vector<int>>;
|
||||
PERF_TEST_P_(Utils_blobFromImages_Resize, NHWC_Crop_MeanScale_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
int batch = input_shape.front();
|
||||
std::vector<int> input_shape_no_batch(input_shape.begin()+1, input_shape.end());
|
||||
|
||||
std::vector<Mat> inputs;
|
||||
for (int i = 0; i < batch; i++) {
|
||||
Mat input(input_shape_no_batch, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
inputs.push_back(input);
|
||||
}
|
||||
|
||||
Image2BlobParams params;
|
||||
params.scalefactor = Scalar::all(1.0/255.0);
|
||||
params.size = Size(640, 640);
|
||||
params.mean = Scalar(104, 117, 123);
|
||||
params.swapRB = true;
|
||||
params.datalayout = DNN_LAYOUT_NHWC;
|
||||
params.paddingmode = DNN_PMODE_CROP_CENTER;
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImagesWithParams(inputs, params);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(Utils_blobFromImages_Resize, NCHW_Crop_MeanScale_SwapRB) {
|
||||
std::vector<int> input_shape = GetParam();
|
||||
int batch = input_shape.front();
|
||||
std::vector<int> input_shape_no_batch(input_shape.begin()+1, input_shape.end());
|
||||
|
||||
std::vector<Mat> inputs;
|
||||
for (int i = 0; i < batch; i++) {
|
||||
Mat input(input_shape_no_batch, CV_8UC3);
|
||||
randu(input, 0, 255);
|
||||
inputs.push_back(input);
|
||||
}
|
||||
|
||||
TEST_CYCLE() {
|
||||
Mat blob = blobFromImages(inputs, 1.0/255.0, Size(640, 640), Scalar(104, 117, 123), true, true, CV_32F);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Utils_blobFromImages_Resize,
|
||||
Values(std::vector<int>{8, 720, 1280},
|
||||
std::vector<int>{8, 1080, 1920})
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -534,8 +534,10 @@ namespace cv {
|
||||
std::vector<float> usedAnchors(numAnchors * 2);
|
||||
for (int i = 0; i < numAnchors; ++i)
|
||||
{
|
||||
usedAnchors[i * 2] = anchors[mask[i] * 2];
|
||||
usedAnchors[i * 2 + 1] = anchors[mask[i] * 2 + 1];
|
||||
const int m = mask[i];
|
||||
CV_Assert(m >= 0 && static_cast<size_t>(m) * 2 + 1 < anchors.size());
|
||||
usedAnchors[i * 2] = anchors[m * 2];
|
||||
usedAnchors[i * 2 + 1] = anchors[m * 2 + 1];
|
||||
}
|
||||
|
||||
cv::Mat biasData_mat = cv::Mat(1, numAnchors * 2, CV_32F, &usedAnchors[0]).clone();
|
||||
@@ -835,6 +837,7 @@ namespace cv {
|
||||
tensor_shape[0] = 0;
|
||||
for (size_t k = 0; k < layers_vec.size(); ++k) {
|
||||
layers_vec[k] = layers_vec[k] >= 0 ? layers_vec[k] : (layers_vec[k] + layers_counter);
|
||||
CV_Assert(layers_vec[k] >= 0 && static_cast<size_t>(layers_vec[k]) < net->out_channels_vec.size());
|
||||
tensor_shape[0] += net->out_channels_vec[layers_vec[k]];
|
||||
}
|
||||
|
||||
|
||||
@@ -255,6 +255,10 @@ struct TorchImporter
|
||||
void readTorchStorage(int index, int type = -1)
|
||||
{
|
||||
long size = readLong();
|
||||
// size is read as a 64-bit value but Mat::create() takes int columns, so a
|
||||
// value above INT_MAX is truncated for the allocation while the THFile_read*Raw
|
||||
// calls below still consume the full 64-bit count, overflowing the buffer.
|
||||
CV_Assert(size >= 0 && size <= INT_MAX);
|
||||
Mat storageMat;
|
||||
|
||||
switch (type)
|
||||
|
||||
@@ -8052,6 +8052,9 @@ void AGAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, boo
|
||||
case AgastFeatureDetector::OAST_9_16:
|
||||
OAST_9_16(_img, kpts, threshold);
|
||||
break;
|
||||
default:
|
||||
CV_Error_(Error::StsBadArg,
|
||||
("Unknown AgastFeatureDetector detector type: %d", static_cast<int>(type)));
|
||||
}
|
||||
|
||||
cv::Mat img = _img.getMat();
|
||||
|
||||
@@ -332,11 +332,13 @@ void SimpleBlobDetectorImpl::findBlobs(InputArray _image, InputArray _binaryImag
|
||||
|
||||
//compute blob radius
|
||||
{
|
||||
std::vector<double> dists;
|
||||
for (size_t pointIdx = 0; pointIdx < contours[contourIdx].size(); pointIdx++)
|
||||
const std::vector<cv::Point>& contour = contours[contourIdx];
|
||||
const size_t contourSize = contour.size();
|
||||
AutoBuffer<double> dists(contourSize);
|
||||
for (size_t pointIdx = 0; pointIdx < contourSize; pointIdx++)
|
||||
{
|
||||
Point2d pt = contours[contourIdx][pointIdx];
|
||||
dists.push_back(norm(center.location - pt));
|
||||
const Point2d& pt = contour[pointIdx];
|
||||
dists[pointIdx] = norm(center.location - pt);
|
||||
}
|
||||
std::sort(dists.begin(), dists.end());
|
||||
center.radius = (dists[(dists.size() - 1) / 2] + dists[dists.size() / 2]) / 2.;
|
||||
|
||||
@@ -104,6 +104,8 @@ public:
|
||||
}
|
||||
virtual void setPatternScale(float _patternScale) CV_OVERRIDE
|
||||
{
|
||||
CV_CheckGT(_patternScale, 0.f, "patternScale must be positive");
|
||||
|
||||
patternScale = _patternScale;
|
||||
std::vector<float> rList;
|
||||
std::vector<int> nList;
|
||||
@@ -2034,8 +2036,8 @@ BriskScaleSpace::subpixel2D(const int s_0_0, const int s_0_1, const int s_0_2, c
|
||||
int tmp4 = tmp3 - 2 * tmp2;
|
||||
int coeff3 = -3 * (tmp3 + s_0_1 - s_2_1);
|
||||
int coeff4 = -3 * (tmp4 + s_1_0 - s_1_2);
|
||||
int coeff5 = (s_0_0 - s_0_2 - s_2_0 + s_2_2) << 2;
|
||||
int coeff6 = -(s_0_0 + s_0_2 - ((s_1_0 + s_0_1 + s_1_2 + s_2_1) << 1) - 5 * s_1_1 + s_2_0 + s_2_2) << 1;
|
||||
int coeff5 = (s_0_0 - s_0_2 - s_2_0 + s_2_2) * 4;
|
||||
int coeff6 = -(s_0_0 + s_0_2 - ((s_1_0 + s_0_1 + s_1_2 + s_2_1) * 2) - 5 * s_1_1 + s_2_0 + s_2_2) * 2;
|
||||
|
||||
// 2nd derivative test:
|
||||
int H_det = 4 * coeff1 * coeff2 - coeff5 * coeff5;
|
||||
|
||||
@@ -441,6 +441,14 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
if (type != FastFeatureDetector::TYPE_5_8 &&
|
||||
type != FastFeatureDetector::TYPE_7_12 &&
|
||||
type != FastFeatureDetector::TYPE_9_16)
|
||||
{
|
||||
CV_Error_(Error::StsBadArg,
|
||||
("Unknown FastFeatureDetector detector type: %d", static_cast<int>(type)));
|
||||
}
|
||||
|
||||
const size_t max_fast_features = std::max(_img.total()/100, size_t(1000)); // Simple heuristic that depends on resolution.
|
||||
|
||||
CV_OCL_RUN(_img.isUMat() && type == FastFeatureDetector::TYPE_9_16,
|
||||
@@ -549,7 +557,7 @@ public:
|
||||
else if(prop == FAST_N)
|
||||
type = static_cast<FastFeatureDetector::DetectorType>(cvRound(value));
|
||||
else
|
||||
CV_Error(Error::StsBadArg, "");
|
||||
CV_Error_(Error::StsBadArg, ("Unknown FastFeatureDetector property: %d", prop));
|
||||
}
|
||||
|
||||
double get(int prop) const
|
||||
@@ -560,7 +568,7 @@ public:
|
||||
return nonmaxSuppression;
|
||||
if(prop == FAST_N)
|
||||
return static_cast<int>(type);
|
||||
CV_Error(Error::StsBadArg, "");
|
||||
CV_Error_(Error::StsBadArg, ("Unknown FastFeatureDetector property: %d", prop));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -221,8 +221,8 @@ struct KeyPoint_LessThan
|
||||
void KeyPointsFilter::removeDuplicated( std::vector<KeyPoint>& keypoints )
|
||||
{
|
||||
int i, j, n = (int)keypoints.size();
|
||||
std::vector<int> kpidx(n);
|
||||
std::vector<uchar> mask(n, (uchar)1);
|
||||
AutoBuffer<int> kpidx(n);
|
||||
AutoBuffer<uchar> mask(n, (uchar)1);
|
||||
|
||||
for( i = 0; i < n; i++ )
|
||||
kpidx[i] = i;
|
||||
|
||||
@@ -839,7 +839,7 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
#endif
|
||||
|
||||
int i, nkeypoints, level, nlevels = (int)layerInfo.size();
|
||||
std::vector<int> nfeaturesPerLevel(nlevels);
|
||||
AutoBuffer<int> nfeaturesPerLevel(nlevels);
|
||||
|
||||
// fill the extractors and descriptors for the corresponding scales
|
||||
float factor = (float)(1.0 / scaleFactor);
|
||||
@@ -877,7 +877,7 @@ static void computeKeyPoints(const Mat& imagePyramid,
|
||||
|
||||
allKeypoints.clear();
|
||||
std::vector<KeyPoint> keypoints;
|
||||
std::vector<int> counters(nlevels);
|
||||
AutoBuffer<int> counters(nlevels);
|
||||
keypoints.reserve(nfeaturesPerLevel[0]*2);
|
||||
|
||||
for( level = 0; level < nlevels; level++ )
|
||||
@@ -1266,7 +1266,25 @@ void ORB_Impl::detectAndCompute( InputArray _image, InputArray _mask,
|
||||
Ptr<ORB> ORB::create(int nfeatures, float scaleFactor, int nlevels, int edgeThreshold,
|
||||
int firstLevel, int wta_k, ORB::ScoreType scoreType, int patchSize, int fastThreshold)
|
||||
{
|
||||
CV_Assert(firstLevel >= 0);
|
||||
CV_CheckGE(nfeatures, 0, "nfeatures must be non-negative");
|
||||
CV_CheckGT(scaleFactor, 1.f, "scaleFactor must be greater than 1");
|
||||
CV_CheckGT(nlevels, 0, "nlevels must be positive");
|
||||
CV_CheckGE(edgeThreshold, 0, "edgeThreshold must be non-negative");
|
||||
CV_CheckGE(firstLevel, 0, "firstLevel must be non-negative");
|
||||
CV_CheckGE(patchSize, 2, "patchSize must be at least 2");
|
||||
|
||||
if (wta_k != 2 && wta_k != 3 && wta_k != 4)
|
||||
{
|
||||
CV_Error_(Error::StsBadArg,
|
||||
("wta_k must be 2, 3, or 4, but got %d", wta_k));
|
||||
}
|
||||
|
||||
if (scoreType != ORB::HARRIS_SCORE && scoreType != ORB::FAST_SCORE)
|
||||
{
|
||||
CV_Error_(Error::StsBadArg,
|
||||
("Unknown ORB score type: %d", static_cast<int>(scoreType)));
|
||||
}
|
||||
|
||||
return makePtr<ORB_Impl>(nfeatures, scaleFactor, nlevels, edgeThreshold,
|
||||
firstLevel, wta_k, scoreType, patchSize, fastThreshold);
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ void SIFT_Impl::buildGaussianPyramid( const Mat& base, std::vector<Mat>& pyr, in
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
std::vector<double> sig(nOctaveLayers + 3);
|
||||
AutoBuffer<double> sig(nOctaveLayers + 3);
|
||||
pyr.resize(nOctaves*(nOctaveLayers + 3));
|
||||
|
||||
// precompute Gaussian sigmas using the following formula:
|
||||
|
||||
@@ -135,4 +135,14 @@ void CV_AgastTest::run( int )
|
||||
|
||||
TEST(Features2d_AGAST, regression) { CV_AgastTest test; test.safe_run(); }
|
||||
|
||||
TEST(Features2d_AGAST, invalidDetectorType)
|
||||
{
|
||||
Mat img = Mat::zeros(16, 16, CV_8UC1);
|
||||
vector<KeyPoint> keypoints;
|
||||
|
||||
EXPECT_THROW(AGAST(img, keypoints, 10, true,
|
||||
static_cast<AgastFeatureDetector::DetectorType>(-1)),
|
||||
cv::Exception);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -105,4 +105,10 @@ void CV_BRISKTest::run( int )
|
||||
|
||||
TEST(Features2d_BRISK, regression) { CV_BRISKTest test; test.safe_run(); }
|
||||
|
||||
TEST(Features2d_BRISK, invalidCreateParameters)
|
||||
{
|
||||
EXPECT_THROW(BRISK::create(30, 3, 0.0f), cv::Exception);
|
||||
EXPECT_THROW(BRISK::create(30, 3, -1.0f), cv::Exception);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -165,4 +165,14 @@ TEST(Features2d_FAST, noNMS)
|
||||
ASSERT_EQ( 0, cvtest::norm(gt_kps, kps, NORM_L2));
|
||||
}
|
||||
|
||||
TEST(Features2d_FAST, invalidDetectorType)
|
||||
{
|
||||
Mat img = Mat::zeros(16, 16, CV_8UC1);
|
||||
vector<KeyPoint> keypoints;
|
||||
|
||||
EXPECT_THROW(FAST(img, keypoints, 10, true,
|
||||
static_cast<FastFeatureDetector::DetectorType>(-1)),
|
||||
cv::Exception);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -195,4 +195,15 @@ TEST(Features2D_ORB, MaskValue)
|
||||
ASSERT_EQ(countNonZero(diff), 0);
|
||||
}
|
||||
|
||||
TEST(Features2D_ORB, invalidCreateParameters)
|
||||
{
|
||||
EXPECT_THROW(ORB::create(500, 1.0f), cv::Exception);
|
||||
EXPECT_THROW(ORB::create(500, 1.2f, 0), cv::Exception);
|
||||
EXPECT_THROW(ORB::create(500, 1.2f, 8, 31, 0, 5), cv::Exception);
|
||||
EXPECT_THROW(ORB::create(500, 1.2f, 8, 31, 0, 2,
|
||||
static_cast<ORB::ScoreType>(-1)), cv::Exception);
|
||||
EXPECT_THROW(ORB::create(500, 1.2f, 8, 31, 0, 2,
|
||||
ORB::HARRIS_SCORE, 1), cv::Exception);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -47,8 +47,8 @@ void find_nearest(const Matrix<typename Distance::ElementType>& dataset, typenam
|
||||
typedef typename Distance::ResultType DistanceType;
|
||||
int n = nn + skip;
|
||||
|
||||
std::vector<int> match(n);
|
||||
std::vector<DistanceType> dists(n);
|
||||
cv::AutoBuffer<int> match(n);
|
||||
cv::AutoBuffer<DistanceType> dists(n);
|
||||
|
||||
dists[0] = distance(dataset[0], query, dataset.cols);
|
||||
match[0] = 0;
|
||||
|
||||
@@ -686,8 +686,8 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<int> centers(branching);
|
||||
std::vector<int> labels(indices_length);
|
||||
cv::AutoBuffer<int> centers(branching);
|
||||
cv::AutoBuffer<int> labels(indices_length);
|
||||
|
||||
int centers_length;
|
||||
(this->*chooseCenters)(branching, dsindices, indices_length, ¢ers[0], centers_length);
|
||||
|
||||
@@ -99,8 +99,8 @@ float search_with_ground_truth(NNIndex<Distance>& index, const Matrix<typename D
|
||||
KNNResultSet<DistanceType> resultSet(nn+skipMatches);
|
||||
SearchParams searchParams(checks);
|
||||
|
||||
std::vector<int> indices(nn+skipMatches);
|
||||
std::vector<DistanceType> dists(nn+skipMatches);
|
||||
cv::AutoBuffer<int> indices(nn+skipMatches);
|
||||
cv::AutoBuffer<DistanceType> dists(nn+skipMatches);
|
||||
int* neighbors = &indices[skipMatches];
|
||||
|
||||
int correct = 0;
|
||||
|
||||
@@ -490,7 +490,7 @@ inline LshStats LshTable<unsigned char>::getStats() const
|
||||
!= end; )
|
||||
if (*iterator < bin_end) {
|
||||
if (is_new_bin) {
|
||||
stats.size_histogram_.push_back(std::vector<unsigned int>(3, 0));
|
||||
stats.size_histogram_.emplace_back(3, 0);
|
||||
stats.size_histogram_.back()[0] = bin_start;
|
||||
stats.size_histogram_.back()[1] = bin_end - 1;
|
||||
is_new_bin = false;
|
||||
|
||||
@@ -160,6 +160,12 @@ bool ExifReader::processRawProfile(const char* profile, size_t profile_len) {
|
||||
}
|
||||
++end;
|
||||
|
||||
// the payload starts with a 6-byte "Exif\0\0" header, so a shorter declared
|
||||
// length underflows the size and pointer handed to parseExif() below
|
||||
if (expected_length < 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 'end' now points to the profile payload.
|
||||
std::string payload = HexStringToBytes(end, expected_length);
|
||||
if (payload.size() == 0) return false;
|
||||
|
||||
@@ -175,28 +175,28 @@ rgb_convert (void *src, void *target, int width, int target_channels, int target
|
||||
*/
|
||||
|
||||
static void
|
||||
basic_conversion (void *src, const struct channel_layout *layout, int src_sampe_size,
|
||||
basic_conversion (void *src, const struct channel_layout *layout, int src_sample_size,
|
||||
int src_width, void *target, int target_channels, int target_depth, bool use_rgb)
|
||||
{
|
||||
switch (target_depth) {
|
||||
case CV_8U:
|
||||
{
|
||||
uchar *d = (uchar *)target, *s = (uchar *)src,
|
||||
*end = ((uchar *)src) + src_width;
|
||||
*end = ((uchar *)src) + src_width * src_sample_size;
|
||||
switch (target_channels) {
|
||||
case 1:
|
||||
for( ; s < end; d += 3, s += src_sampe_size )
|
||||
d[0] = d[1] = d[2] = s[layout->graychan];
|
||||
for( ; s < end; d += 1, s += src_sample_size )
|
||||
d[0] = s[layout->graychan];
|
||||
break;
|
||||
case 3:
|
||||
if (use_rgb)
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
for( ; s < end; d += 3, s += src_sample_size ) {
|
||||
d[0] = s[layout->rchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->bchan];
|
||||
}
|
||||
else
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
for( ; s < end; d += 3, s += src_sample_size ) {
|
||||
d[0] = s[layout->bchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->rchan];
|
||||
@@ -210,21 +210,21 @@ basic_conversion (void *src, const struct channel_layout *layout, int src_sampe_
|
||||
case CV_16U:
|
||||
{
|
||||
ushort *d = (ushort *)target, *s = (ushort *)src,
|
||||
*end = ((ushort *)src) + src_width;
|
||||
*end = ((ushort *)src) + src_width * src_sample_size;
|
||||
switch (target_channels) {
|
||||
case 1:
|
||||
for( ; s < end; d += 3, s += src_sampe_size )
|
||||
d[0] = d[1] = d[2] = s[layout->graychan];
|
||||
for( ; s < end; d += 1, s += src_sample_size )
|
||||
d[0] = s[layout->graychan];
|
||||
break;
|
||||
case 3:
|
||||
if (use_rgb)
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
for( ; s < end; d += 3, s += src_sample_size ) {
|
||||
d[0] = s[layout->rchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->bchan];
|
||||
}
|
||||
else
|
||||
for( ; s < end; d += 3, s += src_sampe_size ) {
|
||||
for( ; s < end; d += 3, s += src_sample_size ) {
|
||||
d[0] = s[layout->bchan];
|
||||
d[1] = s[layout->gchan];
|
||||
d[2] = s[layout->rchan];
|
||||
|
||||
@@ -564,6 +564,37 @@ TEST(Imgcodecs_Pam, read_write)
|
||||
remove(writefile.c_str());
|
||||
remove(writefile_no_param.c_str());
|
||||
}
|
||||
|
||||
// Regression test: a 2-channel (GRAYSCALE_ALPHA) PAM decoded as single channel
|
||||
// used to overflow the output row in basic_conversion() (3 bytes written per
|
||||
// source pixel into a 1-channel row). Verify it decodes safely and correctly.
|
||||
TEST(Imgcodecs_Pam, decode_graya_as_gray)
|
||||
{
|
||||
const int width = 9, height = 3; // odd width to expose off-by-row overflow
|
||||
std::string header = cv::format(
|
||||
"P7\nWIDTH %d\nHEIGHT %d\nDEPTH 2\nMAXVAL 255\n"
|
||||
"TUPLTYPE GRAYSCALE_ALPHA\nENDHDR\n", width, height);
|
||||
|
||||
std::vector<uchar> buf(header.begin(), header.end());
|
||||
Mat gray_ref(height, width, CV_8UC1);
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
uchar gray = (uchar)((y * width + x) * 7 + 1);
|
||||
uchar alpha = (uchar)(255 - gray);
|
||||
gray_ref.at<uchar>(y, x) = gray;
|
||||
buf.push_back(gray); // channel 0: gray
|
||||
buf.push_back(alpha); // channel 1: alpha (must be ignored)
|
||||
}
|
||||
|
||||
Mat decoded;
|
||||
ASSERT_NO_THROW(decoded = imdecode(buf, IMREAD_GRAYSCALE));
|
||||
ASSERT_FALSE(decoded.empty());
|
||||
EXPECT_EQ(width, decoded.cols);
|
||||
EXPECT_EQ(height, decoded.rows);
|
||||
EXPECT_EQ(1, decoded.channels());
|
||||
EXPECT_EQ(0, cvtest::norm(gray_ref, decoded, NORM_INF));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PFM
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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"
|
||||
#include <cmath>
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef tuple<int, int> EMD_Size_Dim_t;
|
||||
typedef perf::TestBaseWithParam<EMD_Size_Dim_t> EMD_Fixture;
|
||||
|
||||
PERF_TEST_P(EMD_Fixture, L1_Distance, testing::Combine(
|
||||
testing::Values(100, 500, 1000),
|
||||
testing::Values(3, 64)
|
||||
))
|
||||
{
|
||||
int size = get<0>(GetParam());
|
||||
int dims = get<1>(GetParam());
|
||||
|
||||
Mat sign1(size, dims + 1, CV_32FC1);
|
||||
Mat sign2(size, dims + 1, CV_32FC1);
|
||||
|
||||
theRNG().fill(sign1, RNG::UNIFORM, 0.1, 1.0);
|
||||
theRNG().fill(sign2, RNG::UNIFORM, 0.1, 1.0);
|
||||
|
||||
declare.in(sign1, sign2);
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
cv::EMD(sign1, sign2, cv::DIST_L1);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -98,8 +98,8 @@ static bool ocl_bilateralFilter_8u(InputArray _src, OutputArray _dst, int d,
|
||||
return false;
|
||||
|
||||
copyMakeBorder(src, temp, radius, radius, radius, radius, borderType);
|
||||
std::vector<float> _space_weight(d * d);
|
||||
std::vector<int> _space_ofs(d * d);
|
||||
AutoBuffer<float> _space_weight(d * d);
|
||||
AutoBuffer<int> _space_ofs(d * d);
|
||||
float * const space_weight = &_space_weight[0];
|
||||
int * const space_ofs = &_space_ofs[0];
|
||||
|
||||
@@ -188,9 +188,9 @@ bilateralFilter_8u( const Mat& src, Mat& dst, int d,
|
||||
Mat temp;
|
||||
copyMakeBorder( src, temp, radius, radius, radius, radius, borderType );
|
||||
|
||||
std::vector<float> _color_weight(cn*256);
|
||||
std::vector<float> _space_weight(d*d);
|
||||
std::vector<int> _space_ofs(d*d);
|
||||
AutoBuffer<float> _color_weight(cn*256);
|
||||
AutoBuffer<float> _space_weight(d*d);
|
||||
AutoBuffer<int> _space_ofs(d*d);
|
||||
float* color_weight = &_color_weight[0];
|
||||
float* space_weight = &_space_weight[0];
|
||||
int* space_ofs = &_space_ofs[0];
|
||||
@@ -283,15 +283,15 @@ bilateralFilter_32f( const Mat& src, Mat& dst, int d,
|
||||
copyMakeBorder( src, temp, radius, radius, radius, radius, borderType );
|
||||
|
||||
// allocate lookup tables
|
||||
std::vector<float> _space_weight(d*d);
|
||||
std::vector<int> _space_ofs(d*d);
|
||||
AutoBuffer<float> _space_weight(d*d);
|
||||
AutoBuffer<int> _space_ofs(d*d);
|
||||
float* space_weight = &_space_weight[0];
|
||||
int* space_ofs = &_space_ofs[0];
|
||||
|
||||
// assign a length which is slightly more than needed
|
||||
len = (float)(maxValSrc - minValSrc) * cn;
|
||||
kExpNumBins = kExpNumBinsPerChannel * cn;
|
||||
std::vector<float> _expLUT(kExpNumBins+2);
|
||||
AutoBuffer<float> _expLUT(kExpNumBins+2);
|
||||
float* expLUT = &_expLUT[0];
|
||||
|
||||
scale_index = kExpNumBins/len;
|
||||
|
||||
@@ -1160,20 +1160,23 @@ static LABLUVLUT_s16_t initLUTforLABLUVs16(const softfloat & un, const softfloat
|
||||
|
||||
AutoBuffer<int16_t> RGB2Labprev(LAB_LUT_DIM*LAB_LUT_DIM*LAB_LUT_DIM*3);
|
||||
AutoBuffer<int16_t> RGB2Luvprev(LAB_LUT_DIM*LAB_LUT_DIM*LAB_LUT_DIM*3);
|
||||
for(int p = 0; p < LAB_LUT_DIM; p++)
|
||||
|
||||
softfloat gammaTab[LAB_LUT_DIM];
|
||||
for(int n = 0; n < LAB_LUT_DIM; n++)
|
||||
gammaTab[n] = applyGamma(softfloat(n)/lld);
|
||||
|
||||
cv::parallel_for_(cv::Range(0, LAB_LUT_DIM), [&](const cv::Range& prange)
|
||||
{
|
||||
for(int p = prange.start; p < prange.end; p++)
|
||||
{
|
||||
for(int q = 0; q < LAB_LUT_DIM; q++)
|
||||
{
|
||||
for(int r = 0; r < LAB_LUT_DIM; r++)
|
||||
{
|
||||
int idx = p*3 + q*LAB_LUT_DIM*3 + r*LAB_LUT_DIM*LAB_LUT_DIM*3;
|
||||
softfloat R = softfloat(p)/lld;
|
||||
softfloat G = softfloat(q)/lld;
|
||||
softfloat B = softfloat(r)/lld;
|
||||
|
||||
R = applyGamma(R);
|
||||
G = applyGamma(G);
|
||||
B = applyGamma(B);
|
||||
softfloat R = gammaTab[p];
|
||||
softfloat G = gammaTab[q];
|
||||
softfloat B = gammaTab[r];
|
||||
|
||||
//RGB 2 Lab LUT building
|
||||
{
|
||||
@@ -1214,6 +1217,7 @@ static LABLUVLUT_s16_t initLUTforLABLUVs16(const softfloat & un, const softfloat
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
int16_t *RGB2LabLUT_s16 = cv::allocSingleton<int16_t>(LAB_LUT_DIM*LAB_LUT_DIM*LAB_LUT_DIM*3*8);
|
||||
int16_t *RGB2LuvLUT_s16 = cv::allocSingleton<int16_t>(LAB_LUT_DIM*LAB_LUT_DIM*LAB_LUT_DIM*3*8);
|
||||
|
||||
@@ -1153,10 +1153,10 @@ namespace cv{
|
||||
//Array used to store info and labeled pixel by each thread.
|
||||
//Different threads affect different memory location of chunksSizeAndLabels
|
||||
const int chunksSizeAndLabelsSize = roundUp(h, 2);
|
||||
std::vector<int> chunksSizeAndLabels(chunksSizeAndLabelsSize);
|
||||
AutoBuffer<int> chunksSizeAndLabels(chunksSizeAndLabelsSize);
|
||||
|
||||
//Tree of labels
|
||||
std::vector<LabelT> P(Plength, 0);
|
||||
AutoBuffer<LabelT> P(Plength, 0);
|
||||
//First label is for background
|
||||
//P[0] = 0;
|
||||
|
||||
@@ -1176,7 +1176,7 @@ namespace cv{
|
||||
}
|
||||
|
||||
//Array for statistics data
|
||||
std::vector<StatsOp> sopArray(h);
|
||||
AutoBuffer<StatsOp> sopArray(h);
|
||||
sop.init(nLabels);
|
||||
|
||||
//Second scan
|
||||
@@ -1218,7 +1218,7 @@ namespace cv{
|
||||
// ............
|
||||
const size_t Plength = size_t(((h + 1) / 2) * size_t((w + 1) / 2)) + 1;
|
||||
|
||||
std::vector<LabelT> P_(Plength, 0);
|
||||
AutoBuffer<LabelT> P_(Plength, 0);
|
||||
LabelT *P = P_.data();
|
||||
//P[0] = 0;
|
||||
LabelT lunique = 1;
|
||||
@@ -1782,10 +1782,10 @@ namespace cv{
|
||||
|
||||
//Array used to store info and labeled pixel by each thread.
|
||||
//Different threads affect different memory location of chunksSizeAndLabels
|
||||
std::vector<int> chunksSizeAndLabels(roundUp(h, 2));
|
||||
AutoBuffer<int> chunksSizeAndLabels(roundUp(h, 2));
|
||||
|
||||
//Tree of labels
|
||||
std::vector<LabelT> P_(Plength, 0);
|
||||
AutoBuffer<LabelT> P_(Plength, 0);
|
||||
LabelT* P = P_.data();
|
||||
//First label is for background
|
||||
//P[0] = 0;
|
||||
@@ -1806,7 +1806,7 @@ namespace cv{
|
||||
}
|
||||
|
||||
//Array for statistics dataof threads
|
||||
std::vector<StatsOp> sopArray(h);
|
||||
AutoBuffer<StatsOp> sopArray(h);
|
||||
|
||||
sop.init(nLabels);
|
||||
//Second scan
|
||||
@@ -1842,7 +1842,7 @@ namespace cv{
|
||||
// ............
|
||||
const size_t Plength = size_t((size_t(h) * size_t(w) + 1) / 2) + 1;
|
||||
|
||||
std::vector<LabelT> P_(Plength, 0);
|
||||
AutoBuffer<LabelT> P_(Plength, 0);
|
||||
LabelT* P = P_.data();
|
||||
P[0] = 0;
|
||||
LabelT lunique = 1;
|
||||
@@ -2315,10 +2315,10 @@ namespace cv{
|
||||
|
||||
//Array used to store info and labeled pixel by each thread.
|
||||
//Different threads affect different memory location of chunksSizeAndLabels
|
||||
std::vector<int> chunksSizeAndLabels(roundUp(h, 2));
|
||||
AutoBuffer<int> chunksSizeAndLabels(roundUp(h, 2));
|
||||
|
||||
//Tree of labels
|
||||
std::vector<LabelT> P_(Plength, 0);
|
||||
AutoBuffer<LabelT> P_(Plength, 0);
|
||||
LabelT *P = P_.data();
|
||||
//First label is for background
|
||||
//P[0] = 0;
|
||||
@@ -2352,7 +2352,7 @@ namespace cv{
|
||||
}
|
||||
|
||||
//Array for statistics dataof threads
|
||||
std::vector<StatsOp> sopArray(h);
|
||||
AutoBuffer<StatsOp> sopArray(h);
|
||||
|
||||
sop.init(nLabels);
|
||||
//Second scan
|
||||
@@ -2387,7 +2387,7 @@ namespace cv{
|
||||
//Obviously, 4-way connectivity upper bound is also good for 8-way connectivity labeling
|
||||
const size_t Plength = (size_t(h) * size_t(w) + 1) / 2 + 1;
|
||||
//array P for equivalences resolution
|
||||
std::vector<LabelT> P_(Plength, 0);
|
||||
AutoBuffer<LabelT> P_(Plength, 0);
|
||||
LabelT *P = P_.data();
|
||||
//first label is for background pixels
|
||||
//P[0] = 0;
|
||||
@@ -4265,10 +4265,10 @@ namespace cv{
|
||||
//Array used to store info and labeled pixel by each thread.
|
||||
//Different threads affect different memory location of chunksSizeAndLabels
|
||||
const int chunksSizeAndLabelsSize = roundUp(h, 2);
|
||||
std::vector<int> chunksSizeAndLabels(chunksSizeAndLabelsSize);
|
||||
AutoBuffer<int> chunksSizeAndLabels(chunksSizeAndLabelsSize);
|
||||
|
||||
//Tree of labels
|
||||
std::vector<LabelT> P(Plength, 0);
|
||||
AutoBuffer<LabelT> P(Plength, 0);
|
||||
//First label is for background
|
||||
//P[0] = 0;
|
||||
|
||||
@@ -4288,7 +4288,7 @@ namespace cv{
|
||||
}
|
||||
|
||||
//Array for statistics data
|
||||
std::vector<StatsOp> sopArray(h);
|
||||
AutoBuffer<StatsOp> sopArray(h);
|
||||
sop.init(nLabels);
|
||||
|
||||
//Second scan
|
||||
@@ -4323,7 +4323,7 @@ namespace cv{
|
||||
//............
|
||||
const size_t Plength = size_t(((h + 1) / 2) * size_t((w + 1) / 2)) + 1;
|
||||
|
||||
std::vector<LabelT> P_(Plength, 0);
|
||||
AutoBuffer<LabelT> P_(Plength, 0);
|
||||
LabelT *P = P_.data();
|
||||
//P[0] = 0;
|
||||
LabelT lunique = 1;
|
||||
|
||||
@@ -101,7 +101,7 @@ static void getSobelKernels( OutputArray _kx, OutputArray _ky,
|
||||
|
||||
if( _ksize % 2 == 0 || _ksize > 31 )
|
||||
CV_Error( cv::Error::StsOutOfRange, "The kernel size must be odd and not larger than 31" );
|
||||
std::vector<int> kerI(std::max(ksizeX, ksizeY) + 1);
|
||||
AutoBuffer<int> kerI(std::max(ksizeX, ksizeY) + 1);
|
||||
|
||||
CV_Assert( dx >= 0 && dy >= 0 && dx+dy > 0 );
|
||||
|
||||
|
||||
@@ -1844,6 +1844,7 @@ void line( InputOutputArray _img, Point pt1, Point pt2, const Scalar& color,
|
||||
void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
|
||||
int thickness, int line_type, int shift, double tipLength)
|
||||
{
|
||||
CV_Assert( tipLength > 0.0 && tipLength <= 1.0 );
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
const double tipSize = norm(pt1-pt2)*tipLength; // Factor to normalize the size of the tip depending on the length of the arrow
|
||||
|
||||
@@ -442,119 +442,78 @@ double EMDSolver::calcFlow(Mat* flow_) const
|
||||
|
||||
int EMDSolver::findBasicVars() const
|
||||
{
|
||||
int i, j;
|
||||
int u_cfound, v_cfound;
|
||||
Node1D u0_head, u1_head, *cur_u, *prev_u;
|
||||
Node1D v0_head, v1_head, *cur_v, *prev_v;
|
||||
bool found;
|
||||
|
||||
CV_Assert(u != 0 && v != 0);
|
||||
|
||||
/* initialize the rows list (u) and the columns list (v) */
|
||||
u0_head.next = u;
|
||||
for (i = 0; i < ssize; i++)
|
||||
{
|
||||
u[i].next = u + i + 1;
|
||||
}
|
||||
u[ssize - 1].next = 0;
|
||||
u1_head.next = 0;
|
||||
// 1. Initialize status flags using contiguous memory to eliminate pointer chasing
|
||||
AutoBuffer<char> computed_buf(ssize + dsize);
|
||||
char* row_computed = computed_buf.data();
|
||||
char* col_computed = computed_buf.data() + ssize;
|
||||
memset(row_computed, 0, ssize + dsize);
|
||||
|
||||
v0_head.next = ssize > 1 ? v + 1 : 0;
|
||||
for (i = 1; i < dsize; i++)
|
||||
{
|
||||
v[i].next = v + i + 1;
|
||||
}
|
||||
v[dsize - 1].next = 0;
|
||||
v1_head.next = 0;
|
||||
// 2. Create BFS queues
|
||||
AutoBuffer<int> queue_buf(ssize + dsize);
|
||||
int* row_queue = queue_buf.data();
|
||||
int* col_queue = queue_buf.data() + ssize;
|
||||
|
||||
/* there are ssize+dsize variables but only ssize+dsize-1 independent equations,
|
||||
so set v[0]=0 */
|
||||
int row_head = 0, row_tail = 0;
|
||||
int col_head = 0, col_tail = 0;
|
||||
|
||||
// Initial condition: enqueue column 0 as the root node and set its value to 0
|
||||
v[0].val = 0;
|
||||
v1_head.next = v;
|
||||
v1_head.next->next = 0;
|
||||
col_computed[0] = true;
|
||||
col_queue[col_tail++] = 0;
|
||||
|
||||
/* loop until all variables are found */
|
||||
u_cfound = v_cfound = 0;
|
||||
while (u_cfound < ssize || v_cfound < dsize)
|
||||
int u_cfound = 0;
|
||||
int v_cfound = 1;
|
||||
|
||||
// 3. Dual-queue interactive BFS traversal over the spanning tree (Time Complexity: O(N + M))
|
||||
while (row_head < row_tail || col_head < col_tail)
|
||||
{
|
||||
found = false;
|
||||
if (v_cfound < dsize)
|
||||
// Process currently marked columns to update their connected rows
|
||||
while (col_head < col_tail)
|
||||
{
|
||||
/* loop over all marked columns */
|
||||
prev_v = &v1_head;
|
||||
cur_v = v1_head.next;
|
||||
found = found || (cur_v != 0);
|
||||
for (; cur_v != 0; cur_v = cur_v->next)
|
||||
{
|
||||
float cur_v_val = cur_v->val;
|
||||
int j = col_queue[col_head++];
|
||||
float cur_v_val = v[j].val;
|
||||
|
||||
j = (int)(cur_v - v);
|
||||
/* find the variables in column j */
|
||||
prev_u = &u0_head;
|
||||
for (cur_u = u0_head.next; cur_u != 0;)
|
||||
// Use adjacency list cols_x to directly access rows connected to column j, avoiding full scans
|
||||
for (Node2D* xp = cols_x[j]; xp != 0; xp = xp->next[1])
|
||||
{
|
||||
int i = xp->i;
|
||||
if (!row_computed[i])
|
||||
{
|
||||
i = (int)(cur_u - u);
|
||||
if (getIsX(i, j))
|
||||
{
|
||||
/* compute u[i] */
|
||||
cur_u->val = getCost(i, j) - cur_v_val;
|
||||
/* ...and add it to the marked list */
|
||||
prev_u->next = cur_u->next;
|
||||
cur_u->next = u1_head.next;
|
||||
u1_head.next = cur_u;
|
||||
cur_u = prev_u->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_u = cur_u;
|
||||
cur_u = cur_u->next;
|
||||
}
|
||||
u[i].val = getCost(i, j) - cur_v_val;
|
||||
row_computed[i] = true;
|
||||
row_queue[row_tail++] = i; // Enqueue the newly resolved row
|
||||
u_cfound++;
|
||||
}
|
||||
prev_v->next = cur_v->next;
|
||||
v_cfound++;
|
||||
}
|
||||
}
|
||||
|
||||
if (u_cfound < ssize)
|
||||
// Process currently marked rows to update their connected columns
|
||||
while (row_head < row_tail)
|
||||
{
|
||||
/* loop over all marked rows */
|
||||
prev_u = &u1_head;
|
||||
cur_u = u1_head.next;
|
||||
found = found || (cur_u != 0);
|
||||
for (; cur_u != 0; cur_u = cur_u->next)
|
||||
int i = row_queue[row_head++];
|
||||
float cur_u_val = u[i].val;
|
||||
|
||||
// Use adjacency list rows_x to directly access columns connected to row i
|
||||
for (Node2D* xp = rows_x[i]; xp != 0; xp = xp->next[0])
|
||||
{
|
||||
float cur_u_val = cur_u->val;
|
||||
i = (int)(cur_u - u);
|
||||
/* find the variables in rows i */
|
||||
prev_v = &v0_head;
|
||||
for (cur_v = v0_head.next; cur_v != 0;)
|
||||
int j = xp->j;
|
||||
if (!col_computed[j])
|
||||
{
|
||||
j = (int)(cur_v - v);
|
||||
if (getIsX(i, j))
|
||||
{
|
||||
/* compute v[j] */
|
||||
cur_v->val = getCost(i, j) - cur_u_val;
|
||||
/* ...and add it to the marked list */
|
||||
prev_v->next = cur_v->next;
|
||||
cur_v->next = v1_head.next;
|
||||
v1_head.next = cur_v;
|
||||
cur_v = prev_v->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_v = cur_v;
|
||||
cur_v = cur_v->next;
|
||||
}
|
||||
v[j].val = getCost(i, j) - cur_u_val;
|
||||
col_computed[j] = true;
|
||||
col_queue[col_tail++] = j; // Enqueue the newly resolved column
|
||||
v_cfound++;
|
||||
}
|
||||
prev_u->next = cur_u->next;
|
||||
u_cfound++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If the number of traversed nodes is insufficient, the graph is disconnected and the spanning tree is incomplete
|
||||
if (u_cfound < ssize || v_cfound < dsize)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1008,4 +967,4 @@ float cv::wrapperEMD(InputArray _sign1,
|
||||
OutputArray _flow)
|
||||
{
|
||||
return EMD(_sign1, _sign2, distType, _cost, lowerBound.get(), _flow);
|
||||
}
|
||||
}
|
||||
@@ -494,7 +494,8 @@ int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
|
||||
if( connectivity != 0 && connectivity != 4 && connectivity != 8 )
|
||||
CV_Error( cv::Error::StsBadFlag, "Connectivity must be 4, 0(=4) or 8" );
|
||||
|
||||
if( _mask.empty() )
|
||||
bool noUserMask = _mask.empty();
|
||||
if( noUserMask )
|
||||
{
|
||||
_mask.create( size.height + 2, size.width + 2, CV_8UC1 );
|
||||
_mask.setTo(0);
|
||||
@@ -508,7 +509,7 @@ int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
|
||||
Mat mask_inner = mask( Rect(1, 1, mask.cols - 2, mask.rows - 2) );
|
||||
copyMakeBorder( mask_inner, mask, 1, 1, 1, 1, BORDER_ISOLATED | BORDER_CONSTANT, Scalar(1) );
|
||||
|
||||
bool is_simple = mask.empty() && (flags & FLOODFILL_MASK_ONLY) == 0;
|
||||
bool is_simple = noUserMask && (flags & FLOODFILL_MASK_ONLY) == 0;
|
||||
|
||||
for( i = 0; i < cn; i++ )
|
||||
{
|
||||
|
||||
@@ -184,31 +184,82 @@ HoughLinesStandard( InputArray src, OutputArray lines, int type,
|
||||
irho, tabSin, tabCos);
|
||||
|
||||
// stage 1. fill accumulator
|
||||
if (use_edgeval) {
|
||||
for( i = 0; i < height; i++ )
|
||||
for( j = 0; j < width; j++ )
|
||||
{
|
||||
if( image[i * step + j] != 0 )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int r = cvRound( j * tabCos[n] + i * tabSin[n] );
|
||||
r += (numrho - 1) / 2;
|
||||
accum[(n + 1) * (numrho + 2) + r + 1] += image[i * step + j];
|
||||
}
|
||||
}
|
||||
// Use the serial implementation for small numangle values to avoid parallel overhead.
|
||||
constexpr int kParallelAngleThreshold = 100;
|
||||
if (numangle < kParallelAngleThreshold) {
|
||||
if (use_edgeval) {
|
||||
for( i = 0; i < height; i++ )
|
||||
for( j = 0; j < width; j++ )
|
||||
{
|
||||
if( image[i * step + j] != 0 )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int r = cvRound( j * tabCos[n] + i * tabSin[n] );
|
||||
r += (numrho - 1) / 2;
|
||||
accum[(n + 1) * (numrho + 2) + r + 1] += image[i * step + j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for( i = 0; i < height; i++ )
|
||||
for( j = 0; j < width; j++ )
|
||||
{
|
||||
if( image[i * step + j] != 0 )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int r = cvRound( j * tabCos[n] + i * tabSin[n] );
|
||||
r += (numrho - 1) / 2;
|
||||
accum[(n + 1) * (numrho + 2) + r + 1]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for( i = 0; i < height; i++ )
|
||||
for( j = 0; j < width; j++ )
|
||||
{
|
||||
if( image[i * step + j] != 0 )
|
||||
for(int n = 0; n < numangle; n++ )
|
||||
{
|
||||
int r = cvRound( j * tabCos[n] + i * tabSin[n] );
|
||||
r += (numrho - 1) / 2;
|
||||
accum[(n + 1) * (numrho + 2) + r + 1]++;
|
||||
}
|
||||
// Extract the coordinates of all edge points
|
||||
std::vector<int> x_coords, y_coords, edge_vals;
|
||||
size_t estimated_edges = (size_t)width * (size_t)height / 10;
|
||||
x_coords.reserve(estimated_edges);
|
||||
y_coords.reserve(estimated_edges);
|
||||
if (use_edgeval) {
|
||||
edge_vals.reserve(estimated_edges);
|
||||
}
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
const uchar* row_ptr = image + y * step;
|
||||
for (int x = 0; x < width; x++) {
|
||||
int val = row_ptr[x];
|
||||
if (val != 0) {
|
||||
x_coords.push_back(x);
|
||||
y_coords.push_back(y);
|
||||
if (use_edgeval) edge_vals.push_back(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int num_edges = (int)x_coords.size();
|
||||
|
||||
// Perform multi-threaded segmentation according to the numangle
|
||||
// Since accum is divided into blocks according to angles, the accum areas written by different threads will not overlap
|
||||
auto process_hough_by_angle = [&](const cv::Range& range) {
|
||||
for (int n = range.start; n < range.end; n++) {
|
||||
float cos_n = tabCos[n];
|
||||
float sin_n = tabSin[n];
|
||||
|
||||
int* accum_n = accum + (n + 1) * (numrho + 2) + 1 + (numrho - 1) / 2;
|
||||
|
||||
if (use_edgeval) {
|
||||
for (int k = 0; k < num_edges; k++) {
|
||||
int r = cvRound(x_coords[k] * cos_n + y_coords[k] * sin_n);
|
||||
accum_n[r] += edge_vals[k];
|
||||
}
|
||||
} else {
|
||||
for (int k = 0; k < num_edges; k++) {
|
||||
int r = cvRound(x_coords[k] * cos_n + y_coords[k] * sin_n);
|
||||
accum_n[r]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cv::parallel_for_(cv::Range(0, numangle), process_hough_by_angle);
|
||||
}
|
||||
|
||||
// stage 2. find local maximums
|
||||
findLocalMaximums( numrho, numangle, threshold, accum, _sort_buf );
|
||||
@@ -308,13 +359,13 @@ HoughLinesSDiv( InputArray image, OutputArray lines, int type,
|
||||
lst.push_back(hough_index(threshold, -1.f, 0.f));
|
||||
|
||||
// Precalculate sin table
|
||||
std::vector<float> _sinTable( 5 * tn * stn );
|
||||
AutoBuffer<float> _sinTable( 5 * tn * stn );
|
||||
float* sinTable = &_sinTable[0];
|
||||
|
||||
for( index = 0; index < 5 * tn * stn; index++ )
|
||||
sinTable[index] = (float)cos( stheta * index * 0.2f );
|
||||
|
||||
std::vector<uchar> _caccum(rn * tn, (uchar)0);
|
||||
AutoBuffer<uchar> _caccum(rn * tn, (uchar)0);
|
||||
uchar* caccum = &_caccum[0];
|
||||
|
||||
// Counting all feature pixels
|
||||
@@ -322,7 +373,7 @@ HoughLinesSDiv( InputArray image, OutputArray lines, int type,
|
||||
for( col = 0; col < w; col++ )
|
||||
fn += _POINT( row, col ) != 0;
|
||||
|
||||
std::vector<int> _x(fn), _y(fn);
|
||||
AutoBuffer<int> _x(fn), _y(fn);
|
||||
int* x = &_x[0], *y = &_y[0];
|
||||
|
||||
// Full Hough Transform (it's accumulator update part)
|
||||
@@ -394,7 +445,7 @@ HoughLinesSDiv( InputArray image, OutputArray lines, int type,
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<uchar> _buffer(srn * stn + 2);
|
||||
AutoBuffer<uchar> _buffer(srn * stn + 2);
|
||||
uchar* buffer = &_buffer[0];
|
||||
uchar* mcaccum = buffer + 1;
|
||||
|
||||
@@ -535,7 +586,7 @@ HoughLinesProbabilistic( Mat& image,
|
||||
|
||||
Mat accum = Mat::zeros( numangle, numrho, CV_32SC1 );
|
||||
Mat mask( height, width, CV_8UC1 );
|
||||
std::vector<float> trigtab(numangle*2);
|
||||
AutoBuffer<float> trigtab(numangle*2);
|
||||
|
||||
for( int n = 0; n < numangle; n++ )
|
||||
{
|
||||
@@ -2331,7 +2382,7 @@ static void HoughCircles( InputArray _image, OutputArray _circles,
|
||||
|
||||
if( type == CV_32FC4 )
|
||||
{
|
||||
std::vector<Vec4f> cw(ncircles);
|
||||
AutoBuffer<Vec4f> cw(ncircles);
|
||||
for( i = 0; i < ncircles; i++ )
|
||||
cw[i] = GetCircle4f(circles[i]);
|
||||
if (ncircles > 0)
|
||||
@@ -2339,7 +2390,7 @@ static void HoughCircles( InputArray _image, OutputArray _circles,
|
||||
}
|
||||
else if( type == CV_32FC3 )
|
||||
{
|
||||
std::vector<Vec3f> cwow(ncircles);
|
||||
AutoBuffer<Vec3f> cwow(ncircles);
|
||||
for( i = 0; i < ncircles; i++ )
|
||||
cwow[i] = GetCircle(circles[i]);
|
||||
if (ncircles > 0)
|
||||
|
||||
@@ -173,8 +173,8 @@ static const void* initInterTab2D( int method, bool fixpt )
|
||||
for( j = 0; j < INTER_TAB_SIZE; j++, tab += ksize*ksize, itab += ksize*ksize )
|
||||
{
|
||||
int isum = 0;
|
||||
NNDeltaTab_i[i*INTER_TAB_SIZE+j][0] = j < INTER_TAB_SIZE/2;
|
||||
NNDeltaTab_i[i*INTER_TAB_SIZE+j][1] = i < INTER_TAB_SIZE/2;
|
||||
NNDeltaTab_i[i*INTER_TAB_SIZE+j][0] = j >= INTER_TAB_SIZE/2;
|
||||
NNDeltaTab_i[i*INTER_TAB_SIZE+j][1] = i >= INTER_TAB_SIZE/2;
|
||||
|
||||
for( k1 = 0; k1 < ksize; k1++ )
|
||||
{
|
||||
|
||||
@@ -128,8 +128,8 @@ medianBlur_8u_O1( const Mat& _src, Mat& _dst, int ksize )
|
||||
# define CV_ALIGNMENT 16
|
||||
#endif
|
||||
|
||||
std::vector<HT> _h_coarse(1 * 16 * (STRIPE_SIZE + 2*r) * cn + CV_ALIGNMENT);
|
||||
std::vector<HT> _h_fine(16 * 16 * (STRIPE_SIZE + 2*r) * cn + CV_ALIGNMENT);
|
||||
AutoBuffer<HT> _h_coarse(1 * 16 * (STRIPE_SIZE + 2*r) * cn + CV_ALIGNMENT);
|
||||
AutoBuffer<HT> _h_fine(16 * 16 * (STRIPE_SIZE + 2*r) * cn + CV_ALIGNMENT);
|
||||
HT* h_coarse = alignPtr(&_h_coarse[0], CV_ALIGNMENT);
|
||||
HT* h_fine = alignPtr(&_h_fine[0], CV_ALIGNMENT);
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@ static bool ocl_morphOp(InputArray _src, OutputArray _dst, InputArray _kernel,
|
||||
if (actual_op < 0)
|
||||
actual_op = op;
|
||||
|
||||
std::vector<ocl::Kernel> kernels(iterations);
|
||||
AutoBuffer<ocl::Kernel> kernels(iterations);
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
int current_op = iterations == i + 1 ? actual_op : op;
|
||||
|
||||
@@ -307,8 +307,8 @@ __kernel void remap_16SC2_16UC1(__global const uchar * srcptr, int src_step, int
|
||||
__global T * dst = (__global T *)(dstptr + dst_index);
|
||||
|
||||
int map2Value = convert_int(map2[0]) & (INTER_TAB_SIZE2 - 1);
|
||||
int dx = (map2Value & (INTER_TAB_SIZE - 1)) < (INTER_TAB_SIZE >> 1) ? 1 : 0;
|
||||
int dy = (map2Value >> INTER_BITS) < (INTER_TAB_SIZE >> 1) ? 1 : 0;
|
||||
int dx = (map2Value & (INTER_TAB_SIZE - 1)) >= (INTER_TAB_SIZE >> 1) ? 1 : 0;
|
||||
int dy = (map2Value >> INTER_BITS) >= (INTER_TAB_SIZE >> 1) ? 1 : 0;
|
||||
int2 gxy = convert_int2(map1[0]) + (int2)(dx, dy);
|
||||
#if WARP_RELATIVE
|
||||
gxy.x += x;
|
||||
|
||||
@@ -793,6 +793,7 @@ void Subdiv2D::getLeadingEdgeList(std::vector<int>& leadingEdgeList) const
|
||||
{
|
||||
leadingEdgeList.clear();
|
||||
int i, total = (int)(qedges.size()*4);
|
||||
//use a std::vector<bool> to benefit from the "bitset size/8" implementation
|
||||
std::vector<bool> edgemask(total, false);
|
||||
|
||||
for( i = 4; i < total; i += 2 )
|
||||
@@ -813,6 +814,7 @@ void Subdiv2D::getTriangleList(std::vector<Vec6f>& triangleList) const
|
||||
{
|
||||
triangleList.clear();
|
||||
int i, total = (int)(qedges.size()*4);
|
||||
//use a std::vector<bool> to benefit from the "bitset size/8" implementation
|
||||
std::vector<bool> edgemask(total, false);
|
||||
Rect2f rect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
|
||||
|
||||
|
||||
@@ -568,7 +568,6 @@ void crossCorr( const Mat& img, const Mat& _templ, Mat& corr,
|
||||
{
|
||||
const double blockScale = 4.5;
|
||||
const int minBlockSize = 256;
|
||||
std::vector<uchar> buf;
|
||||
|
||||
Mat templ = _templ;
|
||||
int depth = img.depth(), cn = img.channels();
|
||||
@@ -624,7 +623,7 @@ void crossCorr( const Mat& img, const Mat& _templ, Mat& corr,
|
||||
if( (ccn > 1 || cn > 1) && cdepth != maxDepth )
|
||||
bufSize = std::max( bufSize, blocksize.width*blocksize.height*CV_ELEM_SIZE(cdepth));
|
||||
|
||||
buf.resize(bufSize);
|
||||
AutoBuffer<uchar> buf(bufSize);
|
||||
|
||||
Ptr<hal::DFT2D> c = hal::DFT2D::create(dftsize.width, dftsize.height, dftTempl.depth(), 1, 1, CV_HAL_DFT_IS_INPLACE, templ.rows);
|
||||
|
||||
@@ -975,13 +974,14 @@ static void common_matchTemplate( Mat& img, Mat& templ, Mat& result, int method,
|
||||
|
||||
for( i = 0; i < result.rows; i++ )
|
||||
{
|
||||
float* rrow = result.ptr<float>(i);
|
||||
float* rrow = result.depth() == CV_32F ? result.ptr<float>(i) : nullptr;
|
||||
double* drow = result.depth() == CV_64F ? result.ptr<double>(i) : nullptr;
|
||||
int idx = i * sumstep;
|
||||
int idx2 = i * sqstep;
|
||||
|
||||
for( j = 0; j < result.cols; j++, idx += cn, idx2 += cn )
|
||||
{
|
||||
double num = rrow[j], t;
|
||||
double num = rrow ? (double)rrow[j] : drow[j], t;
|
||||
double wndMean2 = 0, wndSum2 = 0;
|
||||
|
||||
if( numType == 1 )
|
||||
@@ -1027,7 +1027,8 @@ static void common_matchTemplate( Mat& img, Mat& templ, Mat& result, int method,
|
||||
num = method != cv::TM_SQDIFF_NORMED ? 0 : 1;
|
||||
}
|
||||
|
||||
rrow[j] = (float)num;
|
||||
if (rrow) rrow[j] = (float)num;
|
||||
else drow[j] = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1120,6 +1121,11 @@ static bool ipp_matchTemplate( Mat& img, Mat& templ, Mat& result, int method)
|
||||
if(templ.size().area()*4 > img.size().area())
|
||||
return false;
|
||||
|
||||
// CV_8U SQDIFF/SQDIFF_NORMED suffer from float32 catastrophic cancellation
|
||||
// in IPP's internal accumulators; fall through to the double-precision path instead.
|
||||
if(img.depth() == CV_8U && (method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED))
|
||||
return false;
|
||||
|
||||
if(method == cv::TM_SQDIFF)
|
||||
{
|
||||
if(ipp_sqrDistance(img, templ, result))
|
||||
@@ -1192,9 +1198,18 @@ void cv::matchTemplate( InputArray _img, InputArray _templ, OutputArray _result,
|
||||
|
||||
CV_IPP_RUN_FAST(ipp_matchTemplate(img, templ, result, method))
|
||||
|
||||
crossCorr( img, templ, result, Point(0,0), 0, 0);
|
||||
bool use64f = (depth == CV_8U) && (method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED);
|
||||
Mat result64f;
|
||||
Mat& workResult = use64f ? result64f : result;
|
||||
if (use64f)
|
||||
result64f.create(corrSize, CV_64F);
|
||||
|
||||
common_matchTemplate(img, templ, result, method, cn);
|
||||
crossCorr( img, templ, workResult, Point(0,0), 0, 0);
|
||||
|
||||
common_matchTemplate(img, templ, workResult, method, cn);
|
||||
|
||||
if (use64f)
|
||||
result64f.convertTo(result, CV_32F);
|
||||
}
|
||||
|
||||
CV_IMPL void
|
||||
|
||||
@@ -1128,4 +1128,23 @@ TEST(Drawing, line_connectivity_regression_26413)
|
||||
EXPECT_GT(count4, 15) << "LINE_4 diagonal should have significantly more pixels due to staircase";
|
||||
}
|
||||
|
||||
//This test ensures that the tipLength geometric ratio is strictly bounded within the logical range (0.0, 1.0].
|
||||
TEST(Imgproc_Drawing, arrowedLine_tipLength_validation)
|
||||
{
|
||||
// Create a simple miniature canvas for testing. Added cv:: prefix.
|
||||
cv::Mat img = cv::Mat::zeros(100, 100, CV_8UC3);
|
||||
cv::Point pt1(10, 10), pt2(90, 90);
|
||||
|
||||
// 1. Validate legal parameters: should not throw any exceptions (Normal cases)
|
||||
EXPECT_NO_THROW(cv::arrowedLine(img, pt1, pt2, cv::Scalar(255, 255, 255), 1, 8, 0, 0.1));
|
||||
EXPECT_NO_THROW(cv::arrowedLine(img, pt1, pt2, cv::Scalar(255, 255, 255), 1, 8, 0, 1.0));
|
||||
|
||||
// 2. Validate illegal parameters: expect cv::Exception to be thrown (Boundary violations)
|
||||
// Negative ratio (tipLength <= 0.0)
|
||||
EXPECT_THROW(cv::arrowedLine(img, pt1, pt2, cv::Scalar(255, 255, 255), 1, 8, 0, -0.5), cv::Exception);
|
||||
|
||||
// Overflow ratio (tipLength > 1.0)
|
||||
EXPECT_THROW(cv::arrowedLine(img, pt1, pt2, cv::Scalar(255, 255, 255), 1, 8, 0, 1.5), cv::Exception);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -342,4 +342,19 @@ INSTANTIATE_TEST_CASE_P(/**/,
|
||||
testing::Values(TM_SQDIFF, TM_SQDIFF_NORMED, TM_CCORR, TM_CCORR_NORMED, TM_CCOEFF, TM_CCOEFF_NORMED)));
|
||||
|
||||
|
||||
TEST(Imgproc_MatchTemplate, bug_21786)
|
||||
{
|
||||
// CV_8U identical image/template with large patch sums triggers float32
|
||||
// catastrophic cancellation in TM_SQDIFF. Result must be exactly zero.
|
||||
Mat img(100, 100, CV_8U, Scalar(255));
|
||||
Mat templ(25, 25, CV_8U, Scalar(255));
|
||||
Mat result;
|
||||
|
||||
matchTemplate(img, templ, result, TM_SQDIFF);
|
||||
EXPECT_NEAR(0.0, cv::norm(result, cv::NORM_INF), 1e-6);
|
||||
|
||||
matchTemplate(img, templ, result, TM_SQDIFF_NORMED);
|
||||
EXPECT_NEAR(0.0, cv::norm(result, cv::NORM_INF), 1e-6);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -76,6 +76,36 @@ void Dictionary::writeDictionary(FileStorage& fs, const String &name)
|
||||
bool Dictionary::identify(const Mat &onlyCellPixelRatio, CV_OUT int &idx, CV_OUT int &rotation, double maxCorrectionRate, float validBitIdThreshold) const {
|
||||
CV_Assert(onlyCellPixelRatio.rows == markerSize && onlyCellPixelRatio.cols == markerSize);
|
||||
|
||||
// Fill bit masks of cells that are not black (not0) and not white (not1).
|
||||
const int s = (markerSize * markerSize + 8 - 1) / 8;
|
||||
AutoBuffer<uint8_t> temp(4 * s);
|
||||
uint8_t* not0 = temp.data(), * not1 = not0 + s;
|
||||
uint8_t not0Byte = 0, not1Byte = 0;
|
||||
int currentByte = 0, currentBit = 0;
|
||||
for(int j = 0; j < markerSize; j++) {
|
||||
const float* cellPixelRatioRow = onlyCellPixelRatio.ptr<float>(j);
|
||||
for(int i = 0; i < markerSize; i++) {
|
||||
not0Byte <<= 1; not1Byte <<= 1;
|
||||
if(cellPixelRatioRow[i] > validBitIdThreshold) not0Byte |= 1;
|
||||
if(cellPixelRatioRow[i] < 1 - validBitIdThreshold) not1Byte |= 1;
|
||||
++currentBit;
|
||||
if(currentBit == 8) {
|
||||
not0[currentByte] = not0Byte;
|
||||
not1[currentByte] = not1Byte;
|
||||
not0Byte = not1Byte = 0;
|
||||
++currentByte;
|
||||
currentBit = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentBit != 0) {
|
||||
not0[currentByte] = not0Byte;
|
||||
not1[currentByte] = not1Byte;
|
||||
}
|
||||
uint8_t* notXor = not1 + s, * temp0 = notXor + s;
|
||||
// Computing: notXor = not0 ^ not1
|
||||
hal::xor8u(not0, s, not1, s, notXor, s, s, 1, nullptr);
|
||||
|
||||
int maxCorrectionRecalculed = int(double(maxCorrectionBits) * maxCorrectionRate);
|
||||
|
||||
idx = -1; // by default, not found
|
||||
@@ -84,25 +114,21 @@ bool Dictionary::identify(const Mat &onlyCellPixelRatio, CV_OUT int &idx, CV_OUT
|
||||
for(int m = 0; m < bytesList.rows; m++) {
|
||||
int currentMinDistance = markerSize * markerSize + 1;
|
||||
int currentRotation = -1;
|
||||
for(int r = 0; r < 4; r++) {
|
||||
|
||||
Mat bitsRot = getBitsFromByteList(bytesList.rowRange(m, m + 1), markerSize, r);
|
||||
bitsRot.convertTo(bitsRot, CV_32F);
|
||||
|
||||
// Loop over all bits dictBitsList [m, markerSize * markerSize, 4]; onlyCellPixelRatio [markerSize, markerSize]
|
||||
int currentHamming = 0;
|
||||
for(int i = 0; i < markerSize; i++) {
|
||||
for(int j = 0; j < markerSize; j++) {
|
||||
// If detected bit is too far from the ground truth, consider it false.
|
||||
if(fabs(onlyCellPixelRatio.at<float>(i, j) - static_cast<float>(bitsRot.at<float>(i, j))) > validBitIdThreshold){
|
||||
currentHamming++;
|
||||
}
|
||||
}
|
||||
}
|
||||
const uchar* bytesRot = bytesList.ptr(m);
|
||||
for(int r = 0; r < 4; r++, bytesRot += s) {
|
||||
// Error if: (marker is 0 and input is not 0) or (marker is 1 and input is not 1)
|
||||
// i.e. if: (!bytesRot && not0) || (bytesRot && not1)
|
||||
// This is actually: not0 ^ ((not0 ^ not1) & bytesRot)
|
||||
// Computing: temp0 = (not0 ^ not1) & bytesRot
|
||||
hal::and8u(notXor, s, bytesRot, s, temp0, s, s, 1, nullptr);
|
||||
// Computing the final result (xor is performed internally).
|
||||
int currentHamming = cv::hal::normHamming(not0, temp0, s);
|
||||
|
||||
if(currentHamming < currentMinDistance) {
|
||||
currentMinDistance = currentHamming;
|
||||
currentRotation = r;
|
||||
// Break for perfect distance.
|
||||
if (currentMinDistance == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <limits>
|
||||
#include "math.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -822,7 +822,7 @@ private:
|
||||
float m_ig[4];
|
||||
void setPolynomialExpansionConsts(int n, double sigma)
|
||||
{
|
||||
std::vector<float> buf(n*6 + 3);
|
||||
AutoBuffer<float> buf(n*6 + 3);
|
||||
float* g = &buf[0] + n;
|
||||
float* xg = g + n*2 + 1;
|
||||
float* xxg = xg + n*2 + 1;
|
||||
|
||||
@@ -25,7 +25,10 @@ add_subdirectory(java/tutorial_code)
|
||||
add_subdirectory(dnn)
|
||||
add_subdirectory(gpu)
|
||||
add_subdirectory(tapi)
|
||||
add_subdirectory(opencl)
|
||||
# HACK: CMake 4.x finds and links wrong OpenCL in 32-bit builds on Windows x64
|
||||
if(NOT (WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4))
|
||||
add_subdirectory(opencl)
|
||||
endif()
|
||||
add_subdirectory(sycl)
|
||||
if(WIN32 AND HAVE_DIRECTX)
|
||||
add_subdirectory(directx)
|
||||
@@ -128,7 +131,10 @@ if(WIN32)
|
||||
endif()
|
||||
add_subdirectory(dnn)
|
||||
# add_subdirectory(gpu)
|
||||
add_subdirectory(opencl)
|
||||
# HACK: CMake 4.x finds and links wrong OpenCL in 32-bit builds on Windows x64
|
||||
if(NOT (WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4))
|
||||
add_subdirectory(opencl)
|
||||
endif()
|
||||
add_subdirectory(sycl)
|
||||
# add_subdirectory(opengl)
|
||||
# add_subdirectory(openvx)
|
||||
|
||||
@@ -107,6 +107,8 @@ int main(int argc, char *argv[])
|
||||
pDefaultBLOB.filterByConvexity = false;
|
||||
pDefaultBLOB.minConvexity = 0.95f;
|
||||
pDefaultBLOB.maxConvexity = (float)1e37;
|
||||
// Enable contour collection so we can draw blob outlines (see getBlobContours() below).
|
||||
pDefaultBLOB.collectContours = true;
|
||||
// Descriptor array for BLOB
|
||||
vector<String> typeDesc;
|
||||
// Param array for BLOB
|
||||
@@ -189,6 +191,11 @@ int main(int argc, char *argv[])
|
||||
int i = 0;
|
||||
for (vector<KeyPoint>::iterator k = keyImg.begin(); k != keyImg.end(); ++k, ++i)
|
||||
circle(result, k->pt, (int)k->size, palette[i % 65536]);
|
||||
// Retrieve the per-blob contours collected during detect() and outline each blob.
|
||||
// Requires SimpleBlobDetector::Params::collectContours to be true.
|
||||
const vector<vector<Point> >& blobContours = sbd->getBlobContours();
|
||||
for (size_t c = 0; c < blobContours.size(); ++c)
|
||||
drawContours(result, blobContours, (int)c, Scalar(0, 255, 0), 1);
|
||||
}
|
||||
namedWindow(*itDesc + label, WINDOW_AUTOSIZE);
|
||||
imshow(*itDesc + label, result);
|
||||
|
||||
@@ -10,7 +10,7 @@ using namespace cv;
|
||||
static void help(char** argv)
|
||||
{
|
||||
|
||||
printf("\nShow off image morphology: erosion, dialation, open and close\n"
|
||||
printf("\nShow off image morphology: erosion, dilation, opening and closing\n"
|
||||
"Call:\n %s [image]\n"
|
||||
"This program also shows use of rect, ellipse, cross and diamond kernels\n\n", argv[0]);
|
||||
printf( "Hot keys: \n"
|
||||
|
||||
@@ -21,6 +21,18 @@ PY3 = sys.version_info[0] == 3
|
||||
if PY3:
|
||||
xrange = range
|
||||
|
||||
# Colors for distinguishing multiple QR codes visually
|
||||
QR_COLORS = [
|
||||
(0, 255, 0), # green
|
||||
(255, 0, 0), # blue
|
||||
(0, 0, 255), # red
|
||||
(255, 255, 0), # cyan
|
||||
(0, 255, 255), # yellow
|
||||
(255, 0, 255), # magenta
|
||||
(128, 255, 0), # lime
|
||||
(255, 128, 0), # orange
|
||||
]
|
||||
|
||||
|
||||
class QrSample:
|
||||
def __init__(self, args):
|
||||
@@ -46,15 +58,14 @@ class QrSample:
|
||||
cv.putText(result, message, (20, 20), 1,
|
||||
cv.FONT_HERSHEY_DUPLEX, (0, 0, 255))
|
||||
|
||||
def drawQRCodeContours(self, image, cnt):
|
||||
def drawQRCodeContours(self, image, cnt, color=(0, 255, 0)):
|
||||
if cnt.size != 0:
|
||||
rows, cols, _ = image.shape
|
||||
show_radius = 2.813 * ((rows / cols) if rows > cols else (cols / rows))
|
||||
contour_radius = show_radius * 0.4
|
||||
cv.drawContours(image, [cnt], 0, (0, 255, 0), int(round(contour_radius)))
|
||||
cv.drawContours(image, [cnt], 0, color, int(round(contour_radius)))
|
||||
tpl = cnt.reshape((-1, 2))
|
||||
for x in tuple(tpl.tolist()):
|
||||
color = (255, 0, 0)
|
||||
cv.circle(image, tuple(x), int(round(contour_radius)), color, -1)
|
||||
|
||||
def drawQRCodeResults(self, result, points, decode_info, fps):
|
||||
@@ -64,7 +75,8 @@ class QrSample:
|
||||
if n > 0:
|
||||
for i in range(n):
|
||||
cnt = np.array(points[i]).reshape((-1, 1, 2)).astype(np.int32)
|
||||
self.drawQRCodeContours(result, cnt)
|
||||
color = QR_COLORS[i % len(QR_COLORS)]
|
||||
self.drawQRCodeContours(result, cnt, color)
|
||||
msg = 'QR[{:d}]@{} : '.format(i, *(cnt.reshape(1, -1).tolist()))
|
||||
print(msg, end="")
|
||||
if len(decode_info) > i:
|
||||
|
||||
Reference in New Issue
Block a user