Discontinuous seam carving for video retargeting

Discontinuous seam carving for video retargeting

写本文的目的很简单,我实在是要不到本文对应论文的代码实现,因此决定自己写,博客先写出来放这里,等写好就开源。
本文的工作已经基本完成,剩下的工作包括一些效率上的优化处理,核心的思路会公布在文章中,如有错误,请留言指教。文章本身仅为学术范围内的分享和交流,请勿转载。
说明:本文代码是可以跑的,但是很多tricks没有包含在代码中,因此使用本文的代码速度会很慢,有学术上的交流请跟我联系或下方留言,目前我自己做到的速度大概是一个seam毫秒级,欢迎探讨。

前期准备

本文对应的基础算法是图像/视频缩放领域的经典算法-seam-carving 方法,关于该方法的知识是阅读本文的基础,相关的paper如下:

  • 【SIGGRAPH】07-Seam carving for content-aware image resizing
  • 【SIGGRAPH】08-Improved Seam Carving for Video Retargeting
    相对应的代码可以在github上找到。

核心思想

这篇论文的主要创新点是提出了一种新的能量函数,在此能量函数的基础上,应用经典seam carving 算法对视频的每一帧进行缩放,该能量函数需要同时保持时间和空间一致性。

时间一致性

视频时间一致性的保持,关键在于seam在相邻帧的位置关系。我们知道,如果对视频的每一帧用相同的seam处理,那么视频帧之间的时间一致性毫无疑问会得到保持,但是空间一致性就会遭到破坏。根据论文提出的新的处理方式,有如下的时间一致性能量函数计算过程:

void SeamCarver::calculateTempral(Mat& newEnergy, vector<uint> seam) {

    // we know the seam, and we should compute the new energy term according to the seam
    vector<int> seamVal(energy.cols - 1);
    for (int i = 0; i < energy.rows;++i) {
        seamVal.clear();
        seamVal.resize(energy.cols - 1);
        uint pos = seam[i];
        // first get the temporal row
        for (int m = 0; m < energy.cols-1;++m){
            if (m<pos) {
                seamVal[m] = energy.at<uint32_t>(i, m);
            }
            else {
                seamVal[m] = energy.at<uint32_t>(i, m + 1);
            }
        }
        for (int j = 0; j < energy.cols;++j){
            //left and right
            // not contain left
            int totalEnergy = 0;
            //left and right
            //left first
            for (int l = 0; l < j;l++) {
                totalEnergy += abs(static_cast<int>(energy.at<uint32_t>(i, l) - seamVal[l]));
            }
            //right second
            for (int l = j + 1; l < energy.cols;++l) {
                totalEnergy += abs(static_cast<int>(energy.at<uint32_t>(i, l) - seamVal[l - 1]));
            }
            newEnergy.at<uint32_t>(i, j) = totalEnergy*0.2;

        }
    }
}

我们使用newEnergy来存储对应于每一个像素的 total cost,这里根据论文的方法,首先计算出temporal cost。

空间一致性

video retargeting的另一核心问题就是空间一致性的保持,在论文中,作者认为每一个像素的删除,对于整体spatial coherence的保持是可以通过计算得出的,这里,我们同样基于前一帧的seam,作为我们进行处理的基准,来计算像素的spatial coherence cost:

void SeamCarver::calculateSpatial(Mat &newEnergy, vector<uint> seam) {
    // horizontal and vertical cost
    // horizontal first
    for (int i = 0; i < energy.rows; ++i) {
        for (int j = 0; j < energy.cols; ++j) {
            int totalEnergy = 0;
            //we calculate the horizontal first
            if (j==0&&(j+2)<energy.cols) {// two factors - border pixel
                int before = energy.at<uint32_t>(i, j) - energy.at<uint32_t>(i, j + 1);
                int after = energy.at<uint32_t>(i, j + 1) - energy.at<uint32_t>(i, j + 2);
                // so we can get the abs of the two values
                int minus = abs(abs(before) - abs(after));
                // so we add the minus to the totoalEnergy
                totalEnergy += minus;
            } else if(j+1<energy.cols){ // three factors - interior pixel
                int firstVal = energy.at<uint32_t>(i, j - 1) - energy.at<uint32_t>(i, j);
                int secondVal = energy.at<uint32_t>(i, j)- energy.at<uint32_t>(i, j + 1);
                int before = abs(firstVal) + abs(secondVal);
                int after = energy.at<uint32_t>(i, j - 1) - energy.at<uint32_t>(i, j + 1);
                int minus = abs(abs(before) - abs(after));
                // so we add the minus to the totoalEnergy
                totalEnergy += minus;
            }
            //we calculate the vertical second
            //11 pixels according to the paper
            //the paper is not clear enough about the vertical cost, we use the seam to calculate
            int verticalEnergy = 0;
            if (i+1<energy.rows) {
                uint pos = seam[i + 1]; // we get the seam pixel for the i+1 row
                //search 11 pixels
                int distance = abs((int)pos - j);
                if (distance>11){ // we assign it infinite val
                    verticalEnergy = INFINVAL;
                }
                else { // we calculate the verticalEnergy of the pixel, two cases
                    // the pos == j
                    if (j==pos) {
                        verticalEnergy = 0;
                    }
                    //we need define the GV operation and GD operation first
                    else if (j>pos) {  // first case j>pos
                        int firstEnergy = 0;
                        for (int m = pos; m < j;m++) {
                            firstEnergy += abs(g_v(i, m) - g_d_first(i, m));
                        }
                        for (int m = pos + 1; m <= j;m++) {
                            firstEnergy += abs(g_v(i, m) - g_d_first(i, m-1));
                        }
                        verticalEnergy += firstEnergy;
                    }
                    else {  // second case j<pos similar to the first
                        int secEnergy = 0;
                        for (int m = j; m < pos;m++) {
                            secEnergy += abs(g_v(i, m) - g_d_sec(i, m));
                        }
                        for (int m = j + 1; m <= pos; m++) {
                            secEnergy += abs(g_v(i, m) - g_d_sec(i, m - 1));
                        }
                        verticalEnergy += secEnergy;
                    }
                }
                // so we compute the vertical energy

            }
            totalEnergy += verticalEnergy;
            // so we get all spatial energy involved, then we assign it to the Mat
            newEnergy.at<uint32_t>(i, j) += 0.8*totalEnergy;


        }
    }
}

spatial coherence的计算是本文的核心内容,对于这一部分,论文作者比较模棱两可,一些关键思想在文章中没有体现,根据代码的实验检测,本文的方法应该是正确的处理。

结语

由于一些特殊的原因,本文只公布了核心的计算部分,其余部分的实现都相对简单,如果确实有完整代码的需要,请在下方留言。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值