基于颜色通道分离法去除图像中印章

摘要

本文以“去除图像中的红色印章”为研究对象,应用颜色特征,将图像的前景从背景中分离。编制Python程序并进行仿真,最终提取出的前景图非常令人满意。

问题

给定如下一张图片:

我们希望去除图像中的红色印章,以便能更好地读取文字。

技术路线

该问题中,像素为前景(frontground),印章所在的像素为背景(background)。我们希望能将前景()提取出来。

分析图片我们发现,的颜色是黑色, 印章的颜色是红色的颜色是灰色(接近白色)

前景和背景在颜色上存在差异,这就启发我们通过颜色特征将前景和背景分离。

现在,我们分别提取原始图片的Red, Green和Blue三个颜色通道,得到如下三张图片:




图3,4与原始图像相似,利用价值不高。然而图2,即红色通道灰度值图片,非常值得我们关注:图1中越红的像素点在图2中的灰度值就越大,越接近255,在图2中看起来就越白。我们还得到以下发现:

  1. 印章像素为白色,灰度值接近255
  2. 的像素为灰色(接近白色),灰度值接近255
  3. 的像素为黑色,灰度值接近0

此时,我们就可以通过一个阈值,将前景像素()提取出来。

公式为:

其中:$I_{r}(x,y)$是坐标$(x,y)$处的像素点的红色分量的灰度值,$threshold $为阈值,可以通过求取图2的灰度直方图进行设定,如图5所示


我们可以看到,图5所示的红色通道直方图中,明显存在两个集中区域,左侧的区域灰度值较低,对应颜色为黑色,是前景像素();右侧集中区域灰度值较高,对应颜色为白色区域,是背景像素(印章)。

在这两个灰度集中的区域的中间部分,设定一个阈值,可以将这两个区域分割开来。需要指出的是,阈值的设定对于最终的处理结果具有较大影响,这里我们选择阈值为110.

对于二值化后的图片,我们还可以通过数学形态学中的膨胀算子对图像进行视觉增强操作。

现在总结技术路线

  1. 读取原始图像A
  2. 提取图像的红色通道,得到红色通道灰度值图片B
  3. 计算B的统计直方图C,确定最佳的阈值threshold
  4. 根据阈值,对B进行二值化,得到最终图片D
  5. (可选)应用膨胀算子对D进行操作,得到图片E

源代码

采用Python 2.7,更高版本估计也可以(未测试)。主要的包为OpenCV 3.4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# -*- coding: utf-8 -*-
"""
Created on Wed Jun 13 15:09:40 2018

@author: handsomeboy
"""

#去除印章
import cv2
import numpy as np
import matplotlib.pyplot as plt

#读入图像,三通道
image=cv2.imread("stamp.jpg",cv2.IMREAD_COLOR) #timg.jpeg

#读入图像尺寸
cols,rows,_=image.shape
#缩放比例
ratio=0.3

#缩放后的尺寸
cols=int(ratio*cols)
rows=int(ratio*rows)

#缩放图片
image = cv2.resize(image,(rows,cols) )

#获得三个通道
Bch,Gch,Rch=cv2.split(image)

#cv2.imshow('Blue channel',cv2.merge([Bch,0*Gch,0*Rch]))
#cv2.imshow('Green channel',cv2.merge([0*Bch,Gch,0*Rch]))
#cv2.imshow('Red channel',cv2.merge([0*Bch,0*Gch,Rch]))


cv2.imshow('Blue channel',Bch)
cv2.imshow('Green channel',Gch)
cv2.imshow('Red channel',Rch)

cv2.imwrite('Blue channel.jpg',Bch)
cv2.imwrite('Green channel.jpg',Gch)
cv2.imwrite('Red channel.jpg',Rch)


#红色通道的histgram
#变换程一维向量
pixelSequence=Rch.reshape([rows*cols,])

#统计直方图的组数
numberBins=256

#计算直方图
plt.figure()
manager = plt.get_current_fig_manager()
manager.window.showMaximized()

histogram,bins,patch=plt.hist(pixelSequence,numberBins,facecolor='black',histtype='bar') #facecolor设置为黑色

#设置坐标范围
y_maxValue=np.max(histogram)
plt.axis([0,255,0,y_maxValue])
#设置坐标轴
plt.xlabel("gray Level",fontsize=20)
plt.ylabel('number of pixels',fontsize=20)
plt.title("Histgram of red channel", fontsize=25)
plt.xticks(range(0,255,10))
#显示直方图
plt.pause(0.05)
plt.savefig("histgram.png",dpi=260,bbox_inches="tight")
plt.show()


#红色通道阈值
_,RedThresh = cv2.threshold(Rch,110,255,cv2.THRESH_BINARY)

#膨胀操作
element = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
erode = cv2.erode(RedThresh, element)

#显示效果
cv2.imshow('original color image',image)
cv2.imwrite('scaleimage.jpg',image)

cv2.imshow("RedThresh",RedThresh)
cv2.imwrite('RedThresh.jpg',RedThresh)

cv2.imshow("erode",erode)
cv2.imwrite("erode.jpg",erode)

计算结果

图1,图3,图6分别对应计算流程的A,B,C三张图。下面给出D,E两幅图:


结论

将图1和图7做对比,我们发现,印章完全消失了!效果非常令人满意。

“去除图像中的印章”,这个任务看起来很困难,但是如果知道颜色通道的思想,该任务就显得非常简单。但这里的关键是,能够想到这个思想,这就需要对图像处理的知识掌握扎实,在以后的应用中才会灵活运用。

参考文献

  1. [OpenCV探索之路(二十六):如何去除票据上的印章]
  2. python opencv入门 形态学转换(13)
  3. 《数字图像处理》冈萨雷斯