zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C++工程通过opencv找到自己定义的矩形中的两平行线的距离

OpencvC++ 通过 自己 定义 工程 找到 距离
2023-09-27 14:25:49 时间

1 C++工程,opencv310以上为了使用 createLineSegmentDetector()函数

Detector.h

#pragma once

//#include "opencv2/opencv.hpp"
#include <opencv.hpp>

#include <math.h>
#include <fstream>
#include <string>

#include <cstdio>
#include<algorithm>
#include<deque>
#ifndef PI
#define PI 3.141592653
#endif

using namespace cv;
using namespace std;






// 功能:1)检测缝隙(1D);2)检测曲率半径(3D);3)检测支架正确与否(有无检测);4)检测三维位姿

enum DetectorType
{
	DT_Exist = 1,
	DT_YesOrNO = 2,
	DT_Gap = 3,
	DT_Position = 4,
};

// 放通用的函数,可能用于多个detecor ****************************************************
class Detector
{
public:
	DetectorType	m_Type;

public:
	Detector(DetectorType type);
	~Detector();
};

struct GapParameter
{
	bool			m_bDetected = false;
	double			m_dDistance = FLT_MAX;
	double			m_dParallelism = FLT_MAX;
	double          m_dAngle = FLT_MAX;
};

struct PositionParameter
{
	bool			m_bDetected = false;
	vector<Point3f>			m_vPositions;

};




// ****************************************************
//检测缝隙
class GapDetector : public Detector
{
private:
	vector<GapParameter>	m_Paramters;
	int						m_nTh;

public:
	__declspec(dllexport) bool GetResult(int index, double& distance, double& parallelism, double& angle);

private:
	double Distance_line2line(const Vec4f& line1, const Vec4f& line2);
	double Angle_line2line(const Vec4f& line1, const Vec4f& line2);
	double Angle2_line2line(const Vec4f& line1, const Vec4f& line2);
	double distance2line(const Point2f& point, const Vec4f& FittingLine);
	void calculateParameter(const vector<Vec4f>& Line_Attributes, double& distance, double& parallelism, double& angle);//加角度
	void FindTrueLines(vector<Vec4f> &lines_std, vector<Vec4f> &Line_Attributes);
	bool FindLinesInRect(Mat& parent, Mat& image, Rect& rc, GapParameter& gp);

public:
	__declspec(dllexport) void Run(Mat& image, vector<Rect>& rects);
	__declspec(dllexport) void Run(Mat& image);

	__declspec(dllexport) GapDetector();
	__declspec(dllexport) ~GapDetector();
public:
};

//************************************************************************************************************

extern "C" __declspec(dllexport) void UpdateImage(void* image_data, __int32 width, __int32 height, int counts, char* rects);

Detector.h

#include "Detector.h"
#include<cmath>
#include<ctime>
// ****************************************************
Detector::Detector(DetectorType type) : m_Type(type)
{

}

Detector::~Detector()
{

}

// ****************************************************
//检测缝隙
GapDetector::GapDetector() : Detector(DT_Gap), m_nTh(100)
{

}

GapDetector::~GapDetector()
{

}

// 仅仅找两个物体非常近,并且边线接近平行的情况
void GapDetector::FindTrueLines(vector<Vec4f> &lines_std, vector<Vec4f> &Line_Attributes)
{
	vector<Vec4f> Line_Attribute;
	// 将所有直线排序

	multimap<float, size_t> length2index;
	for (size_t i = 0; i < lines_std.size(); i++)
	{
		Vec4i line_j = lines_std[i];

		float Length1 = sqrt(float((line_j[2] - line_j[0])*(line_j[2] - line_j[0]) + (line_j[3] - line_j[1])*(line_j[3] - line_j[1])));

		if (Length1 > m_nTh)						// 变成一个GapDetector类内部可调参数
			length2index.insert(pair<float, size_t>(Length1, i));
	}

	int index = 0;
	for (multimap<float, size_t>::reverse_iterator iter = length2index.rbegin(); iter != length2index.rend(); iter++, index++)
	{
		Line_Attribute.push_back(lines_std[(*iter).second]);
	}

	// 找直线之中最靠外面的两条 ***************************************************************
	if (Line_Attribute.size() > 2)
	{
		vector<Point2f> Point;
		vector<Point2f> MidPoint;
		Vec4f FittingLine;

		//找到所有直线端点作为拟合直线的输入点集
		for (int i = 0; i < Line_Attribute.size(); i++)
		{
			//直线端点
			Point2f P1;
			P1.x = Line_Attribute[i][0];
			P1.y = Line_Attribute[i][1];

			Point2f P2;
			P2.x = Line_Attribute[i][2];
			P2.y = Line_Attribute[i][3];

			//直线中点
			Point2f PM((Line_Attribute[i][0] + Line_Attribute[i][2]) / 2, (Line_Attribute[i][1] + Line_Attribute[i][3]) / 2);

			Point.push_back(P1);
			Point.push_back(P2);
			MidPoint.push_back(PM);
		}


		fitLine(Point, FittingLine, DIST_L2, 0, 0.01, 0.01);

		multimap<float, size_t> length2fitline;		// 将直线按中点到拟合直线的距离排序
		for (size_t i = 0; i < MidPoint.size(); i++)
		{

			float Length1 = (float)distance2line(MidPoint[i], FittingLine);

			length2fitline.insert(pair<float, size_t>(Length1, i));
		}

		int index2 = 0;
		for (multimap<float, size_t>::reverse_iterator iter = length2fitline.rbegin(); iter != length2fitline.rend(), index2 <= 1; iter++, index2++)
		{
			Line_Attributes.push_back(Line_Attribute[(*iter).second]);
		}
	}
	else
	{
		for (int i = 0; i < Line_Attribute.size(); i++)
		{
			Line_Attributes.push_back(Line_Attribute[i]);
		}
	}
}

