Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Image processing 模糊图像的阈值-第2部分_Image Processing_Opencv_Threshold - Fatal编程技术网

Image processing 模糊图像的阈值-第2部分

Image processing 模糊图像的阈值-第2部分,image-processing,opencv,threshold,Image Processing,Opencv,Threshold,如何设置模糊图像的阈值以使数字尽可能清晰? 在中,我尝试对模糊图像(左)进行自适应阈值化,这会导致扭曲和断开的数字(右): 此后,我尝试使用中所述的形态学闭合操作,以使图像亮度均匀: 如果我自适应地对这张图像设置阈值,我不会得到明显更好的结果。但是,由于亮度大致一致,我现在可以使用普通阈值: 这比以前好多了,但我有两个问题: 我必须手动选择阈值。虽然关闭操作会产生均匀的亮度,但其他图像的亮度级别可能不同 如果阈值水平略有变化,图像的不同部分效果会更好。例如,左上角的9和7部分褪色,应具有较

如何设置模糊图像的阈值以使数字尽可能清晰?

在中,我尝试对模糊图像(左)进行自适应阈值化,这会导致扭曲和断开的数字(右):

此后,我尝试使用中所述的形态学闭合操作,以使图像亮度均匀:

如果我自适应地对这张图像设置阈值,我不会得到明显更好的结果。但是,由于亮度大致一致,我现在可以使用普通阈值:

