图像处理找两条线的距离

2017-11-01 10:53:11 Seven_year_Promise 阅读数 3208
  • 识别并计算两条曲线间的距离

    通过本课程学习,初学者可以熟练使用opencv4 API完成各种常见的图像分割、识别任务。 中高级学习者也一定能有新的体会和收获。 本课程所讲的例子代码来自于实际开发项目,有较高的实用性。

    9人学习 刘山
    免费试看

一、距离定义

(1)欧式距离

             ,实质上是矩形对角线距离

(2)city block

               ,实质上是从一个点到另外一个点的步数,并不能走斜线

(3)chessboard

                ,实质上是凑成一个正方形的对角线


(4)邻接性


       4-连接没有对角线元素,8-连接有对角线元素,连接构成的所有元素一起构成区域(Region)

(5)悖论

        如图两条线,虽然人眼看着相交,但是按照邻接性,并没有相交,因此存在矛盾

       解决方法::背景和物体目标分别进行两种不同的邻接性判断(4-邻接和8-邻接)



二、距离变换(局部掩膜)



(1)M*N的图像中,S子集内部为0,外部为无穷

(2)按照左图,公式为

          

(3)再倒着推,按照右图,公式为

          

     其中D为各种类型的距离,如准欧式距离

     

(4)得到的即为斜切函数

(三)其他相关概念

(1)边缘(edge)

          有大小和方向

          计算方法:梯度,edge的方向和梯度方向垂直

(2)边界

           区域R和背景的界限(边缘点的集合是一种边界)

(3)连通区域的凸性和非凸性

          凸性:区域内任意两点的连线均在区域内

         凸包:包含一个区域的最小凸区域(包括两部分——湖lakes:区域本身的区域;  湾bays:区域之外的背景)



2014-03-10 23:05:42 qianchenglenger 阅读数 18004
  • 识别并计算两条曲线间的距离

    通过本课程学习,初学者可以熟练使用opencv4 API完成各种常见的图像分割、识别任务。 中高级学习者也一定能有新的体会和收获。 本课程所讲的例子代码来自于实际开发项目,有较高的实用性。

    9人学习 刘山
    免费试看

问题:一张输入图片,图片上有两条平行线,求出这两条平行线之间的距离

解决思路:

1. 对图像中的直线进行细化

2. 提取直线的轮廓坐标

3. 对轮廓上的坐标进行直线集合,从而得到直线方程

4. 计算两条直线之间的距离

参考:

问题来源 http://www.opencvchina.com/thread-854-1-1.html

图像细化 http://blog.csdn.net/qianchenglenger/article/details/19332011

图像轮廓提取 http://blog.csdn.net/augusdi/article/details/9000893

直线拟合 http://blog.csdn.net/zhuoyue08/article/details/6803040

两条直线之间的距离公式3:http://zhidao.baidu.com/link?url=ef_DHNkjyq1qq7VgubX3afL2KIUQIB4ukd3zHGp0zz8iPPKC046azyvG5ltHR-i0WaLI72eO7j0sOJI4wZSE4q

工具:

 opencv 2.4.8 + VS2013

代码:

1.头文件 ProcessImage.h

//ProcessImage.h
#pragma once
#include <opencv2/highgui/highgui.hpp>

/* 对输入图像进行细化
 * src为输入图像,用cvThreshold函数处理过的8位灰度图像格式,元素中只有0与1,1代表有元素,0代表为空白
 * dst为对src细化后的输出图像,格式与src格式相同,调用前需要分配空间,元素中只有0与1,1代表有元素,0代表为空白
 * maxIterations限制迭代次数,如果不进行限制,默认为-1,代表不限制迭代次数,直到获得最终结果
 */
void thinImage(IplImage* src, IplImage* dst, int maxIterations = -1);

2.代码实现 ProcessImage.cpp

