Бит-сложа для пользовательского формата изображения



Следующий код предназначен главным образом для преобразования из байтов/битов потока numericals, такие как int, неподписанный интервал, короткий тип int беззнаковый Short и int, float и т. д. Эти функции активно используются в данных изображения программа декодирования. Я чувствую невыносимо медленно, когда имеешь дело с большим изображением. Пожалуйста, помогите мне улучшить мой код? Спасибо!

const unsigned int POW2[32] = 
{1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,
1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,
1073741824,2147483648 };

// Number of bits per word
enum BitCount
{   
BC01=1, BC02=2, BC03=3, BC04=4, BC05=5, BC06=6, BC07=7, BC08=8, BC09=9, BC10=10,
BC11=11,BC12=12,BC13=13,BC14=14,BC15=15,BC16=16,BC17=17,BC18=18,BC19=19,BC20=20,
BC21=21,BC22=22,BC23=23,BC24=24,BC25=25,BC26=26,BC27=27,BC28=28,BC29=29,BC30=30,
BC31=31,BC32=32 };

// Bit position in one byte (8bit)
enum BitPosition
{   
BP0=0, BP1=1, BP2=2, BP3=3, BP4=4, BP5=5, BP6=6, BP7=7 
};

unsigned int GetNbitsWordBE(unsigned int indexWord, const unsigned char * p, BitCount bitCount)
{   
// Subscript numbering from 0
unsigned int offsetBits = indexWord * bitCount;
unsigned int beginByte = offsetBits / 8;
BitPosition beginBit = static_cast<BitPosition>(offsetBits % 8);       

return GetNbitsWordBE(beginByte, beginBit, p, bitCount);
}

unsigned int GetNbitsWordBE(unsigned int beginByte, BitPosition beginBit, const unsigned char * p, BitCount bitCount)
{   
unsigned int result = 0;
const unsigned char * data = p + beginByte;

// Branch #1: special case (take up the integral number of bytes)
if (beginBit==BP0)
{  
   if (bitCount == BC08)
      return static_cast<unsigned int>(data[0]);
   else if (bitCount == BC16)
       return static_cast<unsigned int>(data[1]) + static_cast<unsigned int>(data[0]) * POW2[8];
   else if (bitCount == BC24)
       return static_cast<unsigned int>(data[2]) + static_cast<unsigned int>(data[1]) * POW2[8] + static_cast<unsigned int>(data[0]) * POW2[16];
   else if (bitCount == BC32)
       return static_cast<unsigned int>(data[3]) + static_cast<unsigned int>(data[2]) * POW2[8] + static_cast<unsigned int>(data[1]) * POW2[16] + static_cast<unsigned int>(data[0]) * POW2[24];
   else
       ; // Do nothing
}

// Compute as big as 32-bit number.
// 32-bit number can occupy as much as 5 bytes because it's highly possible 
// that the first bit is not the first bit of the first byte.
unsigned int arRadio[5] = {0,0,0,0,0};
unsigned int arValue[5] = {0,0,0,0,0};
unsigned int occupiedBytesCount = static_cast<unsigned int>( ceil(static_cast<double>(beginBit + bitCount) / 8.0) );

BitPosition beginPos = beginBit;
int idxEnd = (beginBit + bitCount) % 8 - 1; 

if (idxEnd<0) 
   idxEnd=7;

BitPosition endPos = static_cast<BitPosition>(idxEnd);

switch(occupiedBytesCount)
{  
   case 1:
      // 1st byte
      result = GetNbitsWordBE(beginPos,endPos,data[0]);
      break;
   case 2:
      // 2nd byte
      arValue[1] = GetNbitsWordBE(BP0,endPos,data[1]);
      arRadio[1] = 1; 

      // 1st byte
      arValue[0] = GetNbitsWordBE(beginPos,BP7,data[0]);
      arRadio[0] = POW2[endPos+1];
      result = arValue[0]*arRadio[0] + arValue[1]*arRadio[1];
      break;
   case 3:
      // 3rd byte
      arValue[2] = GetNbitsWordBE(BP0,endPos,data[2]);
      arRadio[2] = 1;

      // 2nd byte
      arValue[1] = data[1];
      arRadio[1] = POW2[endPos+1];

      // 1st byte
      arValue[0] = GetNbitsWordBE(beginPos,BP7,data[0]);
      arRadio[0] = POW2[endPos+1+8];
      result = arValue[0]*arRadio[0] + arValue[1]*arRadio[1] + arValue[2]*arRadio[2];
      break;
   case 4:
      // 4th byte
      arValue[3] = GetNbitsWordBE(BP0,endPos,data[3]);
      arRadio[3] = 1;

      // 3rd byte
      arValue[2] = data[2];
      arRadio[2] = POW2[endPos+1];

      // 2nd byte
      arValue[1] = data[1];
      arRadio[1] = POW2[endPos+1+8]; 

      // 1st byte
      arValue[0] = GetNbitsWordBE(beginPos,BP7,data[0]);
      arRadio[0] = POW2[endPos+1+8+8];
      result = arValue[0]*arRadio[0] + arValue[1]*arRadio[1] + arValue[2]*arRadio[2] + arValue[3]*arRadio[3];
      break;
   case 5:
      // 5th byte
      arValue[4] = GetNbitsWordBE(BP0,endPos,data[4]);
      arRadio[4] = 1;

      // 4th byte
      arValue[3] = data[3];
      arRadio[3] = POW2[endPos+1]; 

      // 3rd byte
      arValue[2] = data[2];
      arRadio[2] = POW2[endPos+1+8];

      // 2nd byte
      arValue[1] = data[1];
      arRadio[1] = POW2[endPos+1+8+8];

      // 1st byte
      arValue[0] = GetNbitsWordBE(beginPos,BP7,data[0]);
      arRadio[0] = POW2[endPos+1+8+8+8];
      result = arValue[0]*arRadio[0] + arValue[1]*arRadio[1] + arValue[2]*arRadio[2] + arValue[3]*arRadio[3] + arValue[4]*arRadio[4];
      break;
   default:
      break;
}

return result;
}

