From 19a9c9b97e87567d4e2f1f99cacbb149800d16fb Mon Sep 17 00:00:00 2001 From: Mulham Fetna Date: Sat, 9 May 2026 20:47:59 +0300 Subject: [PATCH 1/3] fix: add explicit NumPy version constraints for Python 3.13+ and 3.14 - Changed install_requires to specify minimum numpy versions per Python version: - Python 3.9-3.12: numpy>=2.0.2 - Python 3.13: numpy>=2.1.3 - Python 3.14+: numpy>=2.3.0 - This fixes NumPy 2.x ABI compatibility issue where wheels compiled against NumPy 1.x fail at runtime with NumPy 2.x Fixes opencv/opencv-python#1201 --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d0c57b48..952f37ce 100755 --- a/setup.py +++ b/setup.py @@ -24,7 +24,9 @@ def main(): install_requires = [ 'numpy<2.0; python_version<"3.9"', - 'numpy>=2; python_version>="3.9"', + 'numpy>=2.0.2; python_version>="3.9" and python_version<"3.13"', + 'numpy>=2.1.3; python_version>="3.13" and python_version<"3.14"', + 'numpy>=2.3.0; python_version>="3.14"', ] python_version = cmaker.CMaker.get_python_version() From 4e4505a2774a50ce1ad5a46b7673f71257d77265 Mon Sep 17 00:00:00 2001 From: Mulham Fetna Date: Sat, 9 May 2026 21:02:40 +0300 Subject: [PATCH 2/3] docs: add multiprocessing fork safety warning Add documentation about OpenCV not being fork-safe and the 'corrupted double-linked list' issue that can occur when using cv2 functions after fork(). Fixes: #1166 --- scripts/__init__.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/scripts/__init__.py b/scripts/__init__.py index 587a42bf..c7086c07 100644 --- a/scripts/__init__.py +++ b/scripts/__init__.py @@ -1,3 +1,22 @@ +""" +OpenCV Python bindings + +This module provides Python bindings for OpenCV. + +Important notes for multiprocessing: +- OpenCV is not fork-safe. Using cv2 functions after fork() can cause + "corrupted double-linked list" errors and memory corruption. +- If you use multiprocessing with fork (the default on Linux/macOS), + either: + 1. Use spawn mode: multiprocessing.set_start_method('spawn') + 2. Call cv2.setNumThreads(0) in each worker before using cv2 +- See: https://github.com/opencv/opencv-python/issues/1166 +""" + +import os +import sys +import warnings + PYTHON_EXTENSIONS_PATHS = [ LOADER_DIR ] + PYTHON_EXTENSIONS_PATHS @@ -21,4 +40,4 @@ if sys.platform.startswith("linux") and ci_and_not_headless: os.environ["QT_QPA_FONTDIR"] = os.path.join( os.path.dirname(os.path.abspath(__file__)), "qt", "fonts" - ) + ) \ No newline at end of file From ee4429e2a80a36b06284fe2ab3ec296cafcf0b8f Mon Sep 17 00:00:00 2001 From: Mulham Fetna Date: Sat, 9 May 2026 21:04:08 +0300 Subject: [PATCH 3/3] Add thread safety fix for JPEG2000 decode (Issue #1007) - Add mutex protection around OpenJPEG decode operations - Prevent segfault/deadlock when multiple threads call imdecode simultaneously - Apply mutex lock in readHeader, readData, and write methods --- patches/patchOpenJPEGThreadSafety | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 patches/patchOpenJPEGThreadSafety diff --git a/patches/patchOpenJPEGThreadSafety b/patches/patchOpenJPEGThreadSafety new file mode 100644 index 00000000..fe8f60cb --- /dev/null +++ b/patches/patchOpenJPEGThreadSafety @@ -0,0 +1,49 @@ +diff -ruN opencv/modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.cpp opencv_patched/modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.cpp +--- opencv/modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.cpp 2024-01-01 00:00:00.000000000 +0000 ++++ opencv_patched/modules/imgcodecs/src/grfmt_jpeg2000_openjpeg.cpp 2026-05-09 00:00:00.000000000 +0000 +@@ -10,8 +10,18 @@ + #include "grfmt_jpeg2000_openjpeg.hpp" + + #include "opencv2/core/utils/logger.hpp" ++#include "opencv2/core/utility.hpp" + + namespace cv { ++namespace detail { ++ ++static Mutex& getOpenJpegMutex() ++{ ++ static Mutex mutex; ++ return mutex; ++} ++ ++} // namespace detail + + namespace { + +@@ -516,6 +526,8 @@ Jpeg2KOpjDecoderBase::Jpeg2KOpjDecoderBase(OPJ_CODEC_FORMAT format) + + bool Jpeg2KOpjDecoderBase::readHeader() + { ++ AutoLock lock(detail::getOpenJpegMutex()); ++ + if (!m_buf.empty()) { + opjBuf_ = detail::OpjMemoryBuffer(m_buf); + stream_ = opjCreateBufferInputStream(&opjBuf_); +@@ -595,6 +607,8 @@ bool Jpeg2KOpjDecoderBase::readHeader() + + bool Jpeg2KOpjDecoderBase::readData( Mat& img ) + { ++ AutoLock lock(detail::getOpenJpegMutex()); ++ + using DecodeFunc = bool(*)(const opj_image_t&, cv::Mat&, uint8_t shift, bool use_rgb); + + if (!opj_decode(codec_.get(), stream_.get(), image_.get())) +@@ -706,6 +720,8 @@ bool Jpeg2KOpjEncoder::isFormatSupported(int depth) const + + bool Jpeg2KOpjEncoder::write(const Mat& img, const std::vector& params) + { ++ AutoLock lock(detail::getOpenJpegMutex()); ++ + CV_Assert(params.size() % 2 == 0); + + const int channels = img.channels(); \ No newline at end of file