目前在计算机图像处理领域会经常用到一些预处理,简单介绍一些常用的对图像进行二值化处理的方法以及如何用代码去实现图像二值化。
import cv2 as cv
# 图像二值化 0白色 1黑色
def threshold_image(image):
#以灰度化形式读取图片
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
#OpenCV中的窗口无法显示中文,未解决
#OpenCV中读取文件路径也不能包含中文,否则会出错
cv.imshow("original", gray)
#OpenCV中读取的图像形式是以数组的形式读取与PIL中的image模块的读取不一样
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # 大律法,全局自适应阈值 参数0可改为任意数字但不起作用
print("大律法阈值:%s" % ret)
cv.imshow("OTSU", binary)
#ret可输出该阈值类型下进行二值化所选取的阈值
ret, binary = cv.threshold(gray, 0, 255,
cv.THRESH_BINARY | cv.THRESH_TRIANGLE) # TRIANGLE法,,全局自适应阈值, 参数0可改为任意数字但不起作用,适用于单个波峰
print("阈值:%s" % ret)
cv.imshow("TRIANGLE", binary)
ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_BINARY) # 自定义阈值为150,大于150的是白色 小于的是黑色
print("阈值:%s" % ret)
cv.imshow("1", binary)
ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_BINARY_INV) # 自定义阈值为150,大于150的是黑色 小于的是白色
print("阈值:%s" % ret)
cv.imshow("2", binary)
src = cv.imread("图片文件路径")
threshold_image(src)
cv.waitKey(0)
cv.destroyAllWindows()
threshold函数中四个参数代表的意义分别是输入图像,阈值(thresh),最大阈值(max Value),阈值化操作类型。
如下表所示,每一种阈值化操作类型,对应着一种源图像上每一个像素点与阈值(thresh)之间比较操作。根据源图像像素和阈值之间的大小关系,目标像素可能被置为0、原像素值、或者设定的最大阈值(maxValue),src(x,y)是图片中某点的灰度值大小。具体二值化效果可自行尝试。
通常我们都是直接利用Image.open()来打开一幅图像,然后直接对这个PIL对象进行操作。如果只是简单的操作还可以,但是如果操作稍微复杂一些,就比较吃力了。因此,通常我们加载完图片后,都是把图片转换成矩阵来进行更加复杂的操作。我们这里通过np.array将打开的图片转换成矩阵形式,然后通过遍历矩阵来实现对其二值化。代码如下:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
def img_to_bin(img_path, threshold):
"""
将图片转化为灰度图,二值化
0为黑,1为白
"""
img_bin =np.array(Image.open(img_path).convert("L"))
for i in range(len(img_bin)):
for j in range(len(img_bin[i])):
#当遍历的图像数组阈值大于设定阈值时重新赋值
if img_bin[i][j] > threshold:
img_bin[i][j] = 1
else:
img_bin[i][j] = 0
return img_bin
if __name__ == '__main__':
path = '图片文件路径'
img= img_to_bin(path,150)
plt.imshow(img)
plt.show()
还有一种方法跟上面的方法大同小异,代码如下:
import numpy as np
from PIL import Image
import scipy.misc
import scipy.ndimage
import matplotlib.pyplot as plt
input_images = np.zeros((500, 500))
path = 'E:/pycharm/GraduationDesign/Test/testtwo.png'
#convert将当前图像转换为灰度模式,并且返回新的图像。
#自己手写的数字应该重新定义矩阵再显示
img = Image.open(path).resize((500, 500)).convert('L')
#图像的尺寸,按照像素数计算。它的返回值为宽度和高度的二元组(width, height)。
width = img.size[0]
height = img.size[1]
threshold=130
#可以改写代码使其成为二值化,此代码可理解为反向二值化
for h in range(height):
for w in range(width):
#getpixel直接获得(h,w)处的像素直接返回这个点三个通道的像素值
#返回给定位置的像素值。如果图像为多通道,则返回一个元组(r,g,b,阈值)。
#如果改成(w,h)出现的图像会倒转
if img.getpixel((w, h)) < threshold:
input_images[h, w] = 1
else:
input_images[h, w] = 0
plt.subplot(122)
plt.title('Binaryzation')
plt.imshow(input_images)
plt.show()
path = "E:/pycharm/GraduationDesign/Test/testtwo111.png"
scipy.misc.imsave(path,input_images)
print("保存完毕")
第二种方法采用的是使用PIL中的Image.point()方法来操作像素数据。Lim.point(table)
=>图像Lim.point(function)
=>图像 返回图像的副本,其中每个像素都通过给定的表进行映射。该表应包含图像中每个波段的256个值。如果使用函数,则应该使用单个参数。对每个可能的像素值调用一次该函数,并将结果表应用于图像的所有波段。实现代码如下:
from PIL import Image
import matplotlib.pyplot as plt
#导入图像文件
path = 'E:/pycharm/GraduationDesign/Test/testfour111.png'
im = Image.open(path )#打开当前路径文件
#将图像转换成灰度图
Lim = im.convert('L' )
# 设定一个初始阈值
threshold = 130
table = []
for i in range(256):
if i < threshold:
table.append(1)
else:
table.append(0)
# 将数组转换成二进制图像,不然无法用imshow方法显示
bim = Lim.point(table,'1' )
plt.imshow(bim)
plt.show()