1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge branch '4.x' into '5.x'

This commit is contained in:
Maksim Shabunin
2024-06-11 19:38:59 +03:00
573 changed files with 72922 additions and 7355 deletions
+1
View File
@@ -125,6 +125,7 @@ void cvSetModeWindow_WinRT(const char* name, double prop_value);
CvRect cvGetWindowRect_W32(const char* name);
CvRect cvGetWindowRect_GTK(const char* name);
CvRect cvGetWindowRect_COCOA(const char* name);
CvRect cvGetWindowRect_WAYLAND(const char* name);
double cvGetModeWindow_W32(const char* name);
double cvGetModeWindow_GTK(const char* name);
+2
View File
@@ -435,6 +435,8 @@ cv::Rect cv::getWindowImageRect(const String& winname)
return cvGetWindowRect_GTK(winname.c_str());
#elif defined (HAVE_COCOA)
return cvGetWindowRect_COCOA(winname.c_str());
#elif defined (HAVE_WAYLAND)
return cvGetWindowRect_WAYLAND(winname.c_str());
#else
return Rect(-1, -1, -1, -1);
#endif
+1 -1
View File
@@ -2154,7 +2154,7 @@ static void showSaveDialog(CvWindow& window)
#ifdef HAVE_TIFF
"TIFF Files (*.tiff;*.tif)\0*.tiff;*.tif\0"
#endif
#ifdef HAVE_JASPER
#if defined(HAVE_JASPER) || defined(HAVE_OPENJPEG)
"JPEG-2000 files (*.jp2)\0*.jp2\0"
#endif
#ifdef HAVE_WEBP
+198 -31
View File
@@ -84,20 +84,73 @@ static int xkb_keysym_to_ascii(xkb_keysym_t keysym) {
return static_cast<int>(keysym & 0xff);
}
static void write_mat_to_xrgb8888(cv::Mat const &img_, void *data) {
// Validate destination data.
CV_CheckFalse((data == nullptr), "Destination Address must not be nullptr.");
static void draw_xrgb8888(void *d, uint8_t a, uint8_t r, uint8_t g, uint8_t b) {
*((uint32_t *) d) = ((a << 24) | (r << 16) | (g << 8) | b);
}
// Validate source img parameters.
CV_CheckFalse(img_.empty(), "Source Mat must not be empty.");
const int ncn = img_.channels();
CV_CheckType(img_.type(),
( (ncn == 1) || (ncn == 3) || (ncn == 4)),
"Unsupported channels, please convert to 1, 3 or 4 channels"
);
static void write_mat_to_xrgb8888(cv::Mat const &img, void *data) {
CV_Assert(data != nullptr);
CV_Assert(img.isContinuous());
// The supported Mat depth is according to imshow() specification.
const int depth = CV_MAT_DEPTH(img_.type());
CV_CheckDepth(img_.type(),
( (depth == CV_8U) || (depth == CV_8S) ||
(depth == CV_16U) || (depth == CV_16S) ||
(depth == CV_32F) || (depth == CV_64F) ),
"Unsupported depth, please convert to CV_8U"
);
for (int y = 0; y < img.rows; y++) {
for (int x = 0; x < img.cols; x++) {
auto p = img.at<cv::Vec3b>(y, x);
draw_xrgb8888((char *) data + (y * img.cols + x) * 4, 0x00, p[2], p[1], p[0]);
}
// Convert to CV_8U
cv::Mat img;
const int mtype = CV_MAKE_TYPE(CV_8U, ncn);
switch(CV_MAT_DEPTH(depth))
{
case CV_8U:
img = img_; // do nothing.
break;
case CV_8S:
// [-128,127] -> [0,255]
img_.convertTo(img, mtype, 1.0, 128);
break;
case CV_16U:
// [0,65535] -> [0,255]
img_.convertTo(img, mtype, 1.0/255. );
break;
case CV_16S:
// [-32768,32767] -> [0,255]
img_.convertTo(img, mtype, 1.0/255. , 128);
break;
case CV_32F:
case CV_64F:
// [0, 1] -> [0,255]
img_.convertTo(img, mtype, 255.);
break;
default:
// it cannot be reachable.
break;
}
CV_CheckDepthEQ(CV_MAT_DEPTH(img.type()), CV_8U, "img should be CV_8U");
// XRGB8888 in Little Endian(Wayland Request) = [B8:G8:R8:X8] in data array.
// X is not used to show. So we can use cvtColor() with GRAY2BGRA or BGR2BGRA or copyTo().
cv::Mat dst(img.size(), CV_MAKE_TYPE(CV_8U, 4), (uint8_t*)data);
if(ncn == 1)
{
cvtColor(img, dst, cv::COLOR_GRAY2BGRA);
}
else if(ncn == 3)
{
cvtColor(img, dst, cv::COLOR_BGR2BGRA);
}
else
{
CV_CheckTrue(ncn==4, "Unexpected channels");
img.copyTo(dst);
}
}
@@ -231,7 +284,13 @@ private:
&handle_pointer_motion, &handle_pointer_button,
&handle_pointer_axis, &handle_pointer_frame,
&handle_pointer_axis_source, &handle_pointer_axis_stop,
&handle_pointer_axis_discrete
&handle_pointer_axis_discrete,
#ifdef WL_POINTER_AXIS_VALUE120_SINCE_VERSION
&handle_axis_value120,
#endif
#ifdef WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION
&handle_axis_relative_direction,
#endif
};
cv_wl_window *focus_window_{};
@@ -277,6 +336,27 @@ private:
CV_UNUSED(axis);
CV_UNUSED(discrete);
}
#ifdef WL_POINTER_AXIS_VALUE120_SINCE_VERSION
static void
handle_axis_value120(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t value120) {
CV_UNUSED(data);
CV_UNUSED(wl_pointer);
CV_UNUSED(axis);
CV_UNUSED(value120);
}
#endif
#ifdef WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION
static void
handle_axis_relative_direction(void *data, struct wl_pointer *wl_pointer, uint32_t axis, uint32_t direction) {
CV_UNUSED(data);
CV_UNUSED(wl_pointer);
CV_UNUSED(axis);
CV_UNUSED(direction);
}
#endif
};
class cv_wl_keyboard {
@@ -543,6 +623,9 @@ private:
cv::Rect last_img_area_;
bool image_changed_ = false;
int real_img_width = 0;
cv::Scalar const outarea_color_ = CV_RGB(0, 0, 0);
void *param_ = nullptr;
CvMouseCallback callback_ = nullptr;
};
@@ -659,7 +742,7 @@ public:
void show_image(cv::Mat const &image);
void create_trackbar(std::string const &name, int *value, int count, CvTrackbarCallback2 on_change, void *userdata);
int create_trackbar(std::string const &name, int *value, int count, CvTrackbarCallback2 on_change, void *userdata);
weak_ptr<cv_wl_trackbar> get_trackbar(std::string const &) const;
@@ -695,7 +778,13 @@ private:
};
struct xdg_toplevel *xdg_toplevel_;
struct xdg_toplevel_listener xdgtop_listener_{
&handle_toplevel_configure, &handle_toplevel_close
&handle_toplevel_configure, &handle_toplevel_close,
#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
&handle_toplevel_configure_bounds,
#endif
#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
&handle_toplevel_wm_capabilities,
#endif
};
bool wait_for_configure_ = true;
@@ -742,6 +831,27 @@ private:
static void handle_toplevel_close(void *data, struct xdg_toplevel *surface);
#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
static void
handle_toplevel_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
{
CV_UNUSED(data);
CV_UNUSED(xdg_toplevel);
CV_UNUSED(width);
CV_UNUSED(height);
}
#endif
#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
static void
handle_toplevel_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities)
{
CV_UNUSED(data);
CV_UNUSED(xdg_toplevel);
CV_UNUSED(capabilities);
}
#endif
static void handle_frame_callback(void *data, struct wl_callback *cb, uint32_t time);
};
@@ -1473,14 +1583,30 @@ cv_wl_viewer::cv_wl_viewer(cv_wl_window *window, int flags)
}
void cv_wl_viewer::set_image(cv::Mat const &image) {
if (image.type() == CV_8UC1) {
cv::Mat bgr;
cv::cvtColor(image, bgr, cv::COLOR_GRAY2BGR);
image_ = bgr.clone();
} else {
image_ = image.clone();
}
image_ = image.clone();
image_changed_ = true;
// See https://github.com/opencv/opencv/issues/25560
// If image_ width is too small enough to show title and buttons, expand it.
// Keep real image width to limit x position for callback functions
real_img_width = image_.size().width;
// Minimum width of title is not defined, so use button width * 3 instead of it.
const int view_min_width = cv_wl_titlebar::btn_width * 3 + cv_wl_titlebar::titlebar_min_width;
const int margin = view_min_width - real_img_width;
if(margin > 0)
{
copyMakeBorder(image_, // src
image_, // dst
0, // top
0, // bottom
0, // left
margin, // right
cv::BORDER_CONSTANT, // borderType
outarea_color_ ); // value(color)
}
}
void cv_wl_viewer::set_mouse_callback(CvMouseCallback callback, void *param) {
@@ -1533,6 +1659,8 @@ void cv_wl_viewer::on_mouse(int event, cv::Point const &p, int flag) {
int x = static_cast<int>((p.x - last_img_area_.x) * ((double) image_.size().width / last_img_area_.width));
int y = static_cast<int>((p.y - last_img_area_.y) *
((double) image_.size().height / last_img_area_.height));
x = cv::min(x, real_img_width);
callback_(event, x, y, flag, param_);
}
}
@@ -1588,6 +1716,11 @@ cv_wl_trackbar::cv_wl_trackbar(cv_wl_window *window, std::string name,
on_change_.value = value;
on_change_.data = data;
on_change_.callback = on_change;
// initilize slider_.value if value is not nullptr.
if (value != nullptr){
set_pos(*value);
}
}
std::string const &cv_wl_trackbar::name() const {
@@ -1603,6 +1736,12 @@ void cv_wl_trackbar::set_pos(int value) {
slider_.value = value;
slider_moved_ = true;
window_->show();
// Update user-ptr value and call on_change() function if cv_wl_trackbar::draw() is not called.
if(slider_moved_) {
on_change_.update(slider_.value);
on_change_.call(slider_.value);
}
}
}
@@ -1612,6 +1751,12 @@ void cv_wl_trackbar::set_max(int maxval) {
slider_.value = maxval;
slider_moved_ = true;
window_->show();
// Update user-ptr and call on_change() function if cv_wl_trackbar::draw() is not called.
if(slider_moved_) {
on_change_.update(slider_.value);
on_change_.call(slider_.value);
}
}
}
@@ -1782,8 +1927,9 @@ void cv_wl_window::show_image(cv::Mat const &image) {
this->show();
}
void cv_wl_window::create_trackbar(std::string const &name, int *value, int count, CvTrackbarCallback2 on_change,
int cv_wl_window::create_trackbar(std::string const &name, int *value, int count, CvTrackbarCallback2 on_change,
void *userdata) {
int ret = 0;
auto exists = this->get_trackbar(name).lock();
if (!exists) {
auto trackbar =
@@ -1792,7 +1938,9 @@ void cv_wl_window::create_trackbar(std::string const &name, int *value, int coun
);
widgets_.emplace_back(trackbar);
widget_geometries_.emplace_back(0, 0, 0, 0);
ret = 1;
}
return ret;
}
weak_ptr<cv_wl_trackbar> cv_wl_window::get_trackbar(std::string const &trackbar_name) const {
@@ -2270,6 +2418,7 @@ std::string const &cv_wl_core::get_window_name(void *handle) {
}
bool cv_wl_core::create_window(std::string const &name, int flags) {
CV_CheckTrue(display_ != nullptr, "Display is not connected.");
auto window = std::make_shared<cv_wl_window>(display_, name, flags);
auto result = windows_.insert(std::make_pair(name, window));
handles_[window.get()] = window->get_title();
@@ -2336,8 +2485,15 @@ void resizeWindowImpl(const char *name, int width, int height) {
throw_system_error("Could not get window name", errno)
}
int createTrackbar2Impl(const char *trackbar_name, const char *window_name, int *val, int count,
CvTrackbarCallback2 on_notify, void *userdata) {
CvRect cvGetWindowRect_WAYLAND(const char* name)
{
CV_UNUSED(name);
CV_LOG_ONCE_WARNING(nullptr, "Function not implemented: User cannot get window rect in Wayland");
return cvRect(-1, -1, -1, -1);
}
CV_IMPL int createTrackbar2Impl(const char *trackbar_name, const char *window_name, int *val, int count,
CvTrackbarCallback2 on_notify, void *userdata) {
if (auto window = CvWlCore::getInstance().get_window(window_name))
window->create_trackbar(trackbar_name, val, count, on_notify, userdata);
@@ -2382,11 +2538,17 @@ void setMouseCallbackImpl(const char *window_name, CvMouseCallback on_mouse, voi
}
void showImageImpl(const char *name, const CvArr *arr) {
auto cv_core = CvWlCore::getInstance();
auto window = cv_core.get_window(name);
// see https://github.com/opencv/opencv/issues/25497
/*
* To reuse the result of getInstance() repeatedly looks like better efficient implementation.
* However, it defined as static shared_ptr member variable in CvWlCore.
* If it reaches out of scope, cv_wl_core::~cv_wl_core() is called and all windows will be destroyed.
* For workaround, avoid it.
*/
auto window = CvWlCore::getInstance().get_window(name);
if (!window) {
cv_core.create_window(name, cv::WINDOW_AUTOSIZE);
if (!(window = cv_core.get_window(name)))
CvWlCore::getInstance().create_window(name, cv::WINDOW_AUTOSIZE);
if (!(window = CvWlCore::getInstance().get_window(name)))
CV_Error_(StsNoMem, ("Failed to create window: %s", name));
}
@@ -2401,11 +2563,16 @@ void setWindowTitle_WAYLAND(const cv::String &winname, const cv::String &title)
int waitKeyImpl(int delay) {
int key = -1;
auto limit = ch::duration_cast<ch::nanoseconds>(ch::milliseconds(delay));
auto limit = ch::duration_cast<ch::nanoseconds>(ch::milliseconds(delay)).count();
auto start_time = ch::duration_cast<ch::nanoseconds>(
ch::steady_clock::now().time_since_epoch())
.count();
// See https://github.com/opencv/opencv/issues/25501
// Too long sleep_for() makes no response to Wayland ping-pong mechanism
// So interval is limited to 33ms (1000ms / 30fps).
auto sleep_time_min = ch::duration_cast<ch::nanoseconds>(ch::milliseconds(33)).count();
while (true) {
auto res = CvWlCore::getInstance().display().run_once();
@@ -2424,11 +2591,11 @@ int waitKeyImpl(int delay) {
.count();
auto elapsed = end_time - start_time;
if (limit.count() > 0 && elapsed >= limit.count()) {
if (limit > 0 && elapsed >= limit) {
break;
}
auto sleep_time = 64000 - elapsed;
auto sleep_time = std::min(limit - elapsed, sleep_time_min);
if (sleep_time > 0) {
std::this_thread::sleep_for(ch::nanoseconds(sleep_time));
}