c++ QT and OpenCV. setMouseCallBack in QLabel? - c++

I'm using the function setMouseCallback to extract the information about pixel coordinates at every mouse event. The program I created works perfectly if I use openCV windows. Precisely:
image is cv::Mat;
cv::namedWindow("Original", WINDOW_NORMAL);
cv::imshow("Original", image);
cv::setMouseCallback("Original", mouseWrapper, NULL);
where
void esempio::onMouse(int event, int x, int y, int flags, void *param)
{
//---------------------------------------------------------
// Code to read the mouse event in the identification of a point
//---------------------------------------------------------
if (event == CV_EVENT_LBUTTONDOWN)
{
std::cout << "1: " << x << "," << y << std::endl;
pp_m.x=x;
pp_m.y=y;
}
}
void mouseWrapper( int event, int x, int y, int flags, void* param )
{
esempio * mainWin = (esempio *)(param);
mainWin->onMouse(event,x,y,flags,0);
}
Now, I would like to use the same code in a QLabel created in my interface. I tried to use the function setWindowTitle to change the name of the QLabel in this way:
ui->label_show->setWindowTitle("Test");
cv::setMouseCallback("Test", mouseWrapper, NULL);
but this approach seems not adequate.
How can I indicate to the function setMouseCallback to work on the desired QLabel?
Thanks

This can be hard because:
I'm not sure that the OS is taking into account titles of child widgets, and I'm not sure that OpenCV will recognize window title of a non-top-level widget;
Qt handles child widgets internally and doesn't expose them to OS unless forced to do that;
Most importantly, OpenCV won't have a chance to call your callback because Qt manages the event loop.
I don't see why not use Qt's own means to react on mouse events.
Call ui->label_show->installEventFilter(this) in constructor of your form and implement virtual eventFilter function. In this function you can use event argument to retrieve event type and mouse coordinates (after casting to QMouseEvent).
See event filters.

Related

Creating a logic gate simulator with GTK, how to make the placing area?

Creating a logic gate simulator with GTK interface
How to make the gate's placing area?
I wanted to use GTK to benefit from system interface integration but I do not know how to make a widget for this placing area. On this area, we should be able to place gates, connect them together, zoom, move view, select, edit, delete gates, etc...
A widget named GtkFixed can receive freely other widgets and can handle signals about editing, selection, etc... like the editing area I want. But I have no idea if this is what I want.
So, my questions are the following:
Is there documentation about what I want to do ?
Am I on the right direction with this GtkFixed widget ?
If not, what should I use ? (maybe the GtkDrawingArea widget ?)
Edit: After more researches, it seams like what I need is a GtkDrawingArea but using the cairo library is like trying to kill a fly with a hammer.
The widget to use is the Gtk::DrawingArea.
Steps:
Create a class inheriting from Gtk::DrawingArea.
Override the default drawing handler by declaring a bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr); method in the inheriting class.
In this function, use the Cairo::Context to render whatever you want, here is the documentation.
This method will be called by Gtk every time it is necessary but it can be forced by calling thequeue_draw() method of the DrawingArea.
Mouse, keyboard and other type of events can be handled by either overriding the event handler or by connecting to the signal a custom function.
To receive a type of event, a flag has to be set with the add_events(eventTypeFlag) method. For the keyboard events, the DrawingArea widget has to grab focus.
Example:
class MyClass: Gtk::DrawingArea {
public:
MyClass() {
set_can_focus();
add_events(Gdk::BUTTON_PRESS_MASK | Gdk::KEY_PRESS_MASK);
}
protected:
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
cr->move_to(0, 0);
cr->rel_line_to(100, 100);
cr->set_source_rgb(1.0, 0.0, 0.0);
cr->set_line_width(6);
cr->stroke();
return true;
}
bool on_button_press_event(GdkEventButton* event) {
grab_focus();
std::cout << "click with button #" << event->button << std::endl;
return true;
}
bool on_key_press_event(GdkEventKey* event) {
std::cout << "key #" << event->keyval << " pressed" << std::endl;
return true;
}
};
Documentation:
Gtkmm and API doc
Gtk drawing area
Cairo context
Gdk events

Is there any better way to move a window?

I am working on an application with Qt Framework for desktop. Since I remove every window decoration I had to implement the main window to receive move event from when the user click on it and move the mouse around.
I tried the following code but I am not satisfied. I wonder if there is any better way to this with more elegance.
QPoint* mouseOffset; //global variable that hold distance of the cursor from
the top left corner of the window.
void ArianaApplication::mouseMoveEvent(QMouseEvent* event)
{
move(event->screenPos().x() - mouseOffset->x(),
event->screenPos().y() - mouseOffset->y());
}
void ArianaApplication::mousePressEvent(QMouseEvent*)
{
mouseOffset = new QPoint(QCursor::pos().x() - pos().x(),
QCursor::pos().y() - pos().y());
}
Would you suggest me something else?
The method is correct, but the implementation can be improved in the following points:
mouseOffset is not necessary to be a pointer, since you are creating dynamic memory unnecessarily and you have the responsibility to eliminate it.
It is not necessary to obtain each component, QPoint supports subtraction.
*.h
QPoint mouseOffset;
*.cpp
void ArianaApplication::mouseMoveEvent(QMouseEvent * event)
{
move(event->globalPos() - mouseOffset);
}
void ArianaApplication::mousePressEvent(QMouseEvent * event)
{
mouseOffset = event->globalPos() - frameGeometry().topLeft();
}

