Measure Angle Between Edges

In this sample,

Explanation

After defining the search windows, the search direction was set to TCVN_ED_LIGHT_TO_DARK, because in this sample the search is performed from the inside to the outside and the objects are lighter than the background.

The parameter nMaxThickness, which defines the number of pixels with which fMinStrength must be reached, was set to "7".

Variables

hr              : HRESULT;
hrFunc          : HRESULT;

ipImageIn       : ITcVnImage;
ipImageInDisp   : ITcVnDisplayableImage;
ipImageRes      : ITcVnImage;
ipImageResDisp  : ITcVnDisplayableImage;

// result
fAngle          : REAL;
ipEdgePoints1   : ITcVnContainer;
ipEdgePoints2   : ITcVnContainer;

// parameters
aInnerPoint     : TcVnPoint2_REAL := [635, 350];
aOuterPoint1    : TcVnPoint2_REAL := [530, 280];
aOuterPoint2    : TcVnPoint2_REAL := [790, 280];
fMinStrength    : REAL := 50;
nSearchLines    : UDINT := 41;
fSearchLineDist : REAL := 1;
nSubpixIter     : UDINT := 10;
eAlgorithm      : ETcVnEdgeDetectionAlgorithm := TCVN_EDA_INTERPOLATION;

// Watchdog
hrWD            : HRESULT;
tStop           : DINT := 15000;
tRest           : DINT;
nFraction       : UDINT;

// drawing
aLine1          : TcVnVector4_LREAL;
aLine2          : TcVnVector4_LREAL;
aColorRed       : TcVnVector4_LREAL := [255, 0, 0];
aColorGreen     : TcVnVector4_LREAL := [0, 175, 0];
aColorYellow    : TcVnVector4_LREAL := [255, 255, 0];
sText           : STRING(255);

Code

hrWD := F_VN_StartRelWatchdog(tStop, hr);
   hrFunc := F_VN_MeasureAngleBetweenEdgesExp(
                ipSrcImage             :=   ipImageIn,
                fAngle                 :=   fAngle
                aInnerPoint            :=   aInnerPoint,
                aOuterPoint1           :=   aOuterPoint1
                aOuterPoint2           :=   aOuterPoint2,
                eEdgeDirection         :=   TCVN_ED_LIGHT_TO_DARK,
                fMinStrength           :=   fMinStrength,
                nSearchLines           :=   nSearchLines,
                fSearchLineDist        :=   fSearchLineDist,
                nMaxThickness          :=   7,
                nSubpixelsIterations   :=   nSubpixIter,
                bAngleInDegrees        :=   TRUE,
                fApproxPrecision       :=   0.0001,
                eAlgorithm             :=   eAlgorithm,
                ipEdgePoints1          :=   ipEdgePoints1,
                ipEdgePoints2          :=   ipEdgePoints2,
                hrPrev                 :=   hr);
hrWD := F_VN_StopWatchdog(hrWD, nFractionProcessed=>nFraction, tRest=>tRest);

// Draw result for visualization
hr := F_VN_ConvertColorSpace(ipImageIn, ipImageRes, TCVN_CST_GRAY_TO_RGB, hr);
sText := CONCAT('Angle ', REAL_TO_STRING(fAngle));
hr := F_VN_PutTextExp(sText, ipImageRes, 25, 200, TCVN_FT_HERSHEY_SIMPLEX, 1.3, aColorGreen, 2, TCVN_LT_8_CONNECTED, FALSE,hr);
sText := CONCAT(CONCAT('Time ', DINT_TO_STRING(tStop - tRest)), 'us');
hr := F_VN_PutTextExp(sText, ipImageRes, 25, 250, TCVN_FT_HERSHEY_SIMPLEX, 1.3, aColorGreen, 2, TCVN_LT_8_CONNECTED, FALSE,hr);
hr := F_VN_DrawPointExp(REAL_TO_UDINT(aInnerPoint[0]), REAL_TO_UDINT(aInnerPoint[1]), ipImageRes, TCVN_DS_CIRCLE, aColorGreen, 3, 2, TCVN_LT_8_CONNECTED, hr);
hr := F_VN_DrawPointExp(REAL_TO_UDINT(aOuterPoint1[0]), REAL_TO_UDINT(aOuterPoint1[1]), ipImageRes, TCVN_DS_X, aColorRed, 3, 2, TCVN_LT_8_CONNECTED, hr);
hr := F_VN_DrawPointExp(REAL_TO_UDINT(aOuterPoint2[0]), REAL_TO_UDINT(aOuterPoint2[1]), ipImageRes, TCVN_DS_X, aColorYellow, 3, 2, TCVN_LT_8_CONNECTED, hr);
hr := F_VN_FitLine(ipEdgePoints1, aLine1, hr);
hr := F_VN_FitLine(ipEdgePoints2, aLine2, hr);
hr := F_VN_DrawLine_TcVnVector4_LREAL(aLine1, ipImageRes, aColorGreen, 2, hr);
hr := F_VN_DrawLine_TcVnVector4_LREAL(aLine2, ipImageRes, aColorGreen, 2, hr);
hr := F_VN_DrawPointsExp(ipEdgePoints1, ipImageRes, TCVN_DS_PLUS, aColorRed, 1, 1, TCVN_LT_8_CONNECTED, hr);
hr := F_VN_DrawPointsExp(ipEdgePoints2, ipImageRes, TCVN_DS_PLUS, aColorYellow, 1, 1, TCVN_LT_8_CONNECTED, hr);

// Display source and result image
hr := F_VN_TransformIntoDisplayableImage(ipImageIn, ipImageInDisp, S_OK);
hr := F_VN_TransformIntoDisplayableImage(ipImageRes, ipImageResDisp, S_OK);

Results

For visualization purposes, aInnerPoint is first displayed as a green circle, aOuterPoint1 as a red x and aOuterPoint2 as a yellow x. The corresponding edge points ipEdgePoints1 and ipEdgePoints2 that were found are also drawn in red or yellow. The lines approximated from the edge points are drawn in green. The calculated angle fAngle in degrees and the required computing time in µs are displayed on the left in the image. For the parameters used in this sample, the result looks like this:

Measure Angle Between Edges 1:

To get a more accurate result, eAlgorithm can be changed to TCVN_EDA_APPROX_ERF and nSubpixIter to 50. However, this also significantly increases the computing time required:

Measure Angle Between Edges 2:

Similar samples