Найти прямоугольное качество объекта с точки зрения

Я получаю изображение с камеры (откалиброванной и без искажений объектива), и мне нужно обнаружить прямоугольный объект. Маркеры являются хорошим примером. Для маркеров я проверяю количество углов, минимальный размер, контрастность и выпуклость доски. У меня была идея, как улучшить это в тех случаях, когда существует большое количество ложных прямоугольников.
Вот пример изображения:

образ

Обычно все они действительны, потому что, ничего не зная о камере, мы не можем определить, допускает ли перспектива такие формы. Я знаю размер (или, по крайней мере, соотношение) прямоугольника в реальной жизни. Поэтому у меня возникла идея, что я смогу игнорировать многие из этих фигур, просто перепроектировав их и проверив на наличие ошибок.
Например, если я использую solvePnPRansac, он не сможет сойтись, если форма невозможна. Если это не сходится, я просто игнорирую это. К сожалению, ни одна из функций решения OpenCV не позволяет проверять меня на наличие ошибок или сходимости. Я действительно нуждаюсь в некотором отношении или качестве, потому что возможно, что некоторые прямоугольники перекрываются. Например, мой объектный искатель идентифицирует эти прямоугольники:

наложение изображения

Один из трех на самом деле правильный или, по крайней мере, «лучший». Но мне нужен какой-то способ узнать, какой это. Я не могу использовать такие вещи, как длина линии из-за перспективы камеры. Так что я просто подумал, что смогу решить и посмотреть, какая из них имеет наименьшую ошибку.

На изображении нет искажений линзы, но даже если есть функции convertPnP, обычно она также позволяет передавать D.
Это вообще возможно или я что-то упустил?
Я полагаю, я мог бы попытаться взломать executePnPRansac просто для того, чтобы вернуть конвергенцию, но, может быть, есть более простой способ?

3

Решение

Я подумал, что могу сделать что-то вроде того, что делается во время калибровки с сеткой. Я могу рассчитать ошибку перепроецирования. Итак, сначала я решаю получить матрицу преобразования. Затем я преобразую точки в 3D с помощью матрицы преобразования, а затем использую projectPoints, чтобы проецировать их обратно в 2D. Затем я проверяю расстояние между исходными 2D-точками и проецируемыми 2D-точками. Это может быть использовано для качества. Объекты, которые не возможны, часто имеют 100 или более пикселей ошибки репроекции в моих изображениях, но возможные объекты имеют менее 20 пикселей. Итак, я только что сделал отсечение 25 пикселей, и, кажется, работает нормально.

Обратите внимание, что возможно больше преобразований, чем я. В моем исходном изображении, возможно, два не возможно с моей текущей камерой, но это все еще отклонило много подделок.

Если ни у кого нет идей, я приму это как ответ.

Вот некоторый код для метода, который я использую:

  //This is the object in 3D
double width = 50.0; //Object is 50mm wide
double height = 30.0; //Object is 30mm tall
cv::Mat object_points(4,3,CV_64FC1);
object_points.at<double>(0,0)=0;
object_points.at<double>(0,1)=0;
object_points.at<double>(0,2)=0;
object_points.at<double>(1,0)=width;
object_points.at<double>(1,1)=0;
object_points.at<double>(1,2)=0;
object_points.at<double>(2,0)=width;
object_points.at<double>(2,1)=height;
object_points.at<double>(2,2)=0;
object_points.at<double>(3,0)=0;
object_points.at<double>(3,1)=height;
object_points.at<double>(3,2)=0;

//Check all rectangles for error
cv::Mat image_points(4,2,CV_64FC1);
for (size_t i = 0; i < rectangles_to_test.size(); i++) {
// Get rectangle points
for (size_t c = 0; c < 4; ++c) {
image_points.at<double>(c,0) = (rectangles_to_test[i].points[c].x);
image_points.at<double>(c,1) = (rectangles_to_test[i].points[c].y);
}

// Calculate transformation matrix
cv::Mat rvec, tvec;
cv::solvePnP(object_points, image_points, M1, D1, rvec, tvec);

cv::Mat rotation;
Matrix4<double> transform;
transform.init_identity();
cv::Rodrigues(rvec, rotation);

for(size_t row = 0; row < 3; ++row) {
for(size_t col = 0; col < 3; ++col) {
transform.set(row, col, rotation.at<double>(row, col));
}
transform.set(row, 3, tvec.at<double>(row, 0));
}

// Calculate projection
std::vector<cv::Point3f> p3(4);
std::vector<cv::Point2f> p2;
Vector4<double> p = transform * Vector4<double>(0, 0, 0, 1);
p3[0] = cv::Point3f((float)p.x, (float)p.y, (float)p.z);
p = transform * Vector4<double>(width, 0, 0, 1);
p3[1] = cv::Point3f((float)p.x, (float)p.y, (float)p.z);
p = transform * Vector4<double>(width, height, 0, 1);
p3[2] = cv::Point3f((float)p.x, (float)p.y, (float)p.z);
p = transform * Vector4<double>(0, height, 0, 1);
p3[3] = cv::Point3f((float)p.x, (float)p.y, (float)p.z);

cv::projectPoints(p3, cv::Mat::zeros(1, 3, CV_64FC1), cv::Mat::zeros(1, 3, CV_64FC1), M1, D1, p2);

// Calculate reprojection error
rectangles_to_test[i].reprojection_error = 0.0;
for (size_t c = 0; c < 4; ++c) {
double dx = p2[c].x - rectangles_to_test[i].points[c].x;
double dy = p2[c].y - rectangles_to_test[i].points[c].y;
rectangles_to_test[i].reprojection_error += std::sqrt(dx*dx + dy*dy);
}
if (rectangles_to_test[i].reprojection_error > reprojection_error_threshold) {
//rectangle is no good
}
}
0

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

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

По вопросам рекламы [email protected]