通过使用黑白二值图像将对应于黑色部分的原始图像的像素改变为黑色的操作被称为掩膜。
- 举个例子,比如说要提取蓝色部分,就先创建这样的二进制图像,使得
HSV
色彩空间中180≤H≤260
的位置的像素值设为1,并将其0和1反转之后与原始图像相乘。 - 这使得可以在某种程度上将图像主体(从背景上)分离出来。
import cv2
import numpy as np
import matplotlib.pyplot as plt#照例导入三个基本库
# BGR -> HSV
def BGR2HSV(_img):#图像转BGR模式转HSV模式
img = _img.copy() / 255.
hsv = np.zeros_like(img, dtype=np.float32)
# get max and min
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()
return hsv
# make mask
def get_mask(hsv):#得到掩膜
mask = np.zeros_like(hsv[..., 0])
#mask[np.where((hsv > 180) & (hsv[0] < 260))] = 255
mask[np.logical_and((hsv[..., 0] > 180), (hsv[..., 0] < 260))] = 1#提取蓝色区域
return mask#返回掩膜图像
# masking
def masking(img, mask):
mask = 1 - mask#反转
out = img.copy()
# mask [h, w] -> [h, w, channel]
mask = np.tile(mask, [3, 1, 1]).transpose([1, 2, 0])#将单通道掩膜图像扩展到三通道掩膜图像
out *= mask#原图与掩膜图像相乘,提取的蓝色区域变黑被隐藏
return out
# Read image
img = cv2.imread("123.jpg").astype(np.float32)#读取原始图片
# RGB > HSV BGR转HSV
hsv = BGR2HSV(img)
# color tracking颜色追踪
mask = get_mask(hsv)#得到掩膜图像
# masking
out = masking(img, mask)#将掩模图像和原图一并传入
out = out.astype(np.uint8)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
掩膜(色彩追踪+形态学处理)
- 上述代码处理的结果不够精细,背景也有部分的残留,可以在掩膜图像上运用开运算和闭运算,使得掩膜图片更加准确
import cv2
import numpy as np
import matplotlib.pyplot as plt#导入三个必要的库
# BGR -> HSV
def BGR2HSV(_img):#图像BGR转HSV模式
img = _img.copy() / 255.
hsv = np.zeros_like(img, dtype=np.float32)
# get max and min
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()
return hsv
# make mask
def get_mask(hsv):#得到掩膜图像
mask = np.zeros_like(hsv[..., 0])
#mask[np.where((hsv > 180) & (hsv[0] < 260))] = 255
mask[np.logical_and((hsv[..., 0] > 180), (hsv[..., 0] < 260))] = 1
return mask
# masking
def masking(img, mask):#将掩膜图像叠加到原图中
mask = 1 - mask
out = img.copy()
# mask [h, w] -> [h, w, channel]
mask = np.tile(mask, [3, 1, 1]).transpose([1, 2, 0])
out *= mask
return out
# Erosion图片腐蚀
def Erode(img, Erode_time=1):
H, W = img.shape
out = img.copy()
# kernel腐蚀核
MF = np.array(((0, 1, 0),
(1, 0, 1),
(0, 1, 0)), dtype=np.int)
# each erode
for i in range(Erode_time):
tmp = np.pad(out, (1, 1), 'edge')#扩充边缘
# erode
for y in range(1, H + 1):
for x in range(1, W + 1):
if np.sum(MF * tmp[y - 1 : y + 2 , x - 1 : x + 2]) < 1 * 4:#只有四邻域全为白,中央点才不会被改变,否则将中央点置0即黑
out[y - 1, x - 1] = 0#解释一下为啥这里是[y-1,x-1],还是因为tmp比out大一圈,tmp中央为[y,x],则out中央为[y-1,x-1]
return out
# Dilation
def Dilate(img, Dil_time=1):
H, W = img.shape
# kernel
MF = np.array(((0, 1, 0),
(1, 0, 1),
(0, 1, 0)), dtype=np.int)
# each dilate time
out = img.copy()
for i in range(Dil_time):
tmp = np.pad(out, (1, 1), 'edge')
for y in range(1, H + 1):
for x in range(1, W + 1):
if np.sum(MF * tmp[y - 1 : y + 2, x - 1 : x + 2]) >= 1:
out[y - 1, x - 1] = 1
return out
# Opening morphology一般形态学运算针对二值图像,刚好可以对应掩膜图像
def Morphology_Opening(img, time=1):#开运算,先腐蚀再膨胀
out = Erode(img, Erode_time=time)
out = Dilate(out, Dil_time=time)
return out
# Closing morphology
def Morphology_Closing(img, time=1):#闭运算,先膨胀再腐蚀
out = Dilate(img, Dil_time=time)
out = Erode(out, Erode_time=time)
return out
# Read image
img = cv2.imread("imori.jpg").astype(np.float32)
# RGB > HSV
hsv = BGR2HSV(img / 255.)
# color tracking
mask = get_mask(hsv)
# closing对掩膜图像先执行5次闭运算
mask = Morphology_Closing(mask, time=5)
# opening再对掩膜图像执行5次开运算
mask = Morphology_Opening(mask, time=5)
# masking
out = masking(img, mask)
out = out.astype(np.uint8)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
图像缩小与放大,其实这个我们在前面已经写过了,普适性会更强,下面这个代码只适用于方形图片
import cv2
import numpy as np
import matplotlib.pyplot as plt#导入三个常用的库
# Grayscale转灰度
def BGR2GRAY(img):
# Grayscale
gray = 0.2126 * img[..., 2] + 0.7152 * img[..., 1] + 0.0722 * img[..., 0]
return gray
# Bi-Linear interpolation双线性插值
def bl_interpolate(img, ax=1., ay=1.):
if len(img.shape) > 2:
H, W, C = img.shape
else:
H, W = img.shape
C = 1
aH = int(ay * H)#获取缩放之后的高度
aW = int(ax * W)#获取缩放之后的宽度
# get position of resized image获取调整大小后图像的位置
y = np.arange(aH).repeat(aW).reshape(aW, -1)#沿着y方向
x = np.tile(np.arange(aW), (aH, 1))#沿着x方向展开
# get position of original position获取原始坐标位置
y = (y / ay)
x = (x / ax)
ix = np.floor(x).astype(np.int)
iy = np.floor(y).astype(np.int)
ix = np.minimum(ix, W-2)#起始坐标
iy = np.minimum(iy, H-2)#起始坐标
# get distance
dx = x - ix
dy = y - iy
if C > 1:
dx = np.repeat(np.expand_dims(dx, axis=-1), C, axis=-1)
dy = np.repeat(np.expand_dims(dy, axis=-1), C, axis=-1)
# interpolation
out = (1-dx) * (1-dy) * img[iy, ix] + dx * (1 - dy) * img[iy, ix+1] + (1 - dx) * dy * img[iy+1, ix] + dx * dy * img[iy+1, ix+1]
out = np.clip(out, 0, 255)
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread("img11.png").astype(np.float)
gray = BGR2GRAY(img)
# Bilinear interpolation
out = bl_interpolate(gray.astype(np.float32), ax=0.1, ay=0.1)
# Bilinear interpolation
out = bl_interpolate(out, ax=10., ay=10.)
out = out.astype(np.uint8)
# Save result
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)
网友评论