unsigned char GetNbitsWordBE(BitPosition beginPosition, BitPosition endPosition, const unsigned char & data)
{   
if (beginPosition==BP0 && endPosition==BP7) 
   return data;

unsigned char result,ucTmp0,ucTmp1;
ucTmp0 = data;
ucTmp1 = static_cast<unsigned char>(ucTmp0<<beginPosition);
result = static_cast<unsigned char>(ucTmp1>>(beginPosition+(7-endPosition)));

return result;
}

Уважаемый Виктор Т
Спасибо за заняв времени, чтобы сделать работу бенчмаркинга для моего кода. Я использую последний-заданные функции в функции моей программы. Я выкладываю потребительская функция, как вы просили для вашей справки следующим образом.

#define IR_5KM_SCANLINE_PIXELS   2291
#define VIS_1KM_SCANLINE_PIXELS  9164

#define SVS_IR_SCANLINE_SIZE     4582
#define SVS_VIS_SCANLINE_SIZE    9164
#define SVS_SCANLINE_SIZE        57301 
#define SVS_IR1_INDEX            2297 
#define SVS_IR2_INDEX            4592 
#define SVS_IR3_INDEX            6887 
#define SVS_IR4_INDEX            9182 
#define SVS_VIS1_INDEX           13766
#define SVS_VIS2_INDEX           22932
#define SVS_VIS3_INDEX           32098
#define SVS_VIS4_INDEX           41264

#define CSV_LINE_NO_SIZE       2
#define CSV_QC_ID_SIZE         1
#define CSV_DOC_ID_SIZE        2
#define CSV_DOC_SIZE           2291
#define CSV_IR_ID_SIZE         2
#define CSV_IR_SCANLINE_SIZE   2864
#define CSV_SIZE_VS_ID         2
#define CSV_VIS_SCANLINE_SIZE  6873
#define CSV_SCANLINE_SIZE      41260
#define CSV_DOC_INDEX          5 
#define CSV_IR1_INDEX          2298 
#define CSV_IR2_INDEX          5164 
#define CSV_IR3_INDEX          8030 
#define CSV_IR4_INDEX          10896
#define CSV_VIS1_INDEX         13762
#define CSV_VIS2_INDEX         20637
#define CSV_VIS3_INDEX         27512
#define CSV_VIS4_INDEX         34387

