2015-01-26 6 views
0

Как сохранить кадр через TangoService_connectOnFrameAvailable() и правильно отобразить его на моем компьютере? Как упоминает this reference page, пиксели сохраняются в формате HAL_PIXEL_FORMAT_YV12. В моей функции обратного вызова для TangoService_connectOnFrameAvailable, я сохранить кадр, как это:Сохранить рамку от TangoService_connectOnFrameAvailable

static void onColorFrameAvailable(void* context, TangoCameraId id, const TangoImageBuffer* buffer) 
{ 
    ... 
    std::ofstream fp; 
    fp.open(imagefile, std::ios::out | std::ios::binary); 
    int offset = 0; 
    for(int i = 0; i < buffer->height*2 + 1; i++) { 
    fp.write((char*)(buffer->data + offset), buffer->width); 
    offset += buffer->stride; 
    } 
    fp.close(); 
} 

Тогда, чтобы избавиться от мета-данных в первой строке и для отображения изображения я бегу:

$ dd if="input.raw" of="new.raw" bs=1 skip=1280 
$ vooya new.raw 

Я был осторожно, чтобы в vooya убедиться, что порядок каналов yvu. Полученный результат: yv12 test image

Что я делаю неправильно, сохраняя изображение и отображая его?

UPDATE в ответ Марк Mullin в:

int offset = buffer->stride; // header offset 
// copy Y channel 
for(int i = 0; i < buffer->height; i++) { 
    fp.write((char*)(buffer->data + offset), buffer->width); 
    offset += buffer->stride; 
} 
// copy V channel 
for(int i = 0; i < buffer->height/2; i++) { 
    fp.write((char*)(buffer->data + offset), buffer->width/2); 
    offset += buffer->stride/2; 
} 
// copy U channel 
for(int i = 0; i < buffer->height/2; i++) { 
    fp.write((char*)(buffer->data + offset), buffer->width/2); 
    offset += buffer->stride/2; 
} 

Это теперь показывает рисунок ниже, но все еще есть некоторые артефакты; Интересно, это из камеры планшета Tango или моей обработки необработанных данных ... какие-то мысли?

yv12 test 2

ответ

1

Не могу точно сказать, что вы делаете неправильно, и танго изображения часто имеют артефакты в них - твоя новая, но я часто вижу ребенка синий как цвет, где яркий свет, кажется, раздражает глубокие системы , и по мере того, как он начинает терять синхронизацию с системой глубины под нагрузкой, вы часто увидите, что выглядит как блестящая сетка (я думаю, это шаблон IR). В конце любая рациональная попытка обрабатывать изображение с помощью openCV и т. д. не удалось, поэтому я вручную написал декодер с некоторой помощью от SO thread here

Это сказало, что данный imagebuffer содержит указатель на необработанные данные из Tango и различные другие переменные, такие как высота и шаг заполняются из данных, полученных в обратном вызове, тогда эта логика создаст карту RGBA - да, я оптимизировал математику в ней, поэтому она немного уродлива - она ​​медленнее, но функционально эквивалентный двойник указан второй. Мой собственный опыт говорит о своей ужасной идее попробовать и сделать это декодирование прямо в обратном вызове (я считаю, что Tango способно потерять синхронизацию со вспышкой для глубины по чисто злобным причинам), поэтому мои работы проходят на этапе визуализации.

Быстрая

uchar* pData = TangoData::cameraImageBuffer; 
uchar* iData = TangoData::cameraImageBufferRGBA; 
int size = (int)(TangoData::imageBufferStride * TangoData::imageBufferHeight); 
float invByte = 0.0039215686274509803921568627451; // (1/255) 

