Ask Your Question
1

How to use Callback to draw a rectangle in a video?

asked 2012-12-14 00:03:44 -0600

David_Lavy gravatar image

updated 2012-12-14 09:10:23 -0600

Hi, I'm trying to select a rectangle in a video, but when I run my code nothing shows up; this is the code I'm using:

cv::Mat frame;
const char* src_window = "Select ROI";

int drag = 0, select_flag = 0;

cv::Point point1, point2;    
bool callback = false;
void mouseHandler(int event, int x, int y, int flags, void* param);

int main(int argc, char** argv) {

cv::VideoCapture cap;

if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
        cap.open(argc == 2 ? argv[1][0] - '0' : 0);
else if( argc == 2 )
    cap.open(argv[1]);

if( !cap.isOpened() )
{
    std::cout << "Could not initialize capturing...\n";
    return 0;
}

cap >> frame;

cv::namedWindow(src_window,CV_WINDOW_AUTOSIZE);
//cv::imshow(src_window,frame);
//cv::setMouseCallback(src_window,mouseHandler,0);

for (;;) {
    cap >> frame;
    if( frame.empty() )
            break;

    if (callback == false) {
        cv::setMouseCallback(src_window,mouseHandler,0);
    }
    else {
    cv::imshow(src_window,frame);
    }
}
    cv::waitKey(0);
    return 0;
}

void mouseHandler(int event, int x, int y, int flags, void* param)
{
if (event == CV_EVENT_LBUTTONDOWN && !drag && !select_flag)
{
    /* left button clicked. ROI selection begins */
    point1 = cv::Point(x, y);
    drag = 1;
}

if (event == CV_EVENT_MOUSEMOVE && drag && !select_flag)
{
    /* mouse dragged. ROI being selected */
    cv::Mat img1 = frame.clone();
    point2 = cv::Point(x, y);
    cv::rectangle(img1, point1, point2, CV_RGB(255, 0, 0), 3, 8, 0);
    cv::imshow(src_window, img1);
}

if (event == CV_EVENT_LBUTTONUP && drag && !select_flag)
{
    cv::Mat img2 = frame.clone();
    point2 = cv::Point(x, y);
    drag = 0;
    select_flag = 1;
    cv::imshow(src_window, img2);
    callback = true;
}
}

I don't know what can I be doing wrong. Thanks for your help.

UPDATE: Thanks to Vladislav Vinogradov now I can stream the video, but when I run the program it shows the first frame and stays like that until I click on the image, then starts the streaming, how can I modify this part so the streaming occurs since the beginning?

cap >> frame;

cv::namedWindow(src_window,CV_WINDOW_AUTOSIZE);
cv::imshow(src_window,frame);

for (;;) {
    if (callback) {
        cap >> frame;
        if( frame.empty() )
                break;
        cv::imshow(src_window,frame);
    }
    else {
        cap >> frame;
        cv::setMouseCallback(src_window,mouseHandler,0);
    }
    cv::waitKey(5);
}
edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
2

answered 2012-12-14 00:53:40 -0600

Vladislav Vinogradov gravatar image

updated 2012-12-14 01:00:18 -0600

Add cv::waitKey with some delay to the end of your for(;;) loop.

From the documentation: This function is the only method in HighGUI that can fetch and handle events, so it needs to be called periodically for normal event processing unless HighGUI is used within an environment that takes care of event processing.

cv::Mat frame;
const char* src_window = "Select ROI";

int drag = 0, select_flag = 0;

cv::Point point1, point2;
bool callback = false;

void mouseHandler(int event, int x, int y, int flags, void* param);

int main(int argc, char** argv)
{
    cv::VideoCapture cap;

    if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
        cap.open(argc == 2 ? argv[1][0] - '0' : 0);
    else if( argc == 2 )
    cap.open(argv[1]);

    if( !cap.isOpened() )
    {
        std::cout << "Could not initialize capturing...\n";
        return 0;
    }

    cap >> frame;

    cv::namedWindow(src_window,CV_WINDOW_AUTOSIZE);
    cv::imshow(src_window,frame);
    cv::setMouseCallback(src_window,mouseHandler,0);

    for (;;)
    {
        if(callback)
        {
            cap >> frame;
            if( frame.empty() )
                    break;
            cv::imshow(src_window,frame);
        }

        cv::waitKey(5);
    }

    return 0;
}

void mouseHandler(int event, int x, int y, int flags, void* param)
{
    if (event == CV_EVENT_LBUTTONDOWN && !drag && !select_flag)
    {
        /* left button clicked. ROI selection begins */
        point1 = cv::Point(x, y);
        drag = 1;
    }

    if (event == CV_EVENT_MOUSEMOVE && drag && !select_flag)
    {
        /* mouse dragged. ROI being selected */
        cv::Mat img1 = frame.clone();
        point2 = cv::Point(x, y);
        cv::rectangle(img1, point1, point2, CV_RGB(255, 0, 0), 3, 8, 0);
        cv::imshow(src_window, img1);
    }

    if (event == CV_EVENT_LBUTTONUP && drag && !select_flag)
    {
        cv::Mat img2 = frame.clone();
        point2 = cv::Point(x, y);
        drag = 0;
        select_flag = 1;
        cv::imshow(src_window, img2);
        callback = true;
    }
}
edit flag offensive delete link more

Comments

Thank you, I modified the last part of the main function and I indicated it in my post as an update, my problem now is, when I run the program it doesn't stream the video since the beginning, it only shows the first frame until I click on the screen, and then streams the video, how can I modify so it can stream the video right after I run my program?

David_Lavy gravatar imageDavid_Lavy ( 2012-12-14 09:04:40 -0600 )edit

Hi..! When I am trying to run this program. I am getting the following error. OpenCV Error: Assertion failed (size.width>0 && size.height>0) in cv::imshow, file E:\VR_Lab\opencv\modules\highgui\src\window.cpp, line 304 Can you help in solving this problem?

saravanan14 gravatar imagesaravanan14 ( 2017-05-28 16:14:46 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2012-12-14 00:03:44 -0600

Seen: 13,090 times

Last updated: Dec 14 '12