如何通过指针用另一个实例替换实例? [英] How to replace an instance with another instance via pointer?

查看:112
本文介绍了如何通过指针用另一个实例替换实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在类实例列表(stl :: list)上进行在线破坏性聚类(聚类替换聚类对象)。

I'm doing online destructive clustering (clusters replace clustered objects) on a list of class instances (stl::list).

我当前的percepUnits列表是: stl :: list< ;ceceptpUnit>单位; ,并且对于每次迭代,我得到一个新的输入列表:percepUnits stl :: list< ;cectpUnit>

My list of current percepUnits is: stl::list<percepUnit> units; and for each iteration I get a new list of input percepUnits stl::list<percepUnit> scratch; that need to be clustered with the units.

我想保持一个固定数量的percepUnits(所以units.size()是常量),所以对于每个新的scratchpunit我需要与最近的percepUnit以单位合并。以下是一个代码片段,它构建了一个结构体( percepUnitDist )的列表( dists percepDist.scratchUnit =&(* scratchUnit); percepDist.unit =&(* unit); 和他们的距离。此外,对于每个项目在划痕中我跟踪哪个项目的单位有最小的距离 minDists

I want to maintain a fixed number of percepUnits (so units.size() is constant), so for each new scratch percepUnit I need to merge it with the nearest percepUnit in units. Following is a code snippet that builds a list (dists) of structures (percepUnitDist) that contain pointers to each pair of items in scratch and units percepDist.scratchUnit = &(*scratchUnit); and percepDist.unit = &(*unit); and their distance. Additionally, for each item in scratch I keep track of which item in units has the least distance minDists.

// For every scratch percepUnit:
for (scratchUnit = scratch.begin(); scratchUnit != scratch.end(); scratchUnit++) { 
    float minDist=2025.1172; // This is the max possible distance in unnormalized CIELuv, and much larger than the normalized dist.
    // For every percepUnit:
    for (unit = units.begin(); unit != units.end(); unit++) { 

        // compare pairs
        float dist = featureDist(*scratchUnit, *unit, FGBG);
        //cout << "distance: " << dist << endl;

        // Put pairs in a structure that caches their distances
        percepUnitDist percepDist;
        percepDist.scratchUnit = &(*scratchUnit); // address of where scratchUnit points to.
        percepDist.unit = &(*unit);
        percepDist.dist = dist;

        // Figure out the percepUnit that is closest to this scratchUnit.
        if (dist < minDist)
            minDist = dist;

        dists.push_back(percepDist); // append dist struct
    }
    minDists.push_back(minDist); // append the min distance to the nearest percepUnit for this particular scratchUnit.
}



现在我只需要循环遍历 percepUnitDist dists 中的项目,并将距离与最小距离进行匹配,以确定哪些在scratch中的percepUnit应与哪些percepUnit以单位合并。合并过程 mergePerceps()创建一个新的percepUnit,它是父方法中的父和单位的加权平均值。

So now I just need to loop through the percepUnitDist items in dists and match the distances with the minimum distances to figure out which percepUnit in scratch should be merged with which percepUnit in units. The merging process mergePerceps() creates a new percepUnit which is a weighted average of the "parent" percepUnits in scratch and units.

我想使用mergePerceps()构造的新的percepUnit替换单元列表中的实例,但是我想在上下文中循环通过percepUnitDists。这是我当前的代码:

I want to replace the instance in the units list with the new percepUnit constructed by mergePerceps(), but I would like to do so in the context of looping through the percepUnitDists. This is my current code:

// Loop through dists and merge all the closest pairs.
// Loop through all dists
for (distIter = dists.begin(); distIter != dists.end(); distIter++) {
    // Loop through all minDists for each scratchUnit.
    for (minDistsIter = minDists.begin(); minDistsIter != minDists.end(); minDistsIter++) {
        // if this is the closest cluster, and the closest cluster has not already been merged, and the scratch has not already been merged.
        if (*minDistsIter == distIter->dist and not distIter->scratchUnit->remove) {

            percepUnit newUnit;
            mergePerceps(*(distIter->scratchUnit), *(distIter->unit), newUnit, FGBG);
            *(distIter->unit) = newUnit; // replace the cluster with the new merged version.

            distIter->scratchUnit->remove = true;
        }
    }
}

使用 *(distIter-> unit)= newUnit; ,通过具有新的percepUnit实例的percepUnitDist指针以单位表示实例,但是这似乎不像我' m看到内存泄漏,暗示单元中的实例不会被替换。

I thought that I could replace the instance in units via the percepUnitDist pointer with the new percepUnit instance using *(distIter->unit) = newUnit;, but that does not seem to be working as I'm seeing a memory leak, implying the instances in the units are not getting replaced.

如何删除单位列表中的percepUnit,并将其替换为新的percepUnit实例,以使新单元位于同一位置?

How do I delete the percepUnit in the units list and replace it with a new percepUnit instance such that the new unit is located in the same location?

这里是percepUnit类。注意cv :: Mat成员。以下是mergePerceps()函数和mergeImages()函数,它取决于:

Here is the percepUnit class. Note the cv::Mat members. Following is the mergePerceps() function and the mergeImages() function on which it depends:

// Function to construct an accumulation.
void clustering::mergeImages(Mat &scratch, Mat &unit, cv::Mat &merged, const string maskOrImage, const string FGBG, const float scratchWeight, const float unitWeight) {

    int width, height, type=CV_8UC3;
    Mat scratchImagePad, unitImagePad, scratchImage, unitImage;

    // use the resolution and aspect of the largest of the pair.
    if (unit.cols > scratch.cols)
        width = unit.cols;
    else
        width = scratch.cols;

    if (unit.rows > scratch.rows)
        height = unit.rows;
    else
        height = scratch.rows;

    if (maskOrImage == "mask") 
        type = CV_8UC1; // single channel mask
    else if (maskOrImage == "image")
        type = CV_8UC3; // three channel image
    else
        cout << "maskOrImage is not 'mask' or 'image'\n";

    merged = Mat(height, width, type, Scalar::all(0));
    scratchImagePad = Mat(height, width, type, Scalar::all(0));
    unitImagePad = Mat(height, width, type, Scalar::all(0));

    // weight images before summation.
    // because these pass by reference, they mess up the images in memory!
    scratch *= scratchWeight;
    unit *= unitWeight;

    // copy images into padded images.
    scratch.copyTo(scratchImagePad(Rect((scratchImagePad.cols-scratch.cols)/2,
                                             (scratchImagePad.rows-scratch.rows)/2,
                                              scratch.cols,
                                              scratch.rows)));

    unit.copyTo(unitImagePad(Rect((unitImagePad.cols-unit.cols)/2,
                                       (unitImagePad.rows-unit.rows)/2,
                                        unit.cols,
                                        unit.rows)));

    merged = scratchImagePad+unitImagePad;
}

// Merge two perceps and return a new percept to replace them.
void clustering::mergePerceps(percepUnit scratch, percepUnit unit, percepUnit &mergedUnit, const string FGBG) {

    Mat accumulation;
    Mat accumulationMask;
    Mat meanColour;
    int x, y, w, h, area;
    float l,u,v;
    int numMerges=0;
    std::vector<float> featuresVar; // Normalized, Sum, Variance.
    //float featuresVarMin, featuresVarMax; // min and max variance accross all features.
    float scratchWeight, unitWeight;

    if (FGBG == "FG") {
        // foreground percepts don't get merged as much.
        scratchWeight = 0.65;
        unitWeight = 1-scratchWeight;
    } else {
        scratchWeight = 0.85;
        unitWeight = 1-scratchWeight;
    }

    // Images TODO remove the meanColour if needbe.
    mergeImages(scratch.image, unit.image, accumulation, "image", FGBG, scratchWeight, unitWeight);
    mergeImages(scratch.mask, unit.mask, accumulationMask, "mask", FGBG, scratchWeight, unitWeight);
    mergeImages(scratch.meanColour, unit.meanColour, meanColour, "image", "FG", scratchWeight, unitWeight); // merge images 


    // Position and size.
    x = (scratch.x1*scratchWeight) + (unit.x1*unitWeight);
    y = (scratch.y1*scratchWeight) + (unit.y1*unitWeight);
    w = (scratch.w*scratchWeight) + (unit.w*unitWeight);
    h = (scratch.h*scratchWeight) + (unit.h*unitWeight);

    // area
    area = (scratch.area*scratchWeight) + (unit.area*unitWeight);

    // colour
    l = (scratch.l*scratchWeight) + (unit.l*unitWeight);
    u = (scratch.u*scratchWeight) + (unit.u*unitWeight);
    v = (scratch.v*scratchWeight) + (unit.v*unitWeight);

    // Number of merges
    if (scratch.numMerges < 1 and unit.numMerges < 1) { // both units are patches
        numMerges = 1;
    } else if (scratch.numMerges < 1 and unit.numMerges >= 1) { // unit A is a patch, B a percept
        numMerges = unit.numMerges + 1;
    } else if (scratch.numMerges >= 1 and unit.numMerges < 1) { // unit A is a percept, B a patch.
        numMerges = scratch.numMerges + 1;
        cout << "merged scratch??" <<endl;
        // TODO this may be an impossible case.
    } else { // both units are percepts
        numMerges = scratch.numMerges + unit.numMerges;
        cout << "Merging two already merged Percepts" <<endl;
        // TODO this may be an impossible case.
    }

    // Create unit.
    mergedUnit = percepUnit(accumulation, accumulationMask, x, y, w, h, area); // time is the earliest value in times?
    mergedUnit.l = l; // members not in the constrcutor.
    mergedUnit.u = u;
    mergedUnit.v = v;
    mergedUnit.numMerges = numMerges;
    mergedUnit.meanColour = meanColour;
    mergedUnit.pActivated = unit.pActivated; // new clusters retain parent's history of activation.
    mergedUnit.scratch = false;
    mergedUnit.habituation = unit.habituation; // we inherent the habituation of the cluster we merged with.
}



EDIT2



更改副本和赋值运算符有性能副作用,似乎没有解决问题。所以我添加了一个自定义函数来做替换,这就像复制操作员制作每个成员的副本,并确保那些副本是深的。问题是,我仍然最终有一个泄漏。

EDIT2

Changing the copy and assignment operators had performance side-effects and did not seem to resolve the problem. So I've added a custom function to do the replacement, which just like the copy operator makes copies of each member and make's sure those copies are deep. The problem is that I still end up with a leak.

所以我改变了这一行: *(distIter-> unit)= newUnit;

So I've changed this line: *(distIter->unit) = newUnit;

到此:(*(distIter-> unit))。clone(newUnit)

其中克隆方法如下:

// Deep Copy of members
void percepUnit::clone(const percepUnit &source) {
    // Deep copy of Mats
    this->image = source.image.clone();
    this->mask = source.mask.clone();
    this->alphaImage = source.alphaImage.clone();
    this->meanColour = source.meanColour.clone();

    // shallow copies of everything else    
    this->alpha = source.alpha;
    this->fadingIn = source.fadingIn;
    this->fadingHold = source.fadingHold;
    this->fadingOut = source.fadingOut;
    this->l = source.l;
    this->u = source.u;
    this->v = source.v;
    this->x1 = source.x1;
    this->y1 = source.y1;
    this->w = source.w;
    this->h = source.h;
    this->x2 = source.x2;
    this->y2 = source.y2;
    this->cx = source.cx;
    this->cy = source.cy;
    this->numMerges = source.numMerges;
    this->id = source.id;
    this->area = source.area;
    this->features = source.features;
    this->featuresNorm = source.featuresNorm;
    this->remove = source.remove;
    this->fgKnockout = source.fgKnockout;
    this->colourCalculated = source.colourCalculated;
    this->normalized = source.normalized;
    this->activation = source.activation;
    this->activated = source.activated;
    this->pActivated = source.pActivated;
    this->habituation = source.habituation;
    this->scratch = source.scratch;
    this->FGBG = source.FGBG;
}

但是,我仍然看到内存增加。如果我注释掉单个替换行,增加不会发生。

And yet, I still see a memory increase. The increase does not happen if I comment out that single replacement line. So I'm still stuck.

如果禁用cv,我可以防止内存增加: :Mat克隆代码在上面的函数中:

I can prevent memory from increasing if I disable the cv::Mat cloning code in the function above:

// Deep Copy of members
void percepUnit::clone(const percepUnit &source) {
    /* try releasing Mats first?
    // No effect on memory increase, but the refCount is decremented.
    this->image.release();
    this->mask.release();
    this->alphaImage.release();
    this->meanColour.release();*/

    /* Deep copy of Mats
    this->image = source.image.clone();
    this->mask = source.mask.clone();
    this->alphaImage = source.alphaImage.clone();
    this->meanColour = source.meanColour.clone();*/

    // shallow copies of everything else    
    this->alpha = source.alpha;
    this->fadingIn = source.fadingIn;
    this->fadingHold = source.fadingHold;
    this->fadingOut = source.fadingOut;
    this->l = source.l;
    this->u = source.u;
    this->v = source.v;
    this->x1 = source.x1;
    this->y1 = source.y1;
    this->w = source.w;
    this->h = source.h;
    this->x2 = source.x2;
    this->y2 = source.y2;
    this->cx = source.cx;
    this->cy = source.cy;
    this->numMerges = source.numMerges;
    this->id = source.id;
    this->area = source.area;
    this->features = source.features;
    this->featuresNorm = source.featuresNorm;
    this->remove = source.remove;
    this->fgKnockout = source.fgKnockout;
    this->colourCalculated = source.colourCalculated;
    this->normalized = source.normalized;
    this->activation = source.activation;
    this->activated = source.activated;
    this->pActivated = source.pActivated;
    this->habituation = source.habituation;
    this->scratch = source.scratch;
    this->FGBG = source.FGBG;
}



EDIT4



虽然我仍然无法解释这个问题,但我注意到另一个提示。我意识到,如果我不规范化那些功能,我使用通过featureDist()集群(但继续克隆cv :: Mats),这个泄漏也可以停止。真的很奇怪的是,我完全重写了代码,仍然问题仍然存在。

EDIT4

While I still can't explain this issue, I did notice another hint. I realized that this leak can also be stopped if I don't normalize those features I use to cluster via featureDist() (but continue to clone cv::Mats). The really odd thing is that I rewrote that code entirely and still the problem persists.

这里是featureDist函数:

Here is the featureDist function:

float clustering::featureDist(percepUnit unitA, percepUnit unitB, const string FGBG) {
    float distance=0;

    if (FGBG == "BG") {
        for (unsigned int i=0; i<unitA.featuresNorm.rows; i++) { 
            distance += pow(abs(unitA.featuresNorm.at<float>(i) - unitB.featuresNorm.at<float>(i)),0.5);
            //cout << "unitA.featuresNorm[" << i << "]: " << unitA.featuresNorm[i] << endl;
            //cout << "unitB.featuresNorm[" << i << "]: " << unitB.featuresNorm[i] << endl;
        }
    // for FG, don't use normalized colour features.
    // TODO To include the area use i=4
    } else if (FGBG == "FG") { 
        for (unsigned int i=4; i<unitA.features.rows; i++) { 
            distance += pow(abs(unitA.features.at<float>(i) - unitB.features.at<float>(i)),0.5);
        }
    } else {
        cout << "FGBG argument was not FG or BG, returning 0." <<endl;
        return 0;
    }

    return pow(distance,2);
}

特征过去是一个浮点数,因此正规化代码是

Features used to be a vector of floats, and thus the normalization code was as follows:

void clustering::normalize(list<percepUnit> &scratch, list<percepUnit> &units) {

    list<percepUnit>::iterator unit;
    list<percepUnit*>::iterator unitPtr;
    vector<float> min,max;
    list<percepUnit*> masterList; // list of pointers.

    // generate pointers
    for (unit = scratch.begin(); unit != scratch.end(); unit++)
        masterList.push_back(&(*unit)); // add pointer to where unit points to.
    for (unit = units.begin(); unit != units.end(); unit++)
        masterList.push_back(&(*unit)); // add pointer to where unit points to.

    int numFeatures = masterList.front()->features.size(); // all percepts have the same number of features.
    min.resize(numFeatures); // allocate for the number of features we have.
    max.resize(numFeatures);

    // Loop through all units to get feature values
    for (int i=0; i<numFeatures; i++) { 

        min[i] = masterList.front()->features[i]; // starting point.
        max[i] = min[i];

        // calculate min and max for each feature.
        for (unitPtr = masterList.begin(); unitPtr != masterList.end(); unitPtr++) {

            if ((*unitPtr)->features[i] < min[i]) 
                min[i] = (*unitPtr)->features[i];
            if ((*unitPtr)->features[i] > max[i])
                max[i] = (*unitPtr)->features[i];
        }
    }

    // Normalize features according to min/max.
    for (int i=0; i<numFeatures; i++) { 
        for (unitPtr = masterList.begin(); unitPtr != masterList.end(); unitPtr++) {
            (*unitPtr)->featuresNorm[i] = ((*unitPtr)->features[i]-min[i]) / (max[i]-min[i]);
            (*unitPtr)->normalized = true;
        }
    }
}

a cv :: Mat所以我可以使用opencv规范化函数,所以我重写了规范化函数如下:

I changed the features type to a cv::Mat so I could use the opencv normalization function, so I rewrote the normalization function as follows:

void clustering::normalize(list<percepUnit> &scratch, list<percepUnit> &units) {

    Mat featureMat = Mat(1,units.size()+scratch.size(), CV_32FC1, Scalar(0));
    list<percepUnit>::iterator unit;

    // For each feature
    for (int i=0; i< units.begin()->features.rows; i++) {

        // for each unit in units
        int j=0;
        float value;
        for (unit = units.begin(); unit != units.end(); unit++) {
            // Populate featureMat j is the unit index, i is the feature index.
            value = unit->features.at<float>(i);
            featureMat.at<float>(j) = value;
            j++;
        }
        // for each unit in scratch
        for (unit = scratch.begin(); unit != scratch.end(); unit++) {
            // Populate featureMat j is the unit index, i is the feature index.
            value = unit->features.at<float>(i);
            featureMat.at<float>(j) = value;
            j++;
        }

        // Normalize this featureMat in place
        cv::normalize(featureMat, featureMat, 0, 1, NORM_MINMAX);

        // set normalized values in percepUnits from featureMat
        // for each unit in units
        j=0;
        for (unit = units.begin(); unit != units.end(); unit++) {
            // Populate percepUnit featuresNorm, j is the unit index, i is the feature index.
            value = featureMat.at<float>(j);
            unit->featuresNorm.at<float>(i) = value;
            j++;
        }
        // for each unit in scratch
        for (unit = scratch.begin(); unit != scratch.end(); unit++) {
            // Populate percepUnit featuresNorm, j is the unit index, i is the feature index.
            value = featureMat.at<float>(j);
            unit->featuresNorm.at<float>(i) = value;
            j++;
        }
    }
}

Massif和我的/ proc内存报告不同意。 Massif说,规范化对内存使用没有影响,只有注释了percepUnit :: clone()操作绕过了泄漏。

这里是所有的代码,如果交互是别的地方我失踪。

Here is all the code, in case the interaction is somewhere else I am missing.

这里是另一个版本的相同代码与依赖于OpenCV GPU移除,以方便测试...

Here is another version of the same code with the dependence on OpenCV GPU removed, to facilitate testing...

推荐答案

Nghia(在opencv论坛上)尝试并使感知恒定大小。果然,如果我修复了spacpUnit的cv :: Mat成员的尺寸和类型,那么泄漏就会消失

It was recommended by Nghia (on the opencv forum) that I try and make the percepts a constant size. Sure enough, if I fix the dimensions and type of the cv::Mat members of percepUnit, then the leak disappears.

对我来说,这是一个在OpenCV中的错误,调用clone()和copyTo()在不同大小的作为类成员的Mats。到目前为止无法在一个简单的程序中重现。泄漏看起来很小,可能是标题泄漏,而不是底层的图像数据。

So it seems to me this is a bug in OpenCV that effects calling clone() and copyTo() on Mats of different sizes that are class members. So far unable to reproduce in a simple program. The leak does seem small enough that it may be the headers leaking, rather than the underlying image data.

这篇关于如何通过指针用另一个实例替换实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