如何从 'ravi' 文件中获取数据?
How can I get data from 'ravi' file?
ravi
文件是什么:
A RAVI file is a video file created by thermal imaging software, such
as Micro-Epsilon TIM Connect or Optris PIX Connect. It contains video
captured by thermal cameras and is saved in a format similar to the
Audio Video Interleave (.AVI) format. RAVI files also store
radiometric information, such as temperature and measurement area
information collected by the thermal camera.
我的问题:
我必须处理 ravi
文件中的数据。我需要像素的温度值(或者帧的最高温度对我来说足够了)。我想检查某个框架的最高温度。最终结果将是一份报告,其中包含帧上的最大温度值(这将是一个图表)。使用 Micro-Epsilon TIM Connect
或 Optris PIX Connect
工具很容易检查和处理,但我无法使用它们(我必须自己编写一个)。
我的问题:
- 如何从
ravi
文件中获取数据(实际上我只需要温度值)?
- 是否有转换器可以将
ravi
文件转换成另一个文件(如果我能从ravi
文件中获取数据则无关紧要)?
注:
- Python 语言是首选,但我对每个想法都持开放态度。
- 我必须使用
ravi
文件,但我无法录制新文件或修改
正在录音。
- 我找到了一个为这种相机提供
SDK
的网站
但我不清楚从 ravi
文件获取数据是
可能的。 Link 到 libirimager2
文档:libirimager2
- 如果我用媒体播放器播放
ravi
文件然后它说使用
codeck 是:Uncompressed packed YUV 4:2:2
(你可以看到越来越
下面的流)
如果我用 OpenCV
解析它或用媒体播放器播放,我可以看到一些流。但是我不确定如何获得温度...
CV2代码:
import cv2
cap = cv2.VideoCapture("my_test.ravi")
if not cap.isOpened():
print("Error opening video stream or file")
while cap.isOpened():
ret, frame = cap.read()
if ret:
cv2.imshow('Frame', frame)
if cv2.waitKey(25) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
获取流:
(我在简单的媒体播放器中也看到相同的 "pink and green" 流。)
官方软件中的流:
ravi
HexEditor 中的文件:
我找到了一个关于 AVI video format 的网站。您可以在下面看到我的文件中的一些行,也许它可以提供帮助。
00000000 52 49 46 46 F8 B1 C6 3F 41 56 49 20 4C 49 53 54 RIFF...?AVI LIST
00000010 CC 7F 00 00 68 64 72 6C 61 76 69 68 38 00 00 00 ....hdrlavih8...
00000020 12 7A 00 00 44 FF DD 00 00 02 00 00 10 08 00 00 .z..D...........
00000030 44 6D 00 00 00 00 00 00 01 00 00 00 08 65 09 00 Dm...........e..
00000040 80 02 00 00 E1 01 00 00 00 00 00 00 00 00 00 00 ................
00000050 00 00 00 00 00 00 00 00 4C 49 53 54 74 7E 00 00 ........LISTt~..
00000060 73 74 72 6C 73 74 72 68 38 00 00 00 76 69 64 73 strlstrh8...vids
00000070 59 55 59 32 00 00 00 00 00 00 00 00 00 00 00 00 YUY2............
00000080 B4 C4 04 00 80 96 98 00 00 00 00 00 A4 50 00 00 .............P..
00000090 08 65 09 00 00 00 00 00 00 00 00 00 00 00 00 00 .e..............
000000A0 00 00 00 00 73 74 72 66 28 00 00 00 28 00 00 00 ....strf(...(...
000000B0 80 02 00 00 E1 01 00 00 01 00 10 00 59 55 59 32 ............YUY2
000000C0 00 65 09 00 60 00 00 00 60 00 00 00 00 00 00 00 .e..`...`.......
000000D0 00 00 00 00 69 6E 64 78 F8 7D 00 00 04 00 00 00 ....indx.}......
000000E0 06 00 00 00 30 30 64 62 00 00 00 00 00 00 00 00 ....00db........
测试资料:
如果您从 http://infrarougekelvin.com/en/optris-logiciel-eng/ 站点下载 PIX Connect Rel. 3.6.3046.0 Software
,您可以在 zip 内的 "Samples" 文件夹中找到几个 ravi
文件。
来自官方文档的附加信息:
Software for thermoIMAGER TIM Infrared camera documentation
视频序列既可以保存为辐射文件 (RAVI) 也可以保存为非辐射文件 (AVI)。 RAVI文件
包含所有温度以及测量区域信息。
如果是辐射记录,请参阅第 1 章。 5.6.2、未激活图片将保存为标准AVI文件
只包含颜色信息。稍后将 RAVI 文件转换为 AVI 文件,反之亦然
可能
更新:
我试过使用PyAV
模块获取数据。该模块能够处理 yuyv422
格式。我得到了相同的 "green-pink" 流,但无法从中获取温度...
使用代码:
# coding=utf-8
import av
import os
ravi_path = "Brake disc.ravi"
container = av.open(ravi_path)
stream = container.streams.video[0]
stream.codec_context.skip_frame = 'NONKEY'
tgt_path = "frames"
if not os.path.isdir(tgt_path):
os.makedirs(tgt_path)
for frame in container.decode(stream):
tgt_filename = os.path.join(tgt_path, 'frame-{:09d}.jpg'.format(frame.pts))
print(frame, tgt_filename)
frame.to_image().save(tgt_filename, quality=80)
脚本输出:
>>> python ravi_test2.py
(<av.VideoFrame #0, pts=0 yuyv422 160x121 at 0x7f501bfa8598>, 'frames/frame-000000000.jpg')
(<av.VideoFrame #1, pts=1 yuyv422 160x121 at 0x7f501bfa8600>, 'frames/frame-000000001.jpg')
(<av.VideoFrame #2, pts=2 yuyv422 160x121 at 0x7f5018e0fdb8>, 'frames/frame-000000002.jpg')
(<av.VideoFrame #3, pts=3 yuyv422 160x121 at 0x7f501bfa8598>, 'frames/frame-000000003.jpg')
(<av.VideoFrame #4, pts=4 yuyv422 160x121 at 0x7f501bfa8600>, 'frames/frame-000000004.jpg')
(<av.VideoFrame #5, pts=5 yuyv422 160x121 at 0x7f5018e0fdb8>, 'frames/frame-000000005.jpg')
我不知道你的相机品牌,但希望视频文件包含原始传感器值作为 16 位无符号整数,可能只是在视频中命名为 YUV422 header,因为它们符合同样每像素 16 位。
您可以通过特定的 non-linear 校准曲线将这些值转换为实际温度值。如果 RAVI-format 是单一文件格式(与某些带有 raw-AVI + 校准 table 的遗留 IR-cameras 相对),那么您应该找到几个浮点常量的位置 and/or table,组成等式
可以对逻辑进行逆向工程,但最好向制造商询问正确的方程式。例如,您在互联网上找到的可能只是校准曲线的旧版本。大多数制造商都随设备一起提供校准库。有些 out-of-product 自行车设备可能很难协商,但您至少应该获得有关该主题的白皮书。
如果您使用 OpenCV,您需要读取原始的 YUV422 帧(16bpp,而不是 24bpp)并在应用查找之前将它们的上下文重新解释为 uint16 table。
// sample C++ code employing private content of OpenCV library
// Particularly container_avi.private.hpp and container_avi.cpp
void mainactual()
{
cv::AVIReadContainer reader;
reader.initStream(cv::String("C:/tello/intro2.avi"));
cv::frame_list frames;
// initializes the stream
reader.parseRiff( frames );
std::cout << "Number of frames: " << frames.size() << std::endl;
int w=reader.getWidth();
int h=reader.getHeight();
std::cout << "size " << cv::Size(w,h) << std::endl;
// a frame in the middle
cv::frame_iterator it=frames.begin() + frames.size()/2;
std::vector< char> data = reader.readFrame( it );
// In your case, data here is supposed to be
// uncompressed YUV422 which is w * h * 2 bytes per frame
// You might need to modify
// bool AVIReadContainer::parseStrl(char stream_id, Codecs codec_)
// to accept your FCC
//
//
//if ( data.size()!=w*h*2 )
//{
// // error
//}
// My video is MJPEG, so I'm confident to just to decode it
cv::Mat img = cv::imdecode( data, cv::IMREAD_UNCHANGED );
cv::imshow("image", img ); // looks fine
cv::waitKey( 0 );
reader.close();
}
编辑:经过测试的制动器 disk.ravi,如下所示。修改解析器以接受未压缩的 YUV2 格式并根据 https://docs.microsoft.com/en-us/previous-versions/windows/desktop/api/Aviriff/ns-aviriff-avioldindex
添加 hack
dwOffset
Specifies the location of the data chunk in the file. The value should be specified as an offset, in bytes, from the start of the 'movi' list; however, in some AVI files it is given as an offset from the start of the file.
cv::Mat img;
if ( data.size()==w*h*2 )
{
std::cout << data.size() << " " << w*h*2 << std::endl;
cv::Mat t( h, w, CV_16UC1, &data[0] );
// img(y,x) = (float)t(y,x)/10.0 - 100.0
t.convertTo( img, CV_32F, 0.1, -100.0 );
}else
return;
double mi,ma;
cv::minMaxLoc( img, &mi, &ma );
std::cout << "range: [" << mi << ", " << ma << "]" << std::endl;
cv::Mat gray;
img.convertTo( gray, CV_8U ); // [0, 255] range saturated
cv::Mat bigger;
cv::resize(gray,bigger,cv::Size(4*w,4*h),0,0,cv::INTER_LINEAR );
cv::Mat jet;
cv::applyColorMap( bigger, jet, cv::COLORMAP_JET );
cv::imshow("image", jet ); // looks fine
cv::waitKey( 0 );
reader.close();
我从仅红外摄像机的一些镜头中发现了什么:
- 帧有一个额外的第一行,用于保存每帧元数据。它应该被丢弃以供展示。
- 图像数据缓冲区帧包含与温度相关的 16 位值(每个像素两个字节,低字节在前)。我可以用 <0.01C 残差拟合一个 4 阶多项式,但它不是完全线性的。它可能是对数的,而不是多项式的。
- 请注意,根据 micro-epsilon 文档,最多可能有 3 行元数据。该格式可能与相机有关,我无法解释第一行元数据。
我不知道来自同一个 .ravi 的所有帧是否具有相同的校准。
校准元数据行从一帧到下一帧非常相似,只有三个 16 位值略有不同(采用两个不同的值),并且每帧一个递增 1。
float t = (float)data[i] / 10.f - 100.f
公式并没有真正产生匹配的温度。
结论:只有使用提供的libirimager才能计算出标定元数据。它也可能依赖于供应商...
ravi
文件是什么:
A RAVI file is a video file created by thermal imaging software, such as Micro-Epsilon TIM Connect or Optris PIX Connect. It contains video captured by thermal cameras and is saved in a format similar to the Audio Video Interleave (.AVI) format. RAVI files also store radiometric information, such as temperature and measurement area information collected by the thermal camera.
我的问题:
我必须处理 ravi
文件中的数据。我需要像素的温度值(或者帧的最高温度对我来说足够了)。我想检查某个框架的最高温度。最终结果将是一份报告,其中包含帧上的最大温度值(这将是一个图表)。使用 Micro-Epsilon TIM Connect
或 Optris PIX Connect
工具很容易检查和处理,但我无法使用它们(我必须自己编写一个)。
我的问题:
- 如何从
ravi
文件中获取数据(实际上我只需要温度值)? - 是否有转换器可以将
ravi
文件转换成另一个文件(如果我能从ravi
文件中获取数据则无关紧要)?
注:
- Python 语言是首选,但我对每个想法都持开放态度。
- 我必须使用
ravi
文件,但我无法录制新文件或修改 正在录音。 - 我找到了一个为这种相机提供
SDK
的网站 但我不清楚从ravi
文件获取数据是 可能的。 Link 到libirimager2
文档:libirimager2 - 如果我用媒体播放器播放
ravi
文件然后它说使用 codeck 是:Uncompressed packed YUV 4:2:2
(你可以看到越来越 下面的流)
如果我用 OpenCV
解析它或用媒体播放器播放,我可以看到一些流。但是我不确定如何获得温度...
CV2代码:
import cv2
cap = cv2.VideoCapture("my_test.ravi")
if not cap.isOpened():
print("Error opening video stream or file")
while cap.isOpened():
ret, frame = cap.read()
if ret:
cv2.imshow('Frame', frame)
if cv2.waitKey(25) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
获取流:
(我在简单的媒体播放器中也看到相同的 "pink and green" 流。)
官方软件中的流:
ravi
HexEditor 中的文件:
我找到了一个关于 AVI video format 的网站。您可以在下面看到我的文件中的一些行,也许它可以提供帮助。
00000000 52 49 46 46 F8 B1 C6 3F 41 56 49 20 4C 49 53 54 RIFF...?AVI LIST
00000010 CC 7F 00 00 68 64 72 6C 61 76 69 68 38 00 00 00 ....hdrlavih8...
00000020 12 7A 00 00 44 FF DD 00 00 02 00 00 10 08 00 00 .z..D...........
00000030 44 6D 00 00 00 00 00 00 01 00 00 00 08 65 09 00 Dm...........e..
00000040 80 02 00 00 E1 01 00 00 00 00 00 00 00 00 00 00 ................
00000050 00 00 00 00 00 00 00 00 4C 49 53 54 74 7E 00 00 ........LISTt~..
00000060 73 74 72 6C 73 74 72 68 38 00 00 00 76 69 64 73 strlstrh8...vids
00000070 59 55 59 32 00 00 00 00 00 00 00 00 00 00 00 00 YUY2............
00000080 B4 C4 04 00 80 96 98 00 00 00 00 00 A4 50 00 00 .............P..
00000090 08 65 09 00 00 00 00 00 00 00 00 00 00 00 00 00 .e..............
000000A0 00 00 00 00 73 74 72 66 28 00 00 00 28 00 00 00 ....strf(...(...
000000B0 80 02 00 00 E1 01 00 00 01 00 10 00 59 55 59 32 ............YUY2
000000C0 00 65 09 00 60 00 00 00 60 00 00 00 00 00 00 00 .e..`...`.......
000000D0 00 00 00 00 69 6E 64 78 F8 7D 00 00 04 00 00 00 ....indx.}......
000000E0 06 00 00 00 30 30 64 62 00 00 00 00 00 00 00 00 ....00db........
测试资料:
如果您从 http://infrarougekelvin.com/en/optris-logiciel-eng/ 站点下载 PIX Connect Rel. 3.6.3046.0 Software
,您可以在 zip 内的 "Samples" 文件夹中找到几个 ravi
文件。
来自官方文档的附加信息:
Software for thermoIMAGER TIM Infrared camera documentation
视频序列既可以保存为辐射文件 (RAVI) 也可以保存为非辐射文件 (AVI)。 RAVI文件 包含所有温度以及测量区域信息。
如果是辐射记录,请参阅第 1 章。 5.6.2、未激活图片将保存为标准AVI文件 只包含颜色信息。稍后将 RAVI 文件转换为 AVI 文件,反之亦然 可能
更新:
我试过使用PyAV
模块获取数据。该模块能够处理 yuyv422
格式。我得到了相同的 "green-pink" 流,但无法从中获取温度...
使用代码:
# coding=utf-8
import av
import os
ravi_path = "Brake disc.ravi"
container = av.open(ravi_path)
stream = container.streams.video[0]
stream.codec_context.skip_frame = 'NONKEY'
tgt_path = "frames"
if not os.path.isdir(tgt_path):
os.makedirs(tgt_path)
for frame in container.decode(stream):
tgt_filename = os.path.join(tgt_path, 'frame-{:09d}.jpg'.format(frame.pts))
print(frame, tgt_filename)
frame.to_image().save(tgt_filename, quality=80)
脚本输出:
>>> python ravi_test2.py
(<av.VideoFrame #0, pts=0 yuyv422 160x121 at 0x7f501bfa8598>, 'frames/frame-000000000.jpg')
(<av.VideoFrame #1, pts=1 yuyv422 160x121 at 0x7f501bfa8600>, 'frames/frame-000000001.jpg')
(<av.VideoFrame #2, pts=2 yuyv422 160x121 at 0x7f5018e0fdb8>, 'frames/frame-000000002.jpg')
(<av.VideoFrame #3, pts=3 yuyv422 160x121 at 0x7f501bfa8598>, 'frames/frame-000000003.jpg')
(<av.VideoFrame #4, pts=4 yuyv422 160x121 at 0x7f501bfa8600>, 'frames/frame-000000004.jpg')
(<av.VideoFrame #5, pts=5 yuyv422 160x121 at 0x7f5018e0fdb8>, 'frames/frame-000000005.jpg')
我不知道你的相机品牌,但希望视频文件包含原始传感器值作为 16 位无符号整数,可能只是在视频中命名为 YUV422 header,因为它们符合同样每像素 16 位。
您可以通过特定的 non-linear 校准曲线将这些值转换为实际温度值。如果 RAVI-format 是单一文件格式(与某些带有 raw-AVI + 校准 table 的遗留 IR-cameras 相对),那么您应该找到几个浮点常量的位置 and/or table,组成等式
可以对逻辑进行逆向工程,但最好向制造商询问正确的方程式。例如,您在互联网上找到的可能只是校准曲线的旧版本。大多数制造商都随设备一起提供校准库。有些 out-of-product 自行车设备可能很难协商,但您至少应该获得有关该主题的白皮书。
如果您使用 OpenCV,您需要读取原始的 YUV422 帧(16bpp,而不是 24bpp)并在应用查找之前将它们的上下文重新解释为 uint16 table。
// sample C++ code employing private content of OpenCV library
// Particularly container_avi.private.hpp and container_avi.cpp
void mainactual()
{
cv::AVIReadContainer reader;
reader.initStream(cv::String("C:/tello/intro2.avi"));
cv::frame_list frames;
// initializes the stream
reader.parseRiff( frames );
std::cout << "Number of frames: " << frames.size() << std::endl;
int w=reader.getWidth();
int h=reader.getHeight();
std::cout << "size " << cv::Size(w,h) << std::endl;
// a frame in the middle
cv::frame_iterator it=frames.begin() + frames.size()/2;
std::vector< char> data = reader.readFrame( it );
// In your case, data here is supposed to be
// uncompressed YUV422 which is w * h * 2 bytes per frame
// You might need to modify
// bool AVIReadContainer::parseStrl(char stream_id, Codecs codec_)
// to accept your FCC
//
//
//if ( data.size()!=w*h*2 )
//{
// // error
//}
// My video is MJPEG, so I'm confident to just to decode it
cv::Mat img = cv::imdecode( data, cv::IMREAD_UNCHANGED );
cv::imshow("image", img ); // looks fine
cv::waitKey( 0 );
reader.close();
}
编辑:经过测试的制动器 disk.ravi,如下所示。修改解析器以接受未压缩的 YUV2 格式并根据 https://docs.microsoft.com/en-us/previous-versions/windows/desktop/api/Aviriff/ns-aviriff-avioldindex
添加 hackdwOffset
Specifies the location of the data chunk in the file. The value should be specified as an offset, in bytes, from the start of the 'movi' list; however, in some AVI files it is given as an offset from the start of the file.
cv::Mat img;
if ( data.size()==w*h*2 )
{
std::cout << data.size() << " " << w*h*2 << std::endl;
cv::Mat t( h, w, CV_16UC1, &data[0] );
// img(y,x) = (float)t(y,x)/10.0 - 100.0
t.convertTo( img, CV_32F, 0.1, -100.0 );
}else
return;
double mi,ma;
cv::minMaxLoc( img, &mi, &ma );
std::cout << "range: [" << mi << ", " << ma << "]" << std::endl;
cv::Mat gray;
img.convertTo( gray, CV_8U ); // [0, 255] range saturated
cv::Mat bigger;
cv::resize(gray,bigger,cv::Size(4*w,4*h),0,0,cv::INTER_LINEAR );
cv::Mat jet;
cv::applyColorMap( bigger, jet, cv::COLORMAP_JET );
cv::imshow("image", jet ); // looks fine
cv::waitKey( 0 );
reader.close();
我从仅红外摄像机的一些镜头中发现了什么:
- 帧有一个额外的第一行,用于保存每帧元数据。它应该被丢弃以供展示。
- 图像数据缓冲区帧包含与温度相关的 16 位值(每个像素两个字节,低字节在前)。我可以用 <0.01C 残差拟合一个 4 阶多项式,但它不是完全线性的。它可能是对数的,而不是多项式的。
- 请注意,根据 micro-epsilon 文档,最多可能有 3 行元数据。该格式可能与相机有关,我无法解释第一行元数据。
我不知道来自同一个 .ravi 的所有帧是否具有相同的校准。 校准元数据行从一帧到下一帧非常相似,只有三个 16 位值略有不同(采用两个不同的值),并且每帧一个递增 1。
float t = (float)data[i] / 10.f - 100.f
公式并没有真正产生匹配的温度。
结论:只有使用提供的libirimager才能计算出标定元数据。它也可能依赖于供应商...