OpenCV-获取图像上起点到终点间所有点坐标

OpenCV-获取图像上起点到终点间所有点坐标

最近做算法,需要用到检测图像上起点到终点间的图像灰度数据做筛选,就需要用到遍历图像起点到终点的所有像素点的坐标,在网上搜的算法要么讲的不清晰,要么算法有编译错误,所以自己重新写了一份算法,发布在这里,希望对大家有所帮助。

算法原理

算法原理比较简单,就是先得到起点到终点的直线方程,然后按照方程,从起点到终点将X方向的坐标带入方程,求解Y方向的坐标值,最后存储传出。

起点到终点的直线可以分为三种:水平直线,竖直直线,倾斜直线。对于水平直线和竖直直线,坐标点求解比较简单。
水平直线Y坐标相同,X坐标由起点到终点遍历++;
竖直直线X坐标相同,Y坐标由起点到终点遍历++;
倾斜直线,直线方程:Y = K * X + B,将起点坐标和终点坐标带入方程求解未知量K、B,得到直线方程,按照起点到终点遍历坐标点,将X方向的数据带入方程,可以求解Y方向坐标,然后传出数据即可。

算法代码


/*
函数功能:
计算起点到终点直线上的所有点坐标
输入:
cv::Point _iptPtStart					起点坐标
cv::Point _iptPTEnd						终点坐标
输出:
std::vector<cv::Point> &optVecPos		起点到终点所有点坐标
返回值:
无
*/
void CalculatePointPos(cv::Point _iptPtStart, cv::Point _iptPtEnd, std::vector<cv::Point> &_optVecPos)
{
	// step0: 检测输入参数,输出参数重置
	_optVecPos.clear();
	if (_iptPtStart == _iptPtEnd)
	{	// 如果输入和输出是同一个点,直接传出输出
		_optVecPos.push_back(_iptPtStart);
		return;
	}
	// step1: 判断点坐标,如果起点和终点的x或者y不相等,计算斜率;如果X或者Y坐标相等,直接计算结果
	std::vector<cv::Point> tempVecPoint;
	// 斜率截距式 直线公式:y = k * x + b
	float fLineSlope = 0.;	// 直线斜率
	float fLineIntercept = 0.;	// 直线截距
	if (_iptPtStart.x == _iptPtEnd.x)
	{	// 起点和终点为垂直
		if (_iptPtStart.y < _iptPtEnd.y)
		{
			for (int y = _iptPtStart.y + 1; y < _iptPtEnd.y; y++)
			{
				tempVecPoint.push_back(cv::Point(_iptPtStart.x, y));
			}
		}
		else
		{
			for (int y = _iptPtStart.y + 1; y > _iptPtEnd.y; y--)
			{
				tempVecPoint.push_back(cv::Point(_iptPtStart.x, y));
			}
		}
	}
	else if (_iptPtStart.y == _iptPtEnd.y)
	{	// 起点和终点为水平
		if (_iptPtStart.x < _iptPtEnd.x)
		{
			for (int x = _iptPtStart.x + 1; x < _iptPtEnd.x; x++)
			{
				tempVecPoint.push_back(cv::Point(x, _iptPtStart.y));
			}
		}
		else
		{
			for (int x = _iptPtStart.x + 1; x > _iptPtEnd.x; x--)
			{
				tempVecPoint.push_back(cv::Point(x, _iptPtStart.y));
			}
		}
	}
	else
	{	// 起点到终点是一条倾斜直线
		fLineSlope = (float)(_iptPtEnd.y - _iptPtStart.y) / (_iptPtEnd.x - _iptPtStart.x);
		fLineIntercept = _iptPtStart.y - _iptPtStart.x * fLineSlope;	// 截距
		// step2: 按照斜率和X坐标,每次步进为1,计算Y方向的坐标,四舍五入求Y点坐标
		if (_iptPtStart.x < _iptPtEnd.x)
		{	// 起点在终点的左侧
			for (int x = _iptPtStart.x; x < _iptPtEnd.x; x++)
			{
				float y = x * fLineSlope + fLineIntercept;
				tempVecPoint.push_back(cv::Point(x, int(y + 0.5)));
			}
		}
		else
		{	// 起点在终点的右侧
			for (int x = _iptPtStart.x; x > _iptPtEnd.x; x--)
			{
				float y = x * fLineSlope + fLineIntercept;
				tempVecPoint.push_back(cv::Point(x, int(y + 0.5)));
			}
		}
	}
	// step3: 输出点坐标
	_optVecPos = tempVecPoint;
}

测试工程代码


#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <string>
#include <vector>
#include <iostream>

