mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Merge remote-tracking branch 'upstream/3.4' into merge-3.4
This commit is contained in:
commit
cd59516433
7
.github/ISSUE_TEMPLATE.md
vendored
7
.github/ISSUE_TEMPLATE.md
vendored
@ -1,3 +1,10 @@
|
||||
<!--
|
||||
If you have a question rather than reporting a bug please go to https://forum.opencv.org where you get much faster responses.
|
||||
If you need further assistance please read [How To Contribute](https://github.com/opencv/opencv/wiki/How_to_contribute).
|
||||
|
||||
This is a template helping you to create an issue which can be processed as quickly as possible. This is the bug reporting section for the OpenCV library.
|
||||
-->
|
||||
|
||||
##### System information (version)
|
||||
<!-- Example
|
||||
- OpenCV => 4.2
|
||||
|
@ -294,20 +294,20 @@ So, make sure [docker](https://www.docker.com/) is installed in your system and
|
||||
@code{.bash}
|
||||
git clone https://github.com/opencv/opencv.git
|
||||
cd opencv
|
||||
docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emcmake python3 ./dev/platforms/js/build_js.py build_js
|
||||
docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk emcmake python3 ./platforms/js/build_js.py build_js
|
||||
@endcode
|
||||
|
||||
In Windows use the following PowerShell command:
|
||||
|
||||
@code{.bash}
|
||||
docker run --rm --workdir /src -v "$(get-location):/src" "emscripten/emsdk" emcmake python3 ./dev/platforms/js/build_js.py build_js
|
||||
docker run --rm --workdir /src -v "$(get-location):/src" "emscripten/emsdk" emcmake python3 ./platforms/js/build_js.py build_js
|
||||
@endcode
|
||||
|
||||
@warning
|
||||
The example uses latest version of emscripten. If the build fails you should try a version that is known to work fine which is `2.0.10` using the following command:
|
||||
|
||||
@code{.bash}
|
||||
docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk:2.0.10 emcmake python3 ./dev/platforms/js/build_js.py build_js
|
||||
docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk:2.0.10 emcmake python3 ./platforms/js/build_js.py build_js
|
||||
@endcode
|
||||
|
||||
### Building the documentation with Docker
|
||||
@ -331,5 +331,5 @@ docker build . -t opencv-js-doc
|
||||
Now run the build command again, this time using the new image and passing `--build_doc`:
|
||||
|
||||
@code{.bash}
|
||||
docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) "opencv-js-doc" emcmake python3 ./dev/platforms/js/build_js.py build_js --build_doc
|
||||
docker run --rm -v $(pwd):/src -u $(id -u):$(id -g) "opencv-js-doc" emcmake python3 ./platforms/js/build_js.py build_js --build_doc
|
||||
@endcode
|
||||
|
@ -88,27 +88,27 @@ B = cv.imread('orange.jpg')
|
||||
# generate Gaussian pyramid for A
|
||||
G = A.copy()
|
||||
gpA = [G]
|
||||
for i in xrange(6):
|
||||
for i in range(6):
|
||||
G = cv.pyrDown(G)
|
||||
gpA.append(G)
|
||||
|
||||
# generate Gaussian pyramid for B
|
||||
G = B.copy()
|
||||
gpB = [G]
|
||||
for i in xrange(6):
|
||||
for i in range(6):
|
||||
G = cv.pyrDown(G)
|
||||
gpB.append(G)
|
||||
|
||||
# generate Laplacian Pyramid for A
|
||||
lpA = [gpA[5]]
|
||||
for i in xrange(5,0,-1):
|
||||
for i in range(5,0,-1):
|
||||
GE = cv.pyrUp(gpA[i])
|
||||
L = cv.subtract(gpA[i-1],GE)
|
||||
lpA.append(L)
|
||||
|
||||
# generate Laplacian Pyramid for B
|
||||
lpB = [gpB[5]]
|
||||
for i in xrange(5,0,-1):
|
||||
for i in range(5,0,-1):
|
||||
GE = cv.pyrUp(gpB[i])
|
||||
L = cv.subtract(gpB[i-1],GE)
|
||||
lpB.append(L)
|
||||
@ -122,7 +122,7 @@ for la,lb in zip(lpA,lpB):
|
||||
|
||||
# now reconstruct
|
||||
ls_ = LS[0]
|
||||
for i in xrange(1,6):
|
||||
for i in range(1,6):
|
||||
ls_ = cv.pyrUp(ls_)
|
||||
ls_ = cv.add(ls_, LS[i])
|
||||
|
||||
|
@ -47,7 +47,7 @@ ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)
|
||||
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
|
||||
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
|
||||
|
||||
for i in xrange(6):
|
||||
for i in range(6):
|
||||
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray',vmin=0,vmax=255)
|
||||
plt.title(titles[i])
|
||||
plt.xticks([]),plt.yticks([])
|
||||
@ -98,7 +98,7 @@ titles = ['Original Image', 'Global Thresholding (v = 127)',
|
||||
'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
|
||||
images = [img, th1, th2, th3]
|
||||
|
||||
for i in xrange(4):
|
||||
for i in range(4):
|
||||
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
|
||||
plt.title(titles[i])
|
||||
plt.xticks([]),plt.yticks([])
|
||||
@ -153,7 +153,7 @@ titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
|
||||
'Original Noisy Image','Histogram',"Otsu's Thresholding",
|
||||
'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
|
||||
|
||||
for i in xrange(3):
|
||||
for i in range(3):
|
||||
plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
|
||||
plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
|
||||
plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
|
||||
@ -196,7 +196,7 @@ bins = np.arange(256)
|
||||
fn_min = np.inf
|
||||
thresh = -1
|
||||
|
||||
for i in xrange(1,256):
|
||||
for i in range(1,256):
|
||||
p1,p2 = np.hsplit(hist_norm,[i]) # probabilities
|
||||
q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes
|
||||
if q1 < 1.e-6 or q2 < 1.e-6:
|
||||
|
@ -268,7 +268,7 @@ fft_filters = [np.fft.fft2(x) for x in filters]
|
||||
fft_shift = [np.fft.fftshift(y) for y in fft_filters]
|
||||
mag_spectrum = [np.log(np.abs(z)+1) for z in fft_shift]
|
||||
|
||||
for i in xrange(6):
|
||||
for i in range(6):
|
||||
plt.subplot(2,3,i+1),plt.imshow(mag_spectrum[i],cmap = 'gray')
|
||||
plt.title(filter_name[i]), plt.xticks([]), plt.yticks([])
|
||||
|
||||
|
@ -108,7 +108,7 @@ from matplotlib import pyplot as plt
|
||||
cap = cv.VideoCapture('vtest.avi')
|
||||
|
||||
# create a list of first 5 frames
|
||||
img = [cap.read()[1] for i in xrange(5)]
|
||||
img = [cap.read()[1] for i in range(5)]
|
||||
|
||||
# convert all to grayscale
|
||||
gray = [cv.cvtColor(i, cv.COLOR_BGR2GRAY) for i in img]
|
||||
|
@ -64,6 +64,20 @@ String dumpString(const String& argument)
|
||||
return cv::format("String: %s", argument.c_str());
|
||||
}
|
||||
|
||||
CV_WRAP static inline
|
||||
String testOverloadResolution(int value, const Point& point = Point(42, 24))
|
||||
{
|
||||
return format("overload (int=%d, point=(x=%d, y=%d))", value, point.x,
|
||||
point.y);
|
||||
}
|
||||
|
||||
CV_WRAP static inline
|
||||
String testOverloadResolution(const Rect& rect)
|
||||
{
|
||||
return format("overload (rect=(x=%d, y=%d, w=%d, h=%d))", rect.x, rect.y,
|
||||
rect.width, rect.height);
|
||||
}
|
||||
|
||||
CV_WRAP static inline
|
||||
AsyncArray testAsyncArray(InputArray argument)
|
||||
{
|
||||
|
@ -3382,16 +3382,24 @@ struct Kernel::Impl
|
||||
haveTempSrcUMats = true; // UMat is created on RAW memory (without proper lifetime management, even from Mat)
|
||||
}
|
||||
|
||||
void addImage(const Image2D& image)
|
||||
/// Preserve image lifetime (while it is specified as Kernel argument)
|
||||
void registerImageArgument(int arg, const Image2D& image)
|
||||
{
|
||||
images.push_back(image);
|
||||
CV_CheckGE(arg, 0, "");
|
||||
CV_CheckLT(arg, (int)MAX_ARRS, "");
|
||||
if (arg < (int)shadow_images.size() && shadow_images[arg].ptr() != image.ptr()) // TODO future: replace ptr => impl (more strong check)
|
||||
{
|
||||
CV_Check(arg, !isInProgress, "ocl::Kernel: clearing of pending Image2D arguments is not allowed");
|
||||
}
|
||||
shadow_images.reserve(MAX_ARRS);
|
||||
shadow_images.resize(std::max(shadow_images.size(), (size_t)arg + 1));
|
||||
shadow_images[arg] = image;
|
||||
}
|
||||
|
||||
void finit(cl_event e)
|
||||
{
|
||||
CV_UNUSED(e);
|
||||
cleanupUMats();
|
||||
images.clear();
|
||||
isInProgress = false;
|
||||
release();
|
||||
}
|
||||
@ -3416,7 +3424,7 @@ struct Kernel::Impl
|
||||
bool isInProgress;
|
||||
bool isAsyncRun; // true if kernel was scheduled in async mode
|
||||
int nu;
|
||||
std::list<Image2D> images;
|
||||
std::vector<Image2D> shadow_images;
|
||||
bool haveTempDstUMats;
|
||||
bool haveTempSrcUMats;
|
||||
};
|
||||
@ -3558,9 +3566,11 @@ int Kernel::set(int i, const void* value, size_t sz)
|
||||
|
||||
int Kernel::set(int i, const Image2D& image2D)
|
||||
{
|
||||
p->addImage(image2D);
|
||||
cl_mem h = (cl_mem)image2D.ptr();
|
||||
return set(i, &h, sizeof(h));
|
||||
int res = set(i, &h, sizeof(h));
|
||||
if (res >= 0)
|
||||
p->registerImageArgument(i, image2D);
|
||||
return res;
|
||||
}
|
||||
|
||||
int Kernel::set(int i, const UMat& m)
|
||||
|
@ -249,7 +249,7 @@ CV_IMPL int cvInitSystem( int, char** )
|
||||
// check initialization status
|
||||
if( !wasInitialized )
|
||||
{
|
||||
// Initialize the stogare
|
||||
// Initialize the storage
|
||||
hg_windows = 0;
|
||||
|
||||
// Register the class
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include "opencv2/core/utils/configuration.private.hpp"
|
||||
#include "opencv2/core/utils/logger.hpp"
|
||||
#include "opencv2/core/utils/tls.hpp"
|
||||
|
||||
#include "pyopencv_generated_include.h"
|
||||
#include "opencv2/core/types_c.h"
|
||||
@ -141,6 +142,51 @@ private:
|
||||
PyGILState_STATE _state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Light weight RAII wrapper for `PyObject*` owning references.
|
||||
* In comparisson to C++11 `std::unique_ptr` with custom deleter, it provides
|
||||
* implicit conversion functions that might be useful to initialize it with
|
||||
* Python functions those returns owning references through the `PyObject**`
|
||||
* e.g. `PyErr_Fetch` or directly pass it to functions those want to borrow
|
||||
* reference to object (doesn't extend object lifetime) e.g. `PyObject_Str`.
|
||||
*/
|
||||
class PySafeObject
|
||||
{
|
||||
public:
|
||||
PySafeObject() : obj_(NULL) {}
|
||||
|
||||
explicit PySafeObject(PyObject* obj) : obj_(obj) {}
|
||||
|
||||
~PySafeObject()
|
||||
{
|
||||
Py_CLEAR(obj_);
|
||||
}
|
||||
|
||||
operator PyObject*()
|
||||
{
|
||||
return obj_;
|
||||
}
|
||||
|
||||
operator PyObject**()
|
||||
{
|
||||
return &obj_;
|
||||
}
|
||||
|
||||
PyObject* release()
|
||||
{
|
||||
PyObject* obj = obj_;
|
||||
obj_ = NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
private:
|
||||
PyObject* obj_;
|
||||
|
||||
// Explicitly disable copy operations
|
||||
PySafeObject(const PySafeObject*); // = delete
|
||||
PySafeObject& operator=(const PySafeObject&); // = delete
|
||||
};
|
||||
|
||||
static void pyRaiseCVException(const cv::Exception &e)
|
||||
{
|
||||
PyObject_SetAttrString(opencv_error, "file", PyString_FromString(e.file.c_str()));
|
||||
@ -293,6 +339,74 @@ bool parseNumpyScalar(PyObject* obj, T& value)
|
||||
return false;
|
||||
}
|
||||
|
||||
TLSData<std::vector<std::string> > conversionErrorsTLS;
|
||||
|
||||
inline void pyPrepareArgumentConversionErrorsStorage(std::size_t size)
|
||||
{
|
||||
std::vector<std::string>& conversionErrors = conversionErrorsTLS.getRef();
|
||||
conversionErrors.clear();
|
||||
conversionErrors.reserve(size);
|
||||
}
|
||||
|
||||
void pyRaiseCVOverloadException(const std::string& functionName)
|
||||
{
|
||||
const std::vector<std::string>& conversionErrors = conversionErrorsTLS.getRef();
|
||||
const std::size_t conversionErrorsCount = conversionErrors.size();
|
||||
if (conversionErrorsCount > 0)
|
||||
{
|
||||
// In modern std libraries small string optimization is used = no dynamic memory allocations,
|
||||
// but it can be applied only for string with length < 18 symbols (in GCC)
|
||||
const std::string bullet = "\n - ";
|
||||
|
||||
// Estimate required buffer size - save dynamic memory allocations = faster
|
||||
std::size_t requiredBufferSize = bullet.size() * conversionErrorsCount;
|
||||
for (std::size_t i = 0; i < conversionErrorsCount; ++i)
|
||||
{
|
||||
requiredBufferSize += conversionErrors[i].size();
|
||||
}
|
||||
|
||||
// Only string concatenation is required so std::string is way faster than
|
||||
// std::ostringstream
|
||||
std::string errorMessage("Overload resolution failed:");
|
||||
errorMessage.reserve(errorMessage.size() + requiredBufferSize);
|
||||
for (std::size_t i = 0; i < conversionErrorsCount; ++i)
|
||||
{
|
||||
errorMessage += bullet;
|
||||
errorMessage += conversionErrors[i];
|
||||
}
|
||||
cv::Exception exception(CV_StsBadArg, errorMessage, functionName, "", -1);
|
||||
pyRaiseCVException(exception);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::Exception exception(CV_StsInternal, "Overload resolution failed, but no errors reported",
|
||||
functionName, "", -1);
|
||||
pyRaiseCVException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
void pyPopulateArgumentConversionErrors()
|
||||
{
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PySafeObject exception_type;
|
||||
PySafeObject exception_value;
|
||||
PySafeObject exception_traceback;
|
||||
PyErr_Fetch(exception_type, exception_value, exception_traceback);
|
||||
PyErr_NormalizeException(exception_type, exception_value,
|
||||
exception_traceback);
|
||||
|
||||
PySafeObject exception_message(PyObject_Str(exception_value));
|
||||
std::string message;
|
||||
getUnicodeString(exception_message, message);
|
||||
#ifdef CV_CXX11
|
||||
conversionErrorsTLS.getRef().push_back(std::move(message));
|
||||
#else
|
||||
conversionErrorsTLS.getRef().push_back(message);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
typedef std::vector<uchar> vector_uchar;
|
||||
|
@ -174,6 +174,14 @@ gen_template_prop_init = Template("""
|
||||
gen_template_rw_prop_init = Template("""
|
||||
{(char*)"${member}", (getter)pyopencv_${name}_get_${member}, (setter)pyopencv_${name}_set_${member}, (char*)"${member}", NULL},""")
|
||||
|
||||
gen_template_overloaded_function_call = Template("""
|
||||
{
|
||||
${variant}
|
||||
|
||||
pyPopulateArgumentConversionErrors();
|
||||
}
|
||||
""")
|
||||
|
||||
class FormatStrings:
|
||||
string = 's'
|
||||
unsigned_char = 'b'
|
||||
@ -775,8 +783,12 @@ class FuncInfo(object):
|
||||
# if the function/method has only 1 signature, then just put it
|
||||
code += all_code_variants[0]
|
||||
else:
|
||||
# try to execute each signature
|
||||
code += " PyErr_Clear();\n\n".join([" {\n" + v + " }\n" for v in all_code_variants])
|
||||
# try to execute each signature, add an interlude between function
|
||||
# calls to collect error from all conversions
|
||||
code += ' pyPrepareArgumentConversionErrorsStorage({});\n'.format(len(all_code_variants))
|
||||
code += ' \n'.join(gen_template_overloaded_function_call.substitute(variant=v)
|
||||
for v in all_code_variants)
|
||||
code += ' pyRaiseCVOverloadException("{}");\n'.format(self.name)
|
||||
|
||||
def_ret = "NULL"
|
||||
if self.isconstructor:
|
||||
|
@ -73,6 +73,44 @@ class Bindings(NewOpenCVTests):
|
||||
except cv.error as _e:
|
||||
pass
|
||||
|
||||
def test_overload_resolution_can_choose_correct_overload(self):
|
||||
val = 123
|
||||
point = (51, 165)
|
||||
self.assertEqual(cv.utils.testOverloadResolution(val, point),
|
||||
'overload (int={}, point=(x={}, y={}))'.format(val, *point),
|
||||
"Can't select first overload if all arguments are provided as positional")
|
||||
|
||||
self.assertEqual(cv.utils.testOverloadResolution(val, point=point),
|
||||
'overload (int={}, point=(x={}, y={}))'.format(val, *point),
|
||||
"Can't select first overload if one of the arguments are provided as keyword")
|
||||
|
||||
self.assertEqual(cv.utils.testOverloadResolution(val),
|
||||
'overload (int={}, point=(x=42, y=24))'.format(val),
|
||||
"Can't select first overload if one of the arguments has default value")
|
||||
|
||||
rect = (1, 5, 10, 23)
|
||||
self.assertEqual(cv.utils.testOverloadResolution(rect),
|
||||
'overload (rect=(x={}, y={}, w={}, h={}))'.format(*rect),
|
||||
"Can't select second overload if all arguments are provided")
|
||||
|
||||
def test_overload_resolution_fails(self):
|
||||
def test_overload_resolution(msg, *args, **kwargs):
|
||||
no_exception_msg = 'Overload resolution failed without any exception for: "{}"'.format(msg)
|
||||
wrong_exception_msg = 'Overload resolution failed with wrong exception type for: "{}"'.format(msg)
|
||||
with self.assertRaises((cv.error, Exception), msg=no_exception_msg) as cm:
|
||||
cv.utils.testOverloadResolution(*args, **kwargs)
|
||||
self.assertEqual(type(cm.exception), cv.error, wrong_exception_msg)
|
||||
|
||||
test_overload_resolution('wrong second arg type (keyword arg)', 5, point=(1, 2, 3))
|
||||
test_overload_resolution('wrong second arg type', 5, 2)
|
||||
test_overload_resolution('wrong first arg', 3.4, (12, 21))
|
||||
# FIXIT: test_overload_resolution('wrong first arg, no second arg', 4.5)
|
||||
test_overload_resolution('wrong args number for first overload', 3, (12, 21), 123)
|
||||
test_overload_resolution('wrong args number for second overload', (3, 12, 12, 1), (12, 21))
|
||||
# One of the common problems
|
||||
test_overload_resolution('rect with float coordinates', (4.5, 4, 2, 1))
|
||||
test_overload_resolution('rect with wrong number of coordinates', (4, 4, 1))
|
||||
|
||||
|
||||
class Arguments(NewOpenCVTests):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user