超像素(superpixel)——SLIC和深度学习法

article/2025/10/1 9:28:46

定义

可以理解成在图像上做的聚类问题。超像素的做法是将感知上相似的像素组在一起,称为一个超像素,以此来提供图像数据的紧凑表示。然后在后续的处理,处理单位就变成了超像素,而不是我们常用的像素。

一般超像素的结果可以为下游任务提供帮助,比如说语义分割、对象检测等。

SLIC

Simple Linear Iterative Clustering,简单的线性迭代聚类

论文2011-PAMI-SLIC Superpixels Compared to State-of-the-art Superpixel Methods

前提:这个算法实在CIELAB这个颜色空间上做的,即每个pixel的值用[l_i, a_i, b_i]^T来表示,其中l_i表示亮度(取值范围0-100,数值越大越亮);a_i表示红色到绿色之间的色域(负值表示绿色,正值表示红色);b_i表示黄色和蓝色之间的色域(负值表示蓝色,正值表示黄色)。

符号表示:

假设一张图片有N个像素,需要我们人为去设定的超参数有且仅有一个,就是超像素的个数k。

那么,每个超像素的平均面积是S=\frac{N}{k},每个超像素中心的平均间隔是\sqrt{S}

算法实现:

关于初始化:

  1. 初始化各个超像素中心的位置。比如一张图片的大小为\sqrt{N}\times\sqrt{N},将其均分\sqrt{k}\times \sqrt{k}个grid,然后设置每个grid的中心为一个超像素的中心。
  2. 微调这些超像素的中心,在以它们为中心的3\times3邻域里进行计算,将超像素中心更换成其中梯度值最小的。这样做的目的是为了防止超像素中心落在边缘/噪点上。
  3. 标签l(i)表示像素i属于哪一个superpixel,距离d(i)表示像素i与其所属的superpixel的中心的距离。初始化每一个像素i的l(i)=-1d(i)=\infty

进行下面迭代直到收敛,收敛的前提是误差满足一定要求:

对于每个聚类中心c_k

        对于以其为中心的2S\times 2S邻域内的每个像素i: 

                计算c_k与i之间的距离D

                如果D< d(i),那么更新d(i)=Dl(i)=k

                [这表明将i分到以c_k为中心的超像素中]

重新计算聚类中心

关于点与点之间距离D的定义:

由两个距离加权而得,分别是颜色域[l, a, b]^T之间的距离和空间域[x, y]^T之间的距离。

颜色域距离: d_c = \sqrt{(l_j-l_i)^2+(a_j-a_i)^2+(b_j-b_i)^2}

空间域距离:d_s = \sqrt{(x_i-x_j)^2+(y_i-y_j)^2}

距离D的计算:

D'=\sqrt{(\frac{d_c}{N_c})^2+(\frac{d_s}{N_s})^2},其中N_s指的是maximum spatial distance,超像素中包含的平均像素个数,即为S;N_c指的是maximum color distance,在实际应用中通常用一个人为设定的常数m来表示即可。

那么,上式可以被重写成D'=\sqrt{(\frac{d_c }{m})^2+(\frac{d_s }{S})^2}

我们实际生活中用的距离公式与上式等价D=\sqrt{​{d_c}^2 +(\frac{d_s }{S})^2m^2}

m越大,距离D受空间域距离影响越大,产生的超像素将更紧凑;m越小,距离D受颜色域影响越大,产生的超像素将更加紧密地附着在图像边界(edge)上。

 代码实现

源码地址:GitHub - aleenaniklaus/SLIC_superpixels: SLIC Superpixels* implementation was my final computer vision project. Superpixels are instrumental in segmentation. This implementation is a proof of concept as taken from SLICsuperpixels paper mentioned in README.SLIC Superpixels* implementation was my final computer vision project. Superpixels are instrumental in segmentation. This implementation is a proof of concept as taken from SLICsuperpixels paper mentioned in README. - GitHub - aleenaniklaus/SLIC_superpixels: SLIC Superpixels* implementation was my final computer vision project. Superpixels are instrumental in segmentation. This implementation is a proof of concept as taken from SLICsuperpixels paper mentioned in README.https://github.com/aleenaniklaus/SLIC_superpixels

稍微修改了一下代码细节,让大家能更加直观地看到超像素分割和原图信息的对应关系。另外,我们还能从超像素图导出一张超像素掩码(superpixel mask),也就是将超像素的边缘设置成0,超像素内部设置为1的mask。这个掩码能在一定程度上反映图片的结构信息。