//点到直线的距离
double GapDetector::distance2line(const Point2f& point, const Vec4f& FittingLine)
{
	Point2f dir(FittingLine[0], FittingLine[1]);

	float length = sqrt(pow(dir.x, 2) + pow(dir.y, 2));
	dir.x /= length;
	dir.y /= length;

	Point2f o2p(point.x - FittingLine[2], point.y - FittingLine[3]);

	float proj = o2p.dot(dir);

	Point2f o2proj(o2p.x - proj * dir.x, o2p.y - proj * dir.y);

	float ret = sqrt(pow(o2proj.x, 2) + pow(o2proj.y, 2));

	return ret;
}

//线到线的距离
double GapDetector::Distance_line2line(const Vec4f& line1, const Vec4f& line2)
{
	Point2f P((line1[0] + line1[2]) / 2, (line1[1] + line1[3]) / 2);			//定义直线中点

	Vec4f __line2(line2[2] - line2[0], line2[3] - line2[1], line2[0], line2[1]);

	return distance2line(P, __line2);
}


//两线之间的平行度或角度
double GapDetector::Angle_line2line(const Vec4f& line1, const Vec4f& line2)
{
	Vec4f __line2(line2[2] - line2[0], line2[3] - line2[1], line2[0], line2[1]);

	Point2f p0(line1[0], line1[1]), p1(line1[2], line1[3]);

	float value = (float)fabs(distance2line(p0, __line2) - distance2line(p1, __line2));

	Point2f dir1(line1[2] - line1[0], line1[3] - line1[1]);
	float length1 = sqrt(pow(dir1.x, 2) + pow(dir1.y, 2));
	dir1.x /= length1;
	dir1.y /= length1;

	Point2f dir2(line2[2] - line2[0], line2[3] - line2[1]);
	float length2 = sqrt(pow(dir2.x, 2) + pow(dir2.y, 2));
	dir2.x /= length2;
	dir2.y /= length2;

	if (dir1.dot(dir2) < 0)
	{
		dir2.x = -dir2.x;
		dir2.y = -dir2.y;
	}

	if (dir1.y < 0)
	{
		dir1.x = -dir1.x;
		dir1.y = -dir1.y;

		dir2.x = -dir2.x;
		dir2.y = -dir2.y;
	}

	Point2f p2o1(line2[2] - line1[2], line2[3] - line1[3]);
	if (dir1.cross(p2o1) > 0)
	{
		if (dir1.cross(dir2) > 0)
			return value;
		else
			return -value;

	}
	else
	{
		if (dir1.cross(dir2) > 0)
			return -value;
		else
			return value;
	}
}


//计算角度
double GapDetector::Angle2_line2line(const Vec4f& line1, const Vec4f& line2)
{
	Vec4f __line2(line2[2] - line2[0], line2[3] - line2[1], line2[0], line2[1]);

	Point2f p0(line1[0], line1[1]), p1(line1[2], line1[3]);

	//float value = (float)fabs(distance2line(p0, __line2) - distance2line(p1, __line2));

	Point2f dir1(line1[2] - line1[0], line1[3] - line1[1]);
	float length1 = sqrt(pow(dir1.x, 2) + pow(dir1.y, 2));
	Point2f dir2(line2[2] - line2[0], line2[3] - line2[1]);
	float length2 = sqrt(pow(dir2.x, 2) + pow(dir2.y, 2));

	float k1 = dir1.y / dir1.x, k2 = dir2.y / dir2.x;
	float n = fabs((k1-k2)/(1+k1*k2));
	float value = atan(n);
	/*dir1.x /= length1;
	dir1.y /= length1;*/

	//dir2.x /= length2;
	//dir2.y /= length2;
	return value;

}


