я решил ее энергично, но не точно, со следующим раствором:
- Ищите линии с по крайней мере 3 зеленых точек близко соответствует линии. (тонкие красные линии на рис.)
- Продолжайте ограничивать линии: От этих линий держите их с точками только на одной стороне линии или очень близко к линии.
- Фильтрующие ограничивающие линии: от ограничивающих линий, возьмите 4 лучших из них с большинством точек на них. (жирные белые линии на рис.)
- Вычислите пересечения четырех оставшихся ограничивающих линий (ни одна из линий не является абсолютно параллельной, поэтому это приводит к 6 пересечениям, из которых мы хотим только 4).
- Из перекрестков удалите один из самых удаленных от среднего положения пересечений, пока не останется только 4 из них.
- Это 4 голубые точки.
Вы можете кормить эти 4 точки в findPerspectiveTransform
функции OpenCV, чтобы найти перспективное преобразование (ака гомография):
Point2f* srcPoints = (Point2f*) malloc(4 * sizeof(Point2f));
std::vector<Point2f> detectedCorners = CheckDet::getOuterCheckerboardCorners(srcImg);
for (int i = 0; i < MIN(4, detectedCorners.size()); i++) {
srcPoints[i] = detectedCorners[i];
}
Point2f* dstPoints = (Point2f*) malloc(4 * sizeof(Point2f));
int dstImgSize = 400;
dstPoints[0] = Point2f(dstImgSize * 1/8, dstImgSize * 1/8);
dstPoints[1] = Point2f(dstImgSize * 7/8, dstImgSize * 1/8);
dstPoints[2] = Point2f(dstImgSize * 7/8, dstImgSize * 7/8);
dstPoints[3] = Point2f(dstImgSize * 1/8, dstImgSize * 7/8);
Mat m = getPerspectiveTransform(srcPoints, dstPoints);
Для нашего примера изображения, входной и выходной findPerspectiveTranform
выглядит следующим образом:
input
(349.1, 383.9) -> (50.0, 50.0)
(588.9, 243.3) -> (350.0, 50.0)
(787.9, 404.4) -> (350.0, 350.0)
(506.0, 593.1) -> (50.0, 350.0)
output
( 1.6 -1.1 -43.8)
( 1.4 2.4 -1323.8)
( 0.0 0.0 1.0)
You ca п, то преобразование точки зрения изображения к плате координаты:
Mat plainBoardImg;
warpPerspective(srcImg, plainBoardImg, m, Size(dstImgSize, dstImgSize));
Результаты в следующем изображении:
Для моего проекта, красные точки, которые вы можете увидеть на доске в вопросе, больше не нужны, но я уверен, что их можно легко вычислить из гомографии, инвертируя его, а затем используя обратный для обратного преобразования точек (0, 0)
, (0, dstImgSize)
, (dstImgSize, dstImgSize)
и (dstImgSize, 0)
.
Алгоритм работает на удивление надежно, однако он не использует всю доступную информацию, поскольку использует только внешние точки (те, которые связаны с белыми линиями). Для дополнительной точности он не использует данные внутренних точек. Я все равно хотел бы найти еще лучшее решение, которое использует данные внутренних точек.
См. [FindChessboardCorners] (http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#findchessboardcorners) и этот [учебник] (http://docs.opencv.org/doc/tutorials/ calib3d/camera_calibration/camera_calibration.html). – beaker
@beaker, mh..Я не уверен, как это должно мне помочь. findChessboardCorners ищет quads - т. е. шахматная доска должна быть полностью пустой - вместо поиска углов. Как использовать этот учебник для моей цели? Любая его часть особенно важна для меня? –
Извините, я не читал, что вы * уже * обнаружили зеленые точки. Попробовали ли 'solvePnP/solvePnPRansac' найти преобразование между точками на идеализированной шахматной доске и найденными точками на вашем изображении? Затем вы можете применить преобразование к идеализированным угловым точкам, чтобы узнать, где они должны находиться в 2D-изображении. – beaker