C++ 从原始图像中读取 16 位二进制数据并将它们存储在向量中

C++ reading 16bit binary data from raw img and store them in vector

这些天我在 malloc 内存上苦苦挣扎。我尝试从原始 img 读取 16 位二进制数据并将它们存储在缓冲区或向量中。这些二进制数据的总大小约为15M。对于这种大小,buf 和 vector 哪个更好?下面是我的代码:

#include <imebra/imebra.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string.h>
#include <vector>
#include<iterator>
#include <algorithm>

#define img_height 2816
#define img_width  2816


//#define img_size img_height*img_width*img_bit //15.1MB

using namespace std;

//MONOCHROME1: indicates that the greyscale ranges from bright to dark with ascending pixel values
//MONOCHROME2: indicates that the greyscale ranges from dark to bright with ascending pixel values



/*
create an Image object
fill the image object with raw dat
create a DICOM dataset
add the image to the DICOM dataset
fill all the necessary DICOM tags (e.g. sop class, instance, patient name, etc)
save the DICOM dataset
*/
int main()
{
    ifstream mydata("/home/lixingyu/123.raw", ios::binary);
    if(!mydata.is_open())
    {
        cout<<"open file failed"<<endl;
        exit(1);
    }
    //get img size
    mydata.seekg (0, mydata.end);
    int img_size = mydata.tellg();
    mydata.seekg (0, mydata.beg);
    cout<<"img_size : "<<img_size<<endl;


/* way 1
    char *buf= new (nothrow) char[img_size];
    uint16_t *rawdata = new (nothrow) uint16_t[img_size];

    if(buf == NULL)
    {
        cout<<"memory allocation failed"<<endl;
        delete [] buf;
    }
    if(rawdata == NULL)
    {
        cout<<"memory allocation failed"<<endl;
        delete [] rawdata;
    }

    mydata.read(rawdata,img_size);
     memcpy(rawdata,buf,img_size); //forced type changed from char to uint16_t
     cout<<"rawdata[first] = "<<rawdata[0]<<endl;
     cout<<"rawdata[last]= "<<rawdata[img_size/2-1]<<endl;

*/

//way 2
    vector<char> raw_8;
    vector<uint16_t> raw_16;
    char value;
    while(! mydata.eof())
    {
        mydata>>value;
        raw_8.push_back(value);
    }
    //raw_8->pop_back();
    copy(raw_8.begin(),raw_8.end(),back_inserter(raw_16));
    copy(raw_16.begin(),raw_16.end(),ostream_iterator<uint16_t>(cout,"\n"));

/*

    imebra::MutableImage image=imebra::MutableImage(img_height,img_width,imebra::bitDepth_t::depthU16,"MONOCHROME2",15);

    // 1. Fill the image with data
    // We use a writing data handler to write into the image.
    // The data is committed into the image only when the writing   
    // data handler golses out of scope.
    imebra::WritingDataHandlerNumeric writeIntoImage(image.getWritingDataHandler());    

    //writeIntoImage.assign(buf,sizeof(buf));   
    for (size_t y(0);y!=img_width;++y)
    {
        for (size_t x(0); x!= img_height; ++x)
        {
            writeIntoImage.setUnsignedLong(y*img_height+x,rawdata[y*img_height+x]);
        }
    }

    // specify the tansfer syntax and the charset
    imebra::charsetsList_t charsets;
    charsets.push_back("ISO 2022 IR 6");    

    //Explicit VR little endian
    imebra::MutableDataSet dataSet("1.2.840.10008.1.2.1",charsets);
  /************ code stop here *************/
    // add the image to the dataSet
    dataSet.setImage(0,image,imebra::imageQuality_t::veryHigh);

    // set the patient name dataSet.setUnicodePatientName(imebra::TagId(imebra::tagId_t::PatientName_0010_0010),imebra::UnicodePatientName(L"fjx",L"",L""));

    // save to a file
    imebra::CodecFactory::save(dataSet,"GH1.dcm",imebra::codecType_t::dicom);

    mydata.close();
    delete [] buf;
    delete [] rawdata;    
}

// sudo g++ -I/home/lixingyu/imebra_5_0_1_1/library/include -o test raw2dcm.cpp -std=c++0x -l imebra -L/home/lixingyu/artifacets
// export LD_LIBRARY_PATH=/home/lixingyu/artifacets:$LD_LIBRARY_PATH  

代码底部的两条注释是编译cmd。 现在的情况是,无论我使用方式 1 还是方式 2,代码都会停在那里(请参阅上面的代码),并且它表示分段错误(核心转储)。

以下是 gdb 调试:

(gdb) bt full
#0  0x00007faecd9854bd in imebra::implementation::codecs::dicomNativeImageCodec::writeInterleavedNotSubsampled<unsigned short> (pImageSamples=0x0, 
    allocatedBits=16, pLittleEndianTagData=0x36a1d11 "", numPixels=7929856, 
    numChannels=1)
    at /home/lixingyu/imebra_5_1_0_0/library/implementation/dicomNativeImageCodecImpl.h:125
#1  0x00007faecd983887 in imebra::implementation::codecs::dicomNativeImageCodec::writeInterleavedNotSubsampled (pImageSamples=0x0, allocatedBits=16, 
    samplesDepth=imebra::bitDepth_t::depthU16, 
    pLittleEndianTagData=0x36a1d10 "", numPixels=7929856, numChannels=1)
    at /home/lixingyu/imebra_5_1_0_0/library/implementation/dicomNativeImageCodecImpl.cpp:396
#2  0x00007faecd9828b4 in imebra::implementation::codecs::dicomNativeImageCodec::setImage (this=0xf3b080, pDestStream=
    std::shared_ptr (count 2, weak 0) 0x36a0780, 
    pImage=std::shared_ptr (count 3, weak 0) 0xf3dff0, allocatedBits=16, 
    bSubSampledX=false, bSubSampledY=false, bInterleaved=false)
    at /home/lixingyu/imebra_5_1_0_0/library/implementation/dicomNativeImageCodecImpl.cpp:311
#3  0x00007faecd81a34e in imebra::implementation::dataSet::setImage (
    this=0x1e5f2a0, frameNumber=0, 
    pImage=std::shared_ptr (count 3, weak 0) 0xf3dff0, 
    quality=imebra::imageQuality_t::veryHigh)

顺便说一下,如果我使用向量来存储从 8 位向量复制的 16 位值。我应该进行数据类型转换吗?我只是使用 copy() 函数将存储在 8 位向量中的数据复制到 16 位向量中。

以下代码必须用{}括起来

imebra::WritingDataHandlerNumeric writeIntoImage(image.getWritingDataHandler());    

//writeIntoImage.assign(buf,sizeof(buf));   
for (size_t y(0);y!=img_width;++y)
{
    for (size_t x(0); x!= img_height; ++x)
    {
        writeIntoImage.setUnsignedLong(y*img_height+x,rawdata[y*img_height+x]);
    }
}

像这样:

{
    imebra::WritingDataHandlerNumeric writeIntoImage(image.getWritingDataHandler());    

    //writeIntoImage.assign(buf,sizeof(buf));   
    for (size_t y(0);y!=img_width;++y)
    {
        for (size_t x(0); x!= img_height; ++x)
        {
            writeIntoImage.setUnsignedLong(y*img_height+x,rawdata[y*img_height+x]);
        }
    }
}

这会导致 WritingDataHandlerNumeric 超出范围并更新图像的缓冲区。

免责声明:我是 Imebra 的作者。