如何从“ ravi”文件中获取数据?

时间:2019-11-17 11:27:40

标签: python opencv image-processing video ravi

什么是ravi文件:

  

RAVI文件是由热成像软件创建的视频文件,例如   作为Micro-Epsilon TIM Connect或Optris PIX Connect。它包含视频   由热像仪捕获并以类似于   音频视频交错(.AVI)格式。 RAVI文件也存储   辐射信息,例如温度和测量区域   热像仪收集的信息。

我的问题:

我必须处理ravi文件中的数据。我需要像素的温度值(或者帧的最高温度足以满足我的需要)。我想检查特定框架上的最高温度。最终结果将是一个报告,其中包含框架上的最高温度值(这将是图形)。使用Micro-Epsilon TIM ConnectOptris PIX Connect工具很容易检查和处理,但是我无法使用它们(我必须编写自己的工具)。

我的问题:

  • 如何从ravi文件中获取数据(实际上我只需要温度值)?
  • 是否有转换器将ravi文件转换为另一个文件(是否可以从ravi文件中获取数据无关?)

注意:

  • Python语言是首选,但我愿意接受每个想法。
  • 我必须使用ravi文件,但无法记录新文件或修改 录音。
  • 我找到了一个为此类摄像机提供SDK的站点 但是我不清楚从ravi文件中获取数据是 可能。链接到libirimager2文档:libirimager2
  • 如果我使用媒体播放器播放ravi文件,则会显示已使用 编解码器为: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()

获取视频流:

(我在一个简单的媒体播放器中也看到了相同的“粉红色和绿色”流。)

shown CV2 frame

官方软件中的流:

enter image description here

HepEditor中的

ravi文件:

我找到了一个有关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文件 包含所有温度以及测量区域信息。

如果是辐射记录,请参见第15章。 5.6.2,未激活的图像将另存为标准AVI文件 仅包含颜色信息。后来无法将RAVI文件转换为AVI文件,反之亦然 可能

更新

我尝试使用PyAV模块来获取数据。此模块能够处理yuyv422格式。我得到了相同的“绿色粉红色”流,但无法从中获取温度...

使用的代码:

# 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')

2 个答案:

答案 0 :(得分:4)

我不知道您的相机的型号,但希望视频文件包含原始传感器值,如16位无符号整数,在视频标题中可能只是将其命名为YUV422,因为它们适合每个像素16位。

您可以通过特定的非线性校准曲线将这些值转换为实际值温度。如果RAVI格式是单一文件格式(与某些带有raw-AVI +校准表的传统IR摄像机相反),则应找到组成方程的少数浮点常数和/或表的位置。

可以对逻辑进行逆向工程,但是最好向制造商询问正确的方程式。例如,您在互联网上找到的内容可能只是校准曲线的旧版本。大多数制造商都与他们的设备一起提供校准库。某些产品停产的周期设备可能很难协商,但是您至少应该获得有关该主题的白皮书。

如果使用OpenCV,则需要读取YUV422原始帧(16bpp,而不是24bpp),并在应用查找表之前将其上下文重新解释为uint16。

// 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

     

指定文件中数据块的位置。该值应指定为距“电影”列表开头的偏移量(以字节为单位);但是,在某些AVI文件中,它是相对于文件开头的偏移量。

不确定拼字游戏是什么,但看起来像刹车盘。 enter image description here

    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();

答案 1 :(得分:1)

我从仅红外相机拍摄的一些镜头中发现了什么:

  • 帧具有额外的第一行,其中包含每帧元数据。应该将其丢弃以显示。
  • 图像数据缓冲区帧保存与温度有关的16位值(每个像素两个字节,低字节在前)。我可以用残差<0.01C拟合4阶多项式,但是它不是完全线性的。它可能是对数的,而不是多项式的。
  • 请注意,根据微型epsilon文档,最多可能有3行元数据。该格式可能取决于相机,并且我无法解释第一行元数据。

我不知道来自同一.ravi的所有帧是否具有相同的校准。 校准元数据行从一帧到下一帧非常相似,只有三个16位值略有不同(取两个不同的值),并且每帧一个递增一个。

float t = (float)data[i] / 10.f - 100.f公式不能真正产生匹配的温度。

结论:只有使用提供的libirimager才能计算出校准元数据。也可能是供应商所依赖的...