基于变化角的Opencv C++裁剪图像

Posted

技术标签:

【中文标题】基于变化角的Opencv C++裁剪图像【英文标题】:Opencv C++ Crop Image based on changing corners 【发布时间】:2017-06-29 22:11:10 【问题描述】:

我问了一个类似的问题,但对于使用 numpy 数组 Opencv Python Crop Image Using Numpy Array 的 python。我正在寻找根据其角落裁剪图像。这是一张展示目标的照片。

我有 python 代码可以解决问题,但需要将其转换为 C++。以下分别是我的工作python代码和部分C++代码。

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++ 代码:

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;

【问题讨论】:

在 Python 中,xy 只是整数列表。鉴于此,为什么在 C++ 中将它们设为 Points 向量的向量? 除此之外,您已经快到了——使用整数向量,在循环内插入每个轮廓中每个点的所有 x 和 y 坐标。然后是std::minmax_element,最后是输入图像上的operator(),以提取子区域。试一试。 @DanMašek 向量点向量的向量是我工作太多,大脑被炸了。我的想法是 x 和 y 是一个列表,所以我把它变成了一个向量,因为我添加了轮廓,所以我添加了它们的类型,导致混乱。您能否详细说明如何为每个计数器中的每个点插入 x 和 y 坐标。另一部分完全有道理。感谢您的帮助! 假设你有std::vector&lt;int&gt; x,那么你可以简单地做x.push_back(contours[i][j].x);y 的类似情况。 【参考方案1】:
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;

试试这个

【讨论】:

感谢您的建议。不幸的是,当我尝试您的代码时,我得到:没有可行的从 'std::__1::__wrap_iter' 到 'int' 的转换所以我将整数更改为 vector::iterator x1 等,但后来我无法得到矩形,因为它需要整数。【参考方案2】:
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;

【讨论】:

以上是关于基于变化角的Opencv C++裁剪图像的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV C++(五)----图像平滑

从二进制图像OpenCV C++中裁剪文本

使用 OpenCV c++ 裁剪图像

如何在 OpenCV c++ 中从图像中裁剪特定的矩形部分(ROI)

OpenCV基础(11)基于OpenCV的边缘检测

网友提问(透视变化)