`

openCV综合运用 ------- 图像细化、线段长度、平行线距离检测

 
阅读更多

      在上述博客中,我分别对平滑滤波、边缘检测、直线检测做了一定程度的了解,那么最终的目的我们是需要解决实际问题,那么今天就试着完成一个简单的综合训练,来在巩固前面所学知识的同时,学到新的东西!

      题目如下:
                                                

    1.分别检测两线段的长度;

    2.算出这两平行线之间的距离。

    题目参考:http://www.opencvchina.com/thread-854-1-2.html

 

先看第一问,要求直线的距离。很容易联想到上一回所说的霍夫变换中的PHTT方法,返回的是直线的方向以及范围,说的具体一点,实际上返回的就是检测到的直线的两端点。我们不妨用霍夫变换直接试试。具体步骤:

                          将图像转换成灰度图像->霍夫变换->将检测直线的端点(绿色圆圈)标记出来

得到下面的结果:

 可以看到,我们检测到了很多条直线,如图有很多直线的端点,尤其是直线端点处,被检测到了多个端点(可以看得出有重叠效果)。其实也不难理解,这条直线在像素上来说是有厚度的,所以难免被检测到多条直线,这样的话就带来了问题,我们无法确定到底哪个是真正直线的两端点,于是就不能够得到线段的长度!那么我们在使用霍夫变换前需要做一些处理。-----------图像细化。

 

图像细化实际上就是图像骨架化,把图像核心的骨架留下,其他的赘余点删除,对于这个图来说就是把这条直线的厚度消除,得到一条单像素厚度的直线段。实际上,图像细化在图像处理、模式识别中使用的非常广发,也是非常关键的过程,这里我们介绍一种比较经典实用的图像细化方法----Zhang并行快速算法:

             具体实现方法、步骤如下:

             首先定义如下的8领域(注意顺序不能变):
                                                                  

            其中P1是我们讨论的像素点,首先前提条件是P1是前景点!若要删除该点,需要满足一下条件:

 过程1:

             (1)2 <= N(P1) <= 6,N(x)为x的8领域中黑点(背景点)的个数;

             (2)A(P1) = 1,A(x)为P2-P8之间按序前后分别为0、1的对数;

             (3)P2*P4*P6 = 0;

             (4)P4*P6*P8 = 0.

满足上述四个条件,可将P1点去除;

过程2:

             (1)2 <= N(P1) <= 6,N(x)为x的8领域中黑点(背景点)的个数;

             (2)A(P1) = 1,A(x)为P2-P8之间按序前后分别为0、1的对数;

             (3)P2*P4*P8 = 0;

             (4)P2*P6*P8 = 0.

满足上述四个条件,可将P1点去除;

以上即为Zhang并行算法的主要步骤,需要反复运行直到无法得到可删除点为止。对于图像细化,这里只做一个简单的了解,很多理论知识以及高级的算法我后续会再进行分析。

给出关键代码函数如下:

 

//寻找按序的前后分别是0、1的对数函数
int Findn(IplImage* img, int i, int j)
{
 CvScalar s1 = cvGet2D(img, i, j);
 CvScalar s2 = cvGet2D(img, i - 1, j);
 CvScalar s3 = cvGet2D(img, i - 1, j + 1);
 CvScalar s4 = cvGet2D(img, i, j + 1);
 CvScalar s5 = cvGet2D(img, i + 1, j + 1);
 CvScalar s6 = cvGet2D(img, i + 1, j);
 CvScalar s7 = cvGet2D(img, i + 1, j - 1);
 CvScalar s8 = cvGet2D(img, i, j - 1);
 CvScalar s9 = cvGet2D(img, i - 1, j - 1);
 int a = s1.val[0];
 int b = s2.val[0];
 int c = s3.val[0];
 int d = s4.val[0];
 int e = s5.val[0];
 int f = s6.val[0];
 int g = s7.val[0];
 int h = s8.val[0];
 int l = s9.val[0];

 int find[] = { a, b, c, d, e, f, g, h, l };//按8领域顺序定义数组,方便操作
 int n = 0;
 for (int x = 2; x < 9; ++x)
 {
  if (find[x] == 0 && find[x + 1] == 255)
  {
   n = n + 1;
  }
 }
 return n;
}

//这是细化直线的功能函数
IplImage* ThinImage(IplImage* img, int k) //确保输入的是二值图像
{
 int condition = 0;//满足的条件个数
 int mark = 0;//成功的标志位
 int firstN = 0;//第一个条件黑点的个数
 CvScalar s;
 for (int n = 0; n < k; ++n)
 {
  for (int i = 1; i < img->height - 1; ++i)
  {
   for (int j = 1; j < img->width - 1;++j)
   {//开始过程1的寻找
    condition = 0;//初始化条件满足数
         //cout << "1" << endl;
    s = cvGet2D(img, i, j);
    if (s.val[0] == 255)//如果这是前景点,即边缘
    {
     //cout << "2" << endl;
     //*************************第一过程****************************
     //*************************step1****************************
     firstN = 0;
     for (int ii = -1; ii < 1; ++ii)
     {
      for (int jj = -1; jj < 1; ++jj)
      {
       s = cvGet2D(img, i + ii, j + jj);
       if (s.val[0] == 255)
       {
        firstN = firstN + 1;
       }
      }
     }
     if (firstN < 3 || firstN > 7)
     {
      continue;
     }
     else
     {
      condition = condition + 1;
     }
     //****************************************************************
     //*************************step2*********************************
     if (Findn(img, i, j) != 1)
     {
      continue;
     }
     else
     {
      condition = condition + 1;
     }
     //****************************************************************
     //*************************step3*********************************
     CvScalar s1 = cvGet2D(img, i - 1, j);
     CvScalar s2 = cvGet2D(img, i, j + 1);
     CvScalar s3 = cvGet2D(img, i + 1, j);
     CvScalar s4 = cvGet2D(img, i, j - 1);
     int a = s1.val[0];//2
     int b = s2.val[0];//4
     int c = s3.val[0];//6
     int d = s4.val[0];//8

     if (a * b * c != 0)
     {
      continue;
     }
     else
     {
      condition = condition + 1;
     }
     //*********************************************************************
     //******************************step4**********************************
     if (b * c * d != 0)
     {
      continue;
     }
     else
     {
      condition = condition + 1;
     }
     //*********************************************************************
     //第一过程的结果操作
     if (condition == 4)
     {
      mark = 1;
      //((char *)(img->imageData + img->widthStep * (i)))[j] = 0;
      CvScalar p;
      p.val[0] = 0;
      cvSet2D(img, i, j, p);
      //cout << "11111111111111111111111111111111111" << endl;
     }
    }
   }
  }

  //****************************过程2**************************
  for (int i = 1; i < img->height - 1; ++i)
  {
   for (int j = 1; j < img->width - 1;++j)
   {//开始过程1的寻找
    condition = 0;//初始化条件满足数
         //cout << "1" << endl;
    s = cvGet2D(img, i, j);
    if (s.val[0] == 255)//如果这是前景点,即边缘
    {
     //cout << "2" << endl;
     //*************************第一过程****************************
     //*************************step1****************************
     firstN = 0;
     for (int ii = -1; ii < 1; ++ii)
     {
      for (int jj = -1; jj < 1; ++jj)
      {
       s = cvGet2D(img, i + ii, j + jj);
       if (s.val[0] == 255)
       {
        firstN = firstN + 1;
       }
      }
     }
     if (firstN < 3 || firstN > 7)
     {
      continue;
     }
     else
     {
      condition = condition + 1;
     }
     //****************************************************************
     //*************************step2*********************************
     if (Findn(img, i, j) != 1)
     {
      continue;
     }
     else
     {
      condition = condition + 1;
     }
     //****************************************************************
     //*************************step3*********************************
     CvScalar s1 = cvGet2D(img, i - 1, j);
     CvScalar s2 = cvGet2D(img, i, j + 1);
     CvScalar s3 = cvGet2D(img, i + 1, j);
     CvScalar s4 = cvGet2D(img, i, j - 1);
     int a = s1.val[0];//2
     int b = s2.val[0];//4
     int c = s3.val[0];//6
     int d = s4.val[0];//8

     if (a * b * d != 0)
     {
      continue;
     }
     else
     {
      condition = condition + 1;
     }
     //*********************************************************************
     //******************************step4**********************************
     if (a * c * d != 0)
     {
      continue;
     }
     else
     {
      condition = condition + 1;
     }
     //*********************************************************************
     //第一过程的结果操作
     if (condition == 4)
     {
      mark = 1;
      //((char *)(img->imageData + img->widthStep * (i)))[j] = 0;
      CvScalar p;
      p.val[0] = 0;
      cvSet2D(img, i, j, p);
      //cout << "222222222222222222222222" << endl;
     }
    }
   }
  }
  //cout << " end " << endl;
 }

 return img;

}
 以上即为图像骨架化的编程实现,让我们看一看效果吧:

 可以看到,直线已经骨架化成功了,那么接下来,我们再使用霍夫变换检测线段。使用PPHT方法,得到线段的方向以及范围信息,并将检测的直线端点标记出来,代码如下:

CvMemStorage* storageline = cvCreateMemStorage(0);
 CvSeq* lines;
 lines = cvHoughLines2(binaryline, storageline, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 300, 100, 10, 1000);
 int n = 0;
 CvPoint* point;
 double temp[8];
 for (int i = 0; i < lines->total; ++i)
 {
  point = (CvPoint*)cvGetSeqElem(lines, i);
  temp[i * 4] = point[0].x;
  temp[i * 4 + 1] = point[0].y;
  temp[i * 4 + 2] = point[1].x;
  temp[i * 4 + 3] = point[1].y;
  cvLine(resultline, point[0], point[1], CV_RGB(255, 0, 0));
  cvCircle(resultline, point[0], 3, CV_RGB(0, 255, 0), 1, 8, 3);
  cvCircle(resultline, point[1], 3, CV_RGB(0, 255, 0), 1, 8, 3);
  double distance = sqrt((point[1].x - point[0].x) * (point[1].x - point[0].x) + (point[1].y - point[0].y) * (point[1].y - point[0].y));  
  cout << "the " << i << " line's distance :" << distance << endl;
  ++n;
 }
 cout << n << endl;
 n = 0;

结果如下:

 成功得到了直线端点坐标的信息,并且输出n = 2,即刚刚好检测到两条直线!nice,这样的话直线长度就很好求了,使用数学方法,计算两坐标之间的距离即可。(结果将在后面显示)

 

第二问实际上在第一问的基础上,就是一个数学问题。

 
如图,正是求两平行线距离x。

                                                                   x = |AC|/sin(a)

于是通过向量求得

                                                         cos = (AB·AC)/|AB||AC|
                                                          sin = sqrt(i - cos^2)

于是便可求得x。

按照如此思路,编程求得上述两问的结果:

 
 

  • 大小: 10 KB
  • 大小: 2.4 KB
  • 大小: 1.3 KB
  • 大小: 1.2 KB
  • 大小: 1.2 KB
  • 大小: 4 KB
  • 大小: 10.9 KB
分享到:
评论

相关推荐

    OpenCV-MinGW-Build-OpenCV-4.5.2-x64.zip

    在本压缩包“OpenCV-MinGW-Build-OpenCV-4.5.2-x64.zip”中,提供的是一份已经针对MinGW编译器优化的OpenCV 4.5.2版本,适用于64位Windows系统。 OpenCV 4.5.2是该库的一个稳定版本,它包含了众多新特性和性能提升...

    OpenCV-MinGW-Build-OpenCV-4.5.0-with-contrib.zip

    OpenCV-MinGW-Build-OpenCV-4.5.0-with-contrib

    opencv-4.5.5-1.5.7-API文档-中文版.zip

    赠送jar包:opencv-4.5.5-1.5.7.jar; 赠送原API文档:opencv-4.5.5-1.5.7-javadoc.jar; 赠送源代码:opencv-4.5.5-1.5.7-sources.jar; 赠送Maven依赖信息文件:opencv-4.5.5-1.5.7.pom; 包含翻译后的API文档:...

    opencv-4.5.5-1.5.7-API文档-中英对照版.zip

    赠送jar包:opencv-4.5.5-1.5.7.jar; 赠送原API文档:opencv-4.5.5-1.5.7-javadoc.jar; 赠送源代码:opencv-4.5.5-1.5.7-sources.jar; 赠送Maven依赖信息文件:opencv-4.5.5-1.5.7.pom; 包含翻译后的API文档:...

    opencv-4.5.1-1.5.5-API文档-中文版.zip

    赠送jar包:opencv-4.5.1-1.5.5.jar; 赠送原API文档:opencv-4.5.1-1.5.5-javadoc.jar; 赠送源代码:opencv-4.5.1-1.5.5-sources.jar; 赠送Maven依赖信息文件:opencv-4.5.1-1.5.5.pom; 包含翻译后的API文档:...

    opencv-4.5.1-1.5.5-API文档-中英对照版.zip

    赠送jar包:opencv-4.5.1-1.5.5.jar; 赠送原API文档:opencv-4.5.1-1.5.5-javadoc.jar; 赠送源代码:opencv-4.5.1-1.5.5-sources.jar; 赠送Maven依赖信息文件:opencv-4.5.1-1.5.5.pom; 包含翻译后的API文档:...

    OpenCV-MinGW-Build-OpenCV-4.5.0-with-contrib-32bit.zip

    这个压缩包"OpenCV-MinGW-Build-OpenCV-4.5.0-with-contrib-32bit.zip"是专为在Windows环境下使用MinGW编译器进行C++开发而准备的。MinGW(Minimalist GNU for Windows)是一个小型的GNU开发工具集,它提供了一个不...

    opencv-4.5.5-opencv-contrib-4.5.5-以及其他OpenCV配置需要的(安装包)

    opencv-4.5.5-opencv-contrib-4.5.5-以及其他OpenCV配置需要的(安装包) opencv-4.5.5-vc14_vc15.exe opencv_contrib-4.5.5.zip cmake-3.24.0-rc1-windows-x86_64.msi jdk-17_windows-x64_bin.msi VTK-8.2.0.zip

    opencv_官网 安装包 opencv-4.1.2-vc14_vc15

    opencv 安装包 opencv-4.1.2-vc14_vc15 opencv 安装包 opencv-4.1.2-vc14_vc15 opencv 安装包 opencv-4.1.2-vc14_vc15 opencv 安装包 opencv-4.1.2-vc14_vc15 opencv 安装包 opencv-4.1.2-vc14_vc15 opencv 安装包 ...

    opencv-4.5.3-android-sdk.zip

    最新的版本“opencv-4.5.3-android-sdk.zip”专为Android平台设计,提供了丰富的API和功能,使得开发者能够在Android设备上实现复杂的图像处理算法。 1. **OpenCV介绍**: OpenCV是一个跨平台的计算机视觉库,由...

    opencv-python-4.10.0.84.tar.gz

    Python版本的OpenCV库,也就是`opencv-python`,为Python程序员提供了方便的接口来利用这个功能丰富的库。在本案例中,我们讨论的是OpenCV的Python接口的4.10.0.84版本,它是一个经过编译的二进制包,文件名为`...

    opencv-4.5.5-opencv-contrib-4.5.5-以及其他OpenCV配置需要的包

    opencv-4.5.5-vc14_vc15.exe opencv_contrib-4.5.5.zip cmake-3.24.0-rc1-windows-x86_64.msi jdk-17_windows-x64_bin.msi VTK-8.2.0.zip

    opencv-4.9.0-android

    这个"opencv-4.9.0-android"版本是OpenCV针对Android平台的特定优化版本,包含了最新的特性和性能改进。 1. **OpenCV库的核心功能**: - 图像处理:包括滤波、边缘检测(如Canny、Sobel、Laplacian)、色彩转换...

    opencv-4.5.4-android-sdk .zip

    opencv-4.5.4-android-sdk .zip

    opencv-4.4.0-androidopencv-4.5.0-android-sdk

    1. **集成OpenCV到Android项目**:首先,开发者需要将下载的opencv-4.5.0-android-sdk.zip或opencv-4.4.0-android-sdk.zip解压,获取到对应的AAR库文件。然后,通过Android Studio的Gradle构建系统,将AAR库添加到...

    opencv_contrib-4.5.5.zip/opencv_contrib-4.5.5.zip

    3. **贡献模块**(opencv_contrib):包含了额外的模块,如Xfeatures2d(特征检测和描述符),ximgproc(图像处理算法),xobjdetect(对象检测),xphoto(照片修复),aruco(二维码和AR标记识别),face(人脸...

    opencv-4.1.0-android-sdk

    8. **额外工具**:OpenCV-4.1.0-android-sdk可能还包括一些辅助工具,如图像查看器、性能测试工具等,方便开发者调试和评估算法性能。 在实际开发中,开发者需要将OpenCV库添加到Android Studio项目中,配置好依赖...

    几个平台版本的opencv,opencv-4.8.0-windows\opencv-4.6.0-android-sdk

    首先,我们关注的是"opencv-4.8.0-windows.exe",这是一个针对Windows平台的OpenCV安装包。OpenCV在Windows上提供了丰富的API和函数,支持C++、Python、Java等多种编程语言,便于开发者进行图像处理和计算机视觉项目...

    OpenCV-MinGW-Build-OpenCV-3.3.1.zip

    # OpenCV-MinGW-Build MinGW version of OpenCV compiled on Windows. ## [OpenCV 3.4.1](https://github.com/huihut/OpenCV-MinGW-Build/tree/OpenCV-3.4.1) ``` git clone -b OpenCV-3.4.1 git@github....

    opencv-4.6.0-vc14-vc15.exe

    这个压缩包"opencv-4.6.0-vc14-vc15.exe"很可能是OpenCV的特定版本,兼容Visual Studio 2014 (VC14) 和 Visual Studio 2015 (VC15) 的编译环境。 OpenCV 4.6.0是该库的一个稳定版本,可能包含了自4.0.0版本以来的...

Global site tag (gtag.js) - Google Analytics