数字图像处理Python实现图像灰度变换、直方图均衡、均值滤波

Python021

数字图像处理Python实现图像灰度变换、直方图均衡、均值滤波,第1张

import CV2

import copy

import numpy as np

import random

使用的是pycharm

因为最近看了《银翼杀手2049》,里面Joi实在是太好看了所以原图像就用Joi了

要求是灰度图像,所以第一步先把图像转化成灰度图像

# 读入原始图像

img = CV2.imread('joi.jpg')

# 灰度化处理

gray = CV2.cvtColor(img, CV2.COLOR_BGR2GRAY)

CV2.imwrite('img.png', gray)

第一个任务是利用分段函数增强灰度对比,我自己随便写了个函数大致是这样的

def chng(a):

if a <255/3:

b = a/2

elif a <255/3*2:

b = (a-255/3)*2 + 255/6

else:

b = (a-255/3*2)/2 + 255/6 +255/3*2

return b

rows = img.shape[0]

cols = img.shape[1]

cover = copy.deepcopy(gray)

for i in range(rows):

for j in range(cols):

cover[i][j] = chng(cover[i][j])

CV2.imwrite('cover.png', cover)

下一步是直方图均衡化

# histogram equalization

def hist_equal(img, z_max=255):

H, W = img.shape

# S is the total of pixels

S = H * W * 1.

out = img.copy()

sum_h = 0.

for i in range(1, 255):

ind = np.where(img == i)

sum_h += len(img[ind])

z_prime = z_max / S * sum_h

out[ind] = z_prime

out = out.astype(np.uint8)

return out

covereq = hist_equal(cover)

CV2.imwrite('covereq.png', covereq)

在实现滤波之前先添加高斯噪声和椒盐噪声(代码来源于网络)

不知道这个椒盐噪声的名字是谁起的感觉隔壁小孩都馋哭了

用到了random.gauss()

percentage是噪声占比

def GaussianNoise(src,means,sigma,percetage):

NoiseImg=src

NoiseNum=int(percetage*src.shape[0]*src.shape[1])

for i in range(NoiseNum):

randX=random.randint(0,src.shape[0]-1)

randY=random.randint(0,src.shape[1]-1)

NoiseImg[randX, randY]=NoiseImg[randX,randY]+random.gauss(means,sigma)

if NoiseImg[randX, randY]<0:

NoiseImg[randX, randY]=0

elif NoiseImg[randX, randY]>255:

NoiseImg[randX, randY]=255

return NoiseImg

def PepperandSalt(src,percetage):

NoiseImg=src

NoiseNum=int(percetage*src.shape[0]*src.shape[1])

for i in range(NoiseNum):

randX=random.randint(0,src.shape[0]-1)

randY=random.randint(0,src.shape[1]-1)

if random.randint(0,1)<=0.5:

NoiseImg[randX,randY]=0

else:

NoiseImg[randX,randY]=255

return NoiseImg

covereqg = GaussianNoise(covereq, 2, 4, 0.8)

CV2.imwrite('covereqg.png', covereqg)

covereqps = PepperandSalt(covereq, 0.05)

CV2.imwrite('covereqps.png', covereqps)

下面开始均值滤波和中值滤波了

就以n x n为例,均值滤波就是用这n x n个像素点灰度值的平均值代替中心点,而中值就是中位数代替中心点,边界点周围补0;前两个函数的作用是算出这个点的灰度值,后两个是对整张图片进行

#均值滤波模板

def mean_filter(x, y, step, img):

sum_s = 0

for k in range(x-int(step/2), x+int(step/2)+1):

for m in range(y-int(step/2), y+int(step/2)+1):

if k-int(step/2) 0 or k+int(step/2)+1 >img.shape[0]

or m-int(step/2) 0 or m+int(step/2)+1 >img.shape[1]:

sum_s += 0

else:

sum_s += img[k][m] / (step*step)

return sum_s

#中值滤波模板

def median_filter(x, y, step, img):

sum_s=[]

for k in range(x-int(step/2), x+int(step/2)+1):

for m in range(y-int(step/2), y+int(step/2)+1):

if k-int(step/2) 0 or k+int(step/2)+1 >img.shape[0]

