Setting Roi with Mouse from a Rectangle on a Video

Setting ROI with mouse from a rectangle on a video

You were almost there. One problem though: case CV_EVENT_RBUTTONUP needs to break, and I would also add a break on default case.

The following code sets the ROI, performs a simple grayscale processing on it and then copies the processed ROI back to the original image.

For testing purposes I changed your code to use my camera instead of loading a file.

Output:

Sample Image

Code:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#include <cv.h>
#include <highgui.h>

using namespace cv;
using namespace std;

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

bool destroy=false;
CvRect box;
bool drawing_box = false;

void draw_box(IplImage* img, CvRect rect)
{
cvRectangle(img, cvPoint(box.x, box.y), cvPoint(box.x+box.width,box.y+box.height),
cvScalar(0,0,255) ,2);

CvRect rect2=cvRect(box.x,box.y,box.width,box.height);
//cvSetImageROI(image, rect2); //here I wanted to set the drawn rect as ROI
}

// Implement mouse callback
void my_mouse_callback( int event, int x, int y, int flags, void* param )
{
IplImage* frame = (IplImage*) param;

switch( event )
{
case CV_EVENT_MOUSEMOVE:
{
if( drawing_box )
{
box.width = x-box.x;
box.height = y-box.y;
}
}
break;

case CV_EVENT_LBUTTONDOWN:
{
drawing_box = true;
box = cvRect( x, y, 0, 0 );
}
break;

case CV_EVENT_LBUTTONUP:
{
drawing_box = false;
if( box.width < 0 )
{
box.x += box.width;
box.width *= -1;
}

if( box.height < 0 )
{
box.y += box.height;
box.height *= -1;
}

draw_box(frame, box);
}
break;

case CV_EVENT_RBUTTONUP:
{
destroy=true;
}
break;

default:
break;
}
}

int main()
{
const char* name = "Box Example";
cvNamedWindow( name );
box = cvRect(0,0,1,1);

CvCapture* capture = cvCaptureFromCAM(0);
if (!capture)
{
printf("!!! Failed cvCaptureFromCAM\n");
return 1;
}

IplImage* image = cvQueryFrame(capture);
if (!image)
{
printf("!!! Failed cvQueryFrame #1\n");
return 2;
}

IplImage* temp = cvCloneImage(image);

// Set up the callback
cvSetMouseCallback(name, my_mouse_callback, (void*) image);

// Main loop
while( 1 )
{
if (destroy)
{
cvDestroyWindow(name); break;
}
cvCopyImage(image, temp);

if (drawing_box)
draw_box(temp, box);

cvMoveWindow(name, 200, 100);
cvShowImage(name, temp);

if (cvWaitKey(15) == 27)
break;
}

cvReleaseImage(&temp);
cvDestroyWindow(name);

cvNamedWindow("Example2", CV_WINDOW_AUTOSIZE);
cvMoveWindow("Example2", 150, 150);

// Retrieve a single frame from the device and set the ROI
IplImage* vid_frame = cvQueryFrame(capture);
if (!vid_frame)
{
printf("!!! Failed cvQueryFrame #2\n");
return 2;
}

cvSetImageROI(vid_frame, box);

// Allocate space for a single-channel ROI (to store grayscale frames)
IplImage* gray_roi = cvCreateImage(cvSize(box.width, box.height), IPL_DEPTH_8U, 1);
IplImage* rgb_roi = cvCreateImage(cvSize(box.width, box.height), IPL_DEPTH_8U, 3);

while(1)
{
if (!vid_frame)
{
vid_frame = cvQueryFrame(capture);
if (!vid_frame)
{
printf("!!! Failed cvQueryFrame #3\n");
break;
}
}

draw_box(vid_frame, box);

// Set ROI and perform some processing (in this case, converting the ROI to grayscale)
cvSetImageROI(vid_frame, box);
cvCvtColor(vid_frame, gray_roi, CV_BGR2GRAY);
//cvShowImage("Example2", gray_roi);

/* At this point gray_roi has the size of thei ROI and contains the processed image.
* For fun, we copy the processed image back to the original image and display it on the screen!
*/
cvCvtColor(gray_roi, rgb_roi, CV_GRAY2BGR);

// As the ROI is still set, cvCopy is affected by it
cvCopy(rgb_roi, vid_frame, NULL);

// Now reset the ROI so cvShowImage displays the full image
cvResetImageROI(vid_frame);
cvShowImage("Example2", vid_frame);

char c = cvWaitKey(33);
if( c == 27 ) break;

vid_frame = NULL;
}
cvSaveImage("processed.jpg", vid_frame);

cvReleaseImage(&gray_roi);
cvReleaseImage(&rgb_roi);
cvReleaseCapture( &capture );
cvDestroyWindow( "Example2" );

return 0;
}

