mirror of
https://github.com/opencv/opencv.git
synced 2024-11-27 20:50:25 +08:00
Merge pull request #25551 from Kumataro:fix25550
highgui: wayland: fix to pass highgui test #25551 Close #25550 - optimize Mat to XRGB8888 conversion with OpenCV functions - extend to support CV_8S/16U/16S/32F/64F - extend to support 1/4 channels - fix to update value timing - initilize slider_ value if value is not nullptr. - Update user-ptr value and call on_change() function if cv_wl_trackbar::draw() is not called. - Update usage of WAYLAND/XDG macro to avoid reference undefined macro. - Update documents ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
1d9a4120fa
commit
8dc9ff5624
@ -366,6 +366,11 @@ for image display). **waitKey(25)** will display a frame and wait approximately
|
||||
press (suitable for displaying a video frame-by-frame). To remove the window, use cv::destroyWindow.
|
||||
|
||||
@note [__Windows Backend Only__] Pressing Ctrl+C will copy the image to the clipboard. Pressing Ctrl+S will show a dialog to save the image.
|
||||
@note [__Wayland Backend Only__] Supoorting format is extended.
|
||||
- If the image is 8-bit signed, the pixels are biased by 128. That is, the
|
||||
value range [-128,127] is mapped to [0,255].
|
||||
- If the image is 16-bit signed, the pixels are divided by 256 and biased by 128. That is, the
|
||||
value range [-32768,32767] is mapped to [0,255].
|
||||
|
||||
@param winname Name of the window.
|
||||
@param mat Image to be shown.
|
||||
@ -394,6 +399,8 @@ CV_EXPORTS_W void resizeWindow(const String& winname, const cv::Size& size);
|
||||
@param winname Name of the window.
|
||||
@param x The new x-coordinate of the window.
|
||||
@param y The new y-coordinate of the window.
|
||||
|
||||
@note [__Wayland Backend Only__] This function is not supported by the Wayland protocol limitation.
|
||||
*/
|
||||
CV_EXPORTS_W void moveWindow(const String& winname, int x, int y);
|
||||
|
||||
@ -404,6 +411,8 @@ The function setWindowProperty enables changing properties of a window.
|
||||
@param winname Name of the window.
|
||||
@param prop_id Window property to edit. The supported operation flags are: (cv::WindowPropertyFlags)
|
||||
@param prop_value New value of the window property. The supported flags are: (cv::WindowFlags)
|
||||
|
||||
@note [__Wayland Backend Only__] This function is not supported.
|
||||
*/
|
||||
CV_EXPORTS_W void setWindowProperty(const String& winname, int prop_id, double prop_value);
|
||||
|
||||
@ -421,6 +430,8 @@ The function getWindowProperty returns properties of a window.
|
||||
@param prop_id Window property to retrieve. The following operation flags are available: (cv::WindowPropertyFlags)
|
||||
|
||||
@sa setWindowProperty
|
||||
|
||||
@note [__Wayland Backend Only__] This function is not supported.
|
||||
*/
|
||||
CV_EXPORTS_W double getWindowProperty(const String& winname, int prop_id);
|
||||
|
||||
@ -431,6 +442,8 @@ The function getWindowImageRect returns the client screen coordinates, width and
|
||||
@param winname Name of the window.
|
||||
|
||||
@sa resizeWindow moveWindow
|
||||
|
||||
@note [__Wayland Backend Only__] This function is not supported by the Wayland protocol limitation.
|
||||
*/
|
||||
CV_EXPORTS_W Rect getWindowImageRect(const String& winname);
|
||||
|
||||
|
@ -98,6 +98,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);
|
||||
|
@ -436,6 +436,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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,10 +285,10 @@ private:
|
||||
&handle_pointer_axis, &handle_pointer_frame,
|
||||
&handle_pointer_axis_source, &handle_pointer_axis_stop,
|
||||
&handle_pointer_axis_discrete,
|
||||
#if WL_POINTER_AXIS_VALUE120_SINCE_VERSION >= 8
|
||||
#ifdef WL_POINTER_AXIS_VALUE120_SINCE_VERSION
|
||||
&handle_axis_value120,
|
||||
#endif
|
||||
#if WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION >= 9
|
||||
#ifdef WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION
|
||||
&handle_axis_relative_direction,
|
||||
#endif
|
||||
};
|
||||
@ -284,7 +337,7 @@ private:
|
||||
CV_UNUSED(discrete);
|
||||
}
|
||||
|
||||
#if WL_POINTER_AXIS_VALUE120_SINCE_VERSION >= 8
|
||||
#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);
|
||||
@ -294,7 +347,7 @@ private:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION >= 9
|
||||
#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);
|
||||
@ -686,7 +739,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;
|
||||
|
||||
@ -723,10 +776,10 @@ private:
|
||||
struct xdg_toplevel *xdg_toplevel_;
|
||||
struct xdg_toplevel_listener xdgtop_listener_{
|
||||
&handle_toplevel_configure, &handle_toplevel_close,
|
||||
#if XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION >= 4
|
||||
#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
|
||||
&handle_toplevel_configure_bounds,
|
||||
#endif
|
||||
#if XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION >= 5
|
||||
#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
|
||||
&handle_toplevel_wm_capabilities,
|
||||
#endif
|
||||
};
|
||||
@ -775,7 +828,7 @@ private:
|
||||
|
||||
static void handle_toplevel_close(void *data, struct xdg_toplevel *surface);
|
||||
|
||||
#if XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION >= 4
|
||||
#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)
|
||||
{
|
||||
@ -786,7 +839,7 @@ private:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION >= 5
|
||||
#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
|
||||
static void
|
||||
handle_toplevel_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities)
|
||||
{
|
||||
@ -1527,13 +1580,7 @@ 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_GRAY2BGR);
|
||||
image_ = bgr.clone();
|
||||
} else {
|
||||
image_ = image.clone();
|
||||
}
|
||||
image_ = image.clone();
|
||||
image_changed_ = true;
|
||||
}
|
||||
|
||||
@ -1642,6 +1689,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 {
|
||||
@ -1657,6 +1709,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1666,6 +1724,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1836,8 +1900,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 =
|
||||
@ -1846,7 +1911,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 {
|
||||
@ -2324,6 +2391,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();
|
||||
@ -2402,6 +2470,13 @@ CV_IMPL void cvResizeWindow(const char *name, int width, int height) {
|
||||
throw_system_error("Could not get window name", errno)
|
||||
}
|
||||
|
||||
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 cvCreateTrackbar(const char *name_bar, const char *window_name, int *value, int count,
|
||||
CvTrackbarCallback on_change) {
|
||||
CV_UNUSED(name_bar);
|
||||
@ -2416,10 +2491,11 @@ CV_IMPL int cvCreateTrackbar(const char *name_bar, const char *window_name, int
|
||||
|
||||
CV_IMPL int cvCreateTrackbar2(const char *trackbar_name, const char *window_name, int *val, int count,
|
||||
CvTrackbarCallback2 on_notify, void *userdata) {
|
||||
int ret = 0;
|
||||
if (auto window = CvWlCore::getInstance().get_window(window_name))
|
||||
window->create_trackbar(trackbar_name, val, count, on_notify, userdata);
|
||||
ret = window->create_trackbar(trackbar_name, val, count, on_notify, userdata);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CV_IMPL int cvGetTrackbarPos(const char *trackbar_name, const char *window_name) {
|
||||
|
@ -48,6 +48,16 @@ inline void verify_size(const std::string &nm, const cv::Mat &img)
|
||||
{
|
||||
EXPECT_NO_THROW(imshow(nm, img));
|
||||
EXPECT_EQ(-1, waitKey(200));
|
||||
|
||||
// see https://github.com/opencv/opencv/issues/25550
|
||||
// Wayland backend is not supported getWindowImageRect().
|
||||
string framework;
|
||||
EXPECT_NO_THROW(framework = currentUIFramework());
|
||||
if(framework == "WAYLAND")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Rect rc;
|
||||
EXPECT_NO_THROW(rc = getWindowImageRect(nm));
|
||||
EXPECT_EQ(rc.size(), img.size());
|
||||
|
Loading…
Reference in New Issue
Block a user