import numpy
import cv2
import tqdm
import argparse# 将原作者的sys转换成params
parser = argparse.ArgumentParser(description='SLIC-python')
parser.add_argument('--img_path', default='lena.png', type=str, help="单张图片的路径")
parser.add_argument('--k', default=500, type=int, help="超像素个数")
parser.add_argument('--SLIC_ITERATIONS', default=4, type=int, help="SLIC计算过程中的迭代次数")
parser.add_argument('--m', default=40, type=int, help="权衡颜色和位置对距离影响的权重参数")
args = parser.parse_args()def generate_pixels():indnp = numpy.mgrid[0:SLIC_height, 0:SLIC_width].swapaxes(0, 2).swapaxes(0, 1)# 迭代SLIC_ITERATIONS次for i in tqdm.tqdm(range(SLIC_ITERATIONS)):SLIC_distances = 1 * numpy.ones(img.shape[:2])# 按次序取出聚类中心SLIC_centers[j]for j in range(SLIC_centers.shape[0]):# 框出该聚类中心的搜索范围x_low, x_high = int(SLIC_centers[j][3] - step), int(SLIC_centers[j][3] + step)y_low, y_high = int(SLIC_centers[j][4] - step), int(SLIC_centers[j][4] + step)# 防止搜索范围超出图像边界[保证搜索范围有效性]if x_low <= 0:x_low = 0if x_high > SLIC_width:x_high = SLIC_widthif y_low <= 0:y_low = 0if y_high > SLIC_height:y_high = SLIC_height# cropimg是该聚类中心对应的2S\times2S内的有效邻域cropimg = SLIC_labimg[y_low: y_high, x_low: x_high]# 挨个像素算出颜色差color_diff = cropimg - SLIC_labimg[int(SLIC_centers[j][4]), int(SLIC_centers[j][3])]# 算出颜色距离color_distance = numpy.sqrt(numpy.sum(numpy.square(color_diff), axis=2))yy, xx = numpy.ogrid[y_low: y_high, x_low: x_high]# 算出空间距离pixdist = ((yy - SLIC_centers[j][4]) ** 2 + (xx - SLIC_centers[j][3]) ** 2) ** 0.5# 运用论文中的(2)式计算邻域内pixel与该邻域中心的聚类中心的距离(加权求和)# SLIC_m is "m" in the paper, (m/S)*dxydist = ((color_distance / SLIC_m) ** 2 + (pixdist / step) ** 2) ** 0.5# 更新距离,更新了距离的pixel也更新聚类中心为SLIC_centers[j]distance_crop = SLIC_distances[y_low: y_high, x_low: x_high]idx = dist < distance_cropdistance_crop[idx] = dist[idx]SLIC_distances[y_low: y_high, x_low: x_high] = distance_cropSLIC_clusters[y_low: y_high, x_low: x_high][idx] = jfor k in range(len(SLIC_centers)):# 对于第k个聚类,找到聚类中心为SLIC_centers[k]的pixelidx = (SLIC_clusters == k)# 分别取出他们的颜色和位置索引colornp = SLIC_labimg[idx]distnp = indnp[idx]# 重新计算聚类中心的颜色和位置坐标(这个聚类中心和k-means中的一样,不一定是已有的点)SLIC_centers[k][0:3] = numpy.sum(colornp, axis=0)sumy, sumx = numpy.sum(distnp, axis=0)SLIC_centers[k][3:] = sumx, sumy### 注:numpy.sum(idx)是该聚类pixel数目SLIC_centers[k] /= numpy.sum(idx)# At the end of the process, some stray labels may remain meaning some pixels
# may end up having the same label as a larger pixel but not be connected to it
# In the SLIC paper, it notes that these cases are rare, however this
# implementation seems to have a lot of strays depending on the inputs givendef create_connectivity():"""按照论文的说法,总有那么些点和它对应的超像素是分离的(比较零散的碎点)运用connected components algorithm来将这些零散的点分配给最近的聚类中心"""label = 0adj_label = 0lims = int(SLIC_width * SLIC_height / SLIC_centers.shape[0])new_clusters = -1 * numpy.ones(img.shape[:2]).astype(numpy.int64)elements = []for i in range(SLIC_width):for j in range(SLIC_height):if new_clusters[j, i] == -1:elements = []elements.append((j, i))for dx, dy in [(-1, 0), (0, -1), (1, 0), (0, 1)]:x = elements[0][1] + dxy = elements[0][0] + dyif (x >= 0 and x < SLIC_width andy >= 0 and y < SLIC_height andnew_clusters[y, x] >= 0):adj_label = new_clusters[y, x]# end# end# endcount = 1counter = 0while counter < count:for dx, dy in [(-1, 0), (0, -1), (1, 0), (0, 1)]:x = elements[counter][1] + dxy = elements[counter][0] + dyif (x >= 0 and x < SLIC_width and y >= 0 and y < SLIC_height):if new_clusters[y, x] == -1 and SLIC_clusters[j, i] == SLIC_clusters[y, x]:elements.append((y, x))new_clusters[y, x] = labelcount += 1# end# end# endcounter += 1# endif (count <= lims >> 2):for counter in range(count):new_clusters[elements[counter]] = adj_label# endlabel -= 1# endlabel += 1# end# endSLIC_new_clusters = new_clusters# enddef display_contours(color):is_taken = numpy.zeros(img.shape[:2], numpy.bool)  # 标志哪些点是聚类与聚类之间的edgecontours = []for i in range(SLIC_width):for j in range(SLIC_height):nr_p = 0for dx, dy in [(-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 1)]:x = i + dxy = j + dyif x >= 0 and x < SLIC_width and y >= 0 and y < SLIC_height:if is_taken[y, x] == False and SLIC_clusters[j, i] != SLIC_clusters[y, x]:nr_p += 1# end# end# endif nr_p >= 2:is_taken[j, i] = Truecontours.append([j, i])# 将这些edge-pixel全用黑色来表示for i in range(len(contours)):img[contours[i][0], contours[i][1]] = colormask[contours[i][0], contours[i][1]] = color# end# enddef find_local_minimum(center):"""微调在3\times3领域内找梯度最小的点作为初始聚类中心"""min_grad = 1loc_min = centerfor i in range(center[0] - 1, center[0] + 2):for j in range(center[1] - 1, center[1] + 2):c1 = SLIC_labimg[j + 1, i]c2 = SLIC_labimg[j, i + 1]c3 = SLIC_labimg[j, i]if ((c1[0] - c3[0]) ** 2) ** 0.5 + ((c2[0] - c3[0]) ** 2) ** 0.5 < min_grad:min_grad = abs(c1[0] - c3[0]) + abs(c2[0] - c3[0])loc_min = [i, j]return loc_mindef calculate_centers():"""按照grid_cell初始化聚类中心"""centers = []for i in range(step, SLIC_width - int(step / 2), step):for j in range(step, SLIC_height - int(step / 2), step):nc = find_local_minimum(center=(i, j))  # 微调color = SLIC_labimg[nc[1], nc[0]]center = [color[0], color[1], color[2], nc[0], nc[1]]  # LAB+XYcenters.append(center)return centers  # 储存聚类中心的信息# 样例命令是slic.py Lenna.png 1000 40
# sys.argv[1]是放图片路径
# sys.argv[2]这个参数指示划分的superpixel的个数
# sys.argv[3]这个参数是论文中的m与论文中的m对应,是计算点与点间的距离时用于衡量颜色距离和空间距离所占权重的重要参数# global variables
img = cv2.imread(args.img_path)
mask = 255 * numpy.ones(img.shape).astype('uint8')
step = int((img.shape[0] * img.shape[1] / args.k) ** 0.5)  # 每个superpixel中心之间的平均距离
SLIC_m = args.m
SLIC_ITERATIONS = args.SLIC_ITERATIONS  # 迭代次数
SLIC_height, SLIC_width = img.shape[:2]
SLIC_labimg = cv2.cvtColor(img, cv2.COLOR_BGR2LAB).astype(numpy.float64)  # BGR转LAB# 初始化距离和每个点所属聚类中心
SLIC_distances = 1 * numpy.ones(img.shape[:2])
SLIC_clusters = -1 * SLIC_distances  ### 我们应该是依靠这个搞出mask #### 聚类中心初始化
SLIC_center_counts = numpy.zeros(len(calculate_centers()))
SLIC_centers = numpy.array(calculate_centers())# main
generate_pixels()  # 迭代SLIC_ITERATIONS次,聚好各组点,算出他们的聚类中心位置和类颜色
create_connectivity()  # 后处理,对一些比较零散的点重新分配给邻近的聚类
calculate_centers()
display_contours([0.0, 0.0, 0.0])
img2 = numpy.hstack((img, mask))
cv2.imwrite(args.img_path.replace(".png","_{}_SLIC.png".format(args.k)), img2)

