计算机视觉——opencv-python

博主自大一暑假开始接触图像处理,在学习一段时间的理论基础后,于大二开学之际开始代码的编写,主要参考资料是 ImageProcessing100Wen-master,现将所学总结为博客,每篇10问


main content

本篇处理的主要问题是图像的一些最基本操作,二值化、池化、滤波等


original material

原始图片包括一张普通蛤蟆的图片 imori.jpg,
以及加了噪声的图片 imori_noise.jpg

在这里插入图片描述
在这里插入图片描述



trouble shooting

q1 通道交换

将图像RGB通道替换为BGR:

###############################基础知识###############################
opencv读取图片的默认像素排列是BGR,需要转换成RGB
img[:,:,2]代表R通道,也就是红色分量图像;
img[:,:,1]代表G通道,也就是绿色分量图像;
img[:,:,0]代表B通道,也就是蓝色分量图像;
import cv2

# 可以使用相对路径,但似乎是需要在同一盘符
img = cv2.imread('D:\study\e_book\picture_processing\ImageProcessing100Wen-master\Question_01_10\imori.jpg')  

r = img[:,:,2].copy()
g = img[:,:,1].copy()
b = img[:,:,0].copy()

img[:,:,0] = r
img[:,:,1] = g
img[:,:,2] = b

cv2.imshow("通道转换完成", img)

# 确保窗口能够正常关闭
cv2.waitKey(0)						# 表示图片停留的时间, 0表示按任意键退出
cv2.destroyAllWindows()				# 表示清除所有的方框界面

效果:
在这里插入图片描述
在这里插入图片描述



q2 灰度化

###############################基础知识###############################
RGB图像灰度化方法:

Gray=max(B+G+R)
将彩色图像中的三分量亮度的最大值作为灰度图的灰度值

Gray=(B+G+R)/3
将彩色图像中的三分量亮度求平均得到一个灰度图;

Gray= 0.072169 * B + 0.715160 * G + 0.212671 * R
OpenCV开放库所采用的灰度权值

Gray= 0.11 * B + 0.59 * G + 0.3 * R
从人体生理学角度所提出的一种权值(人眼对绿色的敏感最高,对蓝色敏感最低)
import cv2
import numpy as np

img = cv2.imread(
    'D:\study\e_book\picture_processing\ImageProcessing100Wen-master\Question_01_10\imori.jpg'
)
r = img[:, :, 2].copy()
g = img[:, :, 1].copy()
b = img[:, :, 0].copy()

img_out = 0.2126 * r + 0.7152 * g + 0.0722 * b
img_out = img_out.astype(np.uint8)

cv2.imshow("result", img_out)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:
在这里插入图片描述
在这里插入图片描述



q3 二值化

# 先将图片转换为灰度图,再进行二值化
import cv2
import numpy as np

img = cv2.imread(
    'D:\study\e_book\picture_processing\ImageProcessing100Wen-master\Question_01_10\imori.jpg'
)
r = img[:, :, 2].copy()
g = img[:, :, 1].copy()
b = img[:, :, 0].copy()
# 灰度图:grey-scale map
img_gsm = 0.2126 * r + 0.7152 * g + 0.0722 * b
img_gsm = img_gsm.astype(np.uint8)

#binarization
th = 128						# 这里暂定阈值为128
img_gsm[img_gsm < th] = 0
img_gsm[img_gsm >= th] = 255
cv2.imshow("result", img_gsm)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:
在这里插入图片描述
在这里插入图片描述



q3 大津二值化算法(Otsu’s Method)

大津二值化算法:利用阈值将原图像分成前景,背景两个图象。当取最佳阈值时,背景应该与前景差别最大,在otsu算法中,衡量差别的标准是最大类间方差
算法主要步骤如下:

在这里插入图片描述


代码实现如下:

import cv2
import numpy as np

# 直接将数据转换成float32,方便后续计算
img = cv2.imread(r'D:\study\e_book\picture_processing\ImageProcessing100Wen-master\Question_01_10\imori.jpg').astype(np.float32)

# 灰度化
def rgb2gray(img):
    b = img[:, :, 0].copy()
    g = img[:, :, 1].copy()
    r = img[:, :, 2].copy()

    gray_img = 0.2126 * r + 0.7152 * g + 0.0722 * b
    gray_img = gray_img.astype(np.uint8)

    return gray_img