//计算两线之间的距离或角度
void GapDetector::calculateParameter(const vector<Vec4f>& Line_Attributes, double& distance, double& parallelism, double& angle)//加角度
{
	/*FileStorage files;
	files.open("0.10mm.yml", FileStorage::APPEND);*/
	char dist[32];
	char para[32];
	char angl[32];
	//一条直线的中点到相邻直线的距离
	for (int j = 0; j < Line_Attributes.size() - 1; j++)
	{
		distance = Distance_line2line(Line_Attributes[j], Line_Attributes[j + 1]);
		parallelism = Angle_line2line(Line_Attributes[j], Line_Attributes[j + 1]);
		angle = Angle2_line2line(Line_Attributes[j], Line_Attributes[j + 1]);



		sprintf_s(dist, "%.2f", distance);

		sprintf_s(para, "%.2f", parallelism);

		//留两位小数 sprintf_s(
		sprintf_s(angl, "%.2f", angle);

		cout << "Distance: " << dist << ", Parallelism: " << para << ", Parallelism: " << angl << endl;
		/*files << "Distance" << dist << "Parallelism" << para;*/
	}


}

//筛选直线
bool GapDetector::FindLinesInRect(Mat& parent, Mat& image, Rect& rc, GapParameter& gp)
{
	bool bRet = false;
	Mat image_roi;
	image_roi = image.clone();

	// 2. 检测所有的直线 ------------------------------------------------------------------
	vector<Vec4f> lines_std;
	Ptr<LineSegmentDetector> ls = createLineSegmentDetector(LSD_REFINE_NONE);
	ls->detect(image_roi, lines_std);

	// 3. 筛选直线 -----------------------------------------------------------------------
	vector<Vec4f> Line_Attributes;						// 筛选出来的直线
	if (lines_std.size() >= 2)							// 超过2条直线时继续
	{
		//#ifdef _DEBUG
		for (size_t j = 0; j < lines_std.size(); j++)
		{
			Point center(cvRound(lines_std[j][0]) + rc.x, cvRound(lines_std[j][1]) + rc.y);
			Point center2(cvRound(lines_std[j][2]) + rc.x, cvRound(lines_std[j][3]) + rc.y);
			line(parent, center, center2, Scalar(255, 0, 255), 1.5, CV_AA);
		}/**/
		//#endif
		// 3.1. 搜索找到最长的两条直线
		FindTrueLines(lines_std, Line_Attributes);

		if (Line_Attributes.size() > 0)
		{
			// 3.2. 计算距离和平行度

			calculateParameter(Line_Attributes, gp.m_dDistance, gp.m_dParallelism, gp.m_dAngle)/*加角度*/;

			//#ifdef _DEBUG
			// 3.3. 在图像上显示找到的直线
			for (size_t j = 0; j < Line_Attributes.size(); j++)
			{
				Point center(cvRound(Line_Attributes[j][0]) + rc.x, cvRound(Line_Attributes[j][1]) + rc.y);
				Point center2(cvRound(Line_Attributes[j][2]) + rc.x, cvRound(Line_Attributes[j][3]) + rc.y);
				line(parent, center, center2, Scalar(0, 255, 0), 1.5, CV_AA);
			}
			//#endif
		}

		bRet = true;
	}

	return bRet;
}

//获取结果
bool GapDetector::GetResult(int index, double& distance, double& parallelism, double& angle)/*角度/)*/
{
	if (index > m_Paramters.size())
		return false;

	distance = m_Paramters[index].m_dDistance;
	parallelism = m_Paramters[index].m_dParallelism;
	angle = m_Paramters[index].m_dAngle;
	//加角度

	return m_Paramters[index].m_bDetected;
}