结果展示

我们用非常经典的lena图片来做展示:

设置超像素为500:

 

 设置超像素为100:

 

深度学习学超像素的方法我后续再补充上来


http://chatgpt.dhexx.cn/article/xOxmoCWY.shtml

相关文章

学习笔记4:ubuntu常用命令

cd //打开路径cd.. //回到上一级目录cd &#xff5e; //回到主目录ls //列表touch demo.c //创建一个“demo.c”文件mkdir project //创建一个“project”文件夹vi . //进入当前目录删除文件 pwd //显示当前路径ifconfig //查看本机IP地址mv 文件名 /PATH //移动文件到某一目…

Ubuntu常用命令(持续更新)

Ubuntu常用命令&#xff08;持续更新&#xff09; 检查更新并升级切换至root账号修改root账号密码下载文件命令wget&#xff0c;举例&#xff1a;安装.deb文件&#xff08;在文件所在目录打开终端&#xff09;查看本机ip地址&#xff08;注意和windows系统的区别ipconfig&#…

Ubuntu常用命令 (超详细版)

1.切换到 root 用户 &#xff0c;输入 “sudo -i ”, 退出 “exit” pwd 显示当前目录&#xff0c; pwd print working directory ls 列出目录下当前文件 cp 复制文件/目录 cp (源文件或目录) (目标文件或目录) cp -r 复制文件夹 包括子目录和文件 r…