Setting ROI with mouse from a rectangle on a video

You were almost there. One problem though: case CV_EVENT_RBUTTONUP needs to break, and I would also add a break on default case.

The following code sets the ROI, performs a simple grayscale processing on it and then copies the processed ROI back to the original image.

For testing purposes I changed your code to use my camera instead of loading a file.

Output:

Sample Image

Code:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#include <cv.h>
#include <highgui.h>

using namespace cv;
using namespace std;

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

bool destroy=false;
CvRect box;
bool drawing_box = false;

void draw_box(IplImage* img, CvRect rect)
{
cvRectangle(img, cvPoint(box.x, box.y), cvPoint(box.x+box.width,box.y+box.height),
cvScalar(0,0,255) ,2);

CvRect rect2=cvRect(box.x,box.y,box.width,box.height);
//cvSetImageROI(image, rect2); //here I wanted to set the drawn rect as ROI
}

// Implement mouse callback
void my_mouse_callback( int event, int x, int y, int flags, void* param )
{
IplImage* frame = (IplImage*) param;

switch( event )
{
case CV_EVENT_MOUSEMOVE:
{
if( drawing_box )
{
box.width = x-box.x;
box.height = y-box.y;
}
}
break;

case CV_EVENT_LBUTTONDOWN:
{
drawing_box = true;
box = cvRect( x, y, 0, 0 );
}
break;

case CV_EVENT_LBUTTONUP:
{
drawing_box = false;
if( box.width < 0 )
{
box.x += box.width;
box.width *= -1;
}

if( box.height < 0 )
{
box.y += box.height;
box.height *= -1;
}

draw_box(frame, box);
}
break;

case CV_EVENT_RBUTTONUP:
{
destroy=true;
}
break;

default:
break;
}
}

int main()
{
const char* name = "Box Example";
cvNamedWindow( name );
box = cvRect(0,0,1,1);

CvCapture* capture = cvCaptureFromCAM(0);
if (!capture)
{
printf("!!! Failed cvCaptureFromCAM\n");
return 1;
}

IplImage* image = cvQueryFrame(capture);
if (!image)
{
printf("!!! Failed cvQueryFrame #1\n");
return 2;
}

IplImage* temp = cvCloneImage(image);

// Set up the callback
cvSetMouseCallback(name, my_mouse_callback, (void*) image);

// Main loop
while( 1 )
{
if (destroy)
{
cvDestroyWindow(name); break;
}
cvCopyImage(image, temp);

if (drawing_box)
draw_box(temp, box);

cvMoveWindow(name, 200, 100);
cvShowImage(name, temp);

if (cvWaitKey(15) == 27)
break;
}

cvReleaseImage(&temp);
cvDestroyWindow(name);

cvNamedWindow("Example2", CV_WINDOW_AUTOSIZE);
cvMoveWindow("Example2", 150, 150);

// Retrieve a single frame from the device and set the ROI
IplImage* vid_frame = cvQueryFrame(capture);
if (!vid_frame)
{
printf("!!! Failed cvQueryFrame #2\n");
return 2;
}

cvSetImageROI(vid_frame, box);

// Allocate space for a single-channel ROI (to store grayscale frames)
IplImage* gray_roi = cvCreateImage(cvSize(box.width, box.height), IPL_DEPTH_8U, 1);
IplImage* rgb_roi = cvCreateImage(cvSize(box.width, box.height), IPL_DEPTH_8U, 3);

while(1)
{
if (!vid_frame)
{
vid_frame = cvQueryFrame(capture);
if (!vid_frame)
{
printf("!!! Failed cvQueryFrame #3\n");
break;
}
}

draw_box(vid_frame, box);

// Set ROI and perform some processing (in this case, converting the ROI to grayscale)
cvSetImageROI(vid_frame, box);
cvCvtColor(vid_frame, gray_roi, CV_BGR2GRAY);
//cvShowImage("Example2", gray_roi);

/* At this point gray_roi has the size of thei ROI and contains the processed image.
* For fun, we copy the processed image back to the original image and display it on the screen!
*/
cvCvtColor(gray_roi, rgb_roi, CV_GRAY2BGR);

// As the ROI is still set, cvCopy is affected by it
cvCopy(rgb_roi, vid_frame, NULL);

// Now reset the ROI so cvShowImage displays the full image
cvResetImageROI(vid_frame);
cvShowImage("Example2", vid_frame);

char c = cvWaitKey(33);
if( c == 27 ) break;

vid_frame = NULL;
}
cvSaveImage("processed.jpg", vid_frame);

cvReleaseImage(&gray_roi);
cvReleaseImage(&rgb_roi);
cvReleaseCapture( &capture );
cvDestroyWindow( "Example2" );

return 0;
}

