Opencv 图像处理(一)

118 阅读2分钟

问题一:通道交换

读取图像,然后将RGB\text{RGB}通道替换成BGR\text{BGR}通道。

下面的代码用于提取图像的红色通道。

注意,cv2.imread() 的系数是按BGR\text{BGR}顺序排列的!

其中的变量red表示的是仅有原图像红通道的imori.jpg

import cv2
img = cv2.imread("imori.jpg")
red = img[:, :, 2].copy()

blue=img[:,:,0].copy()
green=img[:,:,1].copy()

img_new=img.copy()
img_new[:, :, 0] = red
img_new[:, :, 1] = green
img_new[:, :, 2] = blue

plt.subplot(1,2,1),plt.imshow(img)
plt.subplot(122),plt.imshow(img_new)

image.png

问题二:灰度化(Grayscale)

将图像灰度化吧!

灰度是一种图像亮度的表示方法,通过下式计算: Y=0.2126 R+0.7152 G+0.0722 BY = 0.2126\ R + 0.7152\ G + 0.0722\ B

import numpy as np
def BGR2GRAY(img):
	b = img[:, :, 0].copy()
	g = img[:, :, 1].copy()
	r = img[:, :, 2].copy()

	# Gray scale
	out = 0.2126 * r + 0.7152 * g + 0.0722 * b
	out = out.astype(np.uint8)

	return out

img_BGR2GRAY=BGR2GRAY(img)

plt.subplot(1,2,1),plt.imshow(img)
plt.subplot(122),plt.imshow(img_BGR2GRAY)

image.png

问题三:二值化(Thresholding)

把图像进行二值化吧。

二值化是将图像使用黑和白两种颜色表示的方法。

我们将灰度的阈值设置为128128来进行二值化,即:

y={0(ify<128) 255(else)y= \begin{cases} 0& (\text{if}\quad y < 128) \ 255& (\text{else}) \end{cases}
def BGR2GRAY(img):
    b = img[:, :, 0].copy()
    g = img[:, :, 1].copy()
    r = img[:, :, 2].copy()

    # Gray scale
    out = 0.2126 * r + 0.7152 * g + 0.0722 * b
    out = out.astype(np.uint8)

    return out

# binalization


def binarization(img, th=128):
    img[img < th] = 0
    img[img >= th] = 255
    return img

# Read image
img = cv.imread("imori.jpg")

# Grayscale
out1 = BGR2GRAY(img)

# Binarization
out = binarization(out1)

plt.subplot(1,3,1),plt.imshow(img)
plt.subplot(132),plt.imshow(out1)
plt.subplot(133),plt.imshow(out)

image.png

问题四:大津二值化算法(Otsu's Method)

使用大津算法来二值化图像吧。

大津算法,也被称作最大类间方差法,是一种可以自动确定二值化中阈值的算法。

类内方差类间方差的比值计算得来:

  • 小于阈值tt的类记作00,大于阈值tt的类记作11
  • w0w_0w1w_1是被阈值tt分开的两个类中的像素数占总像素数的比率(满足w0+w1=1w_0+w_1=1);
  • S02{S_0}^2S12{S_1}^2是这两个类中像素值的方差;
  • M0M_0M1M_1是这两个类的像素值的平均值;

即:

  • 类内方差:Sw2=w0 S02+w1 S12{S_w}^2=w_0\ {S_0}^2+w_1\ {S_1}^2
  • 类间方差:Sb2=w0 (M0Mt)2+w1 (M1Mt)2=w0 w1 (M0M1)2{S_b}^2 = w_0 \ (M_0 - M_t)^2 + w_1\ (M_1 - M_t)^2 = w_0\ w_1\ (M_0 - M_1) ^2
  • 图像所有像素的方差:St2=Sw2+Sb2=常数{S_t}^2 = {S_w}^2 + {S_b}^2 = \text{常数}

根据以上的式子,我们用以下的式子计算分离度XX

X=Sb2Sw2=Sb2St2Sb2X = \frac{{S_b}^2}{{S_w}^2} = \frac{{S_b}^2}{{S_t}^2 - {S_b}^2}

也就是说: argmaxt X=argmaxt Sb2\arg\max\limits_{t}\ X=\arg\max\limits_{t}\ {S_b}^2 换言之,如果使Sb2=w0 w1 (M0M1)2{S_b}^2={w_0}\ {w_1}\ (M_0 - M_1)^2最大,就可以得到最好的二值化阈值tt

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

   # Gray scale
   out = 0.2126 * r + 0.7152 * g + 0.0722 * b
   out = out.astype(np.uint8)

   return out

def otsu(image, th=127):
    H,W=image.shape

    max_sigma = 0
    max_t = 0
    # determine threshold
    for _t in range(1, 255):
       v0 = out[np.where(out < _t)]
       m0 = np.mean(v0) if len(v0) > 0 else 0.
       w0 = len(v0) / (H * W)
       v1 = out[np.where(out >= _t)]
       m1 = np.mean(v1) if len(v1) > 0 else 0.
       w1 = len(v1) / (H * W)
       sigma = w0 * w1 * ((m0 - m1) ** 2)
       if sigma > max_sigma:
          max_sigma = sigma
          max_t = _t

    # Binarization
    print("threshold >>", max_t)
    th = max_t
    out[out < th] = 0
    out[out >= th] = 255

    return out

# Grayscale
out2 = BGR2GRAY(img)

# Otsu's binarization
out3 = otsu(out2)

plt.subplot(1,3,1),plt.imshow(img)
plt.subplot(132),plt.imshow(out2)
plt.subplot(133),plt.imshow(out3)

image.png