直线类别分类

/*--------------------------------------------------------------------------------------------------
    *  @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------------------------------------------------------------------------------*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值