Ubuntu 常用命令大全——长期不定时更新

1. 系统相关 uname -a 显示当前系统相关信息sudo 临时获取超级用户权限su root 切换 root 用户sudo shutdown 关机sudo reboot 重启sudo nautilus 进入有 root 权限的文件管理器ps -A 查看当前有哪些进程kill 5 位进程号 结束进程 sudo fdisk -l 查看磁盘信息sudo mount /dev/…

爆料一家互联网中厂的年终奖,真香。

前不久刷到宇宙条32岁员工14万的月薪截图&#xff0c;突然想起来已经快四月底了&#xff0c;正是各大互联网公司年终奖开奖的时候&#xff0c;但相比以往&#xff0c;今年互联网圈好像安静了很多。各种“凡尔赛”的年终奖金额刷屏的情况不复存在。 各家大厂都暗戳戳地分完了奖…

OPPO K9试水“捆绑销售”,消费者“赚了”还是“亏了”?

【原创】 号称“充电5分钟&#xff0c;开黑两小时”的OPPO新品K9于5月6日正式发布&#xff0c;这句“似曾相识”的OPPO“过气”广告语&#xff0c;又重新出现在了江湖&#xff0c;说是词穷也好&#xff0c;为了突出手机卖点也罢&#xff0c;反正新品是上了。 出了新品&#x…

2021年多媒体技术圈年终事件大回顾

今年的年终总结&#xff0c;虽迟但到&#xff0c;回看往年的总结&#xff1a; 2018年多媒体技术圈年终事件大回顾 2019年多媒体技术圈年终事件大回顾 2020&#xff08;我鸽了&#xff09; 以下内容均为个人见解&#xff0c;大佬轻拍~ 一月 一月属于WebRTC&#xff0c;W3C和…

OPPO AI Lab 核心岗位开放招聘:至美之路,等你加入!

国产手机越来越受青睐&#xff0c;在中国&#xff0c;更多年轻人选择 OPPO 拍照手机。 十年来&#xff0c;OPPO 一直专注手机拍照的技术创新&#xff0c;开创了“手机自拍美颜”时代。 如今&#xff0c;全球超过 2 亿年轻人正在使用 OPPO 拍照手机。 关于OPPO 使命&#xff1a…

8月顺利拿到OPPO公司Android架构师offer,一面+部长面

上周喜提oppo面试offer&#xff0c;本人在深圳&#xff0c;有4年多的Android项目经验&#xff0c;普通本科学历。面试是相互选择的过程&#xff0c;而OPPO给我的印象确实如其核心价值观所说&#xff1a;本分。 一面、部长面和HR面都蛮顺利&#xff08;一千个人可能要了一百左右…

十年老码农吐血经验:跳槽千万不能选高年终低base的公司,超过15薪就要慎重!...

低base高年终VS高base低年终&#xff0c;哪个更好&#xff1f; 一个工作十年的老码农总结了自己的经验&#xff1a;跳槽千万不能选年终月数多的公司&#xff0c;超过15薪就要好好掂量掂量。能选外企就选外企&#xff0c;奖金基本就是一个月&#xff0c;不会坑你。 一网友惊呼&a…

干翻华为才有年终奖,“性感”小米发布MIX3,滑盖全面屏只要3299元

Are you ok&#xff1f; 小米又发新机了&#xff01; 这次发布会开到故宫了。虽然不知道故宫的花花草草和皇家御喵是不是米粉&#xff0c;但是正戏开始前还是先来一遍Are you ok清新洗脑一下吧&#xff01; 话不多说&#xff0c;先前在8月份和OPPO撞脸的小米MIX 3终于在今天…