How to select ROI in video input in OpenCV (Python)?

If I understand you correctly you simply want to cut a region from the image right?
This should work:

def crop_image(image, x, y, width, height):
"""
image: a cv2 frame
x, y, width, height: the region to cut out
"""
return image[y:y + height, x:x + width]

Remember that cv2 images are simply numpy arrays. Cutting a region of the image is the same as extracting the indexes from the array.

Click mouse and draw fixed rectangle at mouse position in Video (python_opencv)

The problem is that you fixed a point of the rectangle and the other point follows the mouse. In your code it would be here:

cv2.rectangle(frame,(200,cy),(cx,128),(0,0,255),0)

Now, it will depend how the rectangle will be, is the point where you click the top left point? if it is then it should be something like:

cv2.rectangle(frame,(cx,cy),(cx + 80, cy +80),(0,0,255),0)

This example will be for a 80 x 80 rectangle.... In your code this will happen when you click.

However, your code has a lot of unused code... I would do something like this:

import numpy as np
import cv2

drawing = False
point = (0,0)

def mouse_drawing(event, x, y, flags, params):
global point, drawing
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
point= (x, y)

cap = cv2.VideoCapture(0)
cv2.namedWindow("Frame")
cv2.setMouseCallback("Frame", mouse_drawing)

while True:
_, frame = cap.read()
if drawing :
cv2.rectangle(frame,point,(point[0]+80, point[1]+80),(0,0,255),0)

cv2.imshow("Frame", frame)
key = cv2.waitKey(25)
if key== 13:
print('done')
elif key == 27:
break

cap.release()
cv2.destroyAllWindows()

If you want the rectangle to follow your mouse after you clicked and to stop following after you release the button, change in the code I supplied before the mouse_drawing function like this:

def mouse_drawing(event, x, y, flags, params):
global point, drawing
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
point = (x, y)
elif event == cv2.EVENT_MOUSEMOVE:
if drawing is True:
point = (x, y)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
point = (x, y)

Python OpenCV select ROI on video/stream while its playing

You can't use cv2.selectROI() in that case because the function is blocking, i.e. it stops the execution of your program until you have selected your region of interest (or cancelled it).

To achieve what you want you will need to handle the selection of the ROI yourself. Here is a short example of how you can do that, using two left-clicks to define the ROI and a right-click to erase it.

import cv2, sys

cap = cv2.VideoCapture(sys.argv[1])
cv2.namedWindow('Frame', cv2.WINDOW_NORMAL)

# Our ROI, defined by two points
p1, p2 = None, None
state = 0

# Called every time a mouse event happen
def on_mouse(event, x, y, flags, userdata):
global state, p1, p2

# Left click
if event == cv2.EVENT_LBUTTONUP:
# Select first point
if state == 0:
p1 = (x,y)
state += 1
# Select second point
elif state == 1:
p2 = (x,y)
state += 1
# Right click (erase current ROI)
if event == cv2.EVENT_RBUTTONUP:
p1, p2 = None, None
state = 0

# Register the mouse callback
cv2.setMouseCallback('Frame', on_mouse)

while cap.isOpened():
val, frame = cap.read()

# If a ROI is selected, draw it
if state > 1:
cv2.rectangle(frame, p1, p2, (255, 0, 0), 10)
# Show image
cv2.imshow('Frame', frame)

# Let OpenCV manage window events
key = cv2.waitKey(50)
# If ESCAPE key pressed, stop
if key == 27:
cap.release()

OpenCV C++ set ROI from a rectangular area

this blog post is very good in explaining how to find a rectangle with the hough transform and it has also some c++ code with opencv 2 API.

The approach is to find lines, intersect them, and find the rectangle. In your case you will have more rectangles and so it's a little bit more complicated..

But if you manage to obtain such image.. why don't use just some threshold and find connected regions (aka blob)?



Related Topics



Leave a reply



Submit