# 大津二值化算法
def otsu(gray_img):
    h = gray_img.shape[0]
    w = gray_img.shape[1]
    threshold_t = 0
    max_g = 0
    
    # 遍历每一个灰度层
    for t in range(255):           						 # t即为所求阈值
        n0 = gray_img[np.where(gray_img < t)]            # 小于阈值的像素,前景
        n1 = gray_img[np.where(gray_img >= t)]           # 大于阈值的像素,背景
        w0 = len(n0) / (h * w)                           # 前景像素数量占总像素数量的比例
        w1 = len(n1) / (h * w)                           # 背景像素数量占总像素数量的比例
        u0 = np.mean(n0) if len(n0) > 0 else 0.          # 前景平均灰度
        u1 = np.mean(n1) if len(n0) > 0 else 0.          # 背景平均灰度
        
        g = w0 * w1 * (u0 - u1) ** 2                     # 类间方差
        if g > max_g:
            max_g = g
            threshold_t = t                              # 更新阈值
    print('类间方差最大阈值:', threshold_t)
    gray_img[gray_img < threshold_t] = 0
    gray_img[gray_img >= threshold_t] = 255
    return gray_img

gray_img = rgb2gray(img)
otsu_img = otsu(gray_img)
                
cv2.imshow('otsu_img ', otsu_img )
cv2.waitKey(0)
cv2.destroyAllWindows()

该算法来自 大津二值化算法OTSU的理解


q5 HSV变换

HSV:使用色相(Hue)、饱和度(saturation)、明度(Value)来表示色彩

属性概念
色相H是指能够比较确切地表示某种颜色色别的名称
饱和度S色彩的鲜艳程度
明度V指色彩的亮度
R G B → H S V : RGB\rightarrow HSV: RGBHSV

M a x = m a x ( R , G , B ) M i n = m i n ( R , G , B ) Max = max(R,G,B) \\ Min = min(R,G,B) Max=max(R,G,B)Min=min(R,G,B)