//ProcessImage.cpp
#include "ProcessImage.h"
#include <utility>
#include <vector>
void thinImage(IplImage* src, IplImage* dst, int maxIterations)
{
	using namespace cv;
	CvSize size = cvGetSize(src);
	cvCopy(src, dst);//将src中的内容拷贝到dst中  
	int count = 0;  //记录迭代次数  
	while (true)
	{
		count++;
		if (maxIterations != -1 && count > maxIterations) //限制次数并且迭代次数到达  
			break;
		//std::cout << count << ' ';输出迭代次数  
		std::vector<std::pair<int, int> > mFlag; //用于标记需要删除的点  
		//对点标记  
		for (int i = 0; i<size.height; ++i)
		{
			for (int j = 0; j<size.width; ++j)
			{
				//如果满足四个条件,进行标记  
				//  p9 p2 p3  
				//  p8 p1 p4  
				//  p7 p6 p5  
				int p1 = CV_IMAGE_ELEM(dst, uchar, i, j);
				int p2 = (i == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j);
				int p3 = (i == 0 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j + 1);
				int p4 = (j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i, j + 1);
				int p5 = (i == size.height - 1 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j + 1);
				int p6 = (i == size.height - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j);
				int p7 = (i == size.height - 1 || j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j - 1);
				int p8 = (j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i, j - 1);
				int p9 = (i == 0 || j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j - 1);

				if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6)
				{
					int ap = 0;
					if (p2 == 0 && p3 == 1) ++ap;
					if (p3 == 0 && p4 == 1) ++ap;
					if (p4 == 0 && p5 == 1) ++ap;
					if (p5 == 0 && p6 == 1) ++ap;
					if (p6 == 0 && p7 == 1) ++ap;
					if (p7 == 0 && p8 == 1) ++ap;
					if (p8 == 0 && p9 == 1) ++ap;
					if (p9 == 0 && p2 == 1) ++ap;

					if (ap == 1)
					{
						if (p2*p4*p6 == 0)
						{
							if (p4*p6*p8 == 0)
							{
								//标记  
								mFlag.push_back(std::make_pair(i, j));
							}
						}
					}
				}
			}
		}

		//将标记的点删除  
		for (std::vector<std::pair<int, int> >::iterator i = mFlag.begin(); i != mFlag.end(); ++i)
		{
			CV_IMAGE_ELEM(dst, uchar, i->first, i->second) = 0;
		}

		//直到没有点满足,算法结束  
		if (mFlag.size() == 0)
		{
			break;
		}
		else
		{
			mFlag.clear();//将mFlag清空  
		}

		//对点标记  
		for (int i = 0; i<size.height; ++i)
		{
			for (int j = 0; j<size.width; ++j)
			{
				//如果满足四个条件,进行标记  
				//  p9 p2 p3  
				//  p8 p1 p4  
				//  p7 p6 p5  
				int p1 = CV_IMAGE_ELEM(dst, uchar, i, j);
				if (p1 != 1) continue;
				int p2 = (i == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j);
				int p3 = (i == 0 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j + 1);
				int p4 = (j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i, j + 1);
				int p5 = (i == size.height - 1 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j + 1);
				int p6 = (i == size.height - 1) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j);
				int p7 = (i == size.height - 1 || j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i + 1, j - 1);
				int p8 = (j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i, j - 1);
				int p9 = (i == 0 || j == 0) ? 0 : CV_IMAGE_ELEM(dst, uchar, i - 1, j - 1);

				if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6)
				{
					int ap = 0;
					if (p2 == 0 && p3 == 1) ++ap;
					if (p3 == 0 && p4 == 1) ++ap;
					if (p4 == 0 && p5 == 1) ++ap;
					if (p5 == 0 && p6 == 1) ++ap;
					if (p6 == 0 && p7 == 1) ++ap;
					if (p7 == 0 && p8 == 1) ++ap;
					if (p8 == 0 && p9 == 1) ++ap;
					if (p9 == 0 && p2 == 1) ++ap;

					if (ap == 1)
					{
						if (p2*p4*p8 == 0)
						{
							if (p2*p6*p8 == 0)
							{
								//标记  
								mFlag.push_back(std::make_pair(i, j));
							}
						}
					}
				}
			}
		}
		//删除  
		for (std::vector<std::pair<int, int> >::iterator i = mFlag.begin(); i != mFlag.end(); ++i)
		{
			CV_IMAGE_ELEM(dst, uchar, i->first, i->second) = 0;
		}

		//直到没有点满足,算法结束  
		if (mFlag.size() == 0)
		{
			break;
		}
		else
		{
			mFlag.clear();//将mFlag清空  
		}
	}
}
3.主函数所在文件 Source.cpp

