How to remove noise from this image without causing the crack to 'shrink'? I am currently embarking on an image processing project to detect cracks on surfaces using OpenCV and Visual Studio via C++. I have tried writing my program and at the moment, I am stuck because I have difficulties striking a balance between noise in an image and preventing the 'crack' from shrinking due to the dilate() operation. I am completely new to OpenCV and have only coded in C before, so I hope you will be patient and explain things slowly. :)

I am currently working on the photograph below, taken from Google Images, which has the parent URL: http://www.newindianexpress.com/states/kerala/article1330634.ece



I shall type my code below:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/photo/photo.hpp"
#include "highgui.h"
#include &lt;cv.h&gt;
#include &lt;iostream&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

using namespace cv;
using namespace std;

int main( int argc, char** argv ){

    //Declarations
    double alpha; /**&lt; Simple contrast control */ //unused
    int beta;  /**&lt; Simple brightness control */ //unused
    float minVal;
    float maxVal; 
    Mat bw_img;
    Mat contrast1;
    Mat gaussian_img;
    Mat filtered_img;
    Mat weighted_img;
    Mat adaptive_img;

    //Loads image from file and put image matrix into "original_photo"
    Mat original_img = imread ("crack.jpg", 1);

    //Convert color-to-gray image
    cvtColor( original_img, bw_img, CV_BGR2GRAY );
    //imshow("bw_img", bw_img);

    //Gaussian filtering
    int i = 7;
    GaussianBlur(bw_img,gaussian_img,Size(i,i),0,0);
    imshow("gaussian_img", gaussian_img);

    //HPF kernel
    Mat kernel = (Mat_&lt;float&gt;(3,3) &lt;&lt; 
        0,  -1, 0,
        -1, 5, -1,
        0,  -1, 0); 

    filter2D(gaussian_img, filtered_img,-1, kernel, Point(-1,-1),0);

    //Extract high-frequency features, e.g. edges  show up.
    addWeighted(filtered_img, 1.5, bw_img, -0.5, 0,weighted_img);
    imshow("weighted_img",weighted_img);

    //Perform adaptive thresholding
    adaptiveThreshold(weighted_img,adaptive_img,255,ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 51, 20);
    imshow("adaptive_img",adaptive_img);

    //Construct structuring element
    Mat struc_elem = getStructuringElement(MORPH_RECT,Size(5,5));

    //Perform erosion first
    Mat eroded_img;
    erode(adaptive_img,eroded_img,struc_elem);
    imshow("eroded_img",eroded_img);

    //Perform dilation next
    Mat dilate_img;
    dilate(eroded_img,dilate_img,struc_elem);
    imshow("dilate_img",dilate_img);

    double otsu_thresh_val = threshold(dilate_img, dilate_img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
    double high_thresh_val  = otsu_thresh_val,lower_thresh_val = otsu_thresh_val * 0.5;

    Mat cannyOP;
    Canny( dilate_img, cannyOP, lower_thresh_val, high_thresh_val );
    imshow("cannyOP",cannyOP);

    //wait for long long time
    int c = waitKey(20000000000000);

    //if you get impatient, end program
    if (c == 27)
    {
    return 0;
    }
}


The images I got so far are rather noisy, with a lot of black specks after doing erosion followed by dilation. I shall post the photos later as I don't have enough reputation to post more links. Sorry.

I have tried to increase the blockSize and C values in adaptiveThreshold() function, from the current 51/20 to 101/50. The noises were mostly removed, but the crack feature got reduced in size. This image shall be posted later and referred to as Image 2.

I have also tried to maintain the adaptiveThreshold() figures for blockSize and C, and tried to perform a dilation followed by an erosion. The final image was less noisy, though there were still black specks, but the crack became slightly discontinuous. This image shall be posted later and referred to as Image 3.

May I ask, how should I remove noise via either adaptiveThreshold() function or the erode() and dilate() functions without causing the crack to become thinner or wider?

This is because if the crack is thinner, the crack will 'disappear' totally in the final output image.

Thank you! :)
As first preprocessing step use edge-aware smoothing methods before converting your image to binary. These methods do not modify the sharp boundaries that are larger than a parametric size. Following search reveals many methods: 

https://scholar.google.com/scholar?q=edge+aware+smoothing

I am not quite sure if the method will work in your case, but it seems there is an edge aware smoothing filter in OpenCV: 

http://docs.opencv.org/3.1.0/d3/d14/tutorial_ximgproc_disparity_filtering.html