http://answers.opencv.org/question/129819/finding-distance-between-two-curves/

问题:
Hello, Im trying to add tangents along the curve in the image below, like the red lines in the second picture. Then I would like to use the tangents to find the the 90 degrees normal line to the tangent(the green lines). The goal is to find the distance between the two white lines at different places. I use Python and if anyone have any suggestion on how I could do this, or have any suggestions of a better way, I would be very grateful. 
优质解答:
I think this example in C++ should work. Unfortunately I don't know Python DistanceTranform but I think you can use this tutorial in C++ and this one in python to translate it in python. SparseMatrix is only for fun. you don't need it result (in Mat result) is saved in an yml file.
int main(int argc, char* argv[])
{
    Mat img=imread("14878460214049233.jpg",IMREAD_GRAYSCALE);
    imshow("test",img);
    threshold(img,img,200,255,CV_THRESH_BINARY); // to delete some noise
    imshow("test", img);

Mat labels;
    connectedComponents(img,labels,8,CV_16U);
    Mat result(img.size(),CV_32FC1,Scalar::all(0));
    for (int i = 0; i <= 1; i++)
    {
        Mat mask1 = labels == 1+i;
        Mat mask2 = labels == 1+(1-i);
        Mat masknot;
        bitwise_not(mask1,masknot);
        imshow("masknot", masknot);
        Mat dist;
        distanceTransform(masknot,dist, DIST_L2,5,CV_8U);
        imshow("distance float", dist/255);
        dist.copyTo(result,mask2);

}
    imshow("distance 1",result);
    FileStorage fs("distCtr.yml",FileStorage::WRITE);
    fs<<"Image"<<result;
    fs.release();
    waitKey();
    SparseMat ms(result);
    SparseMatConstIterator_<float> it = ms.begin<float>(),it_end = ms.end<float>();
    Mat lig(result.rows,1,CV_8U,Scalar::all(0));
    for (; it != it_end; it ++)
    {
        // print element indices and the element value
        const SparseMat::Node* n = it.node();
        if (lig.at<uchar>(n->idx[0])==0)
        {
            cout<< "("<<n->idx[0]<<","<<n->idx[1]<<") = " <<it.value<float>()<<"\t";
            lig.at<uchar>(n->idx[0])=1;
        }
    }
     return 0;
}

解读:
1、取反,比用threshthold方便;
    bitwise_not(mask1,masknot);
2、connectedComponents 寻找联通区域
官方解释和例子:
 
int cv::connectedComponents  ( InputArray  image,
    OutputArray  labels,
    int  connectivity = 8
    int  ltype = CV_32S 
  )    

computes the connected components labeled image of boolean image

image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0 represents the background label. ltype specifies the output label image type, an important consideration based on the total number of labels or alternatively the total number of pixels in the source image.

Parameters
image the 8-bit single-channel image to be labeled
labels destination labeled image
connectivity 8 or 4 for 8-way or 4-way connectivity respectively
ltype output image label type. Currently CV_32S and CV_16U are supported.

#include <opencv2/core/utility.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Mat img;
int threshval = 100;
static void on_trackbar(intvoid*)
{
    Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);
    Mat labelImage(img.size(), CV_32S);
    int nLabels = connectedComponents(bw, labelImage, 8);
    std::vector<Vec3b> colors(nLabels);
    colors[0] = Vec3b(0, 0, 0);//background
    for(int label = 1; label < nLabels; ++label){
        colors[label] = Vec3b( (rand()&255), (rand()&255), (rand()&255) );
    }
    Mat dst(img.size(), CV_8UC3);
    for(int r = 0; r < dst.rows; ++r){
        for(int c = 0; c < dst.cols; ++c){
            int label = labelImage.at<int>(r, c);
            Vec3b &pixel = dst.at<Vec3b>(r, c);
            pixel = colors[label];
        }
    }
    imshow( "Connected Components", dst );
}
static void help()
{
    cout << "\n This program demonstrates connected components and use of the trackbar\n"
        "Usage: \n"
        "  ./connected_components <image(../data/stuff.jpg as default)>\n"
        "The image is converted to grayscale and displayed, another image has a trackbar\n"
        "that controls thresholding and thereby the extracted contours which are drawn in color\n";
}
const char* keys =
{
    "{help h||}{@image|../data/stuff.jpg|image for converting to a grayscale}"
};
int main( int argc, const char** argv )
{
    CommandLineParser parser(argc, argv, keys);
    if (parser.has("help"))
    {
        help();
        return 0;
    }
    string inputImage ="twolines.jpg";
    img = imread(inputImage.c_str(), 0);
    if(img.empty())
    {
        cout << "Could not read input image file: " << inputImage << endl;
        return -1;
    }
    namedWindow( "Image", 1 );
    imshow( "Image", img );
    namedWindow( "Connected Components", 1 );
    createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar );
    on_trackbar(threshval, 0);
    waitKey(0);
    return 0;
}

