OpenCV如何去除图片中的阴影的实现

作者:ZackSock 时间:2023-07-08 22:49:29 

一、前言

如果你自己打印过东西,应该有过这种经历。如果用自己拍的图片,在手机上看感觉还是清晰可见,但是一打印出来就是漆黑一片。比如下面这两张图片:

OpenCV如何去除图片中的阴影的实现

因为左边的图片有大片阴影,所有打印出来的图片不堪入目(因为打印要3毛钱,所以第二张图片只是我用程序模拟的效果)。

那有什么办法可以解决吗?答案是肯定的,今天我们就来探讨几个去除阴影的方法。

二、如何去除阴影?

首先为了方便处理,我们通常会对图片进行灰度转换(即将图片转换成只有一个图层的灰色图像)。

然后我们分析一下,在上面的图片中有三个主色调,分别是字体颜色(黑色)、纸张颜色(偏白)、阴影颜色(灰色)。知道这点后我们就好办了。我们只需要把灰色和白色部分都处理为白色就好了。

那要我怎么才知道白色和灰色区域呢?对于一个8位的灰度图,黑色部分的像素大致在0-30左右。白色和灰色应该在31-255左右(这个范围只是大致估计,实际情况需要看图片)。如图:

OpenCV如何去除图片中的阴影的实现

左边是原图,右边是处理后的图片。我们将灰色和接近白色的部分都处理成了白色。

那下面我们就开始处理吧。

三、numpy的ndarray数组

可能有些读者没有接触过numpy,这里简单说一下。

numpy是一个第三方的模块,用它我们可以很方便的处理多维数组(ndarray数组)。而图片在OpenCV中的存储方式正好是ndarray,所以我们对数组的操作就是对图片的操作。

在使用之前我们需要安装一下OpenCV模块:


pip install opencv-python

在安装OpenCV时会自动安装numpy。

下面我们主要是看看布尔索引的操作,先看下面代码:


import numpy as np
# 创建一个元素为1, 0, 1, 1的ndarray数组
arr = np.array([1, 0, 1, 1])
# 判断数组中有没有0
res = arr == 0
# 将数组中为0的元素赋值为10
arr[res] = 10

如果没有接触过numpy会不太理解上面的语法。我们来详细说一下:

创建ndarray数组:我们通过np.array可以将现有的列表装换成一个ndarray对象,这个很好理解

判断数组中有没有0:我们可以直接用ndarray对象来判断,比如:arr == 0,他会返回一个元素结构和数量一样的ndarray对象。但是返回的对象原始类型式bool,我们来看看res的输出:

[False True False False]

从结果可以看出,我们比较arr==0就是对数组中每个元素进行比较,并返回比较的布尔值。

将数组中为0的元素赋值为10:而最难理解的arr[res]操作。它其实就是拿到res中为True的视图,比如上面的结果是第二个为True则只会返回第二个元素的视图。我们执行下面的代码:


arr[res] = 10

就是把对应res为True的部分赋值为10,也就是将arr中值为0的部分赋值为10。

下面是arr最后的结果:

[ 1 10 1 1]

可以看到原本的0处理为了1。

四、去除阴影

现在我们知道了布尔索引,我们可以对图片进行处理了。我们只需要读取图片,然后将像素值大于30的部分处理为白色就好了。下面是我们的代码:


import cv2
# 读取图片
img = cv2.imread('page.jpg', 0)
# 将像素值大于30的部分修改为255(白色)
img[img > 30] = 255
# 保存修改后的图片
cv2.imwrite('res.jpg', img)

上面的代码非常简单,我们使用cv2.imread函数读取图片,第一个参数是图片路径,第二个参数表示读取为灰度图。我们来看看效果图:

OpenCV如何去除图片中的阴影的实现

可以看到阴影部分被很好地去除了。有些字比较模糊,我们可以通过调节灰白色地范围调整。比如:


img[img > 40] = 255

具体的值就要根据要处理的图片来决定了。

五、改进

对于上面地处理,还可以做一个小小地改进。我们可以让纸张颜色不那么白,我们来看改进后的代码:


import cv2
import numpy as np
img = cv2.imread('page.jpg', 0)
# 计算灰白色部分像素的均值
pixel = int(np.mean(img[img > 140]))
# 把灰白色部分修改为与背景接近的颜色
img[img > 30] = pixel
cv2.imwrite('res.jpg', img)

在上面的代码中我们不再是将灰白色部分设置为255,而是事先计算了一个数值。


pixel = int(np.mean(img[img > 140]))

猜测阴影部分的颜色值小于140,因此先索引出图像中大于140的部分。然后求平均值,这样我们算出来的大致就是原图的背景颜色,然后将图片不是文字的部分处理为背景颜色,就是最终结果了。下面是我们的效果图:

OpenCV如何去除图片中的阴影的实现

可以看到这次效果要更好了。但是因为背景都是一个颜色,所以看起来还是会有一些差别。

不过有一点需要说一下,上面的操作只适用于比较简单的图片,比如试卷这种。

来源:https://blog.csdn.net/ZackSock/article/details/115293278

标签:OpenCV,去除,图片,阴影
0
投稿

猜你喜欢

  • python中os库的函数使用

    2022-05-03 22:16:57
  • asp三天学好ADO对象之第二天

    2008-10-09 12:49:00
  • django框架中ajax的使用及避开CSRF 验证的方式详解

    2023-05-11 02:10:41
  • Python使用LDAP做用户认证的方法

    2022-03-28 15:32:43
  • python地震数据可视化详解

    2021-05-14 15:41:52
  • python实现逆滤波与维纳滤波示例

    2023-07-01 16:36:25
  • pip更新问题的解决:'python -m pip install --upgrade pip' 报错问题(最新推荐)

    2023-04-23 04:32:13
  • SQL进行排序、分组、统计的10个新技巧

    2009-01-23 13:59:00
  • Django使用httpresponse返回用户头像实例代码

    2021-08-28 04:47:03
  • 解决python 出现unknown encoding: idna 的问题

    2023-10-06 21:26:06
  • 浅析Go语言编程当中映射和方法的基本使用

    2024-04-28 09:13:16
  • Python获取单个程序CPU使用情况趋势图

    2021-11-19 02:36:59
  • git_stats web代码图形统计工具详解

    2023-10-29 23:16:03
  • linux 安装 mysql 8.0.19 详细步骤及问题解决方法

    2024-01-13 22:31:33
  • ASP + Serv-u 实现FTP的代码

    2009-02-02 09:52:00
  • Javascript中实现trim()函数的两种方法

    2024-04-17 10:38:38
  • 如何在一个广告旗帜里轮番显示时间长度不一的不同广告?

    2010-06-26 12:35:00
  • Python3视频转字符动画的实例代码

    2022-02-09 12:29:29
  • ASP UTF-8编码下字符串截取和获取长度函数

    2011-03-30 10:52:00
  • PHP笛卡尔积实现算法示例

    2023-09-08 19:58:09
  • asp之家 网络编程 m.aspxhome.com