前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【算法解析】抖音分割特效算法复现尝试

【算法解析】抖音分割特效算法复现尝试

作者头像
周旋
发布2022-09-19 11:38:58
4900
发布2022-09-19 11:38:58
举报
文章被收录于专栏:行走的机械人行走的机械人

点击上方"蓝色小字"关注我呀

1,前言

大家好呀,好久没写技术文了,一个是最近在秋招就光是刷题了,另一个就是水平有限,还做不到持续输出,菜... ...

另外最近接了几篇广告,2018年之后的公众号都没有留言评论功能了,导致沟通非常受限制,想要开通就需要花4K块钱给中介公司。所以希望大家多多支持一下,赶紧攒够钱然后去开评论。

本文解析一个抖音算法,我试着想复现一下,不过目前还比较失败。先将现在的效果写一篇文章,希望大家可以有所收获。

2,抖音算法效果

原特效算法视频如上,真正咋实现的我也不知道,只能根据它的操作来猜了。

首先视频中,需要选取颜色,该颜色作为分割的依据以及最后分割效果的颜色。

然后需要用画刷人工粗略的划分区域。

所以算法的输入就是人工预分割好的这个mask。包括颜色以及像素位置两部分。

不过我目前写的kmeans算法只用到了选取的颜色。

当前算法实现思路:

通过QT进行了人工分割之后,将各个区域的颜色传递给Kmeans算法,算法根据输入的K个颜色进行迭代,每次迭代遍历所有像素并计算该像素最为接近的颜色区域,然后将该像素分配给该颜色区域。

所以整个算法并没有应用到人工预分割时给每个像素分配的区域,只用到了选取的几个颜色。

3,QT界面以及算法效果演示

为了复现抖音视频中的人工预分割的操作,我写了一个简单的QT界面,操作过程以及算法效果如下视频:

QT界面包括一个菜单栏,主要就是读图与保存图片。

一个工具栏,包括取色器,画笔,生成预览,撤销操作。

一个状态栏,状态栏的颜色可以根据取色器的颜色而变化,并进行一些提示信息。

4,Kmeans算法介绍

本次实验算法就是根据以前写的Kmeans进行了一点小小的改写。

Kmeans之前【手撕算法】系列写过一篇:

【手撕算法】K-means算法实现主题色提取

kmeans算法接口:

代码语言:javascript
复制
KMean(Mat srcImage_, Mat& dstImage_, vector<Vec3b> colors_,int clusters_num, int iterations)

分别是输入图像输出图像人工选取的颜色们,以及颜色数量(Kmeans的K值),迭代次数

算法第一步:

读取人工颜色作为分割聚类的种子点。

代码语言:javascript
复制
    //簇的一个容器,来跟踪图像的变化
    vector<Cluster> clusters;

    //【1】处理color种子点
    int rand_x, rand_y;
    Vec3b pixel;
    for (int i = 0; i < clusters_num; i++) {
        rand_x = rand() % srcImage_.rows;
        rand_y = rand() % srcImage_.cols;
        pixel = colors_.at(i);
        clusters.push_back(Cluster(pixel, rand_x, rand_y));
    }

算法第二,三步:

开启迭代,每次迭代遍历所有像素,并根据颜色距离进行分类。

代码语言:javascript
复制
    //【2】迭代
    //K - Means的开始:我们将算法的所有逻辑放入一个for循环中
    //这是因为,我们可以进行固定次数的迭代:如果过程中算法收敛,它的质心不再变化,我们则打破for
    for (int i = 0; i < iterations; i++) {

        //在每次迭代中,我们重新初始化一些变量,例如距离和索引,这将帮助我们在每次迭代中找到集群最小阈值和索引
        float distance;
        int index;

        //【3】遍历图像每个像素,以选择它们属于哪个集群 :
        for (int x = 0; x < srcImage_.rows; x++) {
            for (int y = 0; y < srcImage_.cols; y++) {
            //现在,对于一个普通的(x, y)像素,分析这个像素属于哪个集群
            //我们遍历k个簇,寻找与该像素距离最近的簇
            float min_dist = FLT_MAX;
            for (int k = 0; k < clusters.size(); k++) {
                //getting the distance
                distance = norm(srcImage_.at<Vec3b>(x, y), clusters.at(k).centroid);
                //check
                if (distance < min_dist) {
                    //update the index and the minimum distance found
                    index = k;
                    min_dist = distance;
                }
            }
            //将像素添加到其簇中
            clusters.at(index).add_pixel(srcImage_.at<Vec3b>(x, y), x, y);

            }
        }

算法第四步:

进行均值漂移,并判断是否达到迭代结束条件。

代码语言:javascript
复制
     bool changed = false;
     for (int k = 0; k < clusters.size(); k++) {
         //获取当前质心作为旧的质心
          Vec3b old_centroid = clusters.at(k).centroid;
         //计算新的质心
            clusters.at(k).calculate_center();
         //check if the new centroid differs by a significative amount to the old one
         if (norm(old_centroid, clusters.at(k).centroid) > 10) {
             changed = true;
         }
       }
     //如果他们都没有改变
     if (!changed || i + 1 == iterations) {
         //break the cycle and go to build the destination image with the cluster
         break;
         iterations = i;
     }
     else {
         //如果改变了,至少需要进行另一次迭代以获得收敛,重置簇但保持新计算的质心
         for (int k = 0; k < clusters.size(); k++) {
             clusters.at(k).clear();
         }
     }

  }

算法第五步:

完成分割,根据结果重新构建结果图。

代码语言:javascript
复制
    Mat showImage = Mat(srcImage_.size(),CV_8UC3);
    for (quint64 k = 0; k < clusters.size(); k++) {//遍历每个簇
        for (quint64 p = 0; p < clusters.at(k).pixel_num; p++)//遍历簇中所有像素
        {
            vector<Point> pix = clusters.at(k).pixels;
            showImage.at<Vec3b>(pix.at(p).x, pix.at(p).y) = colors_.at(k);b(0,255,0); 
        }
    }
    showImage.copyTo(dstImage_);

最终的算法效果:

5,算法总结

其实算法效果还是很拉胯的,将整幅图分割为了固定的几个颜色,但没有达到成块的类似语义分割的效果。

目前打算改进的就是将人工预分割的像素位置分类考虑进算法,并优化计算距离的方法。

整篇文所展示的效果花了我五天时间。。。后续有进展再发文和大家交流。

大家有思路和建议的可以加我微信备注加群,我们在群里讨论哦。

THE END

整个QT项目的代码放百度网盘了:

代码语言:javascript
复制
链接:https://pan.baidu.com/s/1XeU7s0SATfRTR4wGFCQ-OQ 
提取码:aatg

感谢大家的支持!

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-09-08,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 周旋机器视觉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com