制作一个 Mat 类型对象的数组。输出 window 显示相同的帧
Making an array of Mat type objects. The output window shows the same frame
以下是我的代码。它有一个 Mat 类型对象数组。然后我将在 for 循环内创建的 Mat 添加为 imgArr[index] = img。但是当我输出所有帧来看window上的动画时,它只显示最后一帧并且显示同一帧。
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);
}
如果你像这样构造一个 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);
您的代码有很多地方不正确。我将尝试列出它们:
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]
替换为 char* buffer = new char[BytesPerImage];
。您还应该在循环之前预先分配这个中间缓冲区,以便您只需分配一次并多次使用它。然后,在循环之后,释放它: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
,则不会自动管理释放。最好以相反的方式进行:创建 Mat
然后将其用作缓冲区。它看起来像这样:
Mat img(MYHEIGHT, MYWIDTH, CV_16S); //
short* image = static_cast<short*> img.ptr();
进一步操作的一个问题是可能存在"padding bytes"。对于 512x512 图像不太可能,但谁知道呢。请断言以下内容为真(参见 doc):
(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
不是必需的:当您除以一个整数值时,它总是 return 结果的整数部分。此外,鉴于 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
已经提升像素数据
一个小插曲:min
和 max
更新函数可以写成:
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
Mat 创建已经处理完毕。
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);
以下是我的代码。它有一个 Mat 类型对象数组。然后我将在 for 循环内创建的 Mat 添加为 imgArr[index] = img。但是当我输出所有帧来看window上的动画时,它只显示最后一帧并且显示同一帧。
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);
}
如果你像这样构造一个 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);
您的代码有很多地方不正确。我将尝试列出它们:
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]
替换为 char* buffer = new char[BytesPerImage];
。您还应该在循环之前预先分配这个中间缓冲区,以便您只需分配一次并多次使用它。然后,在循环之后,释放它: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
,则不会自动管理释放。最好以相反的方式进行:创建 Mat
然后将其用作缓冲区。它看起来像这样:
Mat img(MYHEIGHT, MYWIDTH, CV_16S); //
short* image = static_cast<short*> img.ptr();
进一步操作的一个问题是可能存在"padding bytes"。对于 512x512 图像不太可能,但谁知道呢。请断言以下内容为真(参见 doc):
(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
不是必需的:当您除以一个整数值时,它总是 return 结果的整数部分。此外,鉴于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
已经提升像素数据一个小插曲:
min
和max
更新函数可以写成: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
Mat 创建已经处理完毕。
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);