H = { 0 i f M i n = M a x 60 ∗ ( G − R ) / ( M a x − M i n ) + 60 i f M i n = B 60 ∗ ( B − G ) / ( M a x − M i n ) + 180 i f M i n = G 60 ∗ ( G − R ) / ( M a x − M i n ) + 60 i f M i n = B H = \left\{ \begin{array}{lrl} 0 & if &Min=Max \\ 60*(G-R)/(Max-Min) + 60 & if &Min = B \\ 60*(B-G)/(Max-Min) + 180 &if &Min = G \\ 60*(G-R)/(Max-Min) + 60 &if &Min = B \\ \end{array} \right. H=060(GR)/(MaxMin)+6060(BG)/(MaxMin)+18060(GR)/(MaxMin)+60ififififMin=MaxMin=BMin=GMin=B


S = M a x − M i n S = Max - Min S=MaxMin


V = m a x V = max V=max


H S V → R G B : HSV\rightarrow RGB: HSVRGB
C = S H ′ = H 60 X = C ⋅ ( 1 − ∣ H ′ m o d 2 − 1 ∣ )   ( R , G , B ) = ( V − C ) ⋅ ( 1 , 1 , 1 ) + { ( 0 , 0 , 0 ) ( i f   H   i s   u n d e f i n e d ) ( C , X , 0 ) ( i f 0 ≤ H ′ < 1 ) ( X , C , 0 ) ( i f 1 ≤ H ′ < 2 ) ( 0 , C , X ) ( i f 2 ≤ H ′ < 3 ) ( 0 , X , C ) ( i f 3 ≤ H ′ < 4 ) ( X , 0 , C ) ( i f 4 ≤ H ′ < 5 ) ( C , 0 , X ) ( i f 5 ≤ H ′ < 6 ) C = S \\ H' = \frac{H}{60}\\ X = C\cdot (1-|H' \quad mod\quad 2-1|) \\ \ \\ (R,G,B)=(V-C)\cdot (1,1,1)+\left\{ \begin{array}{ll} (0,0,0)&(if\ H \ is\ undefined) \\ (C,X,0)&(if\quad 0 \leq H' <1) \\ (X,C,0)&(if\quad 1 \leq H' <2) \\ (0,C,X)&(if\quad 2 \leq H' <3) \\ (0,X,C)&(if\quad 3 \leq H' <4) \\ (X,0,C)&(if\quad 4 \leq H' <5) \\ (C,0,X)&(if\quad 5 \leq H' <6) \\ \end{array} \right. C=SH=60HX=C(1Hmod21) (R,G,B)=(VC)(1,1,1)+(0,0,0)(C,X,0)(X,C,0)(0,C,X)(0,X,C)(X,0,C)(C,0,X)(if H is undefined)(if0H<1)(if1H<2)(if2H<3)(if3H<4)(if4H<5)(if5H<6)


代码如下:

import cv2
import numpy as np

img = cv2.imread('D:/study/e_book/picture_processing/ImageProcessing100Wen-master/Question_01_10/imori.jpg')

img = img.copy()/ 255.
hsv = np.zeros_like(img, dtype=np.float32)

max_v = np.max(img, axis=2).copy()  #求每一个像素RGB中的最大值
min_v = np.min(img, axis=2).copy()  #求每一个像素RGB中的最小值
min_arg = np.argmin(img, axis=2)    #给出最小值对应的索引
##############################BGR->HSV###################################
## min == max
hsv[..., 0][np.where(max_v == min_v)] = 0
## if min == B
ind = np.where(min_arg == 0)
hsv[..., 0][ind] = 60 * (img[..., 1][ind] - img[..., 2][ind]) / (max_v[ind] - min_v[ind] + 60)
## if min == R
ind = np.where(min_arg == 2)
hsv[..., 0][ind] = 60 * (img[..., 0][ind] - img[..., 1][ind]) / (max_v[ind] - min_v[ind]) + 180
## if min == G
ind = np.where(min_arg == 1)
hsv[..., 0][ind] = 60 * (img[..., 2][ind] - img[..., 0][ind]) / (max_v[ind] - min_v[ind]) + 300

hsv[..., 1] = max_v.copy() - min_v.copy()
hsv[..., 2] = max_v.copy()

cv2.imshow('using_hsv',hsv)
cv2.waitKey(0)
cv2.destroyAllWindows()
###############################色相反转###################################
hsv_transform = hsv
hsv_transform[..., 0] = (hsv[..., 0] + 180) % 360
cv2.imshow('hsv_transform',hsv_transform)
cv2.waitKey(0)
cv2.destroyAllWindows()
out = np.zeros_like(img)
################################用RGB显示###############################
H = hsv[..., 0]
S = hsv[..., 1]
V = hsv[..., 2]

C = S
H_ = H / 60.
X = C * (1 - np.abs( H_ % 2 - 1))
Z = np.zeros_like(H)

vals = [[Z,X,C], [Z,C,X], [X,C,Z], [C,X,Z], [C,Z,X], [X,Z,C]]

for i in range(6):
	ind = np.where((i <= H_) & (H_ < (i+1)))
	out[..., 0][ind] = (V - C)[ind] + vals[i][0][ind]
	out[..., 1][ind] = (V - C)[ind] + vals[i][1][ind]
	out[..., 2][ind] = (V - C)[ind] + vals[i][2][ind]

out[np.where(max_v == min_v)] = 0
out = np.clip(out, 0, 1)
out = (out * 255).astype(np.uint8)
cv2.imshow('result', out)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:
在这里插入图片描述
在这里插入图片描述


q6 减色处理

将图像的RGB值由 25 6 3 256^3 2563 压缩至 4 3 4^3 43

import cv2
img = cv2.imread('D:\study\e_book\picture_processing\ImageProcessing100Wen-master\Question_01_10\imori.jpg')

result = 32 + img // 64 * 64
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:
在这里插入图片描述
在这里插入图片描述


q7 平均池化

###############################基础知识##################################
img.shape[0]:图像的垂直尺寸,即高度
img.shape[1]:图像的水平尺寸,即宽度
img.shape[2]:图像通道数
import cv2
import numpy as np

kernel_shape = 8
img = cv2.imread('D:\study\e_book\picture_processing\ImageProcessing100Wen-master\Question_01_10\imori.jpg')
H, W, C = img.shape  # 通道:channel
out = img.copy()

H_num = int(H/kernel_shape)
W_num = int(W/kernel_shape)

for y in range(W_num):
    for x in range(H_num):
        for c in range(C):
            out[kernel_shape*y:kernel_shape*(y+1), kernel_shape*x:kernel_shape*(x+1), c] = \
            np.mean(out[kernel_shape*y:kernel_shape*(y+1), kernel_shape*x:kernel_shape*(x+1), c]).astype(np.int)
            
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:
在这里插入图片描述
在这里插入图片描述


q8 最大池化

import cv2
import numpy as np

kernel_shape = 8
img = cv2.imread('D:\study\e_book\picture_processing\ImageProcessing100Wen-master\Question_01_10\imori.jpg')
H, W, C = img.shape  # 通道:channel
out = img.copy()

H_num = int(H/kernel_shape)
W_num = int(W/kernel_shape)

for y in range(W_num):
    for x in range(H_num):
        for c in range(C):
            out[kernel_shape*y:kernel_shape*(y+1), kernel_shape*x:kernel_shape*(x+1), c] = \
            np.max(out[kernel_shape*y:kernel_shape*(y+1), kernel_shape*x:kernel_shape*(x+1), c]).astype(np.int)
            
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
在这里插入图片描述


q9 高斯滤波

高斯滤波可以使图像平滑,用于去除噪声,算法具体实现步骤如下图所示:

在这里插入图片描述
代码如下:

import cv2
import numpy as np

img = cv2.imread(
    'D:/study/e_book/picture_processing/ImageProcessing100Wen-master/Question_01_10/imori_noise.jpg'
)
if len(img.shape) == 3:
    H, W, C = img.shape
else:
    img = np.expand_dims(img, axis=-1)  # 扩展最后一个参数
    H, W, C = img.shape

############################ 边缘填充0 ######################################
k_size = 3   # 卷积核尺寸为3*3
pad = k_size // 2
out = np.zeros((H + pad * 2, W + pad * 2, C), dtype=np.float)
out[pad: pad + H, pad: pad + W] = img.copy().astype(np.float)

## 准备卷积核
sigma = 1.3
K = np.zeros((k_size, k_size), dtype=np.float)
for x in range(-pad, -pad + k_size):
	for y in range(-pad, -pad + k_size):
		K[y + pad, x + pad] = np.exp( -(x ** 2 + y ** 2) / (2 * (sigma ** 2)))
K /= (2 * np.pi * sigma * sigma)
K /= K.sum()

##########################  对图像进行卷积操作  ###########################
tmp = out.copy()
for y in range(H):
	for x in range(W):
		for c in range(C):
			out[pad + y, pad + x, c] = np.sum(K * tmp[y: y + k_size, x: x + k_size, c])

out = np.clip(out, 0, 255)    ## numpy.clip(a, a_min, a_max)函数将a元素限制在a_min与a_max之间,>max : 让其等于max, <min : 让其等于min
out = out[pad: pad + H, pad: pad + W].astype(np.uint8)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果如下:
在这里插入图片描述
在这里插入图片描述


q10 中值滤波

与高斯滤波相比,改变了卷积核

import cv2
import numpy as np

img = cv2.imread(
    'D:/study/e_book/picture_processing/ImageProcessing100Wen-master/Question_01_10/imori_noise.jpg'
)
if len(img.shape) == 3:
    H, W, C = img.shape
else:
    img = np.expand_dims(img, axis=-1)  # 扩展最后一个参数
    H, W, C = img.shape

## 边缘填0
k_size = 3   # 卷积核尺寸为3*3
pad = k_size // 2
out = np.zeros((H + pad * 2, W + pad * 2, C), dtype=np.float)
out[pad: pad + H, pad: pad + W] = img.copy().astype(np.float)

## 准备卷积核
pad = k_size // 2
out = np.zeros((H + pad*2, W + pad*2, C), dtype=np.float)
out[pad:pad+H, pad:pad+W] = img.copy().astype(np.float)
tmp = out.copy()


for y in range(H):
	for x in range(W):
		for c in range(C):
			out[pad + y, pad + x, c] = np.sum(K * tmp[y: y + k_size, x: x + k_size, c])

out = np.clip(out, 0, 255)    ## numpy.clip(a, a_min, a_max)函数将a元素限制在a_min与a_max之间,>max : 让其等于max, <min : 让其等于min
out = out[pad: pad + H, pad: pad + W].astype(np.uint8)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果如下:
在这里插入图片描述
在这里插入图片描述


summary

博主花了一周的时间,将 ImageProcessing100Wen-master 前10个小问的代码基本理解清楚,之前看书所学的一些基础理论,在代码实现时也起到了不可替代的作用,希望接下来能坚持下去

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清上尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值