一荣俱荣,豪取多项冠军后荣耀着手年终奖改革

企业的效益好了&#xff0c;员工的福利也会相应变好&#xff0c;最近荣耀手机就证明了这个理。 这两天《荣耀品牌手机单台提成奖金方案》曝了出来。据任正非亲自签发的这份内部文件显示&#xff0c;为了激发员工斗志&#xff0c;提升荣耀品牌手机的销售规模&#xff0c;特批准荣…

上汽董事长称不接受与华为合作自动驾驶;曝OPPO给离职员工补发年终奖,此前遭克扣;Google Play 将启用AAB格式应用...

EA周报 2021年7月2日 每个星期7分钟&#xff0c;元宝带你喝一杯IT人的浓缩咖啡&#xff0c;了解天下事、掌握IT核心技术。 周报看点 1、OPPO给离职员工补发年终奖&#xff0c;此前遭克扣&#xff0c;未来将制定方案 2、诺基亚回应“使用鸿蒙传闻”&#xff1a;提供安卓体验的承…

罗永浩宣布春节后回归科技界;2021年年终奖人均水平为2.3万元;消息人士:字节跳动日均进账10.07亿 | EA周报...

EA周报 2022年1月21日 每个星期7分钟&#xff0c;元宝带你喝一杯IT人的浓缩咖啡&#xff0c;了解天下事、掌握IT核心技术。 周报看点 1、消息人士&#xff1a;字节跳动日均进账10.07亿 2、罗永浩宣布春节后回归科技界 3、英特尔跌落神坛&#xff01;CEO回应&#xff1a;是我们骄…

曝 OPPO 给离职员工补发年终奖,此前遭克扣

整理 | 王晓曼 出品 | 程序人生&#xff08;ID&#xff1a;coder _life&#xff09; 7月1日&#xff0c;话题#OPPO补发年终奖#登上热搜前三。有网友爆料称OPPO和vivo将为离职员工补发年终奖。 认证ID为岳灵珊的网友发文解释OPPO补发年终奖的原因&#xff1a;此前公司中层领导克…

百度员工发文抱怨:1月离职,年终奖为0,网友:怪你心太大

程序员求职面试&#xff08;ID&#xff1a;CoderJob&#xff09;整理内容参考自&#xff1a;脉脉 如果员工年底离职&#xff0c;公司是否还要支付该员工上一年度的年终奖金呢&#xff1f;想必很多人也想知道这个问题的答案。 日前&#xff0c;有位百度员工在脉脉上发帖吐槽&…

百度员工抱怨:1月离职,没有年终奖。。。

点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐] 如果员工年底离职&#xff0c;公司是否还要支付该员工上一年度的年终奖金呢&#xff1f;想必很多人也想知道这个问题的答案。 日前&#xff0c;有位百度员工在脉脉上发帖吐槽&#xff1a;1月离职&#xff0c;年终奖为0&am…

OPPO 员工称被强制离职起诉公司,当事人败诉:7 万元年终奖没了,获 2N 赔偿

本文转载自 IT之家 近日&#xff0c;此前 OPPO 员工质疑公司违法解除劳动合同一事迎来最新进展&#xff0c;根据该员工公布的法院判决&#xff0c;其要求的支付 7 万元年终奖未获法院支持&#xff0c;但 OPPO 需要支付 2N 的赔偿。 今年 1 月&#xff0c;在脉脉上认证为 OPPO …

曝OPPO给离职员工补发年终奖,此前遭克扣;7 亿条领英用户数据被出售

【此文章转自乐字节】 一分钟速览新闻点! 字节跳动总裁办负责人华巍,重管人力资源团队 华为回应“诺基亚新手机搭载 HarmonyOS ”消息不实 曝 OPPO 给离职员工补发年终奖,此前遭克扣 传蔚来挖角华为智能驾驶总裁苏箐,当事人回应:勿念 苹果公司和亚马逊在西班牙遭到反…

程序人生 - OPPO 员工称被强制离职起诉公司,当事人败诉:7 万元年终奖没了,获 2N 赔偿

近日&#xff0c;此前 OPPO 员工质疑公司违法解除劳动合同一事迎来最新进展&#xff0c;根据该员工公布的法院判决&#xff0c;其要求的支付 7 万元年终奖未获法院支持&#xff0c;但 OPPO 需要支付 2N 的赔偿。 今年 1 月&#xff0c;在脉脉上认证为 OPPO 员工的账号爆料称&am…