这比以前好多了,但我有两个问题:

  • 我必须手动选择阈值。虽然关闭操作会产生均匀的亮度,但其他图像的亮度级别可能不同
  • 如果阈值水平略有变化,图像的不同部分效果会更好。例如,左上角的9和7部分褪色,应具有较低的阈值,而一些6融合为8,应具有较高的阈值
  • 我认为回到自适应阈值,但是使用非常大的块大小(图像的1/9)可以解决这两个问题。相反,我最终得到了一个奇怪的“光晕效应”,图像的中心要亮得多,但边缘与正常阈值图像大致相同:

    编辑:remi从形态学上打开本文右上角的阈值图像。这不太管用。使用椭圆核,只有3x3足够小,可以避免完全抹去图像,即使这样,数字中也会出现明显的损坏:

    Edit2:mmgp使用维纳滤波器消除模糊。我适应了OpenCV4Android,但它使图像更加模糊!以下是使用我的代码和5x5内核进行过滤之前(左)和之后的图像:

    这是我的改编代码,它过滤到位:

    private void wiener(Mat input, int nRows, int nCols) { // I tried nRows=5 and nCols=5
    
        Mat localMean = new Mat(input.rows(), input.cols(), input.type());
        Mat temp = new Mat(input.rows(), input.cols(), input.type());
        Mat temp2 = new Mat(input.rows(), input.cols(), input.type());
    
        // Create the kernel for convolution: a constant matrix with nRows rows 
        // and nCols cols, normalized so that the sum of the pixels is 1.
        Mat kernel = new Mat(nRows, nCols, CvType.CV_32F, new Scalar(1.0 / (double) (nRows * nCols)));
    
        // Get the local mean of the input.  localMean = convolution(input, kernel)
        Imgproc.filter2D(input, localMean, -1, kernel, new Point(nCols/2, nRows/2), 0); 
    
        // Get the local variance of the input.  localVariance = convolution(input^2, kernel) - localMean^2 
        Core.multiply(input, input, temp);  // temp = input^2
        Imgproc.filter2D(temp, temp, -1, kernel, new Point(nCols/2, nRows/2), 0); // temp = convolution(input^2, kernel)
        Core.multiply(localMean, localMean, temp2); //temp2 = localMean^2
        Core.subtract(temp, temp2, temp); // temp = localVariance = convolution(input^2, kernel) - localMean^2  
    
        // Estimate the noise as mean(localVariance)
        Scalar noise = Core.mean(temp);
    
        // Compute the result.  result = localMean + max(0, localVariance - noise) / max(localVariance, noise) * (input - localMean)
    
        Core.max(temp, noise, temp2); // temp2 = max(localVariance, noise)
    
        Core.subtract(temp, noise, temp); // temp = localVariance - noise
        Core.max(temp, new Scalar(0), temp); // temp = max(0, localVariance - noise)
    
        Core.divide(temp, temp2, temp);  // temp = max(0, localVar-noise) / max(localVariance, noise)
    
        Core.subtract(input, localMean, input);  // input = input - localMean
        Core.multiply(temp, input, input); // input = max(0, localVariance - noise) / max(localVariance, noise) * (input - localMean)
        Core.add(input, localMean, input); // input = localMean + max(0, localVariance - noise) / max(localVariance, noise) * (input - localMean)
    }
    

    您可以尝试的一些提示:

    • 在原始阈值图像(第一张图片右侧有噪声的图像)中应用形态学开口。你应该摆脱大部分的背景噪音,并能够重新连接数字

    • 对原始图像使用不同的预处理,而不是形态闭合,例如中值滤波(倾向于模糊边缘)或将更好地保留边缘,但计算速度较慢

    • 就阈值而言,您可以在CV::threshold中使用CV_OTSU标志来确定全局阈值的最佳值。局部阈值可能仍然更好,但使用双边或中值滤波器时效果更好


    我尝试过分别对每个3x3盒子设置阈值,使用大津算法(CV_Otsu-感谢remi!)来确定每个盒子的最佳阈值。这比对整个图像进行阈值化要好一点,而且可能更健壮一点


    不过,更好的解决方案是受欢迎的。

    我的建议假设您可以识别数独单元,我认为这要求不高。当然,在我看来,尝试应用形态学操作符(尽管我非常喜欢)和/或二值化方法作为第一步是错误的。无论出于何种原因(原始相机角度和/或移动,以及其他原因),您的图像至少部分模糊。所以你需要的是通过执行反褶积来恢复它。当然,要求一个完美的反褶积是太多了,但我们可以尝试一些事情

    其中一个“东西”是,例如,在Matlab中,函数名为
    deconvwnr
    。我注意到垂直方向上的模糊,因此我们可以使用一定长度的垂直核(在下面的示例中为10)执行反褶积,并且还假设输入不是无噪声的(假设为5%)--我只是想给出一个非常肤浅的观点,请放心。在Matlab中,通过执行以下操作,您的问题至少部分得到解决:

    f = imread('some_sudoku_cell.png');
    g = deconvwnr(f, fspecial('motion', 10, 90), 0.05));
    h = im2bw(g, graythresh(g)); % graythresh is the Otsu method
    
    以下是一些单元格的结果(原始、otsu、区域生长的otsu、形态学增强图像、区域生长的形态学增强图像的otsu、反卷积的otsu):







    增强图像是通过使用半径为3的平面磁盘执行original+tophat(original)-bottomhat(original)生成的。我手动选择了区域生长的种子点,并手动选择了最佳阈值

    对于空单元格,您会得到奇怪的结果(原版和大津解压):


    但我不认为你会有麻烦去检测一个单元格是否为空(全局阈值已经解决了这个问题)

    编辑:


    添加了我可以通过另一种方法获得的最佳结果:区域增长。我还尝试了其他一些方法,但这是第二好的方法。

    如果你愿意花一些时间在它上面,有一些消除模糊的技术可以用来在处理之前使图片更清晰。OpenCV中还没有任何内容,但如果这是一个成功或失败的东西,您可以添加它

    有很多关于这个主题的文献: http://www.google.com/search?q=motion+去模糊

    还有OpenCV邮件列表上的一些闲聊:

    您看到的奇怪的“光晕效应”可能是由于OpenCV假设颜色为黑色,而自适应阈值位于/接近图像边缘,并且它使用的窗口“挂起”边缘进入非图像区域。有一些方法可以纠正这一点,最有可能的是,您会制作一个临时图像,该图像至少比来自摄影机的图像高出和宽出两个完整的块大小。然后将相机图像复制到它的中间。然后将temp图像周围的“空白”部分设置为相机图像的平均颜色。现在,当您执行自适应阈值时,数据位于/接近t