【问题标题】:from float array to mat , concatenate blocks of image从 float 数组到 mat ,连接图像块
【发布时间】:2015-12-07 13:03:01
【问题描述】:

我有一个 800x800 的图像,它被分解为 16 个 200x200 的块。

(可以看之前的帖子here

这些块是:vector<Mat> subImages;

我想在它们上使用浮点指针,所以我这样做了:

float *pdata = (float*)( subImages[ idxSubImage ].data );

1) 现在,我希望能够再次获得相同的图像/块,从浮点数组到 Mat 数据。

int Idx = 0;
pdata = (float*)( subImages[ Idx ].data );
namedWindow( "Display window", WINDOW_AUTOSIZE );

for( int i = 0; i < OriginalImgSize.height - 4; i+= 200 )
{
    for( int j = 0; j < OriginalImgSize.width - 4; j+= 200, Idx++ )
    {

        Mat mf( i,j, CV_32F, pdata + 200 );
        imshow( "Display window", mf );          
        waitKey(0);

    }
}

所以,问题是我收到了一个

OpenCV 错误:断言失败

在imshow中。

2) 如何重新组合所有块以获得原始 800x800 图像? 我试过类似的东西:

int Idx = 0;
pdata = (float*)( subImages[ Idx ].data );

Mat big( 800,800,CV_32F );    
for( int i = 0; i < OriginalImgSize.height - 4; i+= 200 )
{
   for( int j = 0; j < OriginalImgSize.width - 4; j+= 200, Idx++ )
   {

       Mat mf( i,j, CV_32F, pdata + 200 );
       Rect roi(j,i,200,200);
       mf.copyTo( big(roi) );


   }
}

imwrite( "testing" , big );

这给了我:

OpenCV Error: Assertion failed (!fixedSize()) in release

mf.copyTo( big(roi) );.

【问题讨论】:

  • 到底想做什么?只需将浮点数据的 16 部分组合成一个垫子?
  • @Humam Helfawi:是的。只是在第一种情况下,我希望能够可视化每个块。

标签: c++ opencv


【解决方案1】:

首先,您需要知道您的子图像在大图像中的位置。为此,您可以将每个子图像的rect 保存到vector&lt;Rect&gt; smallImageRois;

然后您可以使用指针(请记住子图像不是连续的),或者只是使用copyTo 指向正确的位置:

看看:

#include <opencv2\opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;

int main()
{
    Mat3b img = imread("path_to_image");
    resize(img, img, Size(800, 800));

    Mat grayImg;
    cvtColor(img, grayImg, COLOR_BGR2GRAY);
    grayImg.convertTo(grayImg, CV_32F);

    int N = 4;

    if (((grayImg.rows % N) != 0) || ((grayImg.cols % N) != 0))
    {
        // Error
        return -1;
    }

    Size graySize = grayImg.size();
    Size smallSize(grayImg.cols / N, grayImg.rows / N);

    vector<Mat> smallImages;
    vector<Rect> smallImageRois;

    for (int i = 0; i < graySize.height; i += smallSize.height)
    {
        for (int j = 0; j < graySize.width; j += smallSize.width)
        {
            Rect rect = Rect(j, i, smallSize.width, smallSize.height);
            smallImages.push_back(grayImg(rect));
            smallImageRois.push_back(rect);
        }
    }

    // Option 1. Using pointer to subimage data.

    Mat big1(800, 800, CV_32F); 
    int big1step = big1.step1();

    float* pbig1 = big1.ptr<float>(0);

    for (int idx = 0; idx < smallImages.size(); ++idx)
    {
        float* pdata = (float*)smallImages[idx].data;
        int step = smallImages[idx].step1();
        Rect roi = smallImageRois[idx];

        for (int i = 0; i < smallSize.height; ++i)
        {
            for (int j = 0; j < smallSize.width; ++j)
            {
                pbig1[(roi.y + i) * big1step + (roi.x + j)] = pdata[i * step + j];
            }
        }
    }

    // Option 2. USing copyTo
    Mat big2(800, 800, CV_32F); 
    for (int idx = 0; idx < smallImages.size(); ++idx)
    {
        smallImages[idx].copyTo(big2(smallImageRois[idx]));
    }

    return 0;
}

