/*--------------------------------------------------------------------------------------------------
* @Copyright (c) , All rights reserved.
* @file: detectBlockedRect.hpp
* @version: ver 1.0
* @author: 闹闹
* @brief:
* @change:
* @email: 1319144981@qq.com
* Date Version Changed By Changes
* 2021/8/19 10:40:48 1.0 闹闹 create
写一句自己最喜欢的话吧。
为天地立心,为生民立命,为往圣继绝学,为万世开太平。
--------------------------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------------------
* modify_author: 闹闹
* modify_time: 2021/8/27 10:53:52
* modify_content:
* modify_reference:
https://blog.csdn.net/liujiabin076/article/details/74917605
* modify_other:
* modify_version: 1.0.0.2
--------------------------------------------------------------------------------------------------*/
#ifndef detectBlockedRect_h__
#define detectBlockedRect_h__
#pragma once
#pragma warning( disable: 4244)
#include <opencv2/core/core.hpp>
//极坐标的头文件(线特征的类)
#include <opencv2/line_descriptor/descriptor.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <vector>
#include <fstream>
#include "myLSD.hpp"
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 线段检测与线段合并
* @Version: 1.0.0.1
* @Date: 2021/8/26 14:55
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
namespace linedetect
{
typedef cv::line_descriptor::KeyLine KeyLine;
typedef struct _BRectParams{
float lineLen_th; // line minimum length ( lsd detect)
float m_dTheta; // line polar angle variation range [-m_dTheta,+m_dTheta], it is Degree, not Radian.
float theta_dt; // the one line angle variation range
float dR_th; // the one line radius variation range
float merge_lineLen_th_Hori; // horizontal line merged minimum length
float merge_lineLen_th_Verti; // vertical line merged minimum length
}BRectParams;
/*--------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------*/
template <typename PointT>
class CLineParams{ //线参数(极坐标参数)
public:
CLineParams() {};
CLineParams(float r, float theta, PointT p1, PointT p2){
this->pr = r;
this->ptheta = theta;
this->start_vertex = p1;
this->end_vertex = p2;
}
public:
float pr; // polar coordinates radius
float ptheta; // polar coordinates angle
PointT start_vertex, end_vertex; // line start point & end point in Cartesian coordinates
};
/*--------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------*/
typedef CLineParams<cv::Point2f> CLineParams2f;
class LineAllData { //线数据:笛卡尔坐标点、极坐标点、簇idx,线检测的类别,是已经排序过后的
public:
LineAllData() {}
LineAllData(int index, cv::Vec2d polar_line, KeyLine line){
this->index = index;
this->polar_line = polar_line;
this->kline = line;
}
~LineAllData() {}
bool operator<(const LineAllData & t) const{
return index < t.index;
}
public:
int index;
cv::Vec2d polar_line;
KeyLine kline;
};
/*--------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------*/
#define DEG2RAD(d) ((d)*CV_PI/180.0) //角度转弧度
class BlockedRect { //采用谷歌命名规范(私有变量以2个下划线结束,公有变量以一个下划线结束)
private:
typedef std::map<int, std::tuple<float, float,float>> mapl;
int m_width__; //图像的宽
int m_height__; //图像的高
BRectParams params__; //配置参数
std::vector<KeyLine> lines_Hori__; //保存水平线段端点,长度,宽度
std::vector<KeyLine> lines_Verti__; //保存竖直线段端点,长度,宽度
std::vector<int> index_Hori__; //水平直线标签
std::vector<int> index_Verti__; //竖直直线标签
std::vector<cv::Vec2d> polar_lines_Hori__; //保存水平直线的极坐标参数
std::vector<cv::Vec2d> polar_lines_Verti__; //保存竖直直线的极坐标参数
std::vector<CLineParams2f> merge_lines_Hori__; //合并之后的水平线段
std::vector<CLineParams2f> merge_lines_Verti__; //合并之后的竖直线段
std::vector<std::vector<LineAllData> > linesData__; //每条线段的关键线段
mapl line_category_Hori_info__; //存储水平每类线段的信息,平均角度与平均长度
mapl line_category_Verti_info__; //存储竖直每类线段的信息,平均角度与平均长度
public:
BlockedRect() {};
~BlockedRect() {};
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 初始化参数
* @Version: 1.0.0.1
* @Date: 2021/8/19 11:04
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
默认参数
lineLen_th 线路最小长度(lsd检测)
m_dTheta 线极角变化范围[-m_dTheta,+m_dTheta],它是度,而不是弧度。
theta_dt 单线角度变化范围
dR_th 单线半径变化范围
merge_lineLen_th_Hori 水平线合并最小长度
merge_lineLen_th_Verti 垂直线合并最小长度
--------------------------------------------------------------------------------------------------*/
bool initParams(const float lineLen_th = 15.0, const float m_dTheta = 15.0, const float theta_dt = 6.0, const float dR_th = 15.0, const float merge_lineLen_th_Hori = 250.0, const float merge_lineLen_th_Verti = 200.0) {
params__.lineLen_th = lineLen_th;
params__.m_dTheta = m_dTheta;
params__.theta_dt = theta_dt;
params__.dR_th = dR_th;
params__.merge_lineLen_th_Hori = merge_lineLen_th_Hori;
params__.merge_lineLen_th_Verti = merge_lineLen_th_Verti;
if (params__.lineLen_th <= 1e-6 || params__.m_dTheta <= 1e-6 || params__.theta_dt <= 1e-6)
return false;
#if 0
std::cout << "0: " << DEG2RAD(params__.m_dTheta) << std::endl;
std::cout << "90: " << DEG2RAD(90 - params__.m_dTheta) << " " << DEG2RAD(90 + params__.m_dTheta) << std::endl;
std::cout << "180: " << DEG2RAD(180 - params__.m_dTheta)<< " " << DEG2RAD(180 + params__.m_dTheta) << std::endl;
std::cout << "270: " << DEG2RAD(270 - params__.m_dTheta)<< " " << DEG2RAD(270 + params__.m_dTheta) << std::endl;
#endif // _DEBUG
return true;
};
/*--------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 线检测
* @Version: 1.0.0.1
* @Date: 2021/8/19 11:04
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
void detect(cv::Mat& image) {
if (image.empty())
return;
m_width__ = image.cols;
m_height__ = image.rows;
detectLinesHori(image);
//detectLinesVerti(image);
};
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 合并线段
* @Version: 1.0.0.1
* @Date: 2021/8/19 14:48
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*////
std::size_t mergeLines() {
std::size_t line_Hori_count = mergeLinesHori();
return line_Hori_count;
//mergeLinesVerti();
};
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: brief
* @Version: 1.0.0.1
* @Date: 2021/8/26 11:35
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
bool getRect(std::vector<cv::Point2f>& points) {
return false;
};
void drawLines(cv::Mat& img) {
drawLinesHori(img);
//drawLinesVerti(img);
}
void drawMergeLines(cv::Mat& img) {
drawMergeLinesHori(img);
//drawMergeLinesVerti(img);
}
private:
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 检测水平线
* @Version: 1.0.0.1
* @Date: 2021/8/19 11:02
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
bool detectLinesHori(cv::Mat& src) {
cv::Mat gray;
if (src.channels() == 3)
cv::cvtColor(src, gray, CV_BGR2GRAY);
else
src.copyTo(gray);
cv::Mat ydiff, abs_ydiff, gradYBin;
cv::Sobel(gray, ydiff, CV_16S, 0, 1, -1); //y方向计算梯度
cv::convertScaleAbs(ydiff, abs_ydiff);
cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3)); //腐蚀 膨胀
cv::erode(abs_ydiff, abs_ydiff, element);
cv::dilate(abs_ydiff, abs_ydiff, element);
cv::threshold(abs_ydiff, gradYBin, 50, 255, CV_THRESH_BINARY); //阈值化
#ifdef _DEBUG
cv::namedWindow("gradY", 0);
cv::imshow("gradY", gradYBin);
cv::waitKey(0);
#endif // _DEBUG
#ifdef DISPLAY
cv::Mat display;
cv::cvtColor(src, display, cv::COLOR_GRAY2BGR);
#endif //DISPLAY
int width = src.cols;
int height = src.rows;
int count = width * height;
std::vector<KeyLine> lines;
double* input = new double[count]; //创建输入
memset(input, 0, sizeof(double)*count);
int index = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
uchar v = gradYBin.at<uchar>(i, j); //uchar v = src.at<uchar>(i, j);
input[index] = double(v);
index++;
}
}
int n_out; //lsd检测
double* res;
res = mylsd::lsd(&n_out, input, width, height);
for (int i = 0; i < n_out; i++) {
double x1 = res[7 * i + 0];
double y1 = res[7 * i + 1];
double x2 = res[7 * i + 2];
double y2 = res[7 * i + 3];
double angle = atan(fabs((y2 - y1) / (x2 - x1))) * 180 / CV_PI; //角度数
double dis = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
KeyLine k;
k.lineLength = dis;
if (x1 < x2) {
k.startPointX = x1;
k.startPointY = y1;
k.endPointX = x2;
k.endPointY = y2;
k.angle = angle;
k.octave = 0;
}
else {
k.startPointX = x2;
k.startPointY = y2;
k.endPointX = x1;
k.endPointY = y1;
k.angle = angle;
k.octave = 0;
}
float line_len = k.lineLength;
#ifdef DISPLAY
cv::line(display, cv::Point(k.startPointX, k.startPointY), cv::Point(k.endPointX, k.endPointY), cv::Scalar(0, 255, 0), 1);
#endif // DISPLAY
if (params__.lineLen_th > line_len) continue; //忽略长度小的点
//转为极坐标形式
cv::Vec2d polarline = getPolarLine(cv::Vec4d(x1 - width / 2.0, height / 2.0 - y1, x2 - width / 2.0, height / 2.0 - y2));
if (polarline[1] >= DEG2RAD(0) && polarline[1] <= DEG2RAD(90- params__.m_dTheta))
continue;
if (polarline[1] >= DEG2RAD(90 + params__.m_dTheta) && polarline[1] <= DEG2RAD(180))
continue;
if (polarline[1] >= DEG2RAD(180) && polarline[1] <= DEG2RAD(270 - params__.m_dTheta))
continue;
if (polarline[1] >= DEG2RAD(270 + params__.m_dTheta) && polarline[1] <= DEG2RAD(360))
continue;
#ifdef DISPLAY
cv::line(display, cv::Point(k.startPointX, k.startPointY), cv::Point(k.endPointX, k.endPointY), cv::Scalar(0, 0, 255), 1);
#endif // DISPLAY
lines_Hori__.emplace_back(k); //加入变量
polar_lines_Hori__.emplace_back(polarline);
}
if (input) {
delete[] input;
input = NULL;
}
if (res) free((void*)res);
return lines_Hori__.size() >= 2;
};
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 检测竖直线
* @Version: 1.0.0.1
* @Date: 2021/8/19 11:03
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
bool detectLinesVerti(cv::Mat& src) {
cv::Mat gray;
if (src.channels() == 3)
cvtColor(src, gray, CV_BGR2GRAY);
else
src.copyTo(gray);
cv::Mat xdiff,abs_xdiff, gradXBin;
cv::Sobel(gray, xdiff, CV_16S, 1, 0, -1); //x方向梯度计算
cv::convertScaleAbs(xdiff, abs_xdiff);
cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3));
cv::erode(abs_xdiff, abs_xdiff, element);
cv::dilate(abs_xdiff, abs_xdiff, element);
cv::threshold(abs_xdiff, gradXBin, 50, 255, CV_THRESH_OTSU);
#ifdef _DEBUG
cv::namedWindow("gradX", 0);
cv::imshow("gradX", gradXBin);
cv::waitKey(0);
#endif // _DEBUG
int width = src.cols;
int height = src.rows;
int count = width * height;
std::vector<KeyLine> lines;
//创建输入
double* input = new double[count];
memset(input, 0, sizeof(double)*count);
int index = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
uchar v = gradXBin.at<uchar>(i, j);
input[index] = double(v);
index++;
}
}
//lsd检测
int n_out;
double* res;
res = mylsd::lsd(&n_out, input, width, height);
for (int i = 0; i < n_out; i++) {
double x1 = res[7 * i + 0];
double y1 = res[7 * i + 1];
double x2 = res[7 * i + 2];
double y2 = res[7 * i + 3];
double angle = atan(fabs((y2 - y1) / (x2 - x1))) * 180 / CV_PI;
double dis = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
KeyLine k;
k.lineLength = dis;
if (x1 < x2) {
k.startPointX = x1;
k.startPointY = y1;
k.endPointX = x2;
k.endPointY = y2;
k.angle = angle;
k.octave = 0;
}
else {
k.startPointX = x2;
k.startPointY = y2;
k.endPointX = x1;
k.endPointY = y1;
k.angle = angle;
k.octave = 0;
}
float line_len = k.lineLength;
if (params__.lineLen_th > line_len) continue; //忽略长度小的点
//转为极坐标形式
cv::Vec2d polarline = getPolarLine(cv::Vec4d(x1 - width / 2.0, height / 2.0 - y1, x2 - width / 2.0, height / 2.0 - y2));
if (polarline[1] >= DEG2RAD(params__.m_dTheta) && polarline[1] <= DEG2RAD(90 - params__.m_dTheta)) //忽略的线段
continue;
if (polarline[1] >= DEG2RAD(90 + params__.m_dTheta) && polarline[1] <= DEG2RAD(180 - params__.m_dTheta))
continue;
if (polarline[1] >= DEG2RAD(180 + params__.m_dTheta) && polarline[1] <= DEG2RAD(270 - params__.m_dTheta))
continue;
if (polarline[1] >= DEG2RAD(270 + params__.m_dTheta) && polarline[1] <= DEG2RAD(360 - params__.m_dTheta))
continue;
lines_Verti__.push_back(k); //加入变量
polar_lines_Verti__.push_back(polarline);
}
if (input) {
delete[] input;
input = NULL;
}
if (res) free((void*)res);
return lines_Verti__.size() >= 2;
};
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 合并水平线的首函数
* @Version: 1.0.0.1
* @Date: 2021/8/19 14:49
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
std::size_t mergeLinesHori()
{
if (!getLineIndx(polar_lines_Hori__, index_Hori__))
return false;
std::size_t line_num = lines_Hori__.size();
std::vector<LineAllData> line_data;
for (std::size_t i = 0; i < line_num; i++){
KeyLine kl = lines_Hori__[i];
cv::Vec2d pl = polar_lines_Hori__[i];
int idx = index_Hori__[i];
LineAllData lda(idx, pl, kl);
line_data.push_back(lda);
}
std::sort(line_data.begin(), line_data.end()); // sort by the line index
/*for (LineAllData lda : line_data)
std::cout << lda.index << " ";
std::cout << std::endl;*/
std::size_t line_count = mergeLinesHori(line_data, merge_lines_Hori__);
return line_count;
};
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 合并竖直线的首函数
* @Version: 1.0.0.1
* @Date: 2021/8/26 12:04
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
std::size_t mergeLinesVerti()
{
if (!getLineIndx(polar_lines_Verti__, index_Verti__))
return false;
std::size_t line_num = lines_Verti__.size();
std::vector<LineAllData> line_data;
for (std::size_t i = 0; i < line_num; i++){
KeyLine kl = lines_Verti__[i];
cv::Vec2d pl = polar_lines_Verti__[i];
int idx = index_Verti__[i];
LineAllData lda(idx, pl, kl);
line_data.push_back(lda);
}
std::sort(line_data.begin(), line_data.end()); // sort by the line index
/*for (LineAllData lda : line_data)
std::cout << lda.index << " ";
std::cout << std::endl;*/
std::size_t line_count = mergeLinesVerti(line_data, merge_lines_Verti__);
return line_count;
}
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 合并水平线
* @Version: 1.0.0.1
* @Date: 2021/8/19 14:51
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
std::size_t mergeLinesHori(std::vector<LineAllData>& vLda, std::vector<CLineParams2f>& plines) {
if (vLda.size() < 2) return false;
std::vector<int> index_used;
int st = vLda[0].index;
index_used.push_back(st);
//
// get all the differen index : 000111222333 -> 0123
// count the different index : 4
int n_line = 1; //得到类别个数(类别是排序过后的)
for (int i = 0; i < vLda.size(); i++){
if (vLda[i].index != st){
st = vLda[i].index;
index_used.push_back(st);
n_line++;
}
}
if (n_line < 2) return false; //类别个数小于2,则返回
// //split to different pieces
// split the vLda : 000111222333-> 000 \ 111 \ 222 \ 333
int j = 0;
linesData__.clear(); //成员变量,二维变量
line_category_Hori_info__.clear();
for (int i = 0; i < n_line; i++)
{
int idx = index_used[i];
std::vector<LineAllData> split_line_data;
float sum_length = 0;
for (; j < vLda.size() && (vLda[j].index == idx); j++){
split_line_data.push_back(vLda[j]);
sum_length += vLda[j].kline.lineLength; //类别相同的线的长度相加
}
linesData__.push_back(split_line_data);
}
// //merge each pieces to one line
// merge linesData,合并相同类别的线段
CLineParams2f line_category;
#ifdef DISPLAY
cv::Mat display = cv::Mat::zeros(cv::Size(m_width__,m_height__),CV_8UC3);
#endif //DISPLAY
for (int i = 0; i < n_line; i++)
{
std::vector<LineAllData> cline_data = linesData__[i]; //得到每个类别的线段
std::size_t m = cline_data.size();
if (m <= 1)
continue;
float sum_length = 0.0; //length, position,bound box[minx,miny,maxx,maxy]
float mx = 0.0;
cv::Point2f p1(static_cast<float>(m_width__), static_cast<float>(m_height__)), p2(0, 0);
float sum_r = 0.0;
float sum_theta = 0.0;
//每个类别进行循环
for (int j = 0; j < m; j++)
{
LineAllData cline = cline_data[j]; //得到每个线
KeyLine line_segment = cline.kline; //得到每个线的关键线信息
sum_length += line_segment.lineLength; // length
sum_r += cline.polar_line[0];
sum_theta += cline.polar_line[1];
// 根据X坐标选择端点
float min_x = MIN(line_segment.startPointX, line_segment.endPointX);
float min_x_y = line_segment.startPointX < line_segment.endPointX ? line_segment.startPointY : line_segment.endPointY;
float max_x = MAX(line_segment.startPointX, line_segment.endPointX);
float max_x_y = line_segment.startPointX > line_segment.endPointX ? line_segment.startPointY : line_segment.endPointY;
if (p1.x > min_x) //得到线的最小值,最大值
{
p1.x = min_x;
p1.y = min_x_y;
}
if (p2.x < max_x)
{
p2.x = max_x;
p2.y = max_x_y;
}
}
float avg_r = (sum_r / m); //记录均值
float avg_theta = (sum_theta /m);
std::tuple<float, float, float> line_info{ avg_r, avg_theta,sum_length };
line_category_Hori_info__.insert(std::make_pair(i, line_info));
if (sum_length < m_width__ * 0.2) continue; //长度过小则返回
#ifdef DISPLAY
cv::line(display,p1,p2,cv::Scalar(0,255,0),1);
#endif //DISPLAY
float line_sum_len = sqrtf((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y)); //同类线段上下两端的长度
if (line_sum_len > params__.merge_lineLen_th_Hori && sum_length > params__.merge_lineLen_th_Hori / 2.0)
{
float r = sum_r / m;
float theta = sum_theta / m;
if (p2.x> p1.x)
{
line_category.start_vertex = p1;
line_category.end_vertex = p2;
line_category.pr = r;
line_category.ptheta = theta;
}
if (p2.x < p1.x)
{
line_category.start_vertex = p2;
line_category.end_vertex = p1;
line_category.pr = r;
line_category.ptheta = theta;
}
#ifdef DISPLAY
cv::line(display, p1, p2, cv::Scalar(0, 0, 255), 1);
#endif //DISPLAY
plines.push_back(line_category);
}
}
return plines.size();
};
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 合并竖直线
* @Version: 1.0.0.1
* @Date: 2021/8/26 11:53
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
std::size_t mergeLinesVerti(std::vector<LineAllData>& vLda, std::vector<CLineParams2f>& plines) {
if (vLda.size() < 2)
return false;
std::vector<int> index_used;
int st = vLda[0].index;
index_used.push_back(st);
//
// get all the differen index : 000111222333 -> 0123
// count the different index : 4
int n_line = 1;
for (int i = 0; i < vLda.size(); i++)
{
if (vLda[i].index != st)
{
st = vLda[i].index;
index_used.push_back(st);
n_line++;
}
}
if (n_line < 2) return false;
// split to different pieces
// split the vLda : 000111222333-> 000 \ 111 \ 222 \ 333
int j = 0;
linesData__.clear();
for (int i = 0; i < n_line; i++)
{
int idx = index_used[i];
std::vector<LineAllData> split_line_data;
float sum_length = 0;
for (; j < vLda.size() && (vLda[j].index == idx); j++)
{
split_line_data.push_back(vLda[j]);
sum_length += vLda[j].kline.lineLength;
}
linesData__.push_back(split_line_data);
}
// merge each pieces to one line
// merge linesData
CLineParams2f line_category;
#ifdef DISPLAY
cv::Mat display = cv::Mat::zeros(cv::Size(m_width__, m_height__), CV_8UC3);
#endif //DISPLAY
for (int i = 0; i < n_line; i++)
{
std::vector<LineAllData> cline_data = linesData__[i];
std::size_t m = cline_data.size();
if (m <= 1)
continue;
// length, position,bound box[minx,miny,maxx,maxy]
float sum_length = 0.0;
float mx = 0.0;
cv::Point2f p1(static_cast<float>(m_width__), static_cast<float>(m_height__)), p2(0, 0);
float sum_r = 0.0;
float sum_theta = 0.0;
for (int j = 0; j < m; j++)
{
LineAllData cline = cline_data[j];
KeyLine line_segment = cline.kline;
sum_length += line_segment.lineLength; // length
sum_r += cline.polar_line[0];
sum_theta += cline.polar_line[1];
float min_y = MIN(line_segment.startPointY, line_segment.endPointY); //根据Y坐标选择端点
float min_y_x = line_segment.startPointY < line_segment.endPointY ? line_segment.startPointX : line_segment.endPointX;
float max_y = MAX(line_segment.startPointY, line_segment.endPointY);
float max_y_x = line_segment.startPointY > line_segment.endPointY ? line_segment.startPointX : line_segment.endPointX;
if (p1.y > min_y)
{
p1.y = min_y;
p1.x = min_y_x;
}
if (p2.y < max_y)
{
p2.y = max_y;
p2.x = max_y_x;
}
}
float avg_r = (sum_r / m); //记录均值
float avg_theta = (sum_theta / m);
std::tuple<float, float, float> line_info{ avg_r, avg_theta,sum_length };
line_category_Verti_info__.insert(std::make_pair(i, line_info));
if (sum_length < m_height__ * 0.2) continue; //长度过小则返回
#ifdef DISPLAY
cv::line(display, p1, p2, cv::Scalar(0, 255, 0), 1);
#endif //DISPLAY
float line_sum_len = sqrtf((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y)); // 同类线段上下两端的长度
if (line_sum_len > params__.merge_lineLen_th_Verti && sum_length > params__.merge_lineLen_th_Verti / 2.0)
{
float r = sum_r / m;
float theta = sum_theta / m;
if (p2.x > p1.x)
{
line_category.start_vertex = p1;
line_category.end_vertex = p2;
line_category.pr = r;
line_category.ptheta = theta;
}
if (p2.x < p1.x)
{
line_category.start_vertex = p2;
line_category.end_vertex = p1;
line_category.pr = r;
line_category.ptheta = theta;
}
#ifdef DISPLAY
cv::line(display, p1, p2, cv::Scalar(0, 0, 255), 1);
#endif //DISPLAY
plines.push_back(line_category);
}
}
return plines.size();
}
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 画线
* @Version: 1.0.0.1
* @Date: 2021/8/26 14:47
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
void drawLinesHori(cv::Mat& img)
{
for (int i = 0; i < lines_Hori__.size(); i++)
{
KeyLine keyline = lines_Hori__[i];
if( 0 != keyline.octave ) continue;
cv::line(img, keyline.getStartPoint(), keyline.getEndPoint(), cv::Scalar(0, 0, 255), 1);
}
}
void drawLinesVerti(cv::Mat& img)
{
for (int i = 0; i < lines_Verti__.size(); i++)
{
KeyLine keyline = lines_Verti__[i];
if (0 != keyline.octave) continue;
cv::line(img, keyline.getStartPoint(), keyline.getEndPoint(), cv::Scalar(0, 0, 255), 1);
}
}
void drawMergeLinesHori(cv::Mat& img)
{
for (int i = 0; i < merge_lines_Hori__.size(); i++)
{
CLineParams2f ml = merge_lines_Hori__[i];
cv::line(img, ml.start_vertex, ml.end_vertex, cv::Scalar(255, 0, 0), 1);
}
}
void drawMergeLinesVerti(cv::Mat& img) {
for (int i = 0; i < merge_lines_Verti__.size(); i++)
{
CLineParams2f ml = merge_lines_Verti__[i];
cv::line(img, ml.start_vertex, ml.end_vertex, cv::Scalar(255, 0, 0), 1);
}
}
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 转化为极坐标
* @Version: 1.0.0.1
* @Date: 2021/8/19 13:45
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
cv::Vec2d getPolarLine(cv::Vec4d p) {
if (fabs(p[0] - p[2]) < 1e-5){ //垂直直线
if (p[0] > 0)
return cv::Vec2d(fabs(p[0]), 0);
else
return cv::Vec2d(fabs(p[0]), CV_PI);
}
if (fabs(p[1] - p[3]) < 1e-5) { //水平直线
if (p[1] > 1e-5)
return cv::Vec2d(fabs(p[1]), CV_PI / 2);
else
return cv::Vec2d(fabs(p[1]), 3 * CV_PI / 2);
}
float k = (p[1] - p[3]) / (p[0] - p[2]);
float y_intercept = p[1] - k*p[0];
float theta; /*atan 值域范围[-pi/2,pi/2]; atan2 值域范围[-pi,pi],根据直线斜率与截距 判断角度所在象限*/
if (k < 0 && y_intercept > 0) // 第一象限
theta = atan(-1 / k);
else if (k > 0 && y_intercept > 0) // 第二象限,
theta = CV_PI + atan(-1 / k);
else if (k < 0 && y_intercept < 0) // 第三象限
theta = CV_PI + atan(-1 / k);
else if (k > 0 && y_intercept < 0) // 第四象限
theta = 2 * CV_PI + atan(-1 / k);
float _cos = cos(theta);
float _sin = sin(theta);
float r = fabs(p[0] * _cos + p[1] * _sin);
return cv::Vec2d(r, theta);
}
/*--------------------------------------------------------------------------------------------------
* @FuncName:
* @Author: 闹闹
* @Brief: 得到线的序列,将线的角度与距离相差很小的线段,归类
* @Version: 1.0.0.1
* @Date: 2021/8/19 14:57
* @InputParameter:
* @OutputParameter:
* @Returns:
* @Others:
--------------------------------------------------------------------------------------------------*/
bool getLineIndx(std::vector<cv::Vec2d> polarLine, std::vector<int>& index) {
std::size_t polar_num = polarLine.size();
if (polar_num < 2) return false;
index.clear();
index.resize(polar_num);
// init line index and the marked flag
std::vector<int> line_indexed;
line_indexed.resize(polar_num);
for (int i = 0; i < polar_num; i++){
index[i] = i;
line_indexed[i] = 0;
}
for (int i = 0; i < polar_num - 1; i++){
cv::Vec2d pl1 = polarLine[i];
for (int j = i + 1; j < polar_num; j++)
{
if (1 == line_indexed[j]) continue; // marked
cv::Vec2d pl2 = polarLine[j];
float dTheta = fabs(pl2[1] - pl1[1]); //计算两条直线的极坐标差
float dR = fabs(pl2[0] - pl1[0]);
float meanR = fabs(pl2[0] + pl1[0]) / 2;
if (dTheta < DEG2RAD(params__.theta_dt) || fabs(2 * CV_PI - dTheta) < DEG2RAD(params__.theta_dt)){ // have nearly same angle
if (dR < params__.dR_th){ //have nearly same radius
line_indexed[j] = 1; //same index
index[j] = index[i];
}
}
} // for j
} // for i
return true;
}
};
}
#endif // detectBlockedRect_h__
/*----------------------------------------------------------------------------- (C) COPYRIGHT LEI *****END OF FILE------------------------------------------------------------------------------*/
直线类别分类
最新推荐文章于 2024-03-08 20:26:33 发布