一. 业务背景
在我们的某项业务中,需要通过自研的智能硬件“自动化”地拍摄一组组手机的照片,这些照片有时候因为光照的因素需要考虑将背景的颜色整体替换掉,然后再呈现给 C 端用户。这时就有背景替换的需求了。
二. 技术实现
使用 OpenCV ,通过传统的图像处理来实现这个需求。
方案一:
首先想到的是使用 K-means 分离出背景色。
大致的步骤如下:
将二维图像数据线性化
使用 K-means 聚类算法分离出图像的背景色
将背景与手机二值化
使用形态学的腐蚀,高斯模糊算法将图像与背景交汇处高斯模糊化
替换背景色以及对交汇处进行融合处理
k-平均算法(英文:k-means clustering)源于信号处理中的一种向量量化方法,现在则更多地作为一种聚类分析方法流行于数据挖掘领域。k-平均聚类的目的是:把 n 个点(可以是样本的一次观察或一个实例)划分到k个聚类中,使得每个点都属于离他最近的均值(此即聚类中心)对应的聚类,以之作为聚类的标准。这个问题将归结为一个把数据空间划分为Voronoi cells的问题。
K-means 算法思想为:给定n个数据点{x1,x2,…,xn},找到K个聚类中心{a1,a2,…,aK},使得每个数据点与它最近的聚类中心的距离平方和最小,并将这个距离平方和称为目标函数,记为Wn,其数学表达式为:

K-means 算法基本流程:
初始的 K 个聚类中心。
按照距离聚类中心的远近对所有样本进行分类。
重新计算聚类中心,判断是否退出条件:两次聚类中心的距离足够小视为满足退出条件;不退出则重新回到步骤2。
int main() {
Mat src = imread("test.jpg");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
imshow("origin", src);
// 将二维图像数据线性化
Mat data;
for (int i = 0; i < src.rows; i++) {//像素点线性排列
for (int j = 0; j < src.cols; j++)
{
Vec3b point = src.at<Vec3b>(i, j);
Mat tmp = (Mat_<float>(1, 3) << point[0], point[1], point[2]);
&