【讨论】:

  • :太好了!谢谢!只是为了澄清(关于我上一篇文章的最后评论)。每个 smallmage(因此 pdata )的范围为 0-199,对吧?所以,图像 0 有 0-199 ,图像 1 有 0-199 等等。(赞成)
  • 您的子图像不是连续的(因为指的是原始图像的一部分)。例如,您看到对于第一个子图像,第一行的索引从 0 到 199,而第二行的索引从 800 到 999。如果将行更改为 smallImages.push_back(grayImg(rect).clone());,则每个子图像都是连续的,而对于第一个第一行从 0 到 199,第二行从 200 到 399
  • 代码在这两种情况下都能正常工作,因为您使用step而不是width访问pdata
  • :你好!我有一个问题。我期待,使用:cout &lt;&lt; "pointer = " &lt;&lt; (pdata + 1)[ i * step + j ] &lt;&lt; endl; cout &lt;&lt; "data = " &lt;&lt; smallmages[ idx +1].at&lt;int&gt;(i*step+j) &lt;&lt; endl; 产生相同的结果,但他们没有。不要(pdata+1) 指向smallImages[ idx + 1].data?谢谢提前!
  • 简答,不。我会尽快解释清楚
【解决方案2】:

为了将子图像连接成单个正方形图像,您可以使用以下函数:

// Important: all patches should have exactly the same size
Mat concatPatches(vector<Mat> &patches) {
    assert(patches.size() > 0);

    // make it square
    const int patch_width   = patches[0].cols;
    const int patch_height  = patches[0].rows;
    const int patch_stride  = ceil(sqrt(patches.size()));
    Mat image               = Mat::zeros(patch_stride * patch_height, patch_stride * patch_width, patches[0].type());

    for (size_t i = 0, iend = patches.size(); i < iend; i++) {
        Mat &patch = patches[i];
        const int offset_x = (i % patch_stride) * patch_width;
        const int offset_y = (i / patch_stride) * patch_height;

        // copy the patch to the output image
        patch.copyTo(image(Rect(offset_x, offset_y, patch_width, patch_height)));
    }

    return image;
}

它需要一个子图像向量(或我所指的补丁)并将它们连接成一个平方图像。用法示例:

vector<Mat> patches;
vector<Scalar> colours = {Scalar(255, 0, 0), Scalar(0, 255, 0), Scalar(0, 0, 255)};
// fill vector with circles of different colours
for(int i = 0; i < 16; i++) {
    Mat patch = Mat::zeros(100,100, CV_32FC3);
    circle(patch, Point(50,50), 40, colours[i % 3], -1);

    patches.push_back(patch);
}

Mat img = concatPatches(patches);
imshow("img", img);
waitKey();

会生成如下图片

【讨论】:

  • :谢谢你,但你能坚持我的具体代码吗?
  • Mat big = concatPatches(subImages); 应该这样做。
【解决方案3】:

在创建Mat mf之前打印ij的值,相信你很快就能发现错误。

提示 1:ij 第一次将是 0

提示 2:使用copyTo() 的 ROI 如下:

cv::Rect roi(0,0,200,200);
src.copyTo(dst(roi))

编辑:

提示3:尽量不要做这样的指针摆弄,你会遇到麻烦。特别是如果您忽略了该步骤(就像您似乎所做的那样)。

【讨论】:

  • 我编辑了Mat mf( i,j, CV_32F, pdata + 200 );,如果你的意思是步骤。我使用roi作为copyTo。我仍然有错误。至于i,j值?我认为它们没问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-22
  • 1970-01-01
  • 1970-01-01
  • 2020-10-30
  • 2019-07-10
  • 2015-04-01
  • 1970-01-01
相关资源
最近更新 更多