python抓取图片数字_[Python图像处理] 三十.图像量化及采样处理万字详细总结(推荐)...

图像通常是自然界景物的客观反映,并以照片形式或视频记录的介质连续保存,获取图像的目标是从感知的数据中产生数字图像,因此需要把连续的图像数据离散化,转换为数字化图像,其工作主要包括两方面——量化和采样。数字化幅度值称为量化,数字化坐标值称为采样。本文主要讲解图像量化和采样处理的概念,并通过Python和OpenCV实现这些功能。

一.图像量化处理

1.概述

所谓量化(Quantization),就是将图像像素点对应亮度的连续变化区间转换为单个特定值的过程,即将原始灰度图像的空间坐标幅度值离散化。量化等级越多,图像层次越丰富,灰度分辨率越高,图像的质量也越好;量化等级越少,图像层次欠丰富,灰度分辨率越低,会出现图像轮廓分层的现象,降低了图像的质量。图1是将图像的连续灰度值转换为0至255的灰度级的过程。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

如果量化等级为2,则将使用两种灰度级表示原始图片的像素(0-255),灰度值小于128的取0,大于等于128的取128;如果量化等级为4,则将使用四种灰度级表示原始图片的像素,新图像将分层为四种颜色,0-64区间取0,64-128区间取64,128-192区间取128,192-255区间取192,依次类推。

图2是对比不同量化等级的“Lena”图。其中(a)的量化等级为256,(b)的量化等级为64,(c)的量化等级为16,(d)的量化等级为8,(e)的量化等级为4,(f)的量化等级为2。

20201110192835147.png#pic_center

2.操作

下面讲述Python图像量化处理相关代码操作。其核心流程是建立一张临时图片,接着循环遍历原始图像中所有像素点,判断每个像素点应该属于的量化等级,最后将临时图像显示。下列代码将灰度图像转换为两种量化等级。

# -*- coding: utf-8 -*-# BY:Eastmount CSDN 2020-11-10import cv2

import numpy as np

import matplotlib.pyplot as plt#读取原始图像img = cv2.imread('lena.png')#获取图像高度和宽度height = img.shape[0]width = img.shape[1]#创建一幅图像new_img = np.zeros((height, width, 3), np.uint8)#图像量化操作 量化等级为2for i in range(height):

for j in range(width):

for k in range(3): #对应BGR三分量

if img[i, j][k] < 128:

gray = 0

else:

gray = 128

new_img[i, j][k] = np.uint8(gray)

#显示图像cv2.imshow("src", img)cv2.imshow("Quantization", new_img)#等待显示cv2.waitKey(0)cv2.destroyAllWindows()123456789101112131415161718192021222324252627282930313233

其输出结果如图3所示,它将灰度图像划分为两种量化等级。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

下面的代码分别比较了量化等级为2、4、8的量化处理效果。

# -*- coding: utf-8 -*-# BY:Eastmount CSDN 2020-11-10import cv2

import numpy as np

import matplotlib.pyplot as plt#读取原始图像img = cv2.imread('lena.png')#获取图像高度和宽度height = img.shape[0]width = img.shape[1]#创建一幅图像new_img1 = np.zeros((height, width, 3), np.uint8)new_img2 = np.zeros((height, width, 3), np.uint8)new_img3 = np.zeros((height, width, 3), np.uint8)#图像量化等级为2的量化处理for i in range(height):

for j in range(width):

for k in range(3): #对应BGR三分量

if img[i, j][k] < 128:

gray = 0

else:

gray = 128

new_img1[i, j][k] = np.uint8(gray)#图像量化等级为4的量化处理for i in range(height):

for j in range(width):

for k in range(3): #对应BGR三分量

if img[i, j][k] < 64:

gray = 0

elif img[i, j][k] < 128:

gray = 64

elif img[i, j][k] < 192:

gray = 128

else:

gray = 192

new_img2[i, j][k] = np.uint8(gray)#图像量化等级为8的量化处理for i in range(height):