void ReadFileCSV(const char * strFile)
{   
    m_pHeaderInfo = new CFileHeader();

    // Data buffers
    unsigned char* pSVSLine = new unsigned char [SVS_SCANLINE_SIZE];
    unsigned char* pCSVLine = new unsigned char [CSV_SCANLINE_SIZE];

    // Line counter
    unsigned short lineCount;

    FILE * fp = fopen(strFile, "rb");

    if (fp == NULL) 
       return;

    fseek(fp, 0, SEEK_END);
    long pos = ftell(fp);

    // Subtract the header info line (1 line)
    lineCount = static_cast<unsigned short>(pos / CSV_SCANLINE_SIZE) - 1;

    fseek(fp, 0, SEEK_SET);

    // Read the header info line
    fread(&m_pHeaderInfo->header, sizeof(CFileHeader::HEADER_INFO), 1, fp);

    char cArTmp0[128];
    strncpy(cArTmp0, m_pHeaderInfo->header.strRecordNum, 4);
    cArTmp0[4] = 0;
    int iTmp0;
    sscanf(cArTmp0, "%d", &iTmp0);

    if (iTmp0 < lineCount)
       lineCount = static_cast<unsigned short>(iTmp0);

    // Create 2D unsigned char array
    m_rawDoc.Create(lineCount, SVS_DOC_SIZE);

    // Create four 2D unsigned short arrays
    m_usIR1DataBuffer.Create(lineCount  ,   IR_5KM_SCANLINE_PIXELS);
    m_usIR2DataBuffer.Create(lineCount  ,   IR_5KM_SCANLINE_PIXELS);
    m_usIR3DataBuffer.Create(lineCount  ,   IR_5KM_SCANLINE_PIXELS);
    m_usIR4DataBuffer.Create(lineCount  ,   IR_5KM_SCANLINE_PIXELS);

    // Create a 2D unsigned char array
    m_ucVISDataBuffer.Create(lineCount * 4, VIS_1KM_SCANLINE_PIXELS);

    // Start to reading image data line
    for (unsigned int y = 0; y < lineCount; y++)
    {   
        fread(pCSVLine, 1, CSV_SCANLINE_SIZE, fp);
        memcpy(pSVSLine, pCSVLine + CSV_LINE_NO_SIZE + CSV_QC_ID_SIZE, CSV_DOC_ID_SIZE + CSV_DOC_SIZE);

        unsigned short *pUS1, *pUS2, *pUS3, *pUS4;
        pUS1 = reinterpret_cast<unsigned short *>(pSVSLine + SVS_IR1_INDEX);
        pUS2 = reinterpret_cast<unsigned short *>(pSVSLine + SVS_IR2_INDEX);
        pUS3 = reinterpret_cast<unsigned short *>(pSVSLine + SVS_IR3_INDEX);
        pUS4 = reinterpret_cast<unsigned short *>(pSVSLine + SVS_IR4_INDEX);

        for (int x = 0; x < IR_5KM_SCANLINE_PIXELS; x++)
        {   
            pUS1[x] = static_cast<short>(GetNbitsWordBE(x, pCSVLine + CSV_IR1_INDEX, BC10));
            pUS2[x] = static_cast<short>(GetNbitsWordBE(x, pCSVLine + CSV_IR2_INDEX, BC10));
            pUS3[x] = static_cast<short>(GetNbitsWordBE(x, pCSVLine + CSV_IR3_INDEX, BC10));
            pUS4[x] = static_cast<short>(GetNbitsWordBE(x, pCSVLine + CSV_IR4_INDEX, BC10));
        }

        unsigned char *pUC1, *pUC2, *pUC3, *pUC4;
        pUC1 = pSVSLine + SVS_VIS1_INDEX;
        pUC2 = pSVSLine + SVS_VIS2_INDEX;
        pUC3 = pSVSLine + SVS_VIS3_INDEX;
        pUC4 = pSVSLine + SVS_VIS4_INDEX;

        for (int x = 0; x < VIS_1KM_SCANLINE_PIXELS; x++)
        {    
            pUC1[x] = static_cast<unsigned char>(GetNbitsWordBE(x, pCSVLine + CSV_VIS1_INDEX, BC06));
            pUC2[x] = static_cast<unsigned char>(GetNbitsWordBE(x, pCSVLine + CSV_VIS2_INDEX, BC06));
            pUC3[x] = static_cast<unsigned char>(GetNbitsWordBE(x, pCSVLine + CSV_VIS3_INDEX, BC06));
            pUC4[x] = static_cast<unsigned char>(GetNbitsWordBE(x, pCSVLine + CSV_VIS4_INDEX, BC06));
        }

        memcpy(m_rawDoc.Ptr(y,0),               pSVSLine + SVS_DOC_INDEX, SVS_DOC_SIZE);
        memcpy(m_usIR1DataBuffer.Ptr(y,0),      pSVSLine + SVS_IR1_INDEX, SVS_IR_SCANLINE_SIZE);
        memcpy(m_usIR2DataBuffer.Ptr(y,0),      pSVSLine + SVS_IR2_INDEX, SVS_IR_SCANLINE_SIZE);
        memcpy(m_usIR3DataBuffer.Ptr(y,0),      pSVSLine + SVS_IR3_INDEX, SVS_IR_SCANLINE_SIZE);
        memcpy(m_usIR4DataBuffer.Ptr(y,0),      pSVSLine + SVS_IR4_INDEX, SVS_IR_SCANLINE_SIZE);
        memcpy(m_ucVISDataBuffer.Ptr(4*y+0,0),  pSVSLine + SVS_VIS1_INDEX, SVS_VIS_SCANLINE_SIZE);
        memcpy(m_ucVISDataBuffer.Ptr(4*y+1,0),  pSVSLine + SVS_VIS2_INDEX, SVS_VIS_SCANLINE_SIZE);
        memcpy(m_ucVISDataBuffer.Ptr(4*y+2,0),  pSVSLine + SVS_VIS3_INDEX, SVS_VIS_SCANLINE_SIZE);
        memcpy(m_ucVISDataBuffer.Ptr(4*y+3,0),  pSVSLine + SVS_VIS4_INDEX, SVS_VIS_SCANLINE_SIZE);
    }

    fclose(fp);
}