但这个例子说不清楚,我自己做一个例子,3条线
connectedComponents(img,labels,8,CV_16U);
....
            Mat tmp = labels == 1;
            Mat tmp2 = labels == 2;
            Mat tmp3 = labels == 3;
结果3个联通区域都能够找出来。这个函数之前我不知道,找联通区域是自己写函数实现的。
3、     Mat result(img.size(),CV_32FC1,Scalar::all(0));
这句就是生成全白的图片。应该说Mat::ones一直都不好用,采用直接定义的方式应该是正确的方式。
补一下数据格式
• CV_8U - 8-bit unsigned integers ( 0..255 )

• CV_8S - 8-bit signed integers ( -128..127 )

• CV_16U - 16-bit unsigned integers ( 0..65535 )

• CV_16S - 16-bit signed integers ( -32768..32767 )

• CV_32S - 32-bit signed integers ( -2147483648..2147483647 )

• CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )

• CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )

4、 distanceTransform(masknot,dist, DIST_L2,5,CV_8U);
首先对图像进行二值化处理,然后给每个像素赋值为离它最近的背景像素点与其距离(Manhattan距离or欧氏距离),得到distance metric(距离矩阵),那么离边界越远的点越亮。
这个图就能够很好地表示出来。注意在OpenCV中始终是以黑色作为0,也是作为背景的。
5、    dist.copyTo(result,mask2);
带有mask的copy,用法都是平时比较少用的。mask的含义就是只有在mask为255的地方,这个拷贝才有效。
 
6、最为核心的地方到了,这个地方写得非常巧妙
 
for (int i = 0; i <= 1; i++)
    {
        Mat mask1 = labels == 1+i;
        Mat mask2 = labels == 1+(1-i);
        Mat masknot;
        bitwise_not(mask1,masknot);
        imshow("masknot", masknot);
        Mat dist;
        distanceTransform(masknot,dist, DIST_L2,5,CV_8U);
        imshow("distance float", dist/255);
        dist.copyTo(result,mask2);
    }
循环两次,只看一次,在第一次中
mask1 是左边这条线
mask2 是右边这条线
那么,直接mask1做bitwise_not翻转之后,这个时候,mask1上面的这条线是黑色的(0)而背景是白色的(255),distanceTransform计算,那么得到了图像上所有白色区域到这条线的距离。
 
为了把mask2这条线显示出来,直接以mask2为模板,把dist copyto到新的mat里面
 
去,那么留下来的就是mask2上所有到mask1的距离值。
 
非常巧妙,我领悟了半天才明白,赞叹赞叹!
 
7、SparseMat 稀疏矩阵
如果是我做的话,做到这一步可能就直接打印了,但是回答者继续一步
稀疏矩阵意味着只有非0元素会被存储
SparseMat ms(result);
    SparseMatConstIterator_<float> it = ms.begin<float>(),it_end = ms.end<float>();
    Mat lig(result.rows,1,CV_8U,Scalar::all(0));
    for (; it != it_end; it ++)
    {
        // print element indices and the element value
        const SparseMat::Node* n = it.node();
        if (lig.at<uchar>(n->idx[0])==0)
        {
            cout<< "("<<n->idx[0]<<","<<n->idx[1]<<") = " <<it.value<float>()<<"\t";
            lig.at<uchar>(n->idx[0])=1;
        }
    }
 
这段代码也非常棒!它的目的是每一行只取一个值,并且打印出来。
当然,如果资源不成问题的话,直接采用原图循环的方法也很直接。但是我详细稀疏矩阵应该有独特的应用吧。
 
整个解答,思路清晰,代码富有弹性。
 

目前方向:图像拼接融合、图像识别 联系方式:jsxyhelu@foxmail.com