//Source.cpp
#include "ProcessImage.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#define _TEST
using namespace cv;
int main(int argc, char * argv[])
{
	//判断输入是否满足要求
	if (argc != 2)
	{
		std::cout << "argument error!";
		return -1;
	}
	IplImage *pSrc = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
	if (!pSrc)
	{
		std::cout << "read file failed!";
		return -1;
	}

	//显示原图
	namedWindow("原图", CV_WINDOW_AUTOSIZE);
	cvShowImage("原图", pSrc);

	IplImage *pTemp = cvCreateImage(cvGetSize(pSrc), pSrc->depth, pSrc->nChannels);
	IplImage *pDst = cvCreateImage(cvGetSize(pSrc), pSrc->depth, pSrc->nChannels);

	//将原图像转换为二值图像
	cvThreshold(pSrc, pTemp, 128, 1, CV_THRESH_BINARY_INV);
	//细化
	thinImage(pTemp, pDst);

#ifdef _TEST
	//显示细化后的图像
	IplImage *pThinImage = cvCreateImage(cvGetSize(pSrc), pSrc->depth, pSrc->nChannels);
	cvCopy(pDst, pThinImage);
	cvThreshold(pThinImage, pThinImage, 0.5, 255,CV_THRESH_BINARY);
	namedWindow("1 图像细化的结果", CV_WINDOW_AUTOSIZE);
	cvShowImage("1 图像细化的结果", pThinImage);
	cvReleaseImage(&pThinImage);
#endif

	//求轮廓
	CvMemStorage* storage = cvCreateMemStorage(0);
	CvSeq* contours = 0;
	cvFindContours(pDst	, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint(0, 0));

#ifdef _TEST
	//将轮廓画出来
	IplImage *pDrawing1 = cvCreateImage(cvGetSize(pSrc),8,3);
	cvZero(pDrawing1);
	cvDrawContours(pDrawing1, contours, Scalar(255, 0, 0), Scalar(0, 0, 255), 1, 2, 8, cvPoint(0, 0));
	namedWindow("2 求轮廓", CV_WINDOW_AUTOSIZE);
	cvShowImage("2 求轮廓", pDrawing1);
	cvReleaseImage(&pDrawing1);
#endif


	//轮廓已经寻找到,均在contours中存放,我们需要对轮廓进行拟合
	//FitLine函数的用法:
	// 二维空间点拟合时 是 float[4]
	// 三位空间点拟合时 是 float[6]	
	float *line1 = new float[4];
	float *line2 = new float[4];
	// 第一个参数: 存储点序列
	// 第二个参数: 拟合算法,其中 CV_DIST_L2 就是平常的最小二乘法
	// 第三,第四,第五参数推荐值是 0,   0.01,  0.01,
	// 第六参数: line中存储返回值
	// 二维空间时: line[0--3] 分别为 (vx, vy, x0, y0)
	//      其中 vx, vy 是正规化之后的斜率向量。 x0,y0 是直线经过的点。
	// 三维空间时: line[0--5]  分别是 (vx, vy, vz, x0, y0, z0) 。意义同上
	cvFitLine(contours, CV_DIST_L2, 0, 0.01, 0.01, line1);
	cvFitLine(contours->h_next, CV_DIST_L2, 0, 0.01, 0.01, line2);
	
	//输出四个点
	std::cout << "第一条线: " << line1[0] << " " << line1[1] << " " << line1[2] << " " << line1[3] << std::endl;
	std::cout << "第二条线: " << line2[0] << " " << line2[1] << " " << line2[2] << " " << line2[3] << std::endl;
	
#ifdef _TEST
	//根据直线方程公式,我们从直线上取点,并画出来
	IplImage *pDrawing2 = cvCreateImage(cvGetSize(pSrc), 8, 3);
	cvZero(pDrawing2);
	cvLine(pDrawing2, cvPoint(0, (int)(line1[3] - line1[1] / line1[0] * line1[2])),
		cvPoint(pDrawing2->width - 1, (int)((pDrawing2->width - 1 - line1[2])*line1[1] / line1[0] + line1[3])),
		cvScalar(255, 0, 0));
	cvLine(pDrawing2, cvPoint(0, (int)(line2[3] - line2[1] / line2[0] * line2[2])), 
		cvPoint(pDrawing2->width - 1, (int)((pDrawing2->width - 1 - line2[2])*line2[1] / line2[0] + line2[3])), 
		cvScalar(0, 0, 255));
	namedWindow("3 直线拟合", CV_WINDOW_AUTOSIZE);
	cvShowImage("3 直线拟合", pDrawing2);
	cvReleaseImage(&pDrawing2);
#endif

	//我们根据距离方程,求出两条直线的距离
	double distance = abs(line1[0] * (line2[3]-line1[3]) - line1[1] * (line2[2]-line1[2]));	//注意,vx,vy已经正规化了
	std::cout << "两条直线之间的距离为: " << distance << std::endl;
	delete[] line1;
	delete[] line2;

	cvReleaseMemStorage(&storage);
	cvReleaseImage(&pSrc);
	cvReleaseImage(&pTemp);
	cvReleaseImage(&pDst);

	waitKey(0);

	return 0;
}
运行效果:

输入:

输出:


2019-04-23 08:25:48 qq_30460949 阅读数 1677
  • 识别并计算两条曲线间的距离

    通过本课程学习,初学者可以熟练使用opencv4 API完成各种常见的图像分割、识别任务。 中高级学习者也一定能有新的体会和收获。 本课程所讲的例子代码来自于实际开发项目,有较高的实用性。

    9人学习 刘山
    免费试看

代码来自www.opencvchina.com

#include "cv.h"
#include "highgui.h"
#include "cxcore.h"
#include <stdlib.h>
#include <stdio.h>

#ifndef LINESDISHEADER

#define LINESDISHEADER

//对输入图像进行细化
void ThinImage(IplImage* src, IplImage* dst, int iterations=1);

//获取图像上的轮廓 坐标 
void GetContoursPoints(IplImage* src , CvMat** LinePoints);

#endif



#include "LinesDis.h"


//对输入图像进行细化
void ThinImage(IplImage* src, IplImage* dst, int iterations)
{
 CvSize size = cvGetSize(src);

 cvCopy(src, dst);//拷贝一个数组给另一个数组
    int n = 0,i = 0,j = 0;
 for(n=0; n<iterations; n++)
 {
IplImage* t_image;
 
 t_image = cvCloneImage(dst);
  for(i=0; i<size.height;  i++)
  {
   for(int j=0; j<size.width; j++)
   {
    if(CV_IMAGE_ELEM(t_image,byte,i,j)==1)
    {
     int ap=0;
     int p2 = (i==0)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j);
     int p3 = (i==0 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte, i-1, j+1);
     if (p2==0 && p3==1)
     {
      ap++;
     }
     int p4 = (j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i,j+1);
     if(p3==0 && p4==1)
     {
      ap++;
     }
     int p5 = (i==size.height-1 || j==size.width-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j+1);
     if(p4==0 && p5==1)
     {
      ap++;
     }
     int p6 = (i==size.height-1)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j);
     if(p5==0 && p6==1)
     {
      ap++;
     }
     int p7 = (i==size.height-1 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i+1,j-1);
     if(p6==0 && p7==1)
     {
      ap++;
     }
     int p8 = (j==0)?0:CV_IMAGE_ELEM(t_image,byte,i,j-1);
     if(p7==0 && p8==1)
     {
      ap++;
     }
     int p9 = (i==0 || j==0)?0:CV_IMAGE_ELEM(t_image,byte,i-1,j-1);
     if(p8==0 && p9==1)
     {
      ap++;
     }
     if(p9==0 && p2==1)
     {
      ap++;
     }
     if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7)
     {
      if(ap==1)
      {
       if(p2*p4*p8==0)
       {
        if(p2*p6*p8==0)
        {
         CV_IMAGE_ELEM(dst, byte,i,j)=0;
        }
       }
      }
     }                    
    }

   }

  }            
  cvReleaseImage(&t_image);

}

 //将二值图像转换成灰度,以便显示
  i = 0;j = 0;
  size = cvGetSize(dst);
 for(i=0; i<size.height;  i++)
 {
  for(j=0; j<size.width; j++)
  {
   if(CV_IMAGE_ELEM(dst,uchar,i,j)==1)
   {
    CV_IMAGE_ELEM(dst,uchar,i,j) = 255;
   }
   else
   {
    CV_IMAGE_ELEM(dst,uchar,i,j) = 0;
   }
  }
 }

}