int halfi, uvOffset, halfj, uvOffsetHalfj; 
float y_scaled, v_scaled, u_scaled; 
int uOffset = size/4 + size; 
int halfstride = TangoData::imageBufferStride/2; 
for (int i = 0; i < TangoData::imageBufferHeight; ++i) 
{ 
    halfi = i/2; 
    uvOffset = halfi * halfstride; 
    for (int j = 0; j < TangoData::imageBufferWidth; ++j) 
    { 
     halfj = j/2; 
     uvOffsetHalfj = uvOffset + halfj; 
     y_scaled = pData[i * TangoData::imageBufferStride + j] * invByte; 
     v_scaled = 2 * (pData[uvOffsetHalfj + size] * invByte - 0.5f) * Vmax; 
     u_scaled = 2 * (pData[uvOffsetHalfj + uOffset] * invByte - 0.5f) * Umax; 
     *iData++ = (uchar)((y_scaled + 1.13983f * v_scaled) * 255.0);; 
     *iData++ = (uchar)((y_scaled - 0.39465f * u_scaled - 0.58060f * v_scaled) * 255.0); 
     *iData++ = (uchar)((y_scaled + 2.03211f * u_scaled) * 255.0); 
     *iData++ = 255; 
    } 
} 

Понятный

for (int i = 0; i < TangoData::imageBufferHeight; ++i) 
{ 
    for (int j = 0; j < TangoData::imageBufferWidth; ++j) 
    { 
     uchar y = pData[i * image->stride + j]; 
     uchar v = pData[(i/2) * (TangoData::imageBufferStride/2) + (j/2) + size]; 
     uchar u = pData[(i/2) * (TangoData::imageBufferStride/2) + (j/2) + size + (size/4)]; 
     YUV2RGB(y, u, v); 
     *iData++ = y; 
     *iData++ = u; 
     *iData++ = v; 
     *iData++ = 255; 
    } 
} 
0

Я думаю, что есть лучший способ сделать, если вы можете это сделать в автономном режиме. Лучший способ сохранить изображение должно быть что-то вроде этого (не забыли создать папку Pictures или вы ничего не спасти)

void onFrameAvailableRouter(void* context, TangoCameraId id, const TangoImageBuffer* buffer) { 
    //To write the image in a txt file. 
    std::stringstream name_stream; 
    name_stream.setf(std::ios_base::fixed, std::ios_base::floatfield); 
    name_stream.precision(3); 
    name_stream << "/storage/emulated/0/Pictures/" 
       <<cur_frame_timstamp_ 
       <<".txt"; 

    std::fstream f(name_stream.str().c_str(), std::ios::out | std::ios::binary); 
    // size = 1280*720*1.5 to save YUV or 1280*720 to save grayscale 
    int size = stride_ * height_ * 1.5; 
    f.write((const char *) buffer->data,size * sizeof(uint8_t)); 
    f.close(); 
} 

Затем, чтобы преобразовать файл .txt в детские вы можете сделать это

inputFolder = "input" 
outputFolderRGB = "output/rgb" 
outputFolderGray = "output/gray" 

input_filename = "timestamp.txt" 
output_filename = "rgb.png" 
allFile = listdir(inputFolder) 
numberOfFile = len(allFile) 

if "input" in glob.glob("*"): 
    if "output/rgb" in glob.glob("output/*"): 
     print "" 
    else: 
     makedirs("output/rgb") 
     if "output/gray" in glob.glob("output/*"): 
      print "" 
     else: 
      makedirs("output/gray") 

    #The output reportories are ready 
    for file in allFile: 
     count+=1 
     print "current file : ",count,"/",numberOfFile 
     input_filename = file 
     output_filename = input_filename[0:(len(input_filename)-3)]+"png" 

     # load file into buffer 
     data = np.fromfile(inputFolder+"/"+input_filename, dtype=np.uint8) 

     #To get RGB image 
     # create yuv image 
     yuv = np.ndarray((height + height/2, width), dtype=np.uint8, buffer=data)  
     # create a height x width x channels matrix with the datatype uint8 for rgb image 
     img = np.zeros((height, width, channels), dtype=np.uint8);  
     # convert yuv image to rgb image 
     cv2.cvtColor(yuv, cv2.COLOR_YUV2BGRA_NV21, img, channels) 
     cv2.imwrite(outputFolderRGB+"/"+output_filename, img) 

     #If u saved the image in graysacale use this part instead 
     #yuvReal = np.ndarray((height, width), dtype=np.uint8, buffer=data) 
     #cv2.imwrite(outputFolderGray+"/"+output_filename, yuvReal) 
else: 
    print "not any input" 

вы просто должны поставить .txt в папке ввода это питон скрипт, но если вы предпочитаете C++ версии это очень близко.

 Смежные вопросы

  • Нет связанных вопросов^_^