-
-
- 解PnP问题时用二维码的好处
- 二维码识别的流程
- 代码
- 最后
IDE:visual studio 2013
使用库:Eigen opencv2.4.9
文档版本:1.0
解PnP问题时,用二维码的好处
- 二维码由黑白两色组成,容易通过对图像阈值处理而发现
- 二维码具有方向性(只要设计的不为中心对称),可以更好的辅助求解位姿
- 二维码具有可识别性,即可解析二维码内部黑白块的排列顺序,从而确定该二维码是否为我们所要用的二维码
二维码识别的流程
该流程以该二维码为例
- 阈值处理,二值化操作
- 去掉二维码周围一圈,即保存为5*5的信息
- 计算5*5图像内的海明距离,和程序所设定要查找的二维码的海明距离作比较
- 若该二维码即为程序所要查找的二维码,则用opencv自带的findContours查找角点
代码
#include "Marker.h"
/************************************************构造函数****************************************************/
Marker::Marker(): id(-1)
{
}
/************************************************析构函数****************************************************/
Marker::~Marker()
{
}
/*******************************************读取二维码内含信息**********************************************/
int Marker::getMarkerId(cv::Mat &markerImage, int &nRotations)
{
assert(markerImage.rows == markerImage.cols);
assert(markerImage.type() == CV_8UC1);
cv::Mat grey = markerImage;
cv::threshold(grey, grey, 125, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
int cellSize = markerImage.rows / 7;
for (int y = 0; y<7; ++y)
{
int inc = 6;
if (y == 0 || y == 6) inc = 1;
for (int x = 0; x<7; x += inc)
{
int cellX = x * cellSize;
int cellY = y * cellSize;
cv::Mat cell = grey(cv::Rect(cellX, cellY, cellSize, cellSize));
int nZ = cv::countNonZero(cell);
if (nZ >(cellSize*cellSize) / 2)
{
return -1;
}
}
}
cv::Mat bitMatrix = cv::Mat::zeros(5, 5, CV_8UC1);
for (int y = 0; y<5; ++y)
{
for (int x = 0; x<5; ++x)
{
int cellX = (x + 1)*cellSize;
int cellY = (y + 1)*cellSize;
cv::Mat cell = grey(cv::Rect(cellX, cellY, cellSize, cellSize));
int nZ = cv::countNonZero(cell);
if (nZ>(cellSize*cellSize) / 2)
bitMatrix.at<uchar>(y, x) = 1;
}
}
cv::Mat rotations[4];
int distances[4];
rotations[0] = bitMatrix;
distances[0] = hammDistMarker(rotations[0]);
std::pair<int, int> minDist(distances[0], 0);
for (int i = 1; i<4; ++i)
{
rotations[i] = rotate(rotations[i - 1]);
distances[i] = hammDistMarker(rotations[i]);
if (distances[i] < minDist.first)
{
minDist.first = distances[i];
minDist.second = i;
}
}
nRotations = minDist.second;
if (minDist.first == 0)
{
return mat2id(rotations[minDist.second]);
}
return -1;
}
/*****************************************Maker初始的坐标数据**********************************************/
int Marker::hammDistMarker(cv::Mat bits)
{
int ids[5][5] =
{
{ 1, 1, 1, 1, 1 },
{ 1, 1, 0, 1, 1 },
{ 1, 0, 1, 0, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 0, 1, 1 }
};
int ids_1[5][5] =
{
{ 1, 1, 1, 1, 1 },
{ 1, 1, 0, 1, 1 },
{ 1, 0, 1, 1, 0 },
{ 1, 1, 0, 1, 1 },
{ 1, 1, 1, 1, 1 }
};
int dist = 0;
for (int y = 0; y<5; ++y)
{
float minSum = 1e5;
for (int p = 0; p<5; ++p)
{
float sum = 0;
for (int x = 0; x<5; ++x)
{
sum += bits.at<uchar>(y, x) == ids[p][x] ? 0 : 1;
}
if (minSum>sum)
minSum = sum;
}
dist += minSum;
}
return dist;
}
/*********************************************计算二维码信息*************************************************/
int Marker::mat2id(const cv::Mat &bits)
{
int val = 0;
for (int y = 0; y<5; ++y)
{
val <<= 1;
if (bits.at<uchar>(y, 1)) val |= 1;
val <<= 1;
if (bits.at<uchar>(y, 3)) val |= 1;
}
return val;
}
/********************************************CV图像旋转函数*************************************************/
cv::Mat Marker::rotate(cv::Mat in)
{
cv::Mat out;
in.copyTo(out);
for (int i = 0; i<in.rows; ++i)
{
for (int j = 0; j<in.cols; ++j)
{
out.at<uchar>(i, j) = in.at<uchar>(in.cols - j - 1, i);
}
}
return out;
}
/*****************************************Maker初始的坐标数据**********************************************/
bool operator<(const Marker &M1, const Marker&M2)
{
return M1.id<M2.id;
}
最后
相关文章
solvepnp三维位姿估算
PnP 单目相机位姿估计(一):初识PnP问题
PnP 单目相机位姿估计(二):solvePnP利用二维码求解相机世界坐标
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)