Уважаемый Г-Н Мартин
Спасибо за то, что взял время, чтобы прочитать мои фрагменты кода. Пожалуйста, позвольте мне попытаться ответить на ваши вопросы в мой код:
(1) объяснения за кодирование
Дистанционные изображение исходных данных (например, спутниковые изображения) в плен к наземной станции всегда упакованные в виде 6-бит, 10-бит или 12-бит потоков. Эти данные хранятся на строке развертки растровой строки.

Как вы видите в моем коде, ReadFileCSV используется для чтения такого рода растровой строки по одному сформировать двоичный файл открыт, и хранится в unsigned буфера источника чар на некоторое время. Для 6-битового потока, я должен масштабироваться до 8 бит (один байт), а на 10-бит или 12-бит потока, я сделаю, чтобы быть расширены беззнаковое короткое целое. Наконец, я должен сделать беззнаковый тип char (по 6-разрядной системы) или беззнаковое короткое буфер назначения.

(2) POW2-это 2 в степени n, где N может быть задано любое значение от 0 до 32.


const unsigned int POW2[32] =  {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288, 1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912, 1073741824,2147483648 };


Как вы можете видеть, константный беззнаковый инт POW2[32] подобно таблице.

(3) я согласен с вашим предложением "во избежание умножения вместо перекладывания".

(4) я беспокоюсь о производительности трех перегрузка функций (GetNbitsWordBE(....)) тоже. Я не силен в битовые операции (например, переключение, |, ^, ~, и т. д.). Я думаю, что бит-большой-плеер бы не использовать такой сложный и неуклюжий способ превратить ПК неблагоприятных битов, такие как 6-битных, 10-битный, 12-битных, в ближайший благоприятный битов, такие как 8-бит (без знака типа char), 16-битных (короткое целое без знака).

(5) г-н Марк так предположить, что я должен использовать следующие фрагменты кода, чтобы масштабировать мой 6-битных и 10-битных значений для соответствующих 8-бит (без знака типа char) и 16-разрядный (короткое целое без знака) значения. Как я уже приводил здесь (кстати, я не могу заставить его работать):

