Question4 大律法二值化
实施大津的二值化。
大津的二值化被称为判别分析法,是自动决定二值化中的分离的阈值的方法。
这是根据类内分散与类间分散的比率计算的。
灰度亮度值(像素值)的直方图如下。
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('assets/imori.jpg')
gray = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0]
plt.hist(gray.ravel(), bins=255, rwidth=0.8, range=(0, 255))
plt.xlabel('value')
plt.ylabel('appearance')
plt.show()
![](https://img-blog.csdnimg.cn/20210406093955134.jpg)
二值化是将某个值设为边界,设为0或1的方法,但是大津的二值化是自动决定阈值的方法。这里,将由阈值分离的像素分别设为类0、1。
![](https://img-blog.csdnimg.cn/20210406094034681.png)
…属于类0,1的像素数
…属于类0,1的像素值的方差
…属于类0,1的像素值的平均值
…图像整体像素值的平均值
…属于类0,1的像素值的合计值
这样的话
显示类0,1分散权重和的类内分散为下式。
![](https://img-blog.csdnimg.cn/20210406100729555.png)
显示类0,1的平均值与图像整体的平均值相距多远的类间分散成为下式。
![](https://img-blog.csdnimg.cn/20210406100922330.png)
分离的程度定义为:类内分散小,并且类间分散大。(和班级分类相同的想法)
![](https://img-blog.csdnimg.cn/20210406101028205.png)
整个图像的像素的分散是类内分散和类间分散的和。
![](https://img-blog.csdnimg.cn/20210406101226142.png)
因此,分离度X由以下公式定义。
![](https://img-blog.csdnimg.cn/20210406101028211.png)
这个分离度最大就可以了,也就是说类间分散最大就可以了。
![](https://img-blog.csdnimg.cn/20210406101324153.png)
即,以阈值为[0, 255]的各值计算类间分散,最大的阈值是最佳的阈值。
类内分散Sw^2=w0*S0^2+w1*S1 ^2
类间分散Sb^2=w0*(M0-Mt)^2+w1*(M1-Mt)^2=w0*w1*(M0-M1)^2
图像整体像素的分散St^2=Sw^2+Sb^2=(const)
由此,分离度由以下公式定义。
分离度X=Sb^2/Sw^2=Sb^2/(St^2-Sb^2)
argmax_{t} X = argmax_{t} Sb^2
import cv2
import numpy as np
from matplotlib import pyplot as plt
image_path = './images/imori.jpg'
image = cv2.imread(image_path)
b = image[..., 0].copy()
g = image[..., 1].copy()
r = image[..., 2].copy()
y = 0.2126*r + 0.7152*g + 0.0722*b
y = y.astype(np.uint8)
max_sigma = 0
max_t = 0
H, W = y.shape
for i in range(1, 256):
v0 = y[np.where(y < i)]
m0 = np.mean(v0) if len(v0) > 0 else 0.
w0 = len(v0) / (H * W)
v1 = y[np.where(y >= i)]
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
mat_t = i
th = mat_t
y[y < th] = 0
y[y >= th] = 255
cv2.imwrite('./out/4.jpg', y)
cv2.imshow('Image', y)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
import numpy as np
image_path = './images/imori.jpg'
image = cv2.imread(image_path)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ima1 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 25, 0)
ima2 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
cv2.imshow('Image1', ima1)
cv2.imshow('Image2', ima2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Question5 HSV变换
安装HSV变换,反转色相H。
HSV转换是用Hue(色相)、Saturation(彩度)、Value(亮度) 来表现颜色的手法。
- Hue…色调以0~360度表现,表示红色、蓝色等颜色的种类。(0<=H<360)色调对应于下一种颜色。
赤 黄色 緑 水色 青 紫 赤
0 60 120 180 240 300 360
-
Saturation…色彩鲜艳。Saturation低的话灰色就会显著,变成暗沉的颜色。( 0<= S < 1)
-
Value…颜色的亮度。Value越高越接近白色,Value越低越接近黑色。( 0 <= V < 1)
RGB->HSV变换由以下公式定义。
R、G、B在[0,1]的范围内。
Max = max(R,G,B)
Min = min(R,G,B)
H = { 0 (if Min=Max)
60 x (G-R) / (Max-Min) + 60 (if Min=B)
60 x (B-G) / (Max-Min) + 180 (if Min=R)
60 x (R-B) / (Max-Min) + 300 (if Min=G)
V = Max
S = Max - Min
HSV->RGB转换由以下公式定义。
C = S
H' = H / 60
X = C (1 - |H' mod 2 - 1|)
(R,G,B) = (V - C) (1,1,1) + { (0, 0, 0) (if H is undefined)
(C, X, 0) (if 0 <= H' < 1)
(X, C, 0) (if 1 <= H' < 2)
(0, C, X) (if 2 <= H' < 3)
(0, X, C) (if 3 <= H' < 4)
(X, 0, C) (if 4 <= H' < 5)
(C, 0, X) (if 5 <= H' < 6)
在此,反转色相H(加180),在RGB上重新显示图像。
import cv2
import numpy as np
image_path = './images/imori.jpg'
image = cv2.imread(image_path)
img = image.copy() / 255
hsv = np.zeros_like(img, dtype=np.float32)
max_v = np.max(img, axis=2).copy()
min_v = np.min(img, axis=2).copy()
min_arg = np.argmin(img, axis=2)
# H
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
# S
hsv[..., 1] = max_v.copy() - min_v.copy()
# V
hsv[..., 2] = max_v.copy()
hsv[..., 0] = (hsv[..., 0] + 180) % 360
out = np.zeros_like(img)
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.imwrite('./out/hsv.jpg', out)
cv2.imshow('HSV', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
# cv2.imshow('hsv', hsv)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
image_path = './images/imori.jpg'
image = cv2.imread(image_path)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
cv2.imshow('HSV', hsv)
cv2.waitKey(0)
cv2.destroyAllWindows()
Question6 减色处理
在此,将图像的值从256^3 减色为 4^3,即R、G、B in{32、96、160、224}的各4值。
这是量化操作。
关于各值,如下定义。
val = { 32 ( 0 <= val < 64)
96 ( 64 <= val < 128)
160 (128 <= val < 192)
224 (192 <= val < 256)
import cv2
import numpy as np
image_path = './images/imori.jpg'
image = cv2.imread(image_path)
out = image.copy()
out = out // 64 * 64 + 32
cv2.imshow('out', out)
cv2.waitKey(0)
cv2.destroyAllWindows()