Ask Your Question

Revision history [back]

Hello Santhosh! Here is a Sample Implementation to find the Edge points of a Contour! Hope this helps!

#include <opencv2\opencv.hpp>
#include "opencv2\opencv_modules.hpp"

using namespace cv;
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{

    Mat mSrc= imread("D:\\Conti\\Image Samples\\forum\\Test.png",0);

    if(mSrc.empty())
    {
        cout<< "Invalid Input Image!";
        return 0;
    }

image description

    Mat mSrc_Binary,mSrc_Contours,mEndPoints,mResult;

    //Creating a Binary Image
    threshold(mSrc,mSrc_Binary,1,255,THRESH_BINARY);

    //Make sure it is one Pixel width .i.e to replicate a contour Points
    thinning(mSrc_Binary,mSrc_Contours);


    Mat_<int> Kernal(3,3);
    Kernal <<   1, 1, 1,
                1,10, 1,
                1, 1, 1;

    //Multiply the Binary Image with the above Kernal 
    //Credits & Original Author:
    https://stackoverflow.com/questions/26537313/how-can-i-find-endpoints-of-binary-skeleton-image-in-opencv
    /*
    0   0   1   0  * Kernal 1, 1, 1 => 1    3   12  2
    0   1   0   0           1,10, 1    1    11  2   1
    0   0   0   0           1, 1, 1    1    1   1   0
    */
    filter2D(mSrc_Contours,mEndPoints,CV_8UC1,Kernal);

    //We are interested in the pixels whicn are equal to 11
    inRange(mEndPoints,11,11,mEndPoints);

    //Just adding some Visualization!!
    cvtColor(mSrc_Binary,mResult,COLOR_GRAY2BGR);
    dilate(mEndPoints, mEndPoints, Mat(), Point(-1, -1), 2, 1, 1);//Make it Visible
    mResult.setTo(Scalar(0,0,255),mEndPoints);

    imshow("mResult",mResult);

image description

    waitKey();
    return 0;
}

//Adding this code just for the sake of completion
/**
 * Perform one thinning iteration.
 * Normally you wouldn't call this function directly from your code.
 *
 * Parameters:
 *      im    Binary image with range = [0,1]
 *      iter  0=even, 1=odd
 */
void thinningIteration(cv::Mat& img, int iter)
{
    CV_Assert(img.channels() == 1);
    CV_Assert(img.depth() != sizeof(uchar));
    CV_Assert(img.rows > 3 && img.cols > 3);

    cv::Mat marker = cv::Mat::zeros(img.size(), CV_8UC1);

    int nRows = img.rows;
    int nCols = img.cols;

    if (img.isContinuous()) {
        nCols *= nRows;
        nRows = 1;
    }

    int x, y;
    uchar *pAbove;
    uchar *pCurr;
    uchar *pBelow;
    uchar *nw, *no, *ne;    // north (pAbove)
    uchar *we, *me, *ea;
    uchar *sw, *so, *se;    // south (pBelow)

    uchar *pDst;

    // initialize row pointers
    pAbove = NULL;
    pCurr  = img.ptr<uchar>(0);
    pBelow = img.ptr<uchar>(1);

    for (y = 1; y < img.rows-1; ++y) {
        // shift the rows up by one
        pAbove = pCurr;
        pCurr  = pBelow;
        pBelow = img.ptr<uchar>(y+1);

        pDst = marker.ptr<uchar>(y);

        // initialize col pointers
        no = &(pAbove[0]);
        ne = &(pAbove[1]);
        me = &(pCurr[0]);
        ea = &(pCurr[1]);
        so = &(pBelow[0]);
        se = &(pBelow[1]);

        for (x = 1; x < img.cols-1; ++x) {
            // shift col pointers left by one (scan left to right)
            nw = no;
            no = ne;
            ne = &(pAbove[x+1]);
            we = me;
            me = ea;
            ea = &(pCurr[x+1]);
            sw = so;
            so = se;
            se = &(pBelow[x+1]);

            int A  = (*no == 0 && *ne == 1) + (*ne == 0 && *ea == 1) + 
                     (*ea == 0 && *se == 1) + (*se == 0 && *so == 1) + 
                     (*so == 0 && *sw == 1) + (*sw == 0 && *we == 1) +
                     (*we == 0 && *nw == 1) + (*nw == 0 && *no == 1);
            int B  = *no + *ne + *ea + *se + *so + *sw + *we + *nw;
            int m1 = iter == 0 ? (*no * *ea * *so) : (*no * *ea * *we);
            int m2 = iter == 0 ? (*ea * *so * *we) : (*no * *so * *we);

            if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)
                pDst[x] = 1;
        }
    }

    img &= ~marker;
}