//在指定框中检测直线
void GapDetector::Run(Mat& image, vector<Rect>& rects)
{
	cvtColor(image, image, CV_BGR2RGB);
	flip(image, image, 1);
	flip(image, image, -1);

	// 0. 转为灰度图 ----------------------------------------------------------------------
	Mat image_roi;
	cvtColor(image, image_roi, CV_BGR2GRAY);

#ifdef _DEBUG
	for (size_t i = 0; i < rects.size(); i++)
	{
		// 1. 取得矩形区域中的图像 ------------------------------------------------------------
		rectangle(image, rects[i], Scalar(0, 0, 255));		//画矩形
	}
#endif
	for (size_t i = 0; i < rects.size(); i++)
	{
		GapParameter gp;
		m_Paramters.push_back(gp);

		// 1. 取得矩形区域中的图像 ------------------------------------------------------------
		Mat image_rect = image_roi(rects[i]);
		m_Paramters[i].m_bDetected = FindLinesInRect(image, image_rect, rects[i], m_Paramters[0]);
	}

	//flip(image, image, 1);
	cvtColor(image, image, CV_BGR2RGB);
}

//在图片中检测直线
void GapDetector::Run(Mat& image)
{
	cvtColor(image, image, CV_BGR2RGB);
	flip(image, image, 1);
	//	flip(image, image, -1);

	// 0. 转为灰度图 ----------------------------------------------------------------------
	Mat image_roi;
	cvtColor(image, image_roi, CV_BGR2GRAY);

	Rect rc(0, 0, image.cols, image.rows);

	GapParameter gp;
	m_Paramters.push_back(gp);

	m_Paramters[0].m_bDetected = FindLinesInRect(image, image, rc, m_Paramters[0]);

	flip(image, image, 1);
	cvtColor(image, image, CV_BGR2RGB);
}


// ******************************************************************************************************

ProduceDll.cpp

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <opencv.hpp>

#include "Detector.h"
#include <math.h>

using namespace std;
using namespace cv;

Point coord;//储存初始坐标
Rect sqart;//储存矩形框的起始坐标以及长度和宽度
bool draw;
bool flag = 0;//这个标志位是用在如果要将矩形标定的部分单独显示在一个窗口时使用的
Mat image, frame;
double  LinesDis(void* data);

void onMouse(int event, int x, int y, int flags, void *param);//鼠标点击函数声明


//设置函数  
extern "C" __declspec(dllexport)
double  LinesDistance(void* image_data, double para[3])
{
	//VideoCapture capture(0);//测试摄像头有没有打开,/*
	//capture.set(CAP_PROP_FRAME_WIDTH, 2592);
	//capture.set(CAP_PROP_FRAME_HEIGHT, 1944);

	Mat image(480, 640, CV_8UC3);

	memcpy(image.data, image_data, 640 * 480 * 3 * sizeof(uchar));
	cvtColor(image, image, CV_BGR2RGB);
	flip(image, image, 1);
	flip(image, image, -1);


	if (image.empty())
	{
		//	cout << "Unable to load Image" << endl;
		return 1;
	}

	namedWindow("Mouse", 1);

	//调用鼠标回调函数
	setMouseCallback("Mouse", onMouse, 0);

	Rect rect(40, 40, 40, 40);

	GapDetector gd;
	vector<Rect> g_rects;


	//将矩形框得到矩形区域用另一个窗口显示
	if ((flag == 1) && sqart.height > 0 && sqart.width > 0)
	{
		rect = Rect(sqart.x, sqart.y, sqart.width, sqart.height);

	}




	if (sqart.height > 15 && sqart.width > 15)
	{
		rect = Rect(rect.x + 5, rect.y + 5, rect.width - 10, rect.height - 10);
	}

	/*Mat img2 = image.clone();*/
	Mat image_roi = image(rect);

	g_rects.push_back(rect);

	rectangle(image, sqart, Scalar(0, 0, 255), 1);



	gd.Run(image, g_rects);
	imshow("Mouse", image);
	double dist, plis, angle;//加角度
	gd.GetResult(0, dist, plis, angle);//加角度
	para[0] = dist;
	para[1] = plis;
	para[2] = angle;


}

extern "C" __declspec(dllexport)
void  Quit()
{
	destroyAllWindows();

}

//鼠标点击函数
void onMouse(int event, int x, int y, int flags, void *param)
{

	//这个if必须放在switch之前
	if (draw)
	{
		//用MIN得到左上点作为矩形框的其实坐标,如果不加这个,画矩形时只能向一个方向进行
		sqart.x = MIN(x, coord.x);
		sqart.y = MIN(y, coord.y);
		sqart.width = abs(coord.x - x);
		sqart.height = abs(coord.y - y);
		//防止矩形区域超出图像的范围
		/*sqart &= Rect(0, 0, image.cols, image.rows);*/
	}

	switch (event)
	{
	case CV_EVENT_LBUTTONDOWN:
		coord = Point(x, y);
		sqart = Rect(x, y, 0, 0);
		draw = true;
		break;

	case CV_EVENT_LBUTTONUP:
		draw = false;
		flag = 1;
		break;
	}
}


