КАК Найти уголки ромба в OpenCV и вырезать из него меньший прямоугольник?

Я хочу получить простой прямоугольник из искаженного изображения.

Например, когда у меня есть этот вид изображения:
введите описание изображения здесь

… Я хотел бы обрезать область, соответствующую следующему прямоугольнику:
введите описание изображения здесь

… НО мой код извлекает этот большой кадр:
введите описание изображения здесь

Мой код показан ниже:

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;
}

Любые идеи о том, как найти углы ромба и попытаться уменьшить их до меньшего прямоугольника?

2

Решение

Самая сложная часть этой проблемы — это нахождение мест расположения углов ромба. Если изображения в вашем фактическом использовании сильно отличаются от вашего примера, эта конкретная процедура поиска углов ромба может не сработать. Как только это будет достигнуто, вы можете отсортировать угловые точки по их расстоянию от центра изображения. Вы ищете точки, ближайшие к центру изображения.

Во-первых, вы должны определить функтор для сравнения сортировки (это может быть лямбда, если вы можете использовать C ++ 11):

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() вместо того, чтобы построить нарисованный прямоугольник из линий. Результат:

Результат коробки

2

Другие решения

Других решений пока нет …