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

mil*_*azs 5 python video opencv image-processing 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()
Run Code Online (Sandbox Code Playgroud)

正在流式传输:

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

显示的CV2框架

在官方软件中流式传输:

在此处输入图片说明

ravi HexEditor中的文件:

我找到了一个有关AVI视频格式的网站。您可以从我的文件乞求下面看到几行,也许可以帮上忙。

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........
Run Code Online (Sandbox Code Playgroud)

测试材料:

如果您PIX Connect Rel. 3.6.3046.0 Softwarehttp://infrarougekelvin.com/en/optris-logiciel-eng/网站下载,则可以ravi在zip的“ Samples”文件夹中找到几个文件。

官方文档中的其他信息:

ThermoIMAGER TIM红外摄像机文档的软件

视频序列既可以保存为辐射文件(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)
Run Code Online (Sandbox Code Playgroud)

脚本的输出:

>>> 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')
Run Code Online (Sandbox Code Playgroud)

mai*_*ual 4

我不知道您的相机品牌,但期望视频文件包含 16 位无符号整数形式的原始传感器值,这可能只是在视频标头中命名为 YUV422,因为它们适合相同的每像素 16 位。

您可以通过特定的非线性校准曲线将这些值转换为实际温度值。如果 RAVI 格式是单一文件格式(与某些具有原始 AVI + 校准表的传统红外摄像机相反),那么您应该找到构成方程的几个浮点常数和/或表的位置。

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

如果您使用 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();
}
Run Code Online (Sandbox Code Playgroud)

编辑:经过测试的制动盘.ravi,如下所示。修改了解析器以接受未压缩的 YUV2 格式,并根据https://learn.microsoft.com/en-us/previous-versions/windows/desktop/api/Aviriff/ns-aviriff-avioldindex添加了一个 hack

dw偏移量

指定文件中数据块的位置。该值应指定为从“movi”列表开头的偏移量(以字节为单位);然而,在某些 AVI 文件中,它是以距文件开头的偏移量形式给出的。

不知道拼字是什么,但看起来像刹车盘。 在此输入图像描述

    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();
Run Code Online (Sandbox Code Playgroud)