使用opencv測量點到線的距離

首先通過鼠標操作在圖片上隨機點兩個點,創建一條直線。然後點第三個點,該點到直線的距離就出來了。
由於鼠標點擊有誤差,所以測的距離有誤差,還請大佬指點!

#include "opencv2/opencv.hpp"
#include <iostream>
#include <math.h>

using namespace cv;
using namespace std;

//定義一個計算兩點距離的函數
double getDistance(CvPoint pointO, CvPoint pointA)
{
	double distance;
	distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
	distance = sqrtf(distance);
	return distance;
}

//定義一個將長整形轉換成字符串型的函數
string convertToString(long d)
{
	ostringstream os;
	if (os << d)
		return os.str();
	return "invalid conversion";
}


//定義全局變量
static Mat img_src;

static Point point1 = Point(0, 0);//第一個點(x1,y1)
static Point point2 = Point(0, 0);//第二個點(x2,y2)
static Point point3 = Point(0, 0);//第三個點(x3,y3)
static Point point4;//第四個點(x4,y4)
static Point point5;

static Point mouse_dot;
static string window_name = "image";

//定義鼠標事件函數
static void onMouse(int event, int x, int y, int, void*)
{
	if (CV_EVENT_LBUTTONDOWN == event)//鼠標左鍵按下
	{
		mouse_dot = Point(x, y);//接收按下點的座標並賦值
		if (point1.x == 0 && point1.y == 0)//接收第一個點
		{
			point1 = mouse_dot;
			point5 = mouse_dot;
			
		}
		else if (point2.x == 0 && point2.y == 0)//接收第二個點
		{
			point2 = mouse_dot;
			point5 = mouse_dot;
			
		}
		else if (point3.x == 0 && point3.y == 0)//接收第三個點
		{
			point3 = mouse_dot;
			point5 = mouse_dot;
			
		}
	}
	
	else if (CV_EVENT_LBUTTONUP == event)//鼠標左鍵鬆開
	{
		circle(img_src, point5, 2, Scalar(255, 0, 0), 2);//用小圓標誌按下的點
		imshow("output", img_src);//並將小圓點顯示在圖片上
		
		//如果在圖片上點擊完3個點後,將進行下面的操作
		if (point3.x != 0 && point3.y != 0)
		{
			//計算點point3到直線的距離,並求出直線上的點point4,連接point3和point4,並輸出兩點距離
			//建立直線方程Ax+By+C=0-->(y2-y1)*x+(x1-x2)*y+(x2*y1-x1*y2)=0
			long A = point2.y - point1.y;
			long B = point1.x - point2.x;
			long C = point2.x*point1.y - point1.x*point2.y;
			long a = A*A;
			long b = B*B;

			//直線距離公式D=|A*x3+B*y3+C|/sqrt(A^2+B^2)
			long w = (A*point3.x + B*point3.y + C);
			if (w < 0) w = 0 - w;//取絕對值
			long D = long(w / sqrt(a + b));

			//利用公式x4=(x3*B^2-AB*y3-AC)/(A^2+B^2)和A*x4+B*y4+C=0求出直線上的點
			point4.x = int((b*point3.x - A*B*point3.y - A*C) / (a + b));
			if (B == 0) point4.y = point3.y;//排除分母爲零的情況
			else point4.y = int((-C - A*point4.x) / B);
			circle(img_src, point4, 2, Scalar(255, 0, 0), 2);
			line(img_src, point3, point4, Scalar(255, 255, 255), 1, 8);

			//確定文字在圖片上顯示的位置,並輸出文字
			int wedth = (point3.x + point4.x) / 2 ;
			int height = (point3.y + point4.y) / 2-10;
			string length = convertToString(D);
			putText(img_src, length, Point(wedth, height), CV_FONT_HERSHEY_SIMPLEX, 0.4, Scalar(255, 255, 255), 1, 8);
			
			//把所有的點歸零,才能進行下次操作
			point1 = Point(0, 0);
			point2 = Point(0, 0);
			point3 = Point(0, 0);
			point4 = Point(0, 0);
			
			imshow("output", img_src);//刷新圖片
			waitKey(0);
		}
		
		//點擊了兩個點後,用直線連接兩個點
		else if (point2.x != 0 && point2.y != 0)
		{
			line(img_src, point1, point2, Scalar(255, 255, 255), 1, 8);
			imshow("output", img_src);//刷新圖片
		}
			
	}
}



int main(int argc, char** argv)
{
	img_src = imread("zheng_lingjian2.png");
	if (!img_src.data)
	{
		cout << "the image isn't loaded..." << endl;
		return -1;
	}

	namedWindow(window_name, CV_WINDOW_AUTOSIZE);
	setMouseCallback(window_name, onMouse, 0);//執行鼠標操作,且只能在image窗口進行鼠標點擊

	while (true)
	{
		imshow(window_name, img_src);
		int c = waitKey(0);
		//通過Esc鍵退出程序
		if ((c & 255) == 27)
		{ 
			destroyAllWindows();
			cout << "Exiting ...\n";
			break;
		}
	}

	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章