【问题标题】:C++ calculate 2 3x3 Covariance matrices for each region in imageC++ 为图像中的每个区域计算 2 个 3x3 协方差矩阵
【发布时间】:2015-07-06 19:55:40
【问题描述】:

我在 C++ 中有一个图像 img,大小为 mxn,在 OpenCV 中类型为 CV_8UC3。 我有另一个向量b,大小为1xn,将img“水平”分成两部分:

upper_part = {(row,col)|1<=col<=n, 1<=row<=b(1,col)}

lower_part = {(row,col)|1<=col<=n, b(1,col)<row<=m},

其中 1

对于图像的这两个部分,我希望有协方差矩阵 M_uM_l 排序的“每个”通道。这意味着生成的矩阵的大小应该是 3x3,并且应该像这样导出:

M_u = 1/(N_u-1) * sum_{(row,col)\in upper_part} (img(row,col)-mu_u)*(img(row,col)-mu_u)^T,

其中 N_u 是上部元素的数量, mu_u 是描述上部平均 RGB 值的 3x1 向量,img(row,col) 是 3x1 向量,在位置 (row,col) 处具有 img 的 RGB 值。考虑到lower_partM_lN_lmu_l 等效计算。

此外,我还(有时)必须计算CV_8UC1 图像的协方差。当然,矩阵只是一个标量。

是否有主要针对 CV_8UC3 类型的解决方案,如果有,是否有适用于 CV_8UC1 类型图像的解决方案?

我当前的解决方案是遍历每个像素并通过分别获取 img.at<Vec3b>(row,col)img.at<unsigned char>(row,col) 的值来计算它(首先是平均值,然后是协方差,因此对所有像素进行两个循环),但是我'听说过,现在看到的是这个功能效率很低/很慢。由于我必须在循环中执行计算M_uM_l 的过程,因此我想有效地导出协方差。 有什么想法吗?

谢谢。

PS:m~1280n~960

【问题讨论】:

  • 没人知道吗?我想我必须做循环。但是我能以某种方式避免这个缓慢的 .at() 函数吗?
  • 任何避免.at<.,.>(.,.) 的想法都会有所帮助。

标签: c++ opencv matrix covariance


【解决方案1】:

可以在所有像素的单个迭代循环内计算协方差。

我有以下代码迭代图像的整个像素集,只需一次并计算协方差矩阵。这可以很好地扩展到分割图像的情况。

   {
    //img is a CV_8UC3 image in RGB format
    Vec3f sumOfPixels=Vec3f(0,0,0);
    float sumRR=0, sumRG=0, sumRB=0, sumGG=0, sumGB=0, sumBB=0;
    Mat covarianceMat = Mat::zeros(3, 3, CV_32FC1);
    for(int r= 0; r < img.rows; ++r) {
        for(int c=0; c < img.cols; ++c) {
            const Vec3b &currentPixel = img.at<Vec3b>(Point(c,r));
            sumOfPixels += Vec3b(currentPixel[0], currentPixel[1], currentPixel[2]);
            sumRR += currentPixel[0] * currentPixel[0];
            sumRG += currentPixel[0] * currentPixel[1];
            sumRB += currentPixel[0] * currentPixel[2];
            sumGG += currentPixel[1] * currentPixel[1];
            sumGB += currentPixel[1] * currentPixel[2];
            sumBB += currentPixel[2] * currentPixel[2];
        }
    }
    int nPixels = img.rows * img.cols;
    assert(nPixels > 0);
    Vec3f avgOfPixels = sumOfPixels / nPixels;
    covarianceMat.at<float>(0,0) = sumRR/nPixels - avgOfPixels[0]*avgOfPixels[0];
    covarianceMat.at<float>(0,1) = sumRG/nPixels - avgOfPixels[0]*avgOfPixels[1];
    covarianceMat.at<float>(0,2) = sumRB/nPixels - avgOfPixels[0]*avgOfPixels[2];

    covarianceMat.at<float>(1,1) = sumGG/nPixels - avgOfPixels[1]*avgOfPixels[1];
    covarianceMat.at<float>(1,2) = sumGB/nPixels - avgOfPixels[1]*avgOfPixels[2];
    covarianceMat.at<float>(2,2) = sumBB/nPixels - avgOfPixels[2]*avgOfPixels[2];

    covarianceMat.at<float>(1,0) =  covarianceMat.at<float>(0,1);
    covarianceMat.at<float>(2,0) =  covarianceMat.at<float>(0,2);
    covarianceMat.at<float>(2,1) =  covarianceMat.at<float>(1,2);
    cout << "covariance of image: " << covarianceMat << endl;

}

在计算全图的协方差(即:不分割图像)的情况下,您也可以使用opencv的'calcCovarMatrix'来检查协方差是否正确。

    Mat img_copy = img;
    assert(img.type() == img_copy.type());
    img_copy = img.reshape(1, img.rows *img.cols);
    cv::Mat covar, mean;
    cv::calcCovarMatrix(img_copy, covar, mean, CV_COVAR_NORMAL | CV_COVAR_ROWS );
    covar /= (img.rows * img.cols);
    std::cout << "covariance through opencv: " << covar << std::endl;

【讨论】:

  • 非常感谢您的回答。不幸的是,我无法检查它是否按我的意愿正常工作,因为我无法再访问它相关的代码。
猜你喜欢
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 2020-04-13
  • 2013-06-30
  • 2011-09-18
  • 2012-11-22
  • 2015-03-31
  • 2011-05-23
相关资源
最近更新 更多