//获取图像上的轮廓 坐标 
void GetContoursPoints(IplImage* src , CvMat** LinePoints)
{
	CvMemStorage* storage = cvCreateMemStorage(0);
	CvSeq* contour = 0;
	IplImage* binary_image = cvCreateImage(cvGetSize(src),8,1);
	cvCopy(src,binary_image);

	cvFindContours(binary_image , storage , &contour , sizeof(CvContour) , CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,cvPoint(0,0) );

//#define SHOWCON
#ifdef SHOWCON
	IplImage* contours;
	contours = cvCreateImage(cvGetSize(src),8,1);
	cvZero(contours);
	cvNamedWindow("con");
#endif 

	int LinesCount = 0;

	for(;contour!=0 ; contour=contour->h_next)
	{
		if(contour->total < 20 )continue;

		LinePoints[LinesCount] = cvCreateMat(contour->total/8,1,CV_32FC2);
		
	
		for(int i=0; i<contour->total/8 ; i++)
		{
	
			CvPoint * pt = (CvPoint*)cvGetSeqElem(contour, i); // 读出第i个点。
			cvSet2D(LinePoints[LinesCount] , i,0,cvScalar(pt->x,src->height - pt->y,0,0));

			//cvSetReal2D(contours , pt->y , pt->x , 255.0);
#ifdef SHOWCON
			CvScalar val = cvGet2D(LinePoints[LinesCount] , i, 0);
			cvSetReal2D(contours , val.val[1] ,val.val[0],255);
		
			cvShowImage("con" ,contours);
			cvWaitKey(0);
#endif

		
		}
		LinesCount++;

	}

#ifdef SHOWCON
	for(int i=0;i<LinesCount;i++)
	{
		for(int y=0;y<LinePoints[i]->rows;y++)
		{
			CvScalar pt = cvGet2D(LinePoints[i] , y, 0);
			cvSetReal2D(contours , pt.val[1] ,pt.val[0],255);
			printf("(%f,%f) ",pt.val[0],pt.val[1]);
		}
	}


	cvShowImage("con" ,contours);
	cvWaitKey(0);
#endif

	cvReleaseMemStorage(&storage);
	cvReleaseImage(&binary_image);

}

 

// ComputeLinesDis.cpp : Defines the entry point for the console application.
//



#include "LinesDis.h"

int main(int argc, char* argv[])
{
	//对两条直线进行细化
	IplImage *pSrc = NULL,*pDst = NULL,*pTmp = NULL;

	//传入一个灰度图像,从文件中读取图像
	pSrc = cvLoadImage("1.png",CV_LOAD_IMAGE_GRAYSCALE);
	if(!pSrc)
	{
		return 0;
	}

	pTmp = cvCreateImage(cvGetSize(pSrc),pSrc->depth , pSrc->nChannels);
    pDst = cvCreateImage(cvGetSize(pSrc),pSrc->depth,pSrc->nChannels);
	cvZero(pDst);//初始化
	cvThreshold(pSrc,pTmp,128,1,CV_THRESH_BINARY_INV);//做二值处理,将图像转换成0,1
 
	//第一步 对图像中的直线进行细化
	ThinImage(pTmp,pDst,80);


#define SHOWRESULT
#ifdef SHOWRESULT
	cvNamedWindow("src",1);//创建窗口
	cvNamedWindow("dst",1);
	cvShowImage("src",pSrc);
	cvShowImage("dst",pDst);
#endif





	//第二步  提取直线的轮廓坐标
	CvMat*LinesPoints[2];
	LinesPoints[0]=0;LinesPoints[1]=0;
	GetContoursPoints(pDst,LinesPoints);

//#define SHOWCONT
#ifdef SHOWCONT
	IplImage* contours = cvCreateImage(cvGetSize(pDst),8,1);
	cvZero(contours);
	cvNamedWindow("Mcon");
	for(int i=0;i<2;i++)
	{
		for(int y=0;y<LinesPoints[i]->rows;y++)
		{
			CvScalar pt = cvGet2D(LinesPoints[i] , y, 0);
			cvSetReal2D(contours , pt.val[1] ,pt.val[0],255);
			cvShowImage("Mcon" ,contours);
		}
	}


	cvWaitKey(0);
#endif


	//第三步 对轮廓上的坐标进行直线拟合 计算直线方程 By = Ax + b
	float params[4] , k[2] , b[2] , A , B;
	cvFitLine(LinesPoints[0] , CV_DIST_L2,1,0.001,0.001,params);
	k[0] = params[1]/params[0];
	b[0] = params[3] - k[0]*params[2];
	A    = k[0];
	B    = 1;

	printf("y=%f*x+%f \n",k[0]*180.0/3.1415,b[0]);

	cvFitLine(LinesPoints[1] , CV_DIST_L2,1,0.001,0.001,params);
	k[1] = params[1]/params[0];
	b[1] = params[3] - k[0]*params[2];

	printf("y=%f*x+%f \n",k[1]*180.0/3.1415,b[1]);

	//第四部  计算两条直线之间的距离 公式是: |b1-b0| / sqrt(A*A + B*B)
	float 	dis = abs(b[1]-b[0])/sqrt(A*A + B*B);

	printf("dis is %f \n" , dis); 



	// 释放内存
    cvReleaseImage(&pSrc);
	cvReleaseImage(&pDst);
	cvReleaseImage(&pTmp);

	if(LinesPoints[0])
	cvReleaseMat(&LinesPoints[0]);
	
	if(LinesPoints[1]);
	cvReleaseMat(&LinesPoints[1]);
	cvWaitKey(0);

	return 0;
}

 

 

 

2019-07-04 23:16:50 ltshan139 阅读数 969
  • 识别并计算两条曲线间的距离

    通过本课程学习,初学者可以熟练使用opencv4 API完成各种常见的图像分割、识别任务。 中高级学习者也一定能有新的体会和收获。 本课程所讲的例子代码来自于实际开发项目,有较高的实用性。

    9人学习 刘山
    免费试看

前言

Opencv4图像分割和识别实战6的视频课程(https://edu.csdn.net/course/detail/24864)主要是讲解如何求两条曲线之间的距离。对应的,本课作业来求下面图所示的两条直线间距离以巩固课堂上所学的知识。

解决方法一 

1)通过前面所学的投影分割法来分别获得这2条直线上的离散采样点,然后将它们通过直线拟合求得各自的直线方程,如k1x+b和k2x+b2。 

2)在其中一条直线上任取一点(x1,y1),然后向另外一条直线做垂线,该垂线方程很好求,其斜率为-(1/k1)

3)求出垂线方程后,即可求垂线和第二条直线的交点(x2,y2)

4)根据欧式距离公式,即可求得当前点到另外一条直线的距离dist=sqrt((x1-x2)^2+(y1-y2)^2)

解决方法二

第一个方法虽然直观,但是比较繁琐。 我们这里借助于课程里面计算两条曲线间距离的方法来求解。

这里面重点要理解两个概念

1)连通域分析,即连在一起的前景被当作一个独立的目标,并给与对应的label号。它也是传统图像处理中常用的图像分割和识别的手段。

2)distanceTransform()的使用。该api是用来计算前景像素(白色)到最近的背景像素(黑色)的距离。利用它就可以求点到直线的垂直距离了。 

当然,这两个概念以及背后的算法原理会在课堂上结合实例进行详细解释。 

回到本次课后作业,我们可以先进行连通域分析来区分开这两条直线,并分别打上1和2的label号,如下局部放大图所示,上下分别是两条直线的label。

然后想办法,把第一条线变黑,图像其余部分都是白色,调用distanceTransform()来自动计算所有白色像素到第一条(黑色)直线的垂直距离,并且这些白色像素的像素值由255变成各自的垂直距离值了。 其中一部分值如下图所示。

 

上面的操作在类似做一次,就可以求得第一条直线上各点到第二条直线得距离。

具体代码和求两条曲线距离得几乎完全一样,这里就不贴了,课件里面会上传。

 

 

 

2019-03-15 10:04:21 linkequa 阅读数 4815
  • 识别并计算两条曲线间的距离

    通过本课程学习,初学者可以熟练使用opencv4 API完成各种常见的图像分割、识别任务。 中高级学习者也一定能有新的体会和收获。 本课程所讲的例子代码来自于实际开发项目,有较高的实用性。

    9人学习 刘山
    免费试看

1,两条线平行,它们的斜率肯定相同,首先将x和有前面的系数化为相同,设为a和b。

则两条直线方程分别为:
Line 1: ax1 + by1 + c1 = 0
Line 2: ax2 +by2 + c2 = 0
d(Line1,Line2)=c1c2/a2+b2d(Line 1, Line2)=|c1-c2|/\sqrt{a^2+b^2}

2,推导过程

在这里插入图片描述

图像处理与识别

阅读数 9098