2 unity调用 

工程设置

LocalCamera.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Runtime.InteropServices;

using UnityEngine.UI;
public class LocalCamera : MonoBehaviour
{
    private Texture2D viewTexture;
    private WebCamTexture viewTextureCamera;

    public int CameraID;
    public double Distance;
    public double Parallelism;
    public double Ang;
    public byte[] imageData;


    public GameObject tt;
    public GameObject pp;


    double[] a=new double[3];

//	[DllImport("OpencvDLL")]
	[DllImport("D:\\Michael Wang\\SC\\2019\\Line\\ShowLines\\Assets\\Plugin\\OpencvDLL")]
    private static extern double LinesDistance(byte[] image_data, double[] a);

//	[DllImport("OpencvDLL")]
	[DllImport("D:\\Michael Wang\\SC\\2019\\Line\\ShowLines\\Assets\\Plugin\\OpencvDLL")]
    private static extern void Quit();

    // Use this for initialization
    void Start()
    {
        WebCamDevice[] devices = WebCamTexture.devices;
        viewTextureCamera = new WebCamTexture(devices[0].name, 640, 480, 30);
        viewTextureCamera.Play();
        viewTexture = new Texture2D(viewTextureCamera.width, viewTextureCamera.height, TextureFormat.RGB24, false);

    }

    // Update is called once per frame
    void Update()
    {
        viewTexture.SetPixels(viewTextureCamera.GetPixels());
        viewTexture.Apply();
        this.GetComponent<Renderer>().material.mainTexture = viewTexture;
        imageData = viewTexture.GetRawTextureData();
    }

    private void OnApplicationQuit()
    {
        Quit();
    }

    private void LateUpdate()
    {
        LinesDistance(imageData,a);
        Distance = Convert.ToDouble((a[0] / 15f).ToString("f2"));
        Parallelism = Convert.ToDouble((a[1] / 15f).ToString("f2"));
        Ang = Convert.ToDouble((a[2] / 15f).ToString("f2"));

        //Debug.Log(Distance);
        Debug.Log(Ang);
        Text text1 = tt.GetComponent<Text>();
        text1.text = ("距离:"+Convert.ToString( Distance));

        Text text2 = pp.GetComponent<Text>();
        text2.text = ("平行度:" + Convert.ToString(Parallelism));

        //DisplayMeasureDistance();
    }



    //    void DisplayMeasureDistance()
    //    {
    //        GameObject root = GameObject.Find("World");


    //        //Box a and Box b
    //        root.transform.Find("S01/Box_a").gameObject.transform.localPosition = new Vector3(0.0f, 1.125f, 0.5f);
    //        root.transform.Find("S01/Box_b").gameObject.transform.localPosition = new Vector3(0.0f, 1.125f, (0.5f - 0.2f - (float)Distance));

    //        //Length: sizeline and data
    //        root.transform.Find("Length/SizeLine/SizeLine1").gameObject.transform.localPosition = new Vector3(1.0f, 0.0f, 0.3885f + 0.025f / 2.0f - (float)Distance / 2.0f);
    //        root.transform.Find("Length/SizeLine/SizeLine1").gameObject.transform.localScale = new Vector3(0.025f, 0.5f * Math.Abs((float)Distance), 0.025f);
    //        root.transform.Find("Length/SizeLine/SizeLine2").gameObject.transform.localPosition = new Vector3(1.0f, 0.0f, 0.3873f);
    //        root.transform.Find("Length/SizeLine/SizeLine3").gameObject.transform.localPosition = new Vector3(1.0f, 0.0f, (0.3885f + 0.025f - (float)Distance));
    //        root.transform.Find("Length/Data/Num").gameObject.GetComponent<TextMesh>().text = Distance + " ";
    //        root.transform.Find("Length/Data/Num").gameObject.transform.localPosition = new Vector3(-0.3873f + (float)Distance / 2.0f, 0.0f, 1.0f);
    //        root.transform.Find("Length/Data/LowerDeviation").gameObject.transform.localPosition = new Vector3(-0.3873f + (float)Distance / 2.0f + 0.15f, -0.03499997f, 1.0f);
    //        root.transform.Find("Length/Data/UpperDeviation").gameObject.transform.localPosition = new Vector3(-0.3873f + (float)Distance / 2.0f + 0.15f, 0.002f, 1.0f);
    //    }
    //}
}

注意

1 opencv的dll放在与Assets平级,这个如果opencv是配置好的则可能没有问题,如果有问题可以这样尝试一下。

2 VS生成的dll也可以放这儿,如果放在里面的plugin里面不行的话。