for j in range(width):

for k in range(3): #对应BGR三分量

if img[i, j][k] < 32:

gray = 0

elif img[i, j][k] < 64:

gray = 32

elif img[i, j][k] < 96:

gray = 64

elif img[i, j][k] < 128:

gray = 96

elif img[i, j][k] < 160:

gray = 128

elif img[i, j][k] < 192:

gray = 160

elif img[i, j][k] < 224:

gray = 192

else:

gray = 224

new_img3[i, j][k] = np.uint8(gray)#用来正常显示中文标签plt.rcParams['font.sans-serif']=['SimHei']#显示图像titles = ['(a) 原始图像', '(b) 量化-L2', '(c) 量化-L4', '(d) 量化-L8'] images = [img, new_img1, new_img2, new_img3] for i in range(4):

plt.subplot(2,2,i+1), plt.imshow(images[i], 'gray'),

plt.title(titles[i])

plt.xticks([]),plt.yticks([]) plt.show()123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475

输出结果如图4所示,该代码调用matplotlib.pyplot库绘制了四幅图像,其中(a)表示原始图像,(b)表示等级为2的量化处理,(c)表示等级为4的量化处理,(d)表示等级为8的量化处理。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

3.K-Means聚类量化处理

上一小节的量化处理是通过遍历图像中的所有像素点,进行灰度图像的幅度值离散化处理。本小节补充一个基于K-Means聚类算法的量化处理过程,它能够将彩色图像RGB像素点进行颜色分割和颜色量化。注意,在第十九篇文章时详细介绍了K-Means聚类知识,本小节只是带领读者重新回顾下该方法。

# coding: utf-8# BY:Eastmount CSDN 2020-11-10import cv2import numpy as npimport matplotlib.pyplot as plt#读取原始图像img = cv2.imread('nv.png') #图像二维像素转换为一维data = img.reshape((-1,3))data = np.float32(data)#定义中心 (type,max_iter,epsilon)criteria = (cv2.TERM_CRITERIA_EPS +

cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)#设置标签flags = cv2.KMEANS_RANDOM_CENTERS#K-Means聚类 聚集成4类compactness, labels, centers = cv2.kmeans(data, 4, None, criteria, 10, flags)#图像转换回uint8二维类型centers = np.uint8(centers)res = centers[labels.flatten()]dst = res.reshape((img.shape))#图像转换为RGB显示img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)dst = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)#用来正常显示中文标签plt.rcParams['font.sans-serif']=['SimHei']#显示图像titles = ['原始图像', '聚类量化 K=4'] images = [img, dst] for i in range(2):

plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray'),

plt.title(titles[i])

plt.xticks([]),plt.yticks([]) plt.show()1234567891011121314151617181920212223242526272829303132333435363738394041424344

输出结果如图5所示,它通过K-Means聚类算法将彩色人物图像的灰度聚集成四种颜色。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

二.图像采样处理

1.概述

图像采样(Image Sampling)处理是将一幅连续图像在空间上分割成M×N个网格,每个网格用一个亮度值或灰度值来表示,其示意图如图6所示。

20201110194127743.png#pic_center

图像采样的间隔越大,所得图像像素数越少,空间分辨率越低,图像质量越差,甚至出现马赛克效应;相反,图像采样的间隔越小,所得图像像素数越多,空间分辨率越高,图像质量越好,但数据量会相应的增大。图7展示了不同采样间隔的“Lena”图,其中图(a)为原始图像,图(b)为128×128的图像采样效果,图©为64×64的图像采样效果,图(d)为32×32的图像采样效果,图(e)为16×16的图像采样效果,图(f)为8×8的图像采样效果。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

数字图像的质量很大程度上取决于量化和采样中所采用的样本数和灰度级。现实生活中的图像,都需要经过离散化处理转换成数字图像,从而进行后续的计算机处理和图像识别等操作。图8展示了生活图像转换为数字图像的过程。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

2.操作

