如何在OpenCV中找到菱形角并从中裁剪出一个较小的矩形?

时间:2013-07-10 21:33:09

标签: c++ opencv crop rect corner-detection

我愿意从扭曲的图像中得到一个简单的矩形。

例如,一旦我有这种图像: enter image description here

...我想裁剪下面矩形对应的区域: enter image description here

...但我的代码正在提取这个更大的框架: enter image description here

我的代码如下:

int main(int argc, char** argv) {
    cv::Mat img = cv::imread(argv[1]);

    // Convert RGB Mat to GRAY
    cv::Mat gray;
    cv::cvtColor(img, gray, CV_BGR2GRAY);

    // Store the set of points in the image before assembling the bounding box
    std::vector<cv::Point> points;
    cv::Mat_<uchar>::iterator it = gray.begin<uchar>();
    cv::Mat_<uchar>::iterator end = gray.end<uchar>();
    for (; it != end; ++it) {
        if (*it)
            points.push_back(it.pos());
    }

    // Compute minimal bounding box
    Rect box = cv::boundingRect(cv::Mat(points));

    // Draw bounding box in the original image (debug purposes)
    cv::Point2f vertices[4];
    vertices[0] = Point2f(box.x, box.y  +box.height);
    vertices[1] = Point2f(box.x, box.y);
    vertices[2] = Point2f(box.x+ box.width, box.y);
    vertices[3] = Point2f(box.x+ box.width, box.y   +box.height);

    for (int i = 0; i < 4; ++i) {
        cv::line(img, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA);
        cout << "==== vertices (x, y) = " << vertices[i].x << ", " << vertices[i].y << endl;
    }

    cv::imshow("box", img);
    cv::imwrite("box.png", img);

    waitKey(0);

    return 0;
}

有关如何找到菱形边角并尝试将它们缩小为较小矩形的任何想法吗?

1 个答案:

答案 0 :(得分:2)

这个问题最困难的部分实际上是找到菱形角的位置。如果实际使用中的图像与您的示例有很大不同,则查找菱形边角的此特定过程可能无效。一旦达到此目的,您可以根据它们与图像中心的距离对角点进行排序。您正在寻找最接近图像中心的点。

首先,您必须为排序比较定义一个仿函数(如果您可以使用C ++ 11,这可能是一个lambda):

struct CenterDistance
{
    CenterDistance(cv::Point2f pt) : center(pt){}

    template <typename T> bool operator() (cv::Point_<T> p1, cv::Point_<T> p2) const
    {
        return cv::norm(p1-center) < cv::norm(p2-center);
    }

    cv::Point2f center;
};

这实际上不需要是模板operator(),但它可以适用于任何cv::Point_类型。

对于您的示例图像,图像角定义非常明确,因此您可以像FAST一样使用角点检测器。然后,您可以使用cv::convexHull()来获取外部点,这些点应该只是菱形角。

int main(int argc, char** argv) {
    cv::Mat img = cv::imread(argv[1]);

    // Convert RGB Mat to GRAY
    cv::Mat gray;
    cv::cvtColor(img, gray, CV_BGR2GRAY);

    // Detect image corners
    std::vector<cv::KeyPoint> kpts;
    cv::FAST(gray, kpts, 50);

    std::vector<cv::Point2f> points;
    cv::KeyPoint::convert(kpts, points);
    cv::convexHull(points, points);

    cv::Point2f center(img.size().width / 2.f, img.size().height / 2.f);
    CenterDistance centerDistance(center);
    std::sort(points.begin(), points.end(), centerDistance);

    //The two points with minimum distance are what we want
    cv::rectangle(img, points[0], points[1], cv::Scalar(0,255,0));

    cv::imshow("box", img);
    cv::imwrite("box.png", img);

    cv::waitKey(0);

    return 0;
}

请注意,您可以使用cv::rectangle()而不是从行构建绘制的矩形。结果是:

Box result