or m-int(step/2) 0 or m+int(step/2)+1 >img.shape[1]:

sum_s.append(0)

else:

sum_s.append(img[k][m])

sum_s.sort()

return sum_s[(int(step*step/2)+1)]

def median_filter_go(img, n):

img1 = copy.deepcopy(img)

for i in range(img.shape[0]):

for j in range(img.shape[1]):

img1[i][j] = median_filter(i, j, n, img)

return img1

def mean_filter_go(img, n):

img1 = copy.deepcopy(img)

for i in range(img.shape[0]):

for j in range(img.shape[1]):

img1[i][j] = mean_filter(i, j, n, img)

return img1

完整main代码如下:

if __name__ == "__main__":

# 读入原始图像

img = CV2.imread('joi.jpg')

# 灰度化处理

gray = CV2.cvtColor(img, CV2.COLOR_BGR2GRAY)

CV2.imwrite('img.png', gray)

rows = img.shape[0]

cols = img.shape[1]

cover = copy.deepcopy(gray)

for i in range(rows):

for j in range(cols):

cover[i][j] = chng(cover[i][j])

CV2.imwrite('cover.png', cover)

covereq = hist_equal(cover)

CV2.imwrite('covereq.png', covereq)

covereqg = GaussianNoise(covereq, 2, 4, 0.8)

CV2.imwrite('covereqg.png', covereqg)

covereqps = PepperandSalt(covereq, 0.05)

CV2.imwrite('covereqps.png', covereqps)

meanimg3 = mean_filter_go(covereqps, 3)

CV2.imwrite('medimg3.png', meanimg3)

meanimg5 = mean_filter_go(covereqps, 5)

CV2.imwrite('meanimg5.png', meanimg5)

meanimg7 = mean_filter_go(covereqps, 7)

CV2.imwrite('meanimg7.png', meanimg7)

medimg3 = median_filter_go(covereqg, 3)

CV2.imwrite('medimg3.png', medimg3)

medimg5 = median_filter_go(covereqg, 5)

CV2.imwrite('medimg5.png', medimg5)

medimg7 = median_filter_go(covereqg, 7)

CV2.imwrite('medimg7.png', medimg7)

medimg4 = median_filter_go(covereqps, 7)

CV2.imwrite('medimg4.png', medimg4)

Pillow是Python里的图像处理库(PIL:Python Image Library),提供了了广泛的文件格式支持,强大的图像处理能力,主要包括图像储存、图像显示、格式转换以及基本的图像处理操作等。

1)使用 Image 类

PIL最重要的类是 Image class, 你可以通过多种方法创建这个类的实例;你可以从文件加载图像,或者处理其他图像, 或者从 scratch 创建。

要从文件加载图像,可以使用open( )函数,在Image模块中:

>>>from PIL import Image

>>>im = Image.open("E:/photoshop/1.jpg")

加载成功后,将返回一个Image对象,可以通过使用示例属性查看文件内容:

>>>print(im.format, im.size, im.mode)

('JPEG', (600, 351), 'RGB')

>>>

format 这个属性标识了图像来源。如果图像不是从文件读取它的值就是None。size属性是一个二元tuple,包含width和height(宽度和高度,单位都是px)。 mode 属性定义了图像bands的数量和名称,以及像素类型和深度。常见的modes 有 “L” (luminance) 表示灰度图像, “RGB” 表示真彩色图像, and “CMYK” 表示出版图像。

如果文件打开错误,返回 IOError 错误。

只要你有了 Image 类的实例,你就可以通过类的方法处理图像。比如,下列方法可以显示图像:

im.show()

2)读写图像

PIL 模块支持大量图片格式。使用在 Image 模块的 open() 函数从磁盘读取文件。你不需要知道文件格式就能打开它,这个库能够根据文件内容自动确定文件格式。要保存文件,使用 Image 类的 save() 方法。保存文件的时候文件名变得重要了。除非你指定格式,否则这个库将会以文件名的扩展名作为格式保存。

加载文件,并转化为png格式:

"Python Image Library Test"

from PIL import Image

import os

import sys

for infile in sys.argv[1:]:

f,e = os.path.splitext(infile)

outfile = f +".png"