下面讲述Python图像采样处理相关代码操作。其核心流程是建立一张临时图片,设置需要采样的区域大小(如16×16),接着循环遍历原始图像中所有像素点,采样区域内的像素点赋值相同(如左上角像素点的灰度值),最终实现图像采样处理。下列代码是进行16×16采样的过程。

# -*- coding: utf-8 -*-# BY:Eastmount CSDN 2020-11-10import cv2

import numpy as np

import matplotlib.pyplot as plt#读取原始图像img = cv2.imread('lena.png')#获取图像高度和宽度height = img.shape[0]width = img.shape[1]#采样转换成16*16区域numHeight = int(height/16)numWidth = int(width/16)#创建一幅图像new_img = np.zeros((height, width, 3), np.uint8)#图像循环采样16*16区域for i in range(16):

#获取Y坐标

y = i*numHeight for j in range(16):

#获取X坐标

x = j*numWidth #获取填充颜色 左上角像素点

b = img[y, x][0]

g = img[y, x][1]

r = img[y, x][2]

#循环设置小区域采样

for n in range(numHeight):

for m in range(numWidth):

new_img[y+n, x+m][0] = np.uint8(b)

new_img[y+n, x+m][1] = np.uint8(g)

new_img[y+n, x+m][2] = np.uint8(r)

#显示图像cv2.imshow("src", img)cv2.imshow("Sampling", new_img)#等待显示cv2.waitKey(0)cv2.destroyAllWindows()12345678910111213141516171819202122232425262728293031323334353637383940414243444546

其输出结果如图8所示,它将灰度图像采样成16×16的区域。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

同样,可以对彩色图像进行采样处理,下面的代码将彩色风景图像采样处理成8×8的马赛克区域。

# -*- coding: utf-8 -*-# BY:Eastmount CSDN 2020-11-10import cv2

import numpy as np

import matplotlib.pyplot as plt#读取原始图像img = cv2.imread('scenery.png')#获取图像高度和宽度height = img.shape[0]width = img.shape[1]#采样转换成8*8区域numHeight = int(height/8)numwidth = int(width/8)#创建一幅图像new_img = np.zeros((height, width, 3), np.uint8)#图像循环采样8*8区域for i in range(8):

#获取Y坐标

y = i*numHeight for j in range(8):

#获取X坐标

x = j*numwidth #获取填充颜色 左上角像素点

b = img[y, x][0]

g = img[y, x][1]

r = img[y, x][2]

#循环设置小区域采样

for n in range(numHeight):

for m in range(numwidth):

new_img[y+n, x+m][0] = np.uint8(b)

new_img[y+n, x+m][1] = np.uint8(g)

new_img[y+n, x+m][2] = np.uint8(r)

#显示图像cv2.imshow("src", img)cv2.imshow("Sampling", new_img)#等待显示cv2.waitKey(0)cv2.destroyAllWindows()12345678910111213141516171819202122232425262728293031323334353637383940414243444546

其输出结果如图9所示,它将彩色风景图像采样成8×8的区域。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

但上述代码存在一个问题,当图像的长度和宽度不能被采样区域整除时,输出图像的最右边和最下边的区域没有被采样处理。这里推荐读者做个求余运算,将不能整除部分的区域也进行相应的采样处理。

3.局部马赛克处理

前面讲述的代码是对整幅图像进行采样处理,那么如何对图像的局部区域进行马赛克处理呢?下面的代码就实现了该功能。当鼠标按下时,它能够给鼠标拖动的区域打上马赛克,并按下“s”键保存图像至本地。

# -- coding:utf-8 --# BY:Eastmount CSDN 2020-11-10import cv2

import numpy as np

import matplotlib.pyplot as plt#读取原始图像im = cv2.imread('people.png', 1)#设置鼠标左键开启en = False#鼠标事件def draw(event, x, y, flags, param):

global en #鼠标左键按下开启en值

if event==cv2.EVENT_LBUTTONDOWN:

en = True

#鼠标左键按下并且移动