Обычным способом является сдвиг влево на разницу в количество битов между входом и выходом, затем добавьте в старших битов из входного, чтобы заполнить младшие биты.


unsigned char eightbit = (sixbit > 4); 
unsigned short sixteenbit = (tenbit > 4); 
unsigned short sixteenbit = (twelvebit > 8); 

Существует альтернативный подход к младшим битам, что я не очень часто видел, - заполнять их с шумом. Этой маски некоторые ошибки квантования в исходном образце.


unsigned char eightbit = (sixbit > 14); 
unsigned short sixteenbit = (tenbit > 10); 
unsigned short sixteenbit = (twelvebit > 12); 

(6) 10-битный illustartion трансляция

10101010 01110101 00011001
|         |
-----------
 10-bit

10101010 01110101 00011001
      |         |
      -----------
       10-bit

10101010 01110101 01100110
       |          |
       ------------   
         10-bit


805
5
задан 15 июня 2011 в 04:06 Источник Поделиться
Комментарии
2 ответа

Извините, если я недоразумение код, но вот некоторые идеи, как его можно улучшить, ориентируясь на производительность. Это те вещи, которые сразу пришли мне на ум. Я, наверное, пропустил чего, а может быть и выше уровень оптимизации, что можно сделать, что я не видел, потому что я просто взял быстрый взгляд на код.

Какой смысл массива POW2? Это не делает код понятнее, чем с помощью оператора сдвига, и может сделать его более трудным для компилятора, чтобы найти оптимизаций.

Так что вместо того, чтобы делать

something * POW2[16]

вобще

something << 16

В общем, не умножая, а не перекладывание если ты работаешь на битовом уровне. Возьмем, например, случай 4, который может быть записан проще (и скорее всего быстрее, в зависимости от того, насколько умен компилятор) как:

case 4:
// 4th byte
arValue3 = GetNbitsWordBE(BP0, endPos, data[3]);
arValue2 = data[2];
arValue1 = data[1];
arValue0 = GetNbitsWordBE(beginPos, BP7, data[0]);
result = (arValue3) |
(arValue2 << (endPos + 1)) |
(arValue1 << (endPos + 1 + 8)) |
(arValue0 << (endPos + 1 + 8 + 8);

Я сделал arValue в локальные переменные, а не массив, потому что это легче типа. Там может быть разница в производительности в какое-то направление, что вам может понадобиться профиль.

Я также беспокоиться о том, что функция GetNbitsWordBE встроенный и оптимизированный, а также ты хотел. Ой, подожди, там их три! Теперь я в замешательстве. Я бы предпочел не перегружая его, но это вопрос стиля, а не проблемы с производительностью.

4
ответ дан 17 июня 2011 в 10:06 Источник Поделиться

Вы просто пытаетесь конвертировать большое упакованные 10-битных целых чисел в типичные типов C?

Вы рассматривали такой подход, как "округление до ближайшего 32-разрядное число, разыменовать, что и "лишние " биты"? Что-то вроде этого:

uint16_t
get_packed_word(void *buf, int starting_bit, int nbits)
{
uint32_t r;

/* Copy 32 bits... (Via memcpy since otherwise we'd do unaligned access.) */
memcpy(&r, ((char*)buf) + starting_bit/8, sizeof(r));

/* Using htonl because I assume you want big endian... */
r = htonl(r);

/* Shift right to discard extra low bits... */
r >>= ((32 - nbits) - (starting_bit % 8));

/* Discard extra high bits... */
r &= ((1<<nbits) - 1);

return r;
}

Это, кажется, работает для ASCII искусства тестовых данных с nbits = 10... понятия не имею, как она работает с большими объемами данных [хотя немного смещается и дешево, верно?], но это намного проще, чем у вас. Я получил этот подход от того, как некоторые водители жира ручка с FAT12 (относиться к нему как FAT16 с 16-разрядной разыменовывает, но обрезать лишнюю пушистость).

Обновление: глядя на этот раз, мой первоначальный код не обрабатывать некоторые крайние случаи, такие как starting_bit = 7... поэтому я перешла на 32-разрядные числа, а не 16.

1
ответ дан 19 июня 2011 в 05:06 Источник Поделиться