【问题标题】:How to get Magic Color effect like Cam Scanner using OpenCV如何使用 OpenCV 获得像 Cam Scanner 这样的 Magic Color 效果
【发布时间】:2015-12-31 00:25:09
【问题描述】:

这是原图。

Cam Scanner 神奇的色彩效果。

我对图像的过滤器。

我正在改变图像的对比度。

dst.convertTo(dst, -1, 2, 0);

然后使用高斯模糊进行平滑。

cv::GaussianBlur(dst,result,cv::Size(0,0),3);
cv::addWeighted(dst, 1.5, result, -0.5, 0, result);

我应该怎么做才能对我的图像产生这种效果?

更新

直方图均衡后 -

vector<Mat> channels;
Mat img_hist_equalized;
cvtColor(dst, img_hist_equalized, CV_BGR2YCrCb);
split(img_hist_equalized,channels);
equalizeHist(channels[0], channels[0]);
merge(channels,img_hist_equalized);
cvtColor(img_hist_equalized, img_hist_equalized, CV_YCrCb2BGR);

【问题讨论】:

  • 黑白调色板还是灰度调色板?
  • 这似乎是一个自适应阈值
  • 我通过跟踪和错误来做这种事情,手动设置阈值。在这种情况下,目标需要是 BW 或灰度。我可以看到floodtest 的机会——与floodfill 类似的想法——它将分析来自邻居的“白色”像素的最大区域。
  • 你能提供没有天蓝色的东西的原始图像吗?或者我们没有要测试的图像。
  • @Miki 抱歉回复晚了。给你

标签: android c++ c opencv android-ndk


【解决方案1】:

camscanner 应用程序可能正在使用一些复杂的算法来处理各种闪电情况等。但我将尝试介绍解决此类问题的基本方法,这里的基本思想是给定输入的 二值化图像,或者更准确地说,我们可以说 限制 给定图像,如果您查看 OpenCV 文档,有很多关于对给定图像进行阈值处理的参考,所以让我们从 documentation 开始。

  • 全局阈值:在这种方法中,我们假设前景的强度值始终低于某个值,在印刷纸张的上下文中,我们假设墨水颜色始终为黑色和纸张颜色是均匀的,强度大于墨水颜色的强度,所以我们安全地假设一些阈值(比如 40),(最大值为 255)并将输入图像的阈值设置为:

     ret, thresh1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
    

    ret, thresh1 = cv2.threshold(img, 130, 255, cv2.THRESH_BINARY)

There are many disadvantages to this method, First of all it is **NOT** independent of intensity variance, So there is a very less chance that you can accurately estimate  a threshold value which segments text from the given image, It has very limited applications, can be only applied in case where the background paper is exactly white with minimum variation in intensity, so this process cannot be used for **Real world** images.
  • 自适应阈值:该方法涵盖了给定图像中的强度变化问题,这里对相邻像素的值进行阈值处理,因此成功捕获了从低强度到高强度的过渡,反之亦然用这种方法:

     thresh = cv2.adaptiveThreshold(original_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
    

*Further Work*: You may work on various techniques of denoising the binary image, to remove the dots, Or have a look at removing the salt and pepper noise from the image.
  • Otu 的二值化:这是另一种很好的方法,它可以智能地计算最大值之间的阈值,在某些情况下它可能工作得很好,但在你的情况下它似乎失败了。

     ret2,thresh = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    

它基本上做了相同的全局阈值处理但是现在阈值是自动计算的,使得阈值位于两个峰值之间,从而将墨水从纸张中分割出来。

推荐方法: 我想最好的方法是自适应阈值,您可以尝试其他一些预处理技术,例如sharpening imageHistogram Equalisation 等,并分析它如何创建更真实的输出,您可以也尝试做一些后期处理比如denoising the image,Morphological operations

我尝试了图像的去噪,发现它比其他方法更有效,

denoised = cv2.fastNlMeansDenoising(thresh, 11, 31, 9) # you may experiment with the constants here

但我欢迎您尝试上述方法的各种组合,看看哪一种适用于所有情况。

注意:上述技术可能适用于色彩较少的图像。不过这里还有一个excellent answer,可以解决彩色图片的情况。

【讨论】:

  • 这是一个不错的解决方案,但我不认为他们使用二值化。二值化将生成双层图像。但是,在示例中,处理后的图像是干净的、增强的,但具有两种以上的颜色。因此,我不认为自适应二值化可以解决问题。
  • 这是一个不错的解决方案,虽然我还没有尝试过,但它也适用于彩色图像。
  • 不,它不适用于彩色图像,我试图获得给定输入的预期输出,不管魔术颜色实际上是什么,如果我我会尝试为彩色图像解决这个问题获得足够的时间。
  • @ZdaR 感谢您至少尝试
  • 真诚地,这个答案不值得这么多赞赏,我不知道魔术色彩效果也适用于彩色图像,但是如果我有足够的时间,我会相应地更新这个答案正确解决问题,如果字符打印在普通纸上,当前答案将有效。
【解决方案2】:

处理此类图像的一种非常简单但有效的方法是平场校正。

首先,您通过对原始图像I 应用非常 强模糊滤镜来生成“假”平场图像F。 然后将I 乘以F 的平均值,然后将结果图像除以F(逐个像素)得到校正后的图像C。乘法只是为了保持整体亮度,除法是魔法发生的地方。

基本上是这样的:C = (I * mean(F)) / F

生成的校正图像C 将去除大部分(如果不是全部)不需要的大尺寸照明和颜色。然后剩下要做的就是一些对比度拉伸,你得到的结果与提供的参考图像非常相似。 (灰度,高对比度,但没有阈值)

如果您想知道所提供图像的结果是什么样的...

一、平场:

然后是校正后的图像:

最后,在增加对比度之后:

这方面最困难的部分是让平面区域恰到好处,因为您希望将其模糊到足以消除文本,同时尽可能保留背景。在这种情况下,非线性过滤器(例如中值)可以提供帮助。

【讨论】:

  • 感谢您的建议!我的朋友,如果你能提供一个小的概念证明示例,那就太好了。
  • @eldesgraciado 当然,我添加了一个示例,说明原始图像的结果(和中间步骤)是什么样的。
  • 感谢您的回答,但我们不要忘记,CamScanner 还保持图像的质量(似乎增加了图像的分辨率)
  • 我没有那个应用程序,所以我所能做的就是尝试重新创建提供的参考图像(不幸的是,它的分辨率比已经低分辨率的输入图像还要低)。平场校正可能不是完整的答案,但它是摆脱输入图像中一大堆问题的良好第一步。
  • @FelixG 正如您所建议的那样,中值滤波器可以很好地解决问题。如果仅使用线性模糊,则会在每个区域有更多文本的地方出现深色斑点。例如,一段文本可能有 20% 的黑色墨水,然后是几行空白。在这种情况下,即使是完美拍摄的照片,当应用模糊时,文本段落也会产生一个大的灰色斑点。但是使用中值过滤,文本只会消失,只要它占用不到 50% 的局部区域)。我尝试使用上面的图像,文本消失了,中值过滤器半径仅为 11 像素。