/**
 * Function for thinning the given binary image
 *
 * Parameters:
 *      src  The source image, binary with range = [0,255]
 *      dst  The destination image
 */
void thinning(const cv::Mat& src, cv::Mat& dst)
{
    dst = src.clone();
    dst /= 255;         // convert to binary image

    cv::Mat prev = cv::Mat::zeros(dst.size(), CV_8UC1);
    cv::Mat diff;

    do {
        thinningIteration(dst, 0);
        thinningIteration(dst, 1);
        cv::absdiff(dst, prev, diff);
        dst.copyTo(prev);
    } 
    while (cv::countNonZero(diff) > 0);

    //dst *= 255; //We don't need Visualization! Sorry :)!!
}

Hello Santhosh! Here is a Sample Implementation to find the Edge points of a Contour! Hope this helps!

#include <opencv2\opencv.hpp>
#include "opencv2\opencv_modules.hpp"

using namespace cv;
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{

    Mat mSrc= imread("D:\\Conti\\Image Samples\\forum\\Test.png",0);

    if(mSrc.empty())
    {
        cout<< "Invalid Input Image!";
        return 0;
    }

image description

    Mat mSrc_Binary,mSrc_Contours,mEndPoints,mResult;

    //Creating a Binary Image
    threshold(mSrc,mSrc_Binary,1,255,THRESH_BINARY);

    //Make sure it is one Pixel width .i.e to replicate a contour Points
    thinning(mSrc_Binary,mSrc_Contours);


    Mat_<int> Kernal(3,3);
    Kernal <<   1, 1, 1,
                1,10, 1,
                1, 1, 1;

    //Multiply the Binary Image with the above Kernal 
    //Credits & Original Author:
    https://stackoverflow.com/questions/26537313/how-can-i-find-endpoints-of-binary-skeleton-image-in-opencv
    /*
    0   0   1   0  * Kernal 1, 1, 1 => 1    3   12  2
    0   1   0   0           1,10, 1    1    11  2   1
    0   0   0   0           1, 1, 1    1    1   1   0
    */
    filter2D(mSrc_Contours,mEndPoints,CV_8UC1,Kernal);

    //We are interested in the pixels whicn are equal to 11
    inRange(mEndPoints,11,11,mEndPoints);

    //Just adding some Visualization!!
    cvtColor(mSrc_Binary,mResult,COLOR_GRAY2BGR);
    dilate(mEndPoints, mEndPoints, Mat(), Point(-1, -1), 2, 1, 1);//Make it Visible
    mResult.setTo(Scalar(0,0,255),mEndPoints);

    imshow("mResult",mResult);

image description

    waitKey();
    return 0;
}

//Adding this code just for the sake of completion
/**
 * Perform one thinning iteration.
 * Normally you wouldn't call this function directly from your code.
 *
 * Parameters:
 *      im    Binary image with range = [0,1]
 *      iter  0=even, 1=odd
 */
