Robotic Vn
Robotic Vn

Reputation: 577

Canny filter in C++

I try to implement canny filter in C++. I expect to get results like this enter image description here

but I got the result enter image description here

The image after non-maximum suppression and output image seems disjointed, not solid

My code as the follow

#include<stdio.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <cmath>
#include <iostream>
#include <opencv2\opencv.hpp>
#include <time.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

int main(){
    cv::Mat inImage = cv::imread("C:\\Users\\DUY\\Desktop\\lena.jpg");
    cv::Mat outImage;
    cv::Mat rgbaImage;
    cv::Mat greyImage;
    cv::Mat blurImage;
    cv::Mat edgeMag;
    cv::Mat edgeDir;
    cv::Mat suppress;
    cv::cvtColor(inImage, rgbaImage, CV_BGR2RGBA);
    int numRows = rgbaImage.rows;
    int numCols = rgbaImage.cols;


    cv::cvtColor(rgbaImage, greyImage, CV_RGBA2GRAY);
    blurImage.create(numRows, numCols, CV_8UC1);
    edgeMag.create(numRows, numCols, CV_8UC1);
    edgeDir.create(numRows, numCols, CV_8UC1);
    suppress.create(numRows, numCols, CV_8UC1);
    outImage.create(numRows, numCols, CV_8UC1);


    clock_t start, end;
    start = clock();
    //------------------- Gaussian filter-----------------------//
    cv::Mat gaussianMask = (cv::Mat_<int>(5,5) << 2, 4, 5, 4, 2, 4, 9, 12,   9, 4, 5, 12, 15, 12, 5, 
                                            4, 9, 12, 9, 4, 2, 4, 5, 4, 2);

    for(int index_x = 2; index_x < numCols - 2; index_x++){
        for(int index_y = 2; index_y < numRows - 2; index_y++){
            float value = 0;
            for(int i = -2; i <= 2 ; i++){
                for(int j = -2; j <= 2; j++){
                    value = value + greyImage.at<unsigned char>(index_x+j, index_y+i) * gaussianMask.at<int>(i+2,j+2) ;
                }
            }

             value = value/159;

             blurImage.at<unsigned char>(index_x, index_y) = (unsigned char) value;
        }
    }
    end = clock();
    //------------------ Find the intensity gradient of the image---------------------//
    cv::Mat GxMask = (cv::Mat_<int>(3,3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);
    cv::Mat GyMask = (cv::Mat_<int>(3,3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);

    for(int index_x = 1;index_x<numCols -1;index_x++){
       for(int index_y=1;index_y<numRows -1; index_y++){

           float mag = 0;

           float Gx = 0, Gy = 0;
           for(int i=-1;i<=1;i++){
               for(int j=-1;j<=1;j++){

                    Gx = Gx + blurImage.at<unsigned char>(index_x+i, index_y+j) * GxMask.at<int>(i+1,j+1);
                    Gy = Gy + blurImage.at<unsigned char>(index_x+i, index_y+j) * GyMask.at<int>(i+1,j+1);
               }
           }

           mag = sqrt(Gx*Gx + Gy*Gy);
           edgeMag.at<unsigned char>(index_x, index_y) = mag;
           float thisAngle = (atan2(Gx, Gy)/3.14159)*180;
           float newAngle;
           if ( ( (thisAngle < 22.5) && (thisAngle > -22.5) ) || (thisAngle > 157.5) || (thisAngle < -157.5) )
                newAngle = 0;
           if ( ( (thisAngle > 22.5) && (thisAngle < 67.5) ) || ( (thisAngle < -112.5) && (thisAngle > -157.5) ) )
               newAngle = 45;
           if ( ( (thisAngle > 67.5) && (thisAngle < 112.5) ) || ( (thisAngle < -67.5) && (thisAngle > -112.5) ) )
               newAngle = 90;
           if ( ( (thisAngle > 112.5) && (thisAngle < 157.5) ) || ( (thisAngle < -22.5) && (thisAngle > -67.5) ) )
           newAngle = 135;
           edgeDir.at<unsigned char>(index_x, index_y) = newAngle;
       }
    }
    //--------------------------Non-maximum suppression------------------------//
    for(int i = 1;i<numCols -1;i++){
       for(int j=1;j<numRows -1; j++){
            if((edgeDir.at<unsigned char>(i,j) == 0 && edgeMag.at<unsigned char>(i,j) > edgeMag.at<unsigned char>(i+1,j) && edgeMag.at<unsigned char>(i,j) > edgeMag.at<unsigned char>(i-1,j))||
            (edgeDir.at<unsigned char>(i,j) == 90 && edgeMag.at<unsigned char>(i,j) > edgeMag.at<unsigned char>(i,j+1) && edgeMag.at<unsigned char>(i,j) > edgeMag.at<unsigned char>(i,j-1))||
            (edgeDir.at<unsigned char>(i,j) == 45 && edgeMag.at<unsigned char>(i,j) > edgeMag.at<unsigned char>(i+1,j-1) && edgeMag.at<unsigned char>(i,j) > edgeMag.at<unsigned char>(i-1,j+1))||
            (edgeDir.at<unsigned char>(i,j) == 135 && edgeMag.at<unsigned char>(i,j) > edgeMag.at<unsigned char>(i+1,j+1) && edgeMag.at<unsigned char>(i,j) > edgeMag.at<unsigned char>(i-1,j-1))){
                    suppress.at<unsigned char>(i,j) = edgeMag.at<unsigned char>(i,j);   
            }
             else{
                suppress.at<unsigned char>(i,j) = 0;
            }
        }
    }
    //-------------------------Hysteresis---------------------------//
    for(int i = 1;i<numCols -1;i++){
        for(int j=1;j<numRows -1; j++){
            int upperThreshold = 60;
            int lowerThreshold = 30;
            if(suppress.at<unsigned char>(i,j) > upperThreshold){
                outImage.at<unsigned char>(i,j) = 255;
            }
            if(suppress.at<unsigned char>(i,j) < lowerThreshold){
                outImage.at<unsigned char>(i,j)  = 0;
            }
        }
    }

    for(int i = 1;i<numCols -1;i++){
        for(int j=1;j<numRows -1; j++){
            int upperThreshold = 60;
            int lowerThreshold = 30;
            if(suppress.at<unsigned char>(i,j) < upperThreshold && suppress.at<unsigned char>(i,j) > lowerThreshold){
                for(int m = -1; m <= 1; m++){
                    for(int n = -1; n <= 1; n++){
                        if(outImage.at<unsigned char>(i+n,j+m) == 255){
                            outImage.at<unsigned char>(i,j) = 255;
                            break;
                        }
                    }
                }
            }
        }
    }


    float time = ((float)(end-start))/CLOCKS_PER_SEC*1000;
    printf("function: %f ms\n", time);
    //-----------------show image-------------------//
    cv::imshow("raw", inImage);
    cv::imshow("suppress", suppress);
    cv::imshow("out",outImage);
    cv::waitKey();
}

Could you explain for me? Thank you very much

Upvotes: 2

Views: 620

Answers (1)

Settembrini
Settembrini

Reputation: 1386

  • Your gauss-kernel should be calibrated to sum up to 1.
  • 5x5 is probably too small for that gauss kernel (with a larger Gauss kernel, e.g. 11x11, you can use lower tresholds, having a better Signal/noise Ratio)
  • also there seems to be a problem in the hysteresis part. I didn't check your code in detail but for hystersis you need to implement a recursive proedure that follows the weak edges (>thres_low) in the neighborhood of a strong edge, I cannot see such recursive call in your code.

Upvotes: 2

Related Questions