using namespace std;
using namespace cv;

void CalculatePointPos(cv::Point _iptPtStart, cv::Point _iptPtEnd, std::vector<cv::Point> &_optVecPos);

int main()
{
	cv::Mat imgSrc = cv::imread("test.bmp", 0);	// 读取一张图片,也可以创建一个空图片
	
	cv::Mat imgSrc;	// 创建空白图片
	imgSrc.create(cv::Size(1000, 1000), CV_8UC1);

	cv::Mat DrawImg;
	cv::cvtColor(imgSrc, DrawImg, cv::COLOR_GRAY2BGR);
	cv::Point ptStart = cv::Point(800, 800);
	cv::Point ptEnd = cv::Point(600, 600);
	std::vector<cv::Point> vecPos;

	CalculatePointPos(ptStart, ptEnd, vecPos);

	cv::line(DrawImg, ptStart, ptEnd, cv::Scalar(0, 255, 0), 1);
	for (int i = 0; i < vecPos.size(); i++)
	{
		cv::circle(DrawImg, cv::Point(vecPos[i]), 0.1, cv::Scalar(0, 0, 255));
	}
	return 0;
}

/*
函数功能:
计算起点到终点直线上的所有点坐标
输入:
cv::Point _iptPtStart					起点坐标
cv::Point _iptPTEnd						终点坐标
输出:
std::vector<cv::Point> &optVecPos		起点到终点所有点坐标
返回值:
无
*/
void CalculatePointPos(cv::Point _iptPtStart, cv::Point _iptPtEnd, std::vector<cv::Point> &_optVecPos)
{
	// step0: 检测输入参数,输出参数重置
	_optVecPos.clear();
	if (_iptPtStart == _iptPtEnd)
	{	// 如果输入和输出是同一个点,直接传出输出
		_optVecPos.push_back(_iptPtStart);
		return;
	}
	// step1: 判断点坐标,如果起点和终点的x或者y不相等,计算斜率;如果X或者Y坐标相等,直接计算结果
	std::vector<cv::Point> tempVecPoint;
	// 斜率截距式 直线公式:y = k * x + b
	float fLineSlope = 0.;	// 直线斜率
	float fLineIntercept = 0.;	// 直线截距
	if (_iptPtStart.x == _iptPtEnd.x)
	{	// 起点和终点为垂直
		if (_iptPtStart.y < _iptPtEnd.y)
		{
			for (int y = _iptPtStart.y + 1; y < _iptPtEnd.y; y++)
			{
				tempVecPoint.push_back(cv::Point(_iptPtStart.x, y));
			}
		}
		else
		{
			for (int y = _iptPtStart.y + 1; y > _iptPtEnd.y; y--)
			{
				tempVecPoint.push_back(cv::Point(_iptPtStart.x, y));
			}
		}
	}
	else if (_iptPtStart.y == _iptPtEnd.y)
	{	// 起点和终点为水平
		if (_iptPtStart.x < _iptPtEnd.x)
		{
			for (int x = _iptPtStart.x + 1; x < _iptPtEnd.x; x++)
			{
				tempVecPoint.push_back(cv::Point(x, _iptPtStart.y));
			}
		}
		else
		{
			for (int x = _iptPtStart.x + 1; x > _iptPtEnd.x; x--)
			{
				tempVecPoint.push_back(cv::Point(x, _iptPtStart.y));
			}
		}
	}
	else
	{	// 起点到终点是一条倾斜直线
		fLineSlope = (float)(_iptPtEnd.y - _iptPtStart.y) / (_iptPtEnd.x - _iptPtStart.x);
		fLineIntercept = _iptPtStart.y - _iptPtStart.x * fLineSlope;	// 截距
		// step2: 按照斜率和X坐标,每次步进为1,计算Y方向的坐标,四舍五入求Y点坐标
		if (_iptPtStart.x < _iptPtEnd.x)
		{	// 起点在终点的左侧
			for (int x = _iptPtStart.x; x < _iptPtEnd.x; x++)
			{
				float y = x * fLineSlope + fLineIntercept;
				tempVecPoint.push_back(cv::Point(x, int(y + 0.5)));
			}
		}
		else
		{	// 起点在终点的右侧
			for (int x = _iptPtStart.x; x > _iptPtEnd.x; x--)
			{
				float y = x * fLineSlope + fLineIntercept;
				tempVecPoint.push_back(cv::Point(x, int(y + 0.5)));
			}
		}
	}
	// step3: 输出点坐标
	_optVecPos = tempVecPoint;
}

运行结果如下图所示:
算法运行结果
欢迎交流学习,有不当之处欢迎批评指正。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值