You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
6.5 KiB
197 lines
6.5 KiB
#ifndef _ROISELECTOR_HPP_ |
|
#define _ROISELECTOR_HPP_ |
|
|
|
#include "opencv2/core.hpp" |
|
#include "opencv2/highgui.hpp" |
|
#include "opencv2/imgproc.hpp" |
|
|
|
cv::Rect2d selectROI(cv::Mat img, bool fromCenter = true); |
|
cv::Rect2d selectROI(const cv::String& windowName, cv::Mat img, bool showCrossair = true, bool fromCenter = true); |
|
void selectROI(const cv::String& windowName, cv::Mat img, std::vector<cv::Rect2d> & boundingBox, bool fromCenter = true); |
|
|
|
//================================================================================================== |
|
|
|
class ROISelector |
|
{ |
|
public: |
|
cv::Rect2d select(cv::Mat img, bool fromCenter = true) |
|
{ |
|
return select("ROI selector", img, fromCenter); |
|
} |
|
|
|
cv::Rect2d select(const cv::String &windowName, cv::Mat img, bool showCrossair = true, bool fromCenter = true) |
|
{ |
|
|
|
key = 0; |
|
|
|
// set the drawing mode |
|
selectorParams.drawFromCenter = fromCenter; |
|
|
|
// show the image and give feedback to user |
|
cv::imshow(windowName, img); |
|
|
|
// copy the data, rectangle should be drawn in the fresh image |
|
selectorParams.image = img.clone(); |
|
|
|
// select the object |
|
cv::setMouseCallback(windowName, mouseHandler, (void *)&selectorParams); |
|
|
|
// end selection process on SPACE (32) ESC (27) or ENTER (13) |
|
while (!(key == 32 || key == 27 || key == 13)) |
|
{ |
|
// draw the selected object |
|
cv::rectangle(selectorParams.image, selectorParams.box, cv::Scalar(255, 0, 0), 2, 1); |
|
|
|
// draw cross air in the middle of bounding box |
|
if (showCrossair) |
|
{ |
|
// horizontal line |
|
cv::line(selectorParams.image, |
|
cv::Point((int)selectorParams.box.x, |
|
(int)(selectorParams.box.y + selectorParams.box.height / 2)), |
|
cv::Point((int)(selectorParams.box.x + selectorParams.box.width), |
|
(int)(selectorParams.box.y + selectorParams.box.height / 2)), |
|
cv::Scalar(255, 0, 0), 2, 1); |
|
|
|
// vertical line |
|
cv::line(selectorParams.image, |
|
cv::Point((int)(selectorParams.box.x + selectorParams.box.width / 2), |
|
(int)selectorParams.box.y), |
|
cv::Point((int)(selectorParams.box.x + selectorParams.box.width / 2), |
|
(int)(selectorParams.box.y + selectorParams.box.height)), |
|
cv::Scalar(255, 0, 0), 2, 1); |
|
} |
|
|
|
// show the image bouding box |
|
cv::imshow(windowName, selectorParams.image); |
|
|
|
// reset the image |
|
selectorParams.image = img.clone(); |
|
|
|
// get keyboard event, extract lower 8 bits for scancode comparison |
|
key = cv::waitKey(1) & 0xFF; |
|
} |
|
|
|
return selectorParams.box; |
|
} |
|
|
|
void select(const cv::String &windowName, cv::Mat img, std::vector<cv::Rect2d> &boundingBox, bool fromCenter = true) |
|
{ |
|
std::vector<cv::Rect2d> box; |
|
cv::Rect2d temp; |
|
key = 0; |
|
|
|
// show notice to user |
|
printf("Select an object to track and then press SPACE or ENTER button!\n"); |
|
printf("Finish the selection process by pressing ESC button!\n"); |
|
|
|
// while key is not ESC (27) |
|
for (;;) |
|
{ |
|
temp = select(windowName, img, true, fromCenter); |
|
if (key == 27) |
|
break; |
|
if (temp.width > 0 && temp.height > 0) |
|
box.push_back(temp); |
|
} |
|
boundingBox = box; |
|
} |
|
|
|
struct handlerT |
|
{ |
|
// basic parameters |
|
bool isDrawing; |
|
cv::Rect2d box; |
|
cv::Mat image; |
|
|
|
// parameters for drawing from the center |
|
bool drawFromCenter; |
|
cv::Point2f center; |
|
|
|
// initializer list |
|
handlerT() : isDrawing(false), drawFromCenter(true){}; |
|
} selectorParams; |
|
|
|
// to store the tracked objects |
|
std::vector<handlerT> objects; |
|
|
|
private: |
|
static void mouseHandler(int event, int x, int y, int flags, void *param) |
|
{ |
|
ROISelector *self = static_cast<ROISelector *>(param); |
|
self->opencv_mouse_callback(event, x, y, flags, param); |
|
} |
|
|
|
void opencv_mouse_callback(int event, int x, int y, int, void *param) |
|
{ |
|
handlerT *data = (handlerT *)param; |
|
switch (event) |
|
{ |
|
// update the selected bounding box |
|
case cv::EVENT_MOUSEMOVE: |
|
if (data->isDrawing) |
|
{ |
|
if (data->drawFromCenter) |
|
{ |
|
data->box.width = 2 * (x - data->center.x) /*data->box.x*/; |
|
data->box.height = 2 * (y - data->center.y) /*data->box.y*/; |
|
data->box.x = data->center.x - data->box.width / 2.0; |
|
data->box.y = data->center.y - data->box.height / 2.0; |
|
} |
|
else |
|
{ |
|
data->box.width = x - data->box.x; |
|
data->box.height = y - data->box.y; |
|
} |
|
} |
|
break; |
|
|
|
// start to select the bounding box |
|
case cv::EVENT_LBUTTONDOWN: |
|
data->isDrawing = true; |
|
data->box = cv::Rect2d(x, y, 0, 0); |
|
data->center = cv::Point2f((float)x, (float)y); |
|
break; |
|
|
|
// cleaning up the selected bounding box |
|
case cv::EVENT_LBUTTONUP: |
|
data->isDrawing = false; |
|
if (data->box.width < 0) |
|
{ |
|
data->box.x += data->box.width; |
|
data->box.width *= -1; |
|
} |
|
if (data->box.height < 0) |
|
{ |
|
data->box.y += data->box.height; |
|
data->box.height *= -1; |
|
} |
|
break; |
|
} |
|
} |
|
|
|
// save the keypressed characted |
|
int key; |
|
}; |
|
|
|
//================================================================================================== |
|
|
|
static ROISelector _selector; |
|
|
|
cv::Rect2d selectROI(cv::Mat img, bool fromCenter) |
|
{ |
|
return _selector.select("ROI selector", img, true, fromCenter); |
|
}; |
|
|
|
cv::Rect2d selectROI(const cv::String &windowName, cv::Mat img, bool showCrossair, bool fromCenter) |
|
{ |
|
printf("Select an object to track and then press SPACE or ENTER button!\n"); |
|
return _selector.select(windowName, img, showCrossair, fromCenter); |
|
}; |
|
|
|
void selectROI(const cv::String &windowName, cv::Mat img, std::vector<cv::Rect2d> &boundingBox, bool fromCenter) |
|
{ |
|
return _selector.select(windowName, img, boundingBox, fromCenter); |
|
} |
|
|
|
#endif // _ROISELECTOR_HPP_
|
|
|