OpenCV Essentials
上QQ阅读APP看书,第一时间看更新

Selecting regions

Many computer vision applications require to focus interest inside local regions of the images. In that case, it is a very useful user tool to select the desired regions of interest (ROI). In the drawRs example, we show how to select, with the mouse, rectangular regions in the image to locally increase the contrast inside these regions (as shown in the following screenshot). For better control over region selection, we implement a click-and-drag behavior to reshape the rectangular boundary of each region.

Selecting regions

Output image with increased contrast in some rectangular regions

For the sake of simplicity, only the code corresponding to the function callback for mouse events is shown, since the rest is quite similar in the previous examples. The code is as follows:

void cbMouse(int event, int x, int y, int flags, void* userdata) {

  static Point p1, p2; // Static vars hold values between calls
  static bool p2set = false;

  if (event == EVENT_LBUTTONDOWN) { // Left mouse button pressed
      p1 = Point(x, y); // Set orig. point
      p2set = false;
  } else if (event == EVENT_MOUSEMOVE &&
flags == EVENT_FLAG_LBUTTON) {
      if (x >orig_img.size().width) // Check out of bounds
          x = orig_img.size().width;
      else if (x < 0)
          x = 0;
      if (y >orig_img.size().height) // Check out of bounds
          y = orig_img.size().height;
      else if (y < 0)
          y = 0;
      p2 = Point(x, y); // Set final point
      p2set = true;
orig_img.copyTo(tmp_img); // Copy orig. to temp. image
rectangle(tmp_img, p1, p2, Scalar(0, 0, 255));
      imshow(IN_WIN, tmp_img); // Draw temporal image with rect.
  } else if (event == EVENT_LBUTTONUP && p2set) {
Mat submat = orig_img(Rect(p1, p2)); // Set region
      submat.convertTo(submat, -1, 2.0); // Compute contrast
   rectangle(orig_img, p1, p2, Scalar(0, 0, 255));
      imshow(IN_WIN, orig_img); // Show image
  }
  return;
}

The callback function declares static its local variables, so they maintain their values between calls. The variables, p1 and p2, store the points for defining the rectangular region of interest, and p2set holds the Boolean (bool) value that indicates if point p2 is set. When p2set is true, a new selected region can be drawn and its new values computed.

The mouse callback function handles the following events:

  • EVENT_LBUTTONDOWN: This button is also called left button down. The initial position (p1) is set to Point(x, y) where the event occurs. Also, the p2set variable is set to false.
  • EVENT_MOUSEMOVE && EVENT_FLAG_LBUTTON: Move the mouse with the left button down. First, the boundaries should be checked so that we can correct coordinates and avoid errors just in case the final point is out of the window. Then, the temporal p2 point is set to the final position of the mouse and p2set is set to true. Finally, a temporal image is shown in the window with the rectangle drawn on it.
  • EVENT_LBUTTONUP: This button is also called left button up and is valid only if p2set is true.The final region is selected. Then a subarray can be pointed in the original image for further computation. After that, a rectangle around the final region is drawn in the original image and the result is shown into the application window.

Next, we take a closer look at the code:

  • Size Mat::size() const: Returns the matrix size (Size(cols, rows)): This function is used to get the bounds of the image (orig_img) as follows:
    if (x > orig_img.size().width) // Check out bounds
                x = orig_img.size().width;
            else if (x < 0)
                x = 0;
            if (y > orig_img.size().height) // Check out bounds
                y = orig_img.size().height;

    Since Mat::size() returns a Size object, we can access its members width and height to obtain the greatest values for x and y in the image (orig_img) and compare those with the coordinates where the mouse event take place.

  • void Mat::copyTo(OutputArray m) const: This method copies the matrix to another one, reallocating new size and type if it is needed. Before copying, the following method invokes:
    m.create(this->size(), this->type());
    

    In the example, the following method is employed to make a temporal copy of the original image:

    orig_img.copyTo(tmp_img); // Copy orig. to temp. image

    The rectangle that defines the selected region is drawn over this temporal image.

  • void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0): This function draws a rectangle defined by points pt1 and pt2 over the image (img) with the specified color, thickness, and lineType. In the code example, this function is used twice. First, to draw a red (Scalar(0, 0, 255)) rectangle on the temporal image (tmp_img) around the selected area, and then to draw the boundaries of the final selected region in the original image (orig_img):
    rectangle(tmp_img, p1, p2, Scalar(0, 0 ,255));
    //…
    rectangle(orig_img, p1, p2, Scalar(0, 0, 255));
  • Mat::Mat(const Mat& m, const Rect& roi): The constructor takes a submatrix of m limited by the rectangle (roi) that represents a region of interest in the image stored in m. This constructor is applied, in the code example, to get the rectangular region whose contrast has to be converted:
    Mat submat = orig_img(Rect(p1, p2));// Set subarray on orig. image