C ++为图像中的每个区域计算2个3x3协方差矩阵

时间:2015-07-06 19:55:40

标签: c++ opencv matrix covariance

我在OpenCV中使用UIGestureRecognizer类型的大小为img的c ++中的图像mxn。 我有另一个大小为CV_8UC3的{​​{1}}向量b"水平"分为两部分:

1xn

img

其中1 <= b(1,col)&lt; = m(1 <= col&lt; = n)。

对于图像的这两部分,我希望协方差矩阵upper_part = {(row,col)|1<=col<=n, 1<=row<=b(1,col)}lower_part = {(row,col)|1<=col<=n, b(1,col)<row<=m}类型为&#34; per&#34;渠道。这意味着得到的矩阵应该具有3x3的大小,并且应该像:

M_u

其中N_u是上部的元素数量,mu_u是描述上部平均RGB值的3x1向量,M_l是3x1向量,其中RGB值为M_u = 1/(N_u-1) * sum_{(row,col)\in upper_part} (img(row,col)-mu_u)*(img(row,col)-mu_u)^T img(row,col)。考虑到img(row,col)M_lN_l等效计算。

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

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

我目前的解决方案是迭代每个像素并通过分别获得CV_8UC3CV_8UC1的值来计算它(首先是均值,然后是协方差,因此所有像素都有两个循环) ,但我所听到的,现在看到的是,这个功能非常低效/慢。正如我在循环中计算img.at<Vec3b>(row,col)img.at<unsigned char>(row,col)的过程一样,我希望有效地推导出协方差。 有什么想法吗?

谢谢。

PS:M_uM_l

1 个答案:

答案 0 :(得分:0)

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

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

   {
    //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&#39; calcCovarMatrix&#39;来检查协方差是否正确。同样。

    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;