0

I asked a similar question but for python using a numpy array Opencv Python Crop Image Using Numpy Array. I am looking to crop an image based on its corners. Here is a photo to demonstrate the goal. Cropping Goal

I have python code that does the trick but need to convert it to C++. The following is my working python code and partial C++ code respectively.

def crop(self,image):
    grayed = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    (_,thresh) = cv2.threshold(grayed,1,255,cv2.THRESH_BINARY)
    result, contours, _= cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    x, y = [], []
    for i in range(len(contours)):
        for j in range(len(contours[i])):
            x.append(contours[i][j][0][0])
            y.append(contours[i][j][0][1])
    x1, x2, y1, y2 = min(x), max(x), min(y), max(y)
    cropped = image[y1:y2, x1:x2]
    return cropped

C++ Code:

Mat crop(Mat image){
    Mat cropped, grayed, thresh, result;
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    cvtColor(image, grayed, CV_BGR2GRAY);
    threshold( grayed, thresh, 1, 255,THRESH_BINARY);
    findContours( thresh, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);

    std::vector<int> x,y;
    cout << contours.size() << endl;
    for(int i=0; i < contours.size();i++){
        for(int j = 0; j < contours.at(i).size();j++){
            x.push_back(contours.at(i).at(j).x);
            y.push_back(contours.at(i).at(j).y);
        }
    }

   cout << x.size() << endl;
   cout << y.size() << endl;

    vector<int>::iterator it = max(begin(x), end(x));
    int x1 = (*it);
    it = max(begin(x), end(x));
    int x2 = *it;
    it = min(begin(y), end(y));
    int y1 = *it;
    it = max(begin(y), end(y));
    int y2 = *it;

    cout << x1 << "   " << x2 << "    " << y1 << "     " << y2 << endl;

    Rect rect (x1,y1,x2-x1,y2-y1);
    cropped = image(rect);
    return cropped;
}
C.Radford
  • 882
  • 4
  • 13
  • 31
  • In Python, `x` and `y` are simply lists of integers. Given that, why make them vectors of vectors of vectors of Points in C++? – Dan Mašek Jun 29 '17 at 22:14
  • Other than that you're almost there -- use vectors of integers, inside the loops insert all the x and y coordinates for each point in each contour. Then something like `std::minmax_element`, and finally `operator()` on the input image to extract the subregion. Give it a shot. – Dan Mašek Jun 29 '17 at 22:28
  • @DanMašek The vectors of vectors of vectors of points was me working to much and brain getting fried. My thinking was x and y is a list so I made it a vector and since I was adding contours I added their type resulting in the chaos. Could you elaborate more on how to insert the x and y coordinates for each point in each counter possibly. The other part makes total sense. Thanks for you help! – C.Radford Jun 29 '17 at 22:36
  • Assuming you've got `std::vector x`, then you could simply do `x.push_back(contours[i][j].x);`. Similar thing for `y`. – Dan Mašek Jun 29 '17 at 22:39

2 Answers2

0
cv::Mat crop(cv::Mat image){
  cv::Mat cropped, grayed, thresh, result;
  std::vector < std::vector < cv::Point >> contours;
  std::vector<cv::Vec4i> hierarchy;
  cvtColor(image, grayed, cv::COLOR_BGR2GRAY);
  threshold(grayed, thresh, 1, 255, cv::THRESH_BINARY);
  findContours(result, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
  std::vector<int> x, y;

  for (int i = 0; i < contours.size(); i++){
      for (int j = 0; j <= contours.at(i).size(); j++){
          x.push_back(contours.at(i).at(j).x);
          y.push_back(contours.at(i).at(j).y);
      }
  }
  int x1 = std::min_element(x.begin(), x.end());
  int x2 = std::max_element(x.begin(), x.end());
  int y1 = std::min_element(y.begin(), y.end());
  int y2 = std::max_element(y.begin(), y.end())

  cv::Rect rect(x1, y1, x2 - x1, y2 - y1);
  cropped = image(rect);

  return cropped;
}

Try this

BatyaGG
  • 674
  • 1
  • 7
  • 19
  • Thanks for the suggestion. Unfortunately when I tried your code I get: No viable conversion from 'std::__1::__wrap_iter' to 'int' So i changed the ints to vector::iterator x1 ect but then I cant get the rectangle as it requires ints. – C.Radford Jun 30 '17 at 03:12
0
Mat crop(Mat image){
Mat cropped, grayed, thresh, result;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
cvtColor(image, grayed, CV_BGR2GRAY);
threshold( grayed, thresh, 1, 255,THRESH_BINARY);
findContours( thresh, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);

vector<int> x,y;
for(int i=0; i < contours.size();i++){
    for(int j = 0; j < contours.at(i).size();j++){
        x.push_back(contours[i][j].x);
        y.push_back(contours[i][j].y);
    }
}

auto xVals = std::minmax_element(x.begin(), x.end());
auto yVals = std::minmax_element(y.begin(), y.end());

Rect rect (*xVals.first,*yVals.first,(*xVals.second)-(*xVals.first),(*yVals.second)-(*yVals.first));
cropped = image(rect);
return cropped;

}

C.Radford
  • 882
  • 4
  • 13
  • 31