如何在不导致裂缝“缩小”的情况下从该图像中去除噪声?

信息处理 图像处理 opencv C++
2022-01-30 15:34:49

我目前正在进行一个图像处理项目,通过 C++ 使用 OpenCV 和 Visual Studio 检测表面上的裂缝。我已经尝试编写我的程序,但目前我被卡住了,因为我很难在图像中的噪声和防止“裂缝”由于 dilate() 操作而缩小之间取得平衡。我对 OpenCV 完全陌生,之前只用 C 编写过代码,所以我希望你能耐心并慢慢解释。:)

我目前正在处理下面的照片,该照片取自 Google 图片,其父 URL 为:http: //www.newindianexpress.com/states/kerala/article1330634.ece

印度铁路头裂缝

我将在下面输入我的代码:

#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;
    }
}

到目前为止,我得到的图像相当嘈杂,经过腐蚀和膨胀后有很多黑色斑点。我稍后会发布照片,因为我没有足够的声誉来发布更多链接。对不起。

我试图将 AdaptiveThreshold() 函数中的 blockSize 和 C 值从当前的 51/20 增加到 101/50。噪音大部分都被消除了,但裂缝特征的尺寸减小了。此图稍后发布,称为图 2。

我还尝试维护 blockSize 和 C 的adaptiveThreshold() 数字,并尝试执行先膨胀后腐蚀。最终的图像噪点少了一些,虽然还是有黑点,但是裂痕变得有些不连续。此图稍后发布,称为图 3。

请问,我应该如何通过adaptiveThreshold() 函数或erode() 和dilate() 函数去除噪声而不导致裂缝变薄或变宽?

这是因为如果裂纹较薄,裂纹将在最终输出图像中完全“消失”。

谢谢!:)

2个回答

作为第一个预处理步骤,在将图像转换为二进制之前使用边缘感知平滑方法。这些方法不会修改大于参数大小的尖锐边界。以下搜索揭示了许多方法:

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

我不太确定该方法是否适用于您的情况,但似乎 OpenCV 中有一个边缘感知平滑滤波器:

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

您的问题远不是噪音问题——而是混乱问题。(我可能完全错了!)

您需要做的是将曲柄部分与其他所有部分隔离开来。这本质上是分割工作。您可以根据几何形状进行操作,也可以尝试创建更好的图像捕获系统,以帮助仅从其他所有东西中过滤掉杆。

一旦你能做到这一点,就可以通过多种方式识别裂缝。一种是识别边缘,然后使用诸如霍夫变换之类的变换分析边缘,以查看该边缘是否重要。

另一种方法可以如下:

  • 假设:该图片只有曲轴和已知背景(不应与裂纹颜色相同)。一般来说,边缘可识别为强度下降或变化。

  • 假设:曲轴可以是任何颜色;并且强度可能会根据光照条件大致变化,因此我们不想硬编码特定值。但是,我们假设曲轴通常是光滑的(普通纹理),而不是任意设计。

  • 假设:裂缝可以在任何地方,水平或垂直或倾斜的任何位置。或者它也可能不存在。算法应该能够识别裂缝的位置和深度

  • 解决方案:绘制每行、每列和对角线的平均强度。无论哪里有边缘,累积为“黑色”的像素数量都会导致此运行平均值下降。因此,纯水平裂缝将通过跨行强度的下降而被捕获。并且列强度的下降将捕获垂直的。倾斜裂缝会在水平和垂直裂缝中传播其影响,但会被对角线平均值捕获。

row_avg(i)=1/Wj=0j=Wpixel[i][j]...其中 W 是宽度

对 col_avg 应用类似的公式。

row_avg 或 col_avg 中的尖峰还会为您提供边缘/裂缝的宽度/深度和位置。

它也应该能够很好地处理多个裂缝。

我看到的唯一限制是裂缝太小或一些任意不对齐的形状。

免责声明:这不是任何特定的众所周知的算法,但我根据我对这样的行和列运算符的个人经验进行解释。