Finding distance between two curves

本文介绍了一种使用OpenCV计算图像中两条曲线间距离的方法。通过添加切线并找到90度法线来确定距离,提供了详细的C++代码示例及Python应用建议。

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. 
image description
 
image description
 
优质解答:
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
imagethe 8-bit single-channel image to be labeled
labelsdestination labeled image
connectivity8 or 4 for 8-way or 4-way connectivity respectively
ltypeoutput 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( 000); //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,distDIST_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
Drive Curve Lathe Drive Curve Lathe is used to drive a tool along a series of curves in an APT like manner utilizing drive and check curves. It does not use a part surface, since all tool movement is restricted to the XM-YM plane. You begin by defining a tool start-up position relative to two curves. You then "lead" the tool from curve to curve until you finish the machining process. The curves can be lines, arcs, conics, or splines. By default, each curve is extended along its tangency to define intersections for the purpose of finding drive and check curve positions. When the APT mode is enabled, arcs extend to full circles. The APT mode is enabled by setting the parameter CAM_dcl_typ to 1 in the CAM Default file (see CAM Defaults in the Manufacturing User Manual). Figure 1-7 Arc Extensions in Default vs. APT Mode To activate the drive curve lathe submodule, use the GPA &DCLATH. Use global lathe parameters to define the avoidance geometry. The part clearance and engage occur in the machining plane. All tool movements are restricted to the XM-YM plane of the machine coordinate system. Drive Curve Lathe Control Statements Control statements set up machining parameters for motion statements. They select the cutter, control the output of the tool path to the CLSF, and specify other machining parameters that affect the results of the motion statements. Name CUT - Cut Synopsis CUT/ Description CUT specifies that the current tool position and subsequent cutter positions generated in the tool path calculations are to be added to the CLSF. This statement is used in conjunction with the DNTCUT statement. At the beginning of a program, the system assumes that CUT is in effect. Consequently, a program does not require a Cut command until after a DNTCUT statement is programmed. Name DNTCUT - Do Not Cut Synopsis DNTCUT/ Description DNTCUT specifies that the following cutter positions should not be written into the CLSF. The Cut statement will cause the system to resume writing tool positions to the CLSF. Name CUTTER - Cutter Synopsis Description The Cutter statement allows you to specify the tool. You can use the name or entity variable of an existing tool. If the Cutter statement is not programmed, the Drive Curve Lathe machining uses the system defaults. CAUTION: You can only one tool per operation and you must program a new Parameters tool ent An existing tool entity used to generate the current tool path. 'tool name' A string or string variable representing the name of a tool which is used to generate the current tool path. Name FEDRAT - Feedrate Synopsis Description The Feedrate allows you to define a feed rate unit and value. The statement is output in the CLSF exactly as it is written in your GRIP program. NOTE: FEDRAT/... is valid only for Drive Curve Lathe and Sequential Milling submodules. It performs the same function as the &CUTUN and &CUTFED, which are valid for all submodules. &CUTUN, &CUTFED, and FEDRAT can overwrite each other. Therefore, the last FEDRAT or GPA values defined will always apply for Drive Curve Lathe. Parameters IPM A minor word indicating that the feed rate is in inches per minute. IPR A minor word indicating that the feed rate is in inches per revolution. MMPM A minor word indicating that the feed rate is in millimeters per minute. MMPR A minor word indicating that the feed rate is in millimeters per revolution. f A numerical value or variable representing the feed rate. Name INDIRV - In-Direction Vector Synopsis INDIRV/i,j,k Description The In-Direction Vector statement specifies the general direction of the next continuous path motion. INDIRV is used to direct the system when more than one direction is possible, or when you want a direction other than the most obvious one. INDIRV is used together with all continuous path motion statements. If, for example, the cutter is machining along a line that is perpendicular to a circle, the cutter will follow the intrinsic direction of the circle. An INDIRV statement before the next continuous pass motion statement allows you to specify the desired cutting direction. Parameters i,j,k Three numerical values or a three-position numerical array representing the components of a vector pointing in the general direction of the next continuous path motion. Name INTOL - Intol Synopsis INTOL/t Description INTOL specifies the maximum allowable distance the cutter may deviate from an arc, conic, or spline on the concave side of the geometry as the tool path approximates the curve with straight line segments. If the system is generating a circular interpolation record on an arc, the INTOL value is passed to the GPM. If the designated machine tool controller does not support circular interpolation, this value is used by the GPM to approximate the arc. Parameters t A numerical value representing the maximum deviation from the curve being machined. Name OUTTOL - Outtol Synopsis OUTTOL/t Description OUTTOL specifies the maximum allowable distance the cutter may deviate from an arc, conic, or spline on the convex side of the geometry as the tool path approximates the curve with straight line segments. If the system is generating a circular interpolation record on an arc, the OUTOL value is passed to the GPM. If the designated machine tool controller does not support circular interpolation, this value is used by the GPM to approximate the arc. Parameters t A numerical value representing the maximum deviation from the curve being machined. Name OPNAME - Operation Name Synopsis Description The Operation Name statement allows you to specify a string representing the name of the current tool path. OPNAME terminates the current operation and starts a new one. The system saves the operation, including the tool path, in the CLSF and the parameters (e.g., post commands, engage and retract vectors, etc.) used to generate the path. Parameters 'opname' A string or string variable representing the name of the current tool path. DEFLT A minor word indicating that the default operation name will be used. The default operation name is P(n), where n is the next available number. Name REFPNT - Reference Point Synopsis Description The Reference Point is used to position the tool to the drive and check curves. The Reference Point statement applies only to the next GO, GOLFT, GORGT, GOFWD, or GOBACK command. The Reference Point is not output to the CLSF. It establishes a position from which to determine the TO/ON/PAST condition in the GO commnd. In the figure below, the tool goes TO both curves. Refer to the GO statement for more information about TO/ON/PAST. The Reference Point statement is also used before a GOLFT, GORGT, GOFWD, or GOBACK command if multiple intersections exist between the drive and check curves. A Reference Point determines the desired intersection. The REFPNT command is not modal; i.e., a REFPNT command applies only to the next GO, GOLFT, GORGT, GOFWD, or GOBACK command. If a GO command is the first motion command in an operation, a REFPNT command must precede it. Parameters point An existing point representing the location of the Reference Point. x,y,z Three numerical values or a three-position numerical array representing the location, in the WCS, of the Reference Point. Name THICK - Thick Values Synopsis Description The Thick statement allows you to define a distance that the tool offsets away from any of the controlling curves. A positive value represents an offset toward the tool side of the curve. A negative value represents an offset, or "undercut", into the curve. THICK has no effect on curves whose tool position is set to ON. Parameters dcurve A numerical value or variable representing the distance that the tool is offset from the drive curve. ccurve A numeric value or variable representing the distance that the tool is offset from the check curve. OFF A minor word indicating that any current offsets are to be turned off. Name TLLFT - Tool Left Synopsis TLLFT Description The Tool Left statement specifies that the tool will travel along the left side of the drive curve for subsequent tool motions. If, for example, you are standing at the current tool position looking in the same direction as the next tool motion, you would be on the left side of the drive curve. CAUTION: TLLFT does not produce an error message or warning in situations where TLRGT is the correct condition. Name TLON - Tool On Synopsis TLON Description The Tool On statement specifies that the tool center lies on the drive curve for subsequent tool motions Name TLRGT - Tool Right Synopsis TLRGT Description The Tool Right statement specifies that the tool will travel along the right side of the drive curve for subsequent tool motions. If, for example, you are standing at the current tool position looking in the same direction as the next tool motion, you would be on the right side of the drive curve. CAUTION: TLRGT does not produce an error message or warning in situations where TLLFT is the correct condition. 学习这个文档并总结‘’
06-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值