这篇博客将介绍如何使用SLIC分割算法来计算输入图像的超像素,并对每一块超像素区域计算炫彩度量值。然后将每个区域的炫彩度量值加入到掩模图像,以展示图像的最丰富多彩和最不丰富多彩的区域;
并将掩模图像叠加透明层到原始图像上。
1. 效果图
原始图 VS 超像素蒙版图 VS 叠加效果图 如下:小区里的粉色木兰花,挺娇俏的一小朵,并没有完整绽开,却不影响它好看。
从下图可以很容易看出颜色暗的地方是最不炫彩的区域,图中的浅色区域是最炫彩的区域。默认超像素分割100块,距离花朵是最炫彩的,花朵下部的天空背景是最不炫彩的区域。
超像素分割10块,效果图如下:
效果图2,同样是小区里的花,这一次是绽放的青木兰,拍自去年疫情期间。
效果图3:超像素分割设置为5块。 可以清楚的看到,中间的蒙版图分了5块超像素区域,中间颜色最深的白色花朵是最不鲜艳的区域。
2. 步骤
首先可以将滑动窗口应用于循环图像并计算每个ROI的炫彩度量分数。甚至可以应用图像金字塔,如果需要在多个尺度上计算特定区域的彩色度,也可以应用图像金字塔。
- 将Superpixel分段应用于输入图像。
- 单独循环每个超像素,并计算它们各自的彩色分数。
- 维护包含每个超像素的彩色分数的掩模。
- 基于此mask,可以可视化图像的最彩色区域。更丰富多彩的图像的区域将具有更大的彩色度量分数,而那些较不炫彩的区域将拥有更小的值。
- 应用SLIC算法从输入图像中提取超像素;
- 遍历每个超像素,并分别计算炫彩度量值;
- 叠加超像素透明层到原始图像上并展示;
3. 源代码
# USAGE
# python colorful_regions.py --image images/flower.jpg
# 超像素划分只划分为4块
# python colorful_regions.py --image images/flower.jpg -s 5
# 导入必要的包
from skimage.exposure import rescale_intensity
from skimage.segmentation import slic # 切片函数计算超像素
from skimage.util import img_as_float
from skimage import io
import numpy as np
import argparse
import cv2
import imutils
# 超像素区域计算炫彩度
def segment_colorfulness(image, mask):
# 将图像分离为相对的RGB分量
# 然后构建每一个分量的蒙版,计算蒙版区域的统计值
(B, G, R) = cv2.split(image.astype("float"))
R = np.ma.masked_array(R, mask=mask)
G = np.ma.masked_array(G, mask=mask)
B = np.ma.masked_array(B, mask=mask)
# 计算 rg = R - G
rg = np.absolute(R - G)
# 计算 yb = 0.5 * (R + G) - B
yb = np.absolute(0.5 * (R + G) - B)
# 构建 rg、yb的均值和标准偏差
stdRoot = np.sqrt((rg.std() ** 2) + (yb.std() ** 2))
meanRoot = np.sqrt((rg.mean() ** 2) + (yb.mean() ** 2))
# 计算“炫彩度”并返回
return stdRoot + (0.3 * meanRoot)
# 构建命令行参数及解析
# --image 输入图像路径
# --segments 分离超像素个数,默认100,该值越小,较大的超像素越大,允许算法运行得更快。段的数量越大,分割更细粒度,但SLIC需要更长时间运行(由于需要计算更多的集群)。
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
help="path to input image")
ap.add_argument("-s", "--segments", type=int, default=100,
help="# of superpixels")
args = vars(ap.parse_args())
# 使用opencv加载图像,然后展示,开辟空间以展示超像素炫彩度可视化
orig = cv2.imread(args["image"])
orig = imutils.resize(orig, width=300)
vis = np.zeros(orig.shape[:2], dtype="float")
# 加载图像,使用scikit-image的SLIC超像素分割方法
image = io.imread(args["image"])
image = imutils.resize(image, width=300)
# -- 图像
# -- 分段数
# -- True 使用原始的不修改任何原始参数的SLIC超像素分割算法
segments = slic(img_as_float(image), n_segments=args["segments"],
slic_zero=True)
# 循环遍历每一个独立的超像素
for v in np.unique(segments):
# 对分段构建蒙版,并计算统计
mask1 = np.ones(image.shape[:2])
mask = np.ones(image.shape[:2])
mask[segments == v] = 0
# cv2.imshow("image VS mask VS mask1", np.hstack([mask1, mask]))
# cv2.waitKey(0)
# 计算超像素炫彩度,更新可视化数组
C = segment_colorfulness(orig, mask)
vis[segments == v] = C
# 将像素浮点数值重新缩放到典型的8位无符号整数[0-255]数组,以使用opencv展示图像
vis = rescale_intensity(vis, out_range=(0, 255)).astype("uint8")
# 叠加超像素炫彩度到原始图像中,透明度为0.6
alpha = 0.6
overlay = np.dstack([vis] * 3)
output = orig.copy()
cv2.addWeighted(overlay, alpha, output, 1 - alpha, 0, output)
# 展示输出图像
cv2.imshow("Input", orig)
cv2.imshow("Visualization", vis)
cv2.imshow("Output", output)
cv2.waitKey(0)