【问题标题】:Multiplying SVD components of a matrix in OpenCV在OpenCV中乘以矩阵的SVD分量
【发布时间】:2017-02-17 10:05:52
【问题描述】:

我将 SVD 应用于 CV_32FC1 cvMat 并修改了“u”组件中的一些值。现在我试图将 'u、'w' 和 'vt' 分量相乘以获得单个矩阵 A。但 OpenCV 无法将矩阵相乘并出现以下错误。

OpenCV Error: Assertion failed (type == B.type() && (type == CV_32FC1 || type == CV_64FC1 || type == CV_32FC2 || type == CV_64FC2)) in gemm, file /build/buildd/opencv-2.1.0/src/cxcore/cxmatmul.cpp, line 687
terminate called after throwing an instance of 'cv::Exception'
  what():  /build/buildd/opencv-2.1.0/src/cxcore/cxmatmul.cpp:687: error: (-215) type == B.type() && (type == CV_32FC1 || type == CV_64FC1 || type == CV_32FC2 || type == CV_64FC2) in function gemm

当我检查 SVD 对象中的矩阵类型时,它们的 type = 20 似乎与任何默认矩阵类型都不匹配。

#include <iostream>
#include <stdio.h>
#include "cv.h"
#include "highgui.h"
#include "constants.h"

const unsigned int MAX = 10000;

using namespace cv;
using namespace std;

int NO_FRAMES;

Mat resize_image(Mat &src, Mat img)
{
    Mat dst;
    resize(src, dst, Size(img.rows, img.cols));
    return dst;
}

bool check_exit()
{
     return (waitKey(27) > 0)?true:false;
}

int main(int argc, char ** argv)
{
    Mat rgb[MAX];
    Mat ycbcr[MAX];
    Mat wm_rgb[MAX];
    SVD svd[MAX];
    namedWindow("watermark",1);
    namedWindow("RGB", 2);
    namedWindow("YCBCR",3);
    namedWindow("u",4);
    namedWindow("w",5);
    namedWindow("vt",6);
    if (argc < 3)
    {
        cout<<"Video file required! (Supported formats: avi, mp4, mpeg)\n";
        return 1;
    }

    VideoCapture capture(argv[1]);
    Mat watermark = imread(argv[2]);
    if(!capture.isOpened())
    {
        cout<<"Unable to open the video file!\n";
        return 1;
    }

    int i=0;
        capture >> rgb[i];

    while(!rgb[i].empty())
    {
        imshow("RGB", rgb[i]);
        cvtColor(rgb[i], ycbcr[i], CV_RGB2YCrCb);
        imshow("YCBCR", ycbcr[i]);
        i++;
        capture >> rgb[i];

        if(check_exit())
            exit(0);
    }

    NO_FRAMES = i;

    watermark = resize_image(watermark, ycbcr[0]);
    VideoWriter writer("output.avi", CV_FOURCC('d', 'i', 'v', 'x'), 24.0, cvSize(ycbcr[0].cols, ycbcr[0].rows),  true);
    for(int i = 0; i < NO_FRAMES - 1; i++)
    {
        Mat dst(ycbcr[i].rows, ycbcr[i].cols, CV_32FC1);
        ycbcr[i].convertTo(dst, CV_32S); 
        SVD temp(dst, 5);
        imshow("u", temp.u);
        imshow("w", temp.w);
        imshow("vt", temp.vt);
        svd[i] = temp;

        if(check_exit())
            exit(0);
    }


    int j = 0, k = 0;
    for (i = 0; i < NO_FRAMES; i++)
    {
        for (int p = 0; p < svd[i].u.rows; p++)
        {
            for(int q = 0; q < svd[i].u.cols; q++)
            {

                if (p == q)
                {
                    if (j >= watermark.rows)
                    {
                        goto x;
                    }
                    if (k >= watermark.cols)
                    {
                        k = 0;
                        j++;
                    }
                    svd[i].u.at<float>(p, q) = watermark.at<float>(j,k);
                    k++;
                }
            }
        }
    }


x:  for (i = 0; i < NO_FRAMES; i++)
    {
        Mat A(rgb[0].rows, rgb[0].cols, CV_32FC1);

                //Here
                A = svd[i].u * svd[i].w * svd[i].vt;
        Mat B(A.rows, A.cols, CV_32FC1);
        cvtColor(A, B, CV_YCrCb2RGB);
        writer << B;
    }

    capture.release();
    return 0;
}

【问题讨论】:

  • 不修改任何组件是否有效?
  • @DRVic 不,它也不起作用
  • 嗯,这将是一个线索:这不是你在修改元素。我不太了解您为获取 SVD 而调用的例程,但我发现您在循环中调用 SVD temp(dst, 5); 并将结果分配给 svd[i] 感到不安,之后允许使用 temp超出范围。复制到 svd[i] 会做深拷贝吗?
  • 我删除了 temp 并直接初始化了 svd,但问题仍然存在。
  • 我遇到了同样的问题。看起来 openCV 不会创建完整的 u、s、v 矩阵来节省内存。我尝试使用标志 SVD::FULL_UV 但在这种情况下 SVD 因 std::bad_alloc 错误而失败。

标签: c++ opencv matrix svd


【解决方案1】:

该错误出现在矩阵乘法运算 (gemm()) 中,尽管该错误可能已传播到您尝试使用非良矩阵 A 创建新矩阵 B 的下一行。 请注意,OpenCV 中的 SVD 算法产生以下形式的输出: 对于矩阵 A(m x n),SVD 产生以下三个矩阵:

w – 计算出的奇异值 (min(m,n) x 1)

u – 计算的左奇异向量 (m x m)

vt – 右奇异值的转置矩阵 (n x n)

这里的奇异值存储在尺寸为 (min(m,n) x 1) 的紧凑列向量中,而不是作为实际的数学等价物,它是尺寸的对角矩阵 (min(m,n), min(m,n)).

因此,如果您想从单个 SVD 分量重构矩阵,您必须首先将向量“w”转换为对角矩阵形式。你可以使用 OpenCV 的 diag() 方法来做到这一点:

A = svd[i].u * Mat::diag(svd[i].w) * svd[i].vt;

【讨论】:

    【解决方案2】:

    我现在也遇到了这个,想我应该在这里写,在我计算 SVD 时,我的大小就像 2 * (#imagePixels), 因此,U 或 Vt 矩阵之一变得很大,无法在堆上分配,因此出现了这个异常 std::bad_alloc,因为在我的情况下,Vt 大小将是 imagePixels * imagePixels,这是巨大的。

    你的情况可能也会发生这种情况。

    把这个留在这里,以便下一个遇到这个的人也应该看看矩阵大小。

    【讨论】:

      猜你喜欢
      • 2021-07-01
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      • 1970-01-01
      • 2013-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多