【解决方案3】:

我已经使用 Photoshop 找出了实现扫描效果所需的编辑技术。

在 Photoshop 中,可以使用“色阶”功能提供的“设置白点”和“设置黑点”操作来实现扫描效果。这两种操作的结合,产生了在各种移动应用中常被视为“神奇色彩”的扫描效果。

除此之外,高通滤波器可以与上述两个操作一起使用,以实现一些令人兴奋的结果,例如去除阴影。

“黑白”模式下的文档扫描是通过使用 OpenCV 在 LAB 色彩空间中处理图像来实现的。

上述操作可以在 OpenCV 中使用各种阈值技术和少量基本数学运算来实现。

您可以通过this repository 了解我想说的话。

我在上面的 repo 中为该项目添加了完整的 wiki 文档。

这个答案可能看起来不是很丰富,但由于 repo 给出了详尽的讨论,我保持这篇文章简短。

我们可以使用这些技术实现的结果示例:

此图中的标记有助于我们了解 GitHub 存储库中讨论的每种模式的输出类型:

【讨论】:

    【解决方案4】:

    我已经编写了做这种事情的代码,虽然不是用 OpenCV。

    通常,我会分析直方图,根据直方图估计“白色”和“黑色”是什么,然后缩放图像值,使黑色缩放到 0 以下,白色缩放到 1 以上(或 255,具体取决于你的表示),最后钳制颜色值。

    但是,使用 OpenCV 可能有更简单的方法。在应用对比度过滤器之前尝试在裁剪页面上使用直方图均衡 - 这应该以更一致的方式分散像素值,以便在更多情况下调整对比度更可靠。您可以尝试使用 localized 直方图均衡化来帮助减轻由于光照导致的裁剪图像上的渐变,但这可能会导致页面空白区域出现问题。

    【讨论】:

      【解决方案5】:

      我意识到我玩游戏有点晚了,但我发现了这个很棒、简单的解决方案:

      src.convertTo(dst, -1, 1.9, -80);
      

      如果您在处理管道中工作,src 和 dst 可以是同一个图像。

      【讨论】:

      • 它只会改变对比度。在我发布的源图片上试一下,你会看到。
      • 什么是src和dst?它们是相同的位图吗?
      • 从技术上讲,它们是包含图像数据的 Mat 对象。在 src 和 dst 相同的情况下,转换将有效地“就地”发生。如果 src 和 dst 是不同的 Mat 对象,则 dst Mat 将包含转换后的 src 数据。
      • 如果捕获的图像是文档,则应用上述操作后,文档上的文本会变淡。这不是 camscanner 应用程序正在做的事情。
      • 这不是完整的解决方案。它只是整个方法的一部分或获得类似效果的技巧。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-29
      • 2020-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多