Finding distance between two curves相关推荐

  1. 使用cmake宝葫芦炼化Opencv第一丹

    大家还记得西游记里银角大王的那个宝葫芦吗?大圣也被收服进去炼化过.而cmake牌宝葫芦就是把开源的代码适配成您VS法宝调用的dll链接库文件.Cmake处理后可以导入VS平台批量编译,再也不用担心代码 ...

  2. Unity声音 Sound (圣典篇)

    原址:http://game.ceeger.com/Manual/Sound.html Audio Listener 音频侦听器 The Audio Listener acts as a microp ...

  3. 快速离散fr%C3%A9chet距离

    A man is walking a dog on a leash: the man can move on one curve, the dog on the other; both may var ...

  4. 使用HTML5的Canvas和raycasting创建一个伪3D游戏(part1)

    使用HTML5的Canvas和raycasting创建一个伪3D游戏(part1) 刚来这找到一篇好文,自己翻译了下:(原文:http://dev.opera.com/articles/view/cr ...

  5. Bear and Finding Criminals (模拟)

                                          Bear and Finding Criminals There are n cities in Bearland, num ...

  6. Google谷歌通过地址计算两地距离 HOW TO CALCULATE DRIVING DISTANCE BETWEEN 2 LOCATIONS

    1. 通过经纬度,计算直线距离 <script type="text/javascript" src="http://maps.google.com/maps/ap ...

  7. 曲线相似度衡量——曲线距离计算Fréchet distance详解与python计算

    弗朗明歇距离(Fréchet distance)论文可以参考: 理论推导 Eiter, Thomas, and Heikki Mannila. "Computing discrete Fré ...

  8. 牛客网暑期ACM多校训练营(第三场) J Distance to Work 计算几何求圆与多边形相交面积模板...

    链接:https://www.nowcoder.com/acm/contest/141/J 来源:牛客网 Eddy has graduated from college. Currently, he ...

  9. NSGA 2 学习笔记 -- crowding distance

    NSGA-II基于Pareto占优关系对种群中的个体分级,在每一级中计算每个个体在种群中的密度指标,根据占优关系和密度指标对种群中全部个体排序,然后选择相对较好的个体进入下一代迭代循环.常用的密度指标 ...

  10. Wasserstein distance vs Dynamic Time Warping

    这篇博客同时在我的wordpress上发布 In my internship with UCSF Neuroscape lab, I was faced with an important quest ...

最新文章

  1. win7设置java环境变量_win7下JAVA环境变量配置方法
  2. c语言 10以内加法,求助 给小学生出题,自己选加减乘除 做10题 10以内的数 然后统计分...
  3. u-boot移植第三弹——移植2013.10u-boot到RealARM210 cortex-A8开发板(支持moviNAND_Fusing_Tool_v2.0)
  4. NLTK的图形化语料文本下载器downloader
  5. ActiveMQ反序列化漏洞(CVE-2015-5254)复现
  6. 大数据在各个行业的应用_大数据的应用领域有哪些
  7. 2、使用Keras构建回归模型
  8. NB-IOT之一个完整的BC95 UDP从开机到数据发送接收过程
  9. 仿京东商城源码java_Java+SSM实现类似京东的3C电子商城系统
  10. ASP.NET网络版进销存管理系统源码【源码免费分享】
  11. 用matlab读pcap文件,libpcap读取本地pcap文件
  12. 无需编码 9款优秀的数据地图可视化工具平台
  13. filter grok 判断_logstash grok使用案例
  14. SangforAC(深信服)Web单点登录
  15. 3_1 操作系统定义、分类及功能【包含linux操作系统基础知识】
  16. 用ESP8266实现 手机控制车库门开关
  17. 微信小程序真机调试常见问题汇总
  18. 出国留学考试指导大全:托福85分是个坎儿
  19. 大数据在地理信息系统的应用
  20. 一些kaldi常用的术语和命令(二)

热门文章

  1. 学习3ds max插件开发过程中的一些小结
  2. 解决Mac系统finder卡顿转菊花的问题
  3. Linux学习笔记(8)文件搜索与帮助(find)
  4. windows下把文件压缩成tar.gz格式
  5. Eureka 注册中心 简单搭建
  6. .7-Vue源码之AST(3)
  7. Postfix 故障记录
  8. gethostbyname
  9. Maven常用命令 - 构建反应堆中指定模块
  10. Netty4.0学习笔记系列之五:自定义通讯协议