【opencv】两条平行线之间的距离

article/2025/9/1 2:12:10

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

解决思路:

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;
}
运行效果:

输入:

输出:



http://chatgpt.dhexx.cn/article/vecMVhN9.shtml

相关文章

OpenCV计算两条平行线之间的距离

代码来自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* s…

用vue实现tab切换

用vue实现tab切换 html代码 <div id"app"><ul class"tab-tilte"><li click"cur0" :class"{active:cur0}">html</li><li click"cur1" :class"{active:cur1}">css</li><li…

tab切换(用jQuery实现)?

页面中经常用到的tab栏&#xff0c;来分类展示内容 我认为掌握tab栏切换算是从静态页面到动态页面所迈出的第一步&#xff0c;并且在以后的工作中(jQuery框架开发)会作为jQuery中的常用事件和方法&#xff0c;反复的使用&#xff0c;所以掌握tab栏切换至关重要&#xff01;&am…

JQUERY实现TAB切换

博主是一枚前端小菜鸟&#xff0c;因为挺长时间没接触页面布局了&#xff0c;居然连tab栏切换都给忘了&#xff0c;后来博主看了一些前端资料还有书&#xff0c;发现网上的很多方法都杂乱无章&#xff0c;看的云里雾里的&#xff0c;冗余代码太多&#xff0c;这让新手小白会很苦…

React实现tab切换

下面来编写一个tab选项卡切换效果&#xff0c;效果如下图所示&#xff1a; 下面我放上该组件的代码&#xff1a; import React, { Component } from react; import { Link } from react-router; import ../scss/base.scss; import ../scss/tab.scss;class TabController exten…

vue实现Tab切换功能

在项目开发中&#xff0c;我们经常会碰到Tab切换的功能&#xff0c;而在Vue中想实现这样的功能也应该有很多种&#xff0c;常用的三种应该是 Tab路由切换、Tab动态组件切换、通过v-show设置Tab显示隐藏。每种方法实现起来其实都不难&#xff0c;看看官网介绍或看几篇博客应该就…

tab切换效果

1.效果图 2.分析步骤 1.首先写vue先引入&#xff1a;<script src"https://cdn.jsdelivr.net/npm/vue2.6.14/dist/vue.js"></script> 2.接着写静态布局 3.挂载dom 4.添加指令 5.肯定要储存数据 6. 最后效果实现 3.代码块部分 按步骤操作 1.首先&#xf…

vue中如何实现tab切换功能?

一、v-show控制内容切换 1&#xff09;简单版原理&#xff1a;用点击事件改变num值作为开关&#xff0c;控制tab样式和内容显示隐藏。 2&#xff09;数据渲染原理&#xff1a;主要利用v-for绑定的index来控制&#xff0c;跟上面差不多。 二、组件切换。 知识点主要是vue中is的…

点击tabs切换不同的内容

1.通过v-for遍历posts,然后渲染数据 2.定义currentTabs变量 3.运用computed计算属性 4.点击按钮时&#xff0c;切换下边的内容 5.点击切换tabs时&#xff0c;高亮当前tabs 4.将切换tabs的文件封装成组件&#xff0c;可以使用keep-alive进行缓存数据 5.使用keep-alive触发的生命…

Tab选项卡切换

Tab选项卡切换 基本代码 HTML代码&#xff1a; <div id"notice" class"notice"><!-- 标题--><div id"notice-tit" class"notice-tit"><ul><li><a href"#">公告</a></li>…

【JS实现tab切换】

JavaScript实现tab切换。 点击科技显示图一, 点击探索显示图二。 body部分&#xff1a; <div class"box"><ul><li class"active">科技</li><li>探索</li></ul><ol><li class"active">科…

Tab页面切换

页面效果如图 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta http-equiv"X-UA-Compatible" content"IEedge"> <meta name"viewport" content"widthdevice-…

Vue实现Tab切换效果

通过Vue实现简单的Tab切换 实现思路是点击上方的标题&#xff0c;下方的内容随之发生改变&#xff0c;上方和下方用的是两个块&#xff0c;是兄弟节点&#xff0c;所以需要点击tab标题和下方内容一一对应&#xff0c;基予两个模块若下标相同是一个内容实现的。Tab切换第一步先…

html的tab切换

离开学还有10天了&#x1f630; 今天再水一篇博客 &#xff08;如图&#xff09; 通过点击来切换tab。 具体思路十分简单&#xff0c;将这些都先包含进一个大的div 先是html部分 <div class"body1"><div class"game"><ul><li>…

Vue实现选项卡切换,tab切换

1、实现tab切换就是 单击一个选项卡显示其对应的内容&#xff0c;且被点击的选项卡改变颜色&#xff0c;下面有两种实现方法&#xff08;都不要忘了vue.js的目录要写正确&#xff09; 2、第一种方法效果图 这个没什么可说的&#xff0c;直接看代码吧&#xff08;两种方式&…

最简单的Tab切换

HTML <div class"main"><div class"btn"><!-- Tab标题 --><span class"active spanList">课程介绍</span><span class"spanList">用户故事</span><span class"spanList">…

简单的tab选项卡切换

Tab选项卡切换 我们在网页上经常能看到的一个现象点击某一文字就会跳转出宁一个页面、而在同一个页面中点击头部内容&#xff0c;主体内容也会随之改变。前者是a 标签所实现的效果&#xff0c;而后者则是tab选项卡的切换。接下来我们一起来看看tab选项卡怎么个切换方法&#x…

前端——tab 栏切换案例

案例 当鼠标点击上面相应的选项卡&#xff08;tab&#xff09;&#xff0c;下面内容跟随变化 分析 Tab栏切换有2个大的模块上面的模块选项卡&#xff0c;点击某一个&#xff0c;当前这一个底色会是红色&#xff0c;其余不变&#xff08;排他思想&#xff09; 修改类名的方式…

tab栏切换

tab栏切换 当鼠标点击上面相应的选项卡(tab)&#xff0c;下面内容也跟随变化。 【案例分析】 1&#xff1a;Tab栏切换与两个大的模块 2&#xff1a;上面的模块选项卡&#xff0c;点击某一个&#xff0c;当前这一个底色会变成红色&#xff0c;其他不变(排它思想) &#xff0c;…