OpenCV QT
计算点到点之间的距离
/**
* 计算点到点之间的距离
* @brief caleDistance
* @param pt1
* @param pt2
* @return
*/
static float calePoint2PointDistance(cv::Point2f pt1, cv::Point2f pt2);
float U::calePoint2PointDistance(cv::Point2f pt1, cv::Point2f pt2)
{
float distance = pow((pt1.x - pt2.x), 2) + pow((pt1.y - pt2.y), 2);
distance = sqrt(distance);
return distance;
}
计算点到直线之间的最短距离
/**
* 计算点到直线之间的最短距离
* @brief calePoint2LineDistance
* @param pt
* @param line
* @return
*/
static float calePoint2LineDistance(cv::Point2f pt, cv::Vec4f line);
float U::calePoint2LineDistance(cv::Point2f pt, cv::Vec4f line)
{
float a = line[1] - line[3];
float b = line[2] - line[0];
float c = line[0] * line[3] - line[1] * line[2];
float distance = (abs(a * pt.x + c * pt.y + c)) / (sqrt(a * a + b * b));
return distance;
}
直线拟合
多个点拟合一条最优直线
/**
* 直线拟合
* @brief fitLine
* @param points
* @return
*/
static cv::Vec4f fitLine(std::vector<cv::Point2f> points);
cv::Vec4f U::fitLine(std::vector<cv::Point2f> points)
{
cv::Vec4f line;
cv::fitLine(points, line, cv::DIST_L2, 0, 0.01, 0.01);
return line;
}
图像中指定区域填充指定颜色
/**
* 图像中指定区域填充指定颜色
* @brief fillRect
* @param src
* @param color
* @param xStart
* @param xEnd
* @param yStart
* @param yEnd
* @return
*/
static cv::Mat fillRect(cv::Mat src, cv::Vec3b color, int xStart, int xEnd, int yStart, int yEnd);
cv::Mat U::fillRect(cv::Mat src, cv::Vec3b color, int xStart, int xEnd, int yStart, int yEnd)
{
for (int i = xStart; i < xEnd; ++i)
{
for (int j = yStart; j < yEnd; ++j)
{
src.at<cv::Vec3b>(j, i) = color;
}
}
return src;
}
排序矩形4点顺序
轮廓处理可以拿到外切矩形,矩形4个点是无序的,有时候会需要使用到点坐标,但是无法定位到具体的点,在这里可以进行排序,然后取对应的点
/**
* 排序矩形4点顺序
* @brief sortRecpPoint
* @param points
* @return 左上,右上,右下,左下
*/
static std::vector<cv::Point2f> sortRecpPoint(std::vector<cv::Point2f> points);
std::vector<cv::Point2f> U::sortRecpPoint(std::vector<cv::Point2f> points)
{
//点按照x坐标从小到大排序
QList<cv::Point2f> temp;
for (int i = 0; i < points.size() ; i++)
{
int insertIndex = -1;
for (int j = 0; j < temp.size(); j++)
{
if (points[i].x < temp[j].x)
{
insertIndex = j;
continue;
}
}
if (insertIndex > 0)
{
temp.insert(insertIndex, cv::Point2f(points[i].x, points[i].y));
}
else
{
temp.append(cv::Point2f(points[i].x, points[i].y));
}
}
//根据x坐标,判断y坐标大小,确定点的位置
cv::Point2f tl;
cv::Point2f tr;
cv::Point2f bl;
cv::Point2f br;
if (temp[0].y < temp[1].y)
{
tl.x = temp[0].x;
tl.y = temp[0].y;
bl.x = temp[1].x;
bl.y = temp[1].y;
}
else
{
tl.x = temp[1].x;
tl.y = temp[1].y;
bl.x = temp[0].x;
bl.y = temp[0].y;
}
if (temp[2].y < temp[3].y)
{
tr.x = temp[2].x;
tr.y = temp[2].y;
br.x = temp[3].x;
br.y = temp[3].y;
}
else
{
tr.x = temp[3].x;
tr.y = temp[3].y;
br.x = temp[2].x;
br.y = temp[2].y;
}
//根据左上,右上,右下,左下顺序排序
std::vector<cv::Point2f> result;
result.push_back(tl);
result.push_back(tr);
result.push_back(br);
result.push_back(bl);
return result;
}
判断2条直线是否相交
2条直线是否相交,如果相交返回交点坐标
/**
* 判断2条直线是否相交
* 相交:交点
* @brief calcLine2LineIntersect
* @param line1Start
* @param line1End
* @param line2Start
* @param line2End
* @return
* Vec3d[0]=intersect?
* Vec3d[1]=intersectX
* Vec3d[2]=intersectY
*/
static cv::Vec3f calcLine2LineIntersect(cv::Point2f line1Start, cv::Point2f line1End, cv::Point2f line2Start, cv::Point2f line2End);
cv::Vec3f U::calcLine2LineIntersect(cv::Point2f line1Start, cv::Point2f line1End, cv::Point2f line2Start, cv::Point2f line2End)
{
cv::Vec4f l1(line1Start.x, line1Start.y, line1End.x, line1End.y);
cv::Vec4f l2(line2Start.x, line2Start.y, line2End.x, line2End.y);
float x1 = l1[0];
float y1 = l1[1];
float x2 = l1[2];
float y2 = l1[3];
float a1 = -(y2 - y1);
float b1 = x2 - x1;
float c1 = (y2 - y1) * x1 - (x2 - x1) * y1;
float x3 = l2[0];
float y3 = l2[1];
float x4 = l2[2];
float y4 = l2[3];
float a2 = -(y4 - y3);
float b2 = x4 - x3;
float c2 = (y4 - y3) * x3 - (x4 - x3) * y3;
// 判断结果
bool r = false;
float x0 = 0;
float y0 = 0;
// 判断相交
// l1垂直于x轴,l2倾斜于x轴
if (b1 == 0 && b2 != 0)
{
r = true;
}
// l1倾斜于x轴,l2垂直于x轴
else if ((b1 != 0) && b2 == 0)
{
r = true;
}
else if (b1 != 0 && b2 != 0 && a1 / b1 != a2 / b2)
{
r = true;
}
if (r)
{
//计算交点
x0 = (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1);
y0 = (a1 * c2 - a2 * c1) / (a2 * b1 - a1 * b2);
}
return cv::Vec3f(r, x0, y0);
}
计算三角形的夹角
一直三角形3个顶点坐标,求每个顶点对应角度
/**
* 计算三角形的夹角
* @brief caleTrigonAngle
* @param p1
* @param p2
* @param p3
* @return 顺序为传入点的顺序
*/
static cv::Vec3f caleTrigonAngle(cv::Point2f p1, cv::Point2f p2, cv::Point2f p3);
cv::Vec3f U::caleTrigonAngle(cv::Point2f p1, cv::Point2f p2, cv::Point2f p3)
{
float a = sqrt((p2.x - p3.x) * (p2.x - p3.x) + (p2.y - p3.y) * (p2.y - p3.y));
float b = sqrt((p1.x - p3.x) * (p1.x - p3.x) + (p1.y - p3.y) * (p1.y - p3.y));
float c = sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
float A = (acos((a * a - b * b - c * c) / (-2 * b * c))) * 180 / M_PI;
float B = (acos((b * b - a * a - c * c) / (-2 * a * c))) * 180 / M_PI;
float C = (acos((c * c - a * a - b * b) / (-2 * a * b))) * 180 / M_PI;
return cv::Vec3f(A, B, C);
}
统计图像中黑白像素点数量
/**
* 统计图像中黑白像素点数量
* @brief pixelCounter
* @param mat 二值图像
* @return
* Vec3i[0]=b
* Vec3i[1]=w
* Vec3i[2]=o(其它)
*/
static cv::Vec3i pixelCounter(cv::Mat src);
cv::Vec3i U::pixelCounter(cv::Mat src)
{
int countBlack = 0;
int countWhite = 0;
int countOther = 0;
//通过迭代器访问图像的像素点
cv::Mat_<uchar>::iterator itor = src.begin<uchar>();
cv::Mat_<uchar>::iterator itorEnd = src.end<uchar>();
for (; itor != itorEnd; ++itor)
{
if ((*itor) == 255)
{
//白:像素值 ptr=255
countWhite++;
}
else if ((*itor) == 0)
{
//黑:像素值 ptr=0
countBlack++;
}
else
{
countOther++;
}
}
return cv::Vec3i(countBlack, countWhite, countOther);
}
获取图像中指定区域
根据矩形裁剪图像中的一部分
/**
* 获取图像中指定区域
* @brief roi
* @param src
* @param tl 左上角
* @param w 宽
* @param h 高
* @return
*/
static cv::Mat roi(cv::Mat src, cv::Point2f tl, float w, float h);
cv::Mat U::roi(cv::Mat src, cv::Point2f tl, float w, float h)
{
cv::Rect2f roiRect(tl.x, tl.y, w, h);
cv::Mat roi = src(roiRect);
return roi;
}
cv::Mat转QImage
cv::Mat对象转为QImage对象
/**
* OpenCV Mat图像转QImage
* @brief Mat2QImage
* @param src
* @return
*/
QImage Mat2QImage(cv::Mat mat);
QImage U::Mat2QImage(cv::Mat mat)
{
const unsigned char* data = mat.data;
int width = mat.cols;
int height = mat.rows;
int bytesPerLine = static_cast<int>(mat.step);
switch (mat.type())
{
//ARGB
case CV_8UC4:
{
QImage image(data, width, height, bytesPerLine, QImage::Format_ARGB32);
return image;
}
//BGR
case CV_8UC3:
{
QImage image(data, width, height, bytesPerLine, QImage::Format_RGB888);
return image.rgbSwapped();
}
//Gray shale
case CV_8UC1:
{
QImage image(data, width, height, bytesPerLine, QImage::Format_Grayscale8);
return image;
}
//Unsupported format
default:
{
qDebug() << "Unsupported cv::Mat type:" << mat.type() << ", Empty QImage will be returned!";
return QImage();
}
}
}
图像旋转
图像旋转OpenCV有仿射变换的旋转操作,但是结果不是我们想要的,往往我们需要的旋转是保留图像所有数据,因此这个函数的结果是不同的。具体描述请参考另一篇专门介绍旋转操作:OpenCV QT 图像旋转后点还原到原图坐标
/**
* 图像旋转
* @brief rotate
* @param src
* @param angle
* @return
*/
static cv::Mat rotate(cv::Mat src, float angle);
cv::Mat U::rotate(cv::Mat src, float angle)
{
//旋转默认正角度是逆时针,与我的常用操作相反,所以我在这里取反,不是必要操作
angle = -angle;
double scale = 1.0;
//原图中心点
cv::Point2f center(src.size().width / 2.0f, src.size().height / 2.0f);
//定义旋转矩阵
cv::Mat rot = cv::getRotationMatrix2D(center, angle, scale);
//计算旋转后图像最大外切矩形
cv::Rect2f bbox = cv::RotatedRect(cv::Point2f(), src.size(), angle).boundingRect2f();
rot.at<double>(0, 2) += bbox.width / 2.0f - src.cols / 2.0f;
rot.at<double>(1, 2) += bbox.height / 2.0f - src.rows / 2.0f;
cv::Mat result;
//旋转出结果
cv::warpAffine(src, result, rot, bbox.size());
return result;
}
点绕另一点旋转后坐标
/**
* 一个点绕另中心点旋转一定角度后的坐标
* @brief rotatePoint
* @param center 中心点
* @param rotater 旋转点
* @param angle 角度,顺时针
* @return
*/
static cv::Point2f rotatePoint(cv::Point2f center, cv::Point2f rotater, float angle);
cv::Point2f U::rotatePoint(cv::Point2f center, cv::Point2f rotater, float angle)
{
//角度转弧度
float radian = angle * CV_PI / 180;
//三角函数计算坐标
float x = (rotater.x - center.x) * cos(radian) - (rotater.y - center.y) * sin(radian) + center.x ;
float y = (rotater.x - center.x) * sin(radian) + (rotater.y - center.y) * cos(radian) + center.y ;
return cv::Point2f(x, y);
}