制作垫子类型对象的数组.输出窗口显示同一帧

Making an array of Mat type objects. The output window shows the same frame

本文关键字:显示 一帧 窗口 输出 类型 对象 数组      更新时间:2023-10-16

以下是我的代码。它具有垫子类型对象的数组。我将垫子内部添加为for循环,为imgarr [index] = img。但是,当我输出所有帧以查看窗口上的动画时,它只是显示了最后一个帧并显示了相同的帧。

namedWindow( "Display window", WINDOW_AUTOSIZE );// Create a window for display.
int numFrames = endFrame - startFrame;          // Total number of frames
Mat imgArr[100];
for(long int FrameNumber = startFrame; FrameNumber < endFrame; FrameNumber++){
    fp.seekg( BytesPerFrame*(FrameNumber), std::ios::beg);
    char buffer[BytesPerImage];
    fp.read(buffer, BytesPerImage);
    short image[512*512];
    short min = 20000, max=1000;

    for ( int i = 0; i < BytesPerImage; i=i+2 )
    {
        int a;
        a = floor(i/2)+1;
        //  take first character
        image[a] = (static_cast<unsigned int>(static_cast<unsigned char>(buffer[i+1]))*256+static_cast<unsigned int>(static_cast<unsigned char>(buffer[i])));
        if(image[a] < min){
            min = image[a];
        }
        if(image[a] > max){
            max = image[a];
        }
    }
    // Processing the image
    Mat img(512, 512, CV_16S, image);
    img -= (min);
    img *= (32767/max); // (330000/2500);
    img *= ((max/min)/2) + 2;    // 16;
    imgArr[FrameNumber-startFrame] = img;
}
for(int i = 0; i<numFrames; i++){
    imshow( "Display window", imgArr[i]);                   // Show our image inside it.
    waitKey(50);
}

您的代码有很多事情。我将尝试列出它们:

namedWindow( "Display window", WINDOW_AUTOSIZE );// Create a window for display.
int numFrames = endFrame - startFrame;          // Total number of frames
Mat imgArr[100];

第一个问题:如果您的帧数numFrames大于100怎么办?这会更安全:

std::vector<Mat> imgVector;
imgVector.reserve(numFrames);

,然后在每个新框架下您的 push_back图像。让我们继续。

for(long int FrameNumber = startFrame; FrameNumber < endFrame; FrameNumber++){
    fp.seekg( BytesPerFrame*(FrameNumber), std::ios::beg); //Hmmm, when did you compute BytesPerFrame?
    char buffer[BytesPerImage]; //This is actually not C++, you probably even got a warning

您应该用char buffer[BytesPerImage]替换CC_4。您还应该在循环之前先对此中间缓冲区进行预先分配,以便您仅分配一次并使用它多次。然后,在循环之后,您将其分配为:delete[] buffer;

    fp.read(buffer, BytesPerImage); //This seems fine
    short image[512*512]; //What's this?

什么是512?我稍后可以理解查看您的代码,但是您应该在某个地方定义以下位置:

const int MYWIDTH = 512;
const int MYHEIGHT = 512;
const int BYTES_PER_IMAGE = MYWIDTH * MYHEIGHT * 2; //Maybe also the 2 should be a constant named `BYTES_PER_PIXEL`

另外,在这种情况下,让我们用short* image = new short[MYWIDTH*MYHEIGHT];动态分配数据。但是,这无法正常工作:不幸的是,如果您从外部缓冲区构建Mat,则不会自动管理DealLocation。最好以相反的方式进行:创建您的Mat,然后将其用作缓冲区。看起来像这样:

    Mat img(MYHEIGHT, MYWIDTH, CV_16S); //
    short* image = static_cast<short*> img.ptr();

进一步操作的一个问题是可能存在"填充字节"。对于512x512图像,它不太可能,但谁知道。请断言以下内容是正确的(请参阅文档):

    (img.cols == img.step1() )

然后:

    short min = 20000, max=1000; 

为什么不max=0?另外,min可以初始化为32767,或更优雅地到std::numeric_limits<short>::max()#include <limits.h>

    for ( int i = 0; i < BytesPerImage; i=i+2 )
    {
        int a;
        a = floor(i/2)+1;
        //  take first character
        image[a] = (static_cast<unsigned int>(static_cast<unsigned char>(buffer[i+1]))*256+static_cast<unsigned int>(static_cast<unsigned char>(buffer[i])));
        if(image[a] < min){
            min = image[a];
        }
        if(image[a] > max){
            max = image[a];
        }
    }

我理解的是:您的输入缓冲区是一个16位图像,以大型末日表示(最重要的字节是在最不重要的意义之前)。我看到的问题:

  • 如果最重要的字节超过127,该怎么办?然后,您的输出值将溢出,如128*256=32768 > 32767
  • floor(i/2)floor不是必需的:当您划分整数值时,它总是返回结果的整数部分。另外,鉴于您的for循环的定义,i始终是偶数(您增加2),因此floor操作是两次不必要的。。
  • int a; a = floor(i/2)+1;删除+1:对0索引像素进行思考,您会立即看到将值分配给错误的像素。使用最后一个像素,您实际上将有一个分段故障。您的指示变为:const int a = i/2;(EHI,多么简单!:))
  • image[a] = [...];:您正在做的某些演员是有效的,尤其是unsigned char的演员。不过,我想知道,为什么不首先将buffer读为unsigned char的缓冲区。所有的unsigned int转换都可以省略,因为您不需要它的最低字节,而使用整数 256已经可以促进像素数据
  • 客串:minmax更新功能可以写为:

    min = std::min(min,image[a]);
    max = std::max(max,image[a]);
    

让我们继续:

    // Processing the image
    Mat img(512, 512, CV_16S, image); //Already done, now remove

垫子的创作已经得到照顾。

   img -= (min);
   img *= (32767/max); // (330000/2500);

好吧,使用OpenCV库具有更容易的当量,我们稍后会谈论它。这里的一个问题:这次您应该真正使用float作为您的部门

   img *= (float(32767)/max);

顺便说一句,我认为在这种情况下,您想要分母的max-min

   img *= (float(32767)/(max-min));

以下我不明白:

   img *= ((max/min)/2) + 2;    // 16;

寻找进一步,

 imgArr[FrameNumber-startFrame] = img;

鉴于我在上面建议的更改(图像的std::vector),这变为:

 imgVector.push_back(img); 

完成!


最后一个注意:在我看来,您要尝试使用cv::normalize可以获得您的工作。您可以做:

cv::normalize(img, img, 0, 32767, NORM_MINMAX, CV_16UC1);

如果您构造了一个cv :: mat这样:

short pixels[512*512];
Mat img(512, 512, CV_16S, pixels);

离开范围后,指向像素的指针将无效。

要么克隆垫子:

imgArr[FrameNumber-startFrame] = img.clone();

或预先分配它,然后阅读现有像素:

Mat img(512, 512, CV_16S);
fp.read(img.data, BytesPerImage);

也:请用:

替换整个for ( int i = 0; i < BytesPerImage; i=i+2 )(恐怖!)循环
double minVal,maxVal;
minMaxLoc(img, &minVal, &maxVal, 0,0);