elif event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_LBUTTONDOWN:

#调用函数打马赛克

if en:

drawMask(y,x)

#鼠标左键弹起结束操作

elif event==cv2.EVENT_LBUTTONUP:

en = False

#图像局部采样操作 def drawMask(x, y, size=10):

#size*size采样处理

m = int(x / size * size)

n = int(y / size * size)

print(m, n)

#10*10区域设置为同一像素值

for i in range(size):

for j in range(size):

im[m+i][n+j] = im[m][n]#打开对话框cv2.namedWindow('image')#调用draw函数设置鼠标操作cv2.setMouseCallback('image', draw)#循环处理while(1):

cv2.imshow('image', im)

#按ESC键退出

if cv2.waitKey(10)&0xFF==27:

break

#按s键保存图片

elif cv2.waitKey(10)&0xFF==115:

cv2.imwrite('sava.png', im)#退出窗口cv2.destroyAllWindows()1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

其输出结果如图10所示,它将人物的脸部进行马赛克处理,按下S键保存图片,按下ESC键退出。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

三.图像金字塔

http://dxb.myzx.cn/jilin/

前面讲解的图像采样处理可以降低图像的大小,本小节将补充图像金字塔知识,了解专门用于图像向上采样和向下采样的pyrUp()和pyrDown()函数。

图像金字塔是指由一组图像且不同分别率的子图集合,它是图像多尺度表达的一种,以多分辨率来解释图像的结构,主要用于图像的分割或压缩。一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低,且来源于同一张原始图的图像集合。如图11所示,它包括了四层图像,将这一层一层的图像比喻成金字塔。图像金字塔可以通过梯次向下采样获得,直到达到某个终止条件才停止采样,在向下采样中,层级越高,则图像越小,分辨率越低。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

生成图像金字塔主要包括两种方式——向下取样、向上取样。在图11中,将图像G0转换为G1、G2、G3,图像分辨率不断降低的过程称为向下取样;将G3转换为G2、G1、G0,图像分辨率不断增大的过程称为向上取样。

1.图像向下取样

http://ask.baikezh.com/hunan/

在图像向下取样中,使用最多的是高斯金字塔。它将对图像Gi进行高斯核卷积,并删除原图中所有的偶数行和列,最终缩小图像。其中,高斯核卷积运算就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值(权重不同)经过加权平均后得到。常见的3×3和5×5高斯核如下:

20201110200156219.png#pic_center

高斯核卷积让临近中心的像素点具有更高的重要度,对周围像素计算加权平均值,如图12所示,其中心位置权重最高为0.4。

20201110200216838.png#pic_center

显而易见,原始图像Gi具有M×N个像素,进行向下取样之后,所得到的图像Gi+1具有M/2×N/2个像素,只有原图的四分之一。通过对输入的原始图像不停迭代以上步骤就会得到整个金字塔。注意,由于每次向下取样会删除偶数行和列,所以它会不停地丢失图像的信息。

在OpenCV中,向下取样使用的函数为pyrDown(),其原型如下所示:

dst = pyrDown(src[, dst[, dstsize[, borderType]]])

– src表示输入图像,

– dst表示输出图像,和输入图像具有一样的尺寸和类型

– dstsize表示输出图像的大小,默认值为Size()

– borderType表示像素外推方法,详见cv::bordertypes

向下取样的代码如下所示:

http://zzdxb.baikezh.com/

# -*- coding: utf-8 -*-# BY:Eastmount CSDN 2020-11-10import cv2

import numpy as np

import matplotlib.pyplot as plt#读取原始图像img = cv2.imread('nv.png')#图像向下取样r = cv2.pyrDown(img)#显示图像cv2.imshow('original', img)cv2.imshow('PyrDown', r)cv2.waitKey()cv2.destroyAllWindows()1234567891011121314151617

输出结果如图13所示,它将原始图像压缩成原图的四分之一。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

多次向下取样的代码参考下列文件。

# -*- coding: utf-8 -*-# BY:Eastmount CSDN 2020-11-10import cv2