Qt mouseReleaseEvent() not trigggered?

I got a library to display pictures, lets call it PictureGLWidget, with:
class PictureGLWidget: public QGLWidget {
so PictureGLWidget extends QGLWidget. In PictureGlWidget the
void PictureGlWidget::mouseReleaseEvent(QMouseEvent* releaseEvent);
is already implemented.
I started an own project, lets say class MyMainWindow, where I just use a PictureGlWidget as a Pointerobject:
PictureGlWidget * myPictureGLWidget = new PictureGlWidget(...);
//..
layout->addWidget(myPictureGLWidget , 0, 1);
Here at this point, I already can see the PictureGlWidget and the corresponding picture in my MainwindowWidget. When I click in that PictureGlWidget, hold the mouse, I can move the picture (like 2D-scrolling), since it is much bigge than my little MainWindow.
Further on PictureGlWidget provides a function
bool PictureGlWidget::getPictureLocation(double& xPos, double& yPos);
which just tells me the Pictures center position, where I released the current clipping of the picture. Remeber my picture is much bigger than my little MainWindowWidget and thus much much more bigger than my PictureGLWidget. Imagine the picture has 4000x4000px (0,0 upper left). The PictureGLWidget is only to display lets say 800x800px. So the getPictureLocation() sets the center cooridinates of the current displayed picture part and it would return something like (400, 400), which might be somewhere in the midldle upper left corner.
I would like to grab the current displayed pictureparts (just a little part of that big picture) center position, after scrolling in that Widget and I released the mouse. I thought I do that by overwriting the
MyMainWindow::mouseReleaseEvent(QMouseEvent *event){ qDebug() << "Mouse released!"; }
method, but did not connected it anywhere yet. Currently it is not reacting on my mouseReleases and that text is not displayed.
The virtual protected methods in QWidget that you can override to react on some events don't need to be "connected". These are not Qt slots but classical functions Qt automatically calls when necessary.
As explained in Qt Event system doc, if the implementation PictureGlWidget::mouseReleaseEvent(QMouseEvent*) accept the event, it is not propagated to the parent widget. But you can install an event filter to your PictureGLWidget and receive events before they are sent to it.
PictureGlWidget * myPictureGLWidget = new PictureGlWidget(...);
layout->addWidget(myPictureGLWidget , 0, 1);
myPictureGLWidget->installEventFilter(this);
Then implements the right method in your main window:
bool MyMainWindow::eventFilter(QObject *object, QEvent *event)
{
if (object == myPictureGLWidget && event->type() == QEvent::MouseButtonRelease) {
QMouseEvent * mouseEvent = static_cast<QMouseEvent *>(event);
// Do what you need here
}
// The event will be correctly sent to the widget
return false;
// If you want to stop the event propagation now:
// return true
}
You can even decide if, after doing what you have to do, you want to stop the event, or send it to the PictureQLWidget instace (the normal behavior).
Doc:
http://doc.qt.io/qt-4.8/qobject.html#installEventFilter
http://doc.qt.io/qt-4.8/qobject.html#eventFilter
Do not forget the Q_OBJECT keyword in your MyGLwidget custom class declaration

Having time waiting in C++ programs

I read this book. For graphics I installed FLTK on my compiler, MS visual studio 2012. The machine I'm using is MS Windows 7.
I have read that book until chapter 17 and I haven't studied any method for waiting. By waiting I mean executing a statement, making the system to wait for a while, and executing second statement.
In the following there is a simple example that draws two shapes on the window. The graphics libraries used for the book are here.
For example in this code I have two circles with two different positions and different radiuses.
I want to attach first circle (c1), than wait one second, detach the c1 and attach the c2 this time. What is simplest method for waiting for one second of time (or more) please?
#include <Windows.h>
#include <GUI.h>
using namespace Graph_lib;
//---------------------------------
class Test : public Window {
public:
Test(Point p, int w, int h, const string& title):
Window(p, w, h, title),
quit_button(Point(x_max()-90,20), 60, 20, "Quit", cb_quit),
c1(Point(100,100), 50),
c2(Point(300,200), 100) {
attach(quit_button);
attach(c1);
attach(c2);
}
private:
Circle c1, c2;
Button quit_button;
void quit() { hide(); }
static void cb_quit(Address, Address pw) {reference_to<Test>(pw).quit();}
};
//------------------
int main() {
Test ts(Point(300,250), 800, 600, "Test");
return gui_main();
}
If you're using c++11:
std::this_thread::sleep_for(std::chrono::seconds(1));
Otherwise use the Windows function Sleep.
And if you want to wait without blocking the main thread you can use std::async:
#include <future>
// in your Test's constructor
std::async([&]()
{
attach(quit_button);
attach(c1);
std::this_thread::sleep_for(std::chrono::seconds(1));
attach(c2);
});
That might not be working though since I don't know much about the library you're using.
You need to use callbacks to put a delay into drawing. The add_timeout method in the FLTK allows you to set a timer that will be called once after a delay. In the callback you can attach the c2.
By sleeping in between attach(c1) and attach(c2) does not pass control back to the GUI thread to allow it to draw anything. By using the add_timeout control is passed back to the GUI thread so it can draw c1. One second later your callback will be called where you can attach c2.
// The function that will be called after the timeout. The testWindow object will be of type Test*
void callback(void* testWindow)
{
Test* t = reinterpret_cast<Test*>(testWindow);
t->doCallback();
}
class Test : public Window
{
public:
Test(Point p, int w, int h, const string& title):
Window(p, w, h, title),
quit_button(Point(x_max()-90,20), 60, 20, "Quit", cb_quit),
c1(Point(100,100), 50),
c2(Point(300,200), 100)
{
attach(quit_button);
attach(c1);
// Setup the timeout and pass a pointer to the Test window to the call back
Fl::add_timeout(1.0, callback, this);
}
// Method that is called by callback() and will attach c2
void doCallback()
{
attach(c2);
}
// rest of class
You want to use the Sleep function, which takes milliseconds:
Sleep(1000);
As you have found out, Sleep isn't the answer, because you need to let control pass back to the system while waiting, or else the window won't get updated.
What you need is a timeout. FLTK provides add_timeout:
http://www.fltk.org/doc-1.1/Fl.html#Fl.add_timeout

how to use cv::setMouseCallback

I'm trying to use cv::setMouseCallback in my c++ project. I just don't get it.
let that I habe a class Stuff how can tell this class you got a frame and run the cv::setMouseCallback on this frame here is an example of what I'm trying to do :
class Stuff{
public:
Stuff();
void setFrame(cv::Mat);
void mouse (int,int, int, int,void*);
private :
cv::Mat frame;
int key;
};
Stuff::Stuff(){}
void Stuff::setFrame(cv::Mat framex){
frame = framex;
}
int main (){
Stuff obj;
cv::Mat frame = cv::imread ("examople.jpg");
char* name;
cv::imshow(name,frame);
cv::setMouseCallback(name,obj.mouse,&frame) // I' stop here because that's exactlly what just don't work
}
this the error message that get:
Stuff::mouse : function call missing argument list; use '&Stuff::mouse ' to create a pointer to member
the real program is too big to put its code here that why I'm trying to simplify the question
you must declare a mouse handler as static inside your class. For instance, I have a dragger with a member mouser, that I want to be called. I declare an helper static void mouser, that cast the void* received and calls the member:
class dragger {
void mouser(int event, int x, int y) {
current_img = original_img.clone();
Point P(x, y);
...
}
static void mouser(int event, int x, int y, int, void* this_) {
static_cast<dragger*>(this_)->mouser(event, x, y);
}
and instance in dragger constructor in this way
dragger(string w, Mat m) :
window_id(w), status(0), original_img(m), /*black(0, 0, 0),*/ K(5, 5)
{
...
setMouseCallback(w, mouser, this);
}
...
}
First of all you need to create a named window in the main function. namedWindow( "image", 0 ); or something similar will do the job.
The mouse callback function is not associated to the frame variable but it is associated to the window. In your case it would be:
char* name = "image";
cv::namedWindow( name, 0 );
cv::setMousCallback(name, obj.mouse,&frame);
The callbacks are functions that call other functions when an event happens on a window. For the mouse, an event can be the mouse movement, the left, right or middle clicks. Here you can find a list of them, as well as good explanations.
So when this "event" takes place in the window, opencv calls the function whose name was specified in the setMouseCallback as an argument, in your case Stuff::mouse. if you define the function like this:
Stuff::mouse( int event, int x, int y, int flags, void* params )
when it is called the event variable will be filled with the value of the trigger, the x and y with the positions off the mouse on the image etc.
If you want to pass the frame in the mouse function you use it as in this question, if you consider the correction of patxiska's answer.
So with a switch you can find out what kind of event it was:
switch( event ){
case CV_EVENT_LBUTTONDOWN:
//...
break;
case CV_EVENT_RBUTTONDOWN:
//...
break;
case CV_EVENT_FLAG_CTRLKEY:
//...
break;
}
and take your frame typecasting it from void* back to a cv::Mat.
Here you can find another example of Opencv's site on how to use a mouse callback.
Hope I helped, I haven't used opencv for a while and I don't have my sample source files now. Callbacks are simplified in the Opencv GUI but that's the logic of working with any GUI. Input such as mouse and keyboard trigger events and the callback functions pass the events to the functions of your implementation.