C++工程通过opencv找到自己定义的矩形中的两平行线的距离
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里面不行的话。
相关文章
- opencv中的子库
- 【VS开发】【计算机视觉】OpenCV读写xml文件《C++版本》
- 关于opencv的几个小总结
- 超简单的pyTorch训练->onnx模型->C++ OpenCV DNN推理(附源码地址)
- 基于opencv实现SVM分类器【附源码】
- 基于opencv的模板匹配【C++/Qt】【附源码】
- Ubuntu 16.04下为Android编译OpenCV 3.2.0 Manager
- 配置使用OpenCV静态链接库
- OpenCV获取不规则区域的最大内切圆(附Python / C++源码)
- 实战 | OpenCV如何将不同轮廓合并成一个轮廓(附Python / C++源码)
- OpenCV技巧 | 二值图孔洞填充方法与实现(附Python/C++源码)
- C++ | PaddleOCR+OpenCV实现文字识别步骤与代码演示
- opencv十字瞄准线 图像上长按左键画矩形单击右键清除05并保存矩形坐标
- Improving Opencv 3 : Mask operations on matrices
- OpenCV中的快速特征检测——FAST(Features from Accelerated Segment Test)
- OpenCV中的霍夫线变换、概率霍夫线变换
- 【OpenCV】-重映射
- Delaunay Triangulation and Voronoi Diagram using OpenCV ( C++ / Python )
- 《Mastering Opencv ...读书笔记系列》车牌识别(I)
- opencv-minMaxldx寻找最大值和最小值
- C++opencv图像的缩放
- C++ 使用 opencv 库时 Point 在已经引入了 core.hpp 的情况下仍无法识别的可能原因