import numpy as np

import matplotlib.pyplot as plt#读取原始图像img = cv2.imread('nv.png')#图像向下取样r1 = cv2.pyrDown(img)r2 = cv2.pyrDown(r1)r3 = cv2.pyrDown(r2)#显示图像cv2.imshow('original', img)cv2.imshow('PyrDown1', r1)cv2.imshow('PyrDown2', r2)cv2.imshow('PyrDown3', r3)cv2.waitKey()cv2.destroyAllWindows()123456789101112131415161718192021

输出结果如图14所示,每次向下取样均为上次的四分之一,并且图像的清晰度会降低。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

2.图像向上取样

http://dxb.myzx.cn/oldage/

在图像向上取样是由小图像不断放图像的过程。它将图像在每个方向上扩大为原图像的2倍,新增的行和列均用0来填充,并使用与“向下取样”相同的卷积核乘以4,再与放大后的图像进行卷积运算,以获得“新增像素”的新值。如图15所示,它在原始像素45、123、89、149之间各新增了一行和一列值为0的像素。

20201110200658375.png#pic_center

注意,向上取样放大后的图像比原始图像要模糊。同时,向上采样和向下采样不是互逆的操作,经过两种操作后,是无法恢复原始图像的。

http://dxb.myzx.cn/oldage/

在OpenCV中,向上取样使用的函数为pyrUp(),其原型如下所示:

dst = pyrUp(src[, dst[, dstsize[, borderType]]])

– src表示输入图像,

– dst表示输出图像,和输入图像具有一样的尺寸和类型

– dstsize表示输出图像的大小,默认值为Size()

– borderType表示像素外推方法,详见cv::bordertypes

向上取样的代码如下所示:

# -*- coding: utf-8 -*-# BY:Eastmount CSDN 2020-11-10import cv2

import numpy as np

import matplotlib.pyplot as plt#读取原始图像img = cv2.imread('lena.png')#图像向上取样r = cv2.pyrUp(img)#显示图像cv2.imshow('original', img)cv2.imshow('PyrUp', r)cv2.waitKey()cv2.destroyAllWindows()1234567891011121314151617

输出结果如图16所示,它将原始图像扩大为原图像的四倍,即向上一次取样。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

多次向上取样的代码参考下列文件。

http://ask.baikezh.com/chengdou/

# -*- coding: utf-8 -*-import cv2

import numpy as np

import matplotlib.pyplot as plt#读取原始图像img = cv2.imread('lena2.png')#图像向上取样r1 = cv2.pyrUp(img)r2 = cv2.pyrUp(r1)r3 = cv2.pyrUp(r2)#显示图像cv2.imshow('original', img)cv2.imshow('PyrUp1', r1)cv2.imshow('PyrUp2', r2)cv2.imshow('PyrUp3', r3)cv2.waitKey()cv2.destroyAllWindows()1234567891011121314151617181920

输出结果如图17所示,每次向上取样均为上次图像的四倍,但图像的清晰度会降低。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0Vhc3Rtb3VudA==,size_16,color_FFFFFF,t_70#pic_center

四.本章小结

本文主要讲解了图像的量化处理和采样处理,从基本概率到操作,再到扩展进行全方位讲解,并且补充了基于K-Means聚类算法的量化处理和局部马赛克特效处理,最后补充了图像金字塔相关知识。该章节知识点能够将生活中的图像转换为数字图像,更好地为后续的图像处理提供帮助。希望这篇基础性文章对读者有一定帮助,也希望这些知识点为读者从事Python图像处理相关项目实践或科学研究提供一定基础。

http://ask.baikezh.com/hefei/

时光嘀嗒嘀嗒的流失,这是我在CSDN写下的第八篇年终总结,比以往时候来的更早一些。《敏而多思,宁静致远》,仅以此篇纪念这风雨兼程的一年,这感恩的一年。列车上只写了一半,这两天完成,思远,思君O(∩_∩)O

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值