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 <cv.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
using namespace std;
int main( int argc, char** argv ){
//Declarations
double alpha; /**< Simple contrast control */ //unused
int beta; /**< 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_<float>(3,3) <<
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! :)