void thinningIteration(cv::Mat& img, int iter)
{
    CV_Assert(img.channels() == 1);
    CV_Assert(img.depth() != sizeof(uchar));
    CV_Assert(img.rows > 3 && img.cols > 3);

    cv::Mat marker = cv::Mat::zeros(img.size(), CV_8UC1);

    int nRows = img.rows;
    int nCols = img.cols;

    if (img.isContinuous()) {
        nCols *= nRows;
        nRows = 1;
    }

    int x, y;
    uchar *pAbove;
    uchar *pCurr;
    uchar *pBelow;
    uchar *nw, *no, *ne;    // north (pAbove)
    uchar *we, *me, *ea;
    uchar *sw, *so, *se;    // south (pBelow)

    uchar *pDst;

    // initialize row pointers
    pAbove = NULL;
    pCurr  = img.ptr<uchar>(0);
    pBelow = img.ptr<uchar>(1);

    for (y = 1; y < img.rows-1; ++y) {
        // shift the rows up by one
        pAbove = pCurr;
        pCurr  = pBelow;
        pBelow = img.ptr<uchar>(y+1);

        pDst = marker.ptr<uchar>(y);

        // initialize col pointers
        no = &(pAbove[0]);
        ne = &(pAbove[1]);
        me = &(pCurr[0]);
        ea = &(pCurr[1]);
        so = &(pBelow[0]);
        se = &(pBelow[1]);

        for (x = 1; x < img.cols-1; ++x) {
            // shift col pointers left by one (scan left to right)
            nw = no;
            no = ne;
            ne = &(pAbove[x+1]);
            we = me;
            me = ea;
            ea = &(pCurr[x+1]);
            sw = so;
            so = se;
            se = &(pBelow[x+1]);

            int A  = (*no == 0 && *ne == 1) + (*ne == 0 && *ea == 1) + 
                     (*ea == 0 && *se == 1) + (*se == 0 && *so == 1) + 
                     (*so == 0 && *sw == 1) + (*sw == 0 && *we == 1) +
                     (*we == 0 && *nw == 1) + (*nw == 0 && *no == 1);
            int B  = *no + *ne + *ea + *se + *so + *sw + *we + *nw;
            int m1 = iter == 0 ? (*no * *ea * *so) : (*no * *ea * *we);
            int m2 = iter == 0 ? (*ea * *so * *we) : (*no * *so * *we);

            if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)
                pDst[x] = 1;
        }
    }

    img &= ~marker;
}

/**
 * Function for thinning the given binary image
 *
 * Parameters:
 *      src  The source image, binary with range = [0,255]
 *      dst  The destination image
 */
void thinning(const cv::Mat& src, cv::Mat& dst)
{
    dst = src.clone();
    dst /= 255;         // convert to binary image

    cv::Mat prev = cv::Mat::zeros(dst.size(), CV_8UC1);
    cv::Mat diff;

    do {
        thinningIteration(dst, 0);
        thinningIteration(dst, 1);
        cv::absdiff(dst, prev, diff);
        dst.copyTo(prev);
    } 
    while (cv::countNonZero(diff) > 0);

    //dst *= 255; //We don't need Visualization! Sorry :)!!
}

Hello Santhosh! Here is a Sample Implementation to find the Edge points of a Contour! Hope this helps!

#include <opencv2\opencv.hpp>
#include "opencv2\opencv_modules.hpp"

using namespace cv;
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{

    Mat mSrc= imread("D:\\Conti\\Image Samples\\forum\\Test.png",0);

    if(mSrc.empty())
    {
        cout<< "Invalid Input Image!";
        return 0;
    }

image description

    Mat mSrc_Binary,mSrc_Contours,mEndPoints,mResult;

    //Creating a Binary Image
    threshold(mSrc,mSrc_Binary,1,255,THRESH_BINARY);

    //Make sure it is one Pixel width .i.e to replicate a contour Points
    thinning(mSrc_Binary,mSrc_Contours);


    Mat_<int> Kernal(3,3);
    Kernal <<   1, 1, 1,
                1,10, 1,
                1, 1, 1;

    //Multiply the Binary Image with the above Kernal 
    //Credits & Original Author:
    https://stackoverflow.com/questions/26537313/how-can-i-find-endpoints-of-binary-skeleton-image-in-opencv
    /*
    0   0   1   0  * Kernal 1, 1, 1 => 1    3   12  2
    0   1   0   0           1,10, 1    1    11  2   1
    0   0   0   0           1, 1, 1    1    1   1   0
    */
    filter2D(mSrc_Contours,mEndPoints,CV_8UC1,Kernal);

    //We are interested in the pixels whicn are equal to 11
    inRange(mEndPoints,11,11,mEndPoints);

    //Just adding some Visualization!!
    cvtColor(mSrc_Binary,mResult,COLOR_GRAY2BGR);
    dilate(mEndPoints, mEndPoints, Mat(), Point(-1, -1), 2, 1, 1);//Make it Visible
    mResult.setTo(Scalar(0,0,255),mEndPoints);

    imshow("mResult",mResult);

image description

    waitKey();
    return 0;
}