【opencv】两条平行线之间的距离
问题:一张输入图片,图片上有两条平行线,求出这两条平行线之间的距离
解决思路:
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;
}
运行效果:
输入:
输出:
【opencv】两条平行线之间的距离相关推荐
- OpenCV计算两条平行线之间的距离
代码来自www.opencvchina.com #include "cv.h" #include "highgui.h" #include "cxco ...
- 求空间两条直线之间的距离
1. 前言 最近老板让写一段空间点匹配的代码, 其中涉及到求空间两直线之间的距离,写起来满费劲的, 这里做一个记录. 2. 处理思路 空间两直线之间的位置关系主要可以分为: 重合, 平行, 相交, 异 ...
- 平行线判断函数+求平行线之间的距离
struct LINE {CvPoint pt0;CvPoint pt1;LINE( CvPoint pta, CvPoint ptb ){pt0 = pta;pt1 = ptb;}LINE(){pt ...
- 利用高德地图API获取任意两座城市之间的距离!异地也有惊喜!
工作中有时会遇到这样一种场景:年末需要统计所有员工该年的航旅出差情况,然后根据他们的飞行距离补贴一定的交通费.例如如下所示情况: 然而,如果我们使用地图APP等工具逐一进行手工查询,在一家规模稍大的公 ...
- 两条平行线相交于一点
2019独角兽企业重金招聘Python工程师标准>>> 欧几里德几何说,两条平行的直线永远无法相交,爱因斯坦站在宇宙空间的角度猜测两条平行线有可能能相交,但到底如何相交,爱因斯坦也没 ...
- sklearn计算两个向量之间的距离
from sklearn.feature_extraction.text import CountVectorizer from sklearn.metrics.pairwise import euc ...
- 算法----- 给定一颗二叉树,找到二叉树上任意两个节点之间的距离(Java版本)
题目: 给定一颗二叉树,找到二叉树上任意两个节点之间的距离 class TreeNode {TreeNode left;TreeNode right;} 思路: 首先找到一个节点的路径,然后找到另一个 ...
- 高德经纬度距离计算php,计算两个经纬度之间的距离 单位(m)
/** * 计算两个经纬度之间的距离 单位(m) * * @param lat1 * @param lng1 * @param lat2 * @param lng2 * @return */ publ ...
- 百度地图 使用两条平行线表示路线
根据他人的程序修改的,原文是如何利用百度地图JSAPI画带箭头的线? 在此,使用两条平行线表示路线. 1.坐标计算: 2.代码如下: <%@ page language="java&q ...
最新文章
- 如何使用 Cockpit 管理你的树莓派
- 学习笔记100—强制免费下载 百度文库等网站上文档 以及客道巴巴文档 教程
- 深入分析Java Web技术内幕pdf
- python中numpy.ndarray与list的区别?以及用matplotlab.pyplot绘图时的注意事项。
- 力扣:12正数转罗马数字(python) 简单粗暴解决方法
- 计算几何 - XOJ 1171 线段求交
- excel 表生成insert语句。
- Android中集成第三方库的方法和问题
- Android动态logo,Android模仿拉勾网logo动画效果
- word打开html显示空白,电脑打开Word文档内容显示不全或显示空白怎么办
- nginx 安装到Java代码上传图片利用ftp过程遇到的问题总结
- java读取加密excel_Java 加密和解密Excel文档
- Java的环境变量在哪个文件夹_Java设置环境变量
- 微信开放平台开发——网页微信扫码登录(OAuth2.0)
- js距离单位换算_javascript实现的平方米、亩、公顷单位换算小程序
- MySQL中tinytext、text、mediumtext和longtext等类型详解
- 微服务研究 - Swoole框架-Swoft初探
- jq里的event对象
- 蒜头君爬楼梯(2) - 计蒜客
- Gartner2019年十大安全项目详解