if infile != outfile:

try:

Image.open(infile).save(outfile)

except IOError:

print("Cannot convert", infile)

save() 方法的第二个参数可以指定文件格式。

3)创建缩略图

缩略图是网络开发或图像软件预览常用的一种基本技术,使用Python的Pillow图像库可以很方便的建立缩略图,如下:

# create thumbnail

size = (128,128)

for infile in glob.glob("E:/photoshop/*.jpg"):

f, ext = os.path.splitext(infile)

img = Image.open(infile)

img.thumbnail(size,Image.ANTIALIAS)

img.save(f+".thumbnail","JPEG")

上段代码对photoshop下的jpg图像文件全部创建缩略图,并保存,glob模块是一种智能化的文件名匹配技术,在批图像处理中经常会用到。

注意:Pillow库不会直接解码或者加载图像栅格数据。当你打开一个文件,只会读取文件头信息用来确定格式,颜色模式,大小等等,文件的剩余部分不会主动处理。这意味着打开一个图像文件的操作十分快速,跟图片大小和压缩方式无关。

4)图像的剪切、粘贴与合并操作

Image 类包含的方法允许你操作图像部分选区,PIL.Image.Image.crop 方法获取图像的一个子矩形选区,如:

# crop, paste and merge

im = Image.open("E:/photoshop/lena.jpg")

box = (100,100,300,300)

region = im.crop(box)

矩形选区有一个4元元组定义,分别表示左、上、右、下的坐标。这个库以左上角为坐标原点,单位是px,所以上诉代码复制了一个 200×200 pixels 的矩形选区。这个选区现在可以被处理并且粘贴到原图。

region = region.transpose(Image.ROTATE_180)

im.paste(region, box)

当你粘贴矩形选区的时候必须保证尺寸一致。此外,矩形选区不能在图像外。然而你不必保证矩形选区和原图的颜色模式一致,因为矩形选区会被自动转换颜色。

5)分离和合并颜色通道

对于多通道图像,有时候在处理时希望能够分别对每个通道处理,处理完成后重新合成多通道,在Pillow中,很简单,如下:

r,g,b = im.split()

im = Image.merge("RGB", (r,g,b))

对于split( )函数,如果是单通道的,则返回其本身,否则,返回各个通道。

6)几何变换

对图像进行几何变换是一种基本处理,在Pillow中包括resize( )和rotate( ),如用法如下:

out = im.resize((128,128))

out = im.rotate(45) # degree conter-clockwise

其中,resize( )函数的参数是一个新图像大小的元祖,而rotate( )则需要输入顺时针的旋转角度。在Pillow中,对于一些常见的旋转作了专门的定义:

out = im.transpose(Image.FLIP_LEFT_RIGHT)

out = im.transpose(Image.FLIP_TOP_BOTTOM)

out = im.transpose(Image.ROTATE_90)

out = im.transpose(Image.ROTATE_180)

out = im.transpose(Image.ROTATE_270)

7)颜色空间变换

在处理图像时,根据需要进行颜色空间的转换,如将彩色转换为灰度:

cmyk = im.convert("CMYK")

gray = im.convert("L")

8)图像滤波

图像滤波在ImageFilter 模块中,在该模块中,预先定义了很多增强滤波器,可以通过filter( )函数使用,预定义滤波器包括:

BLUR、CONTOUR、DETAIL、EDGE_ENHANCE、EDGE_ENHANCE_MORE、EMBOSS、FIND_EDGES、SMOOTH、SMOOTH_MORE、SHARPEN。其中BLUR就是均值滤波,CONTOUR找轮廓,FIND_EDGES边缘检测,使用该模块时,需先导入,使用方法如下:

from PIL import ImageFilter

imgF = Image.open("E:/photoshop/lena.jpg")

outF = imgF.filter(ImageFilter.DETAIL)

conF = imgF.filter(ImageFilter.CONTOUR)

edgeF = imgF.filter(ImageFilter.FIND_EDGES)

imgF.show()

outF.show()

conF.show()

edgeF.show()

除此以外,ImageFilter模块还包括一些扩展性强的滤波器:

class PIL.ImageFilter.GaussianBlur(radius=2)