Как записать только регулярно расположенные элементы из буфера символов на диск в C ++ - PullRequest
4 голосов
/ 20 июля 2010

Как я могу записать только каждый третий элемент в буфер символов в файл для быстрого C ++?

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

Команда C ++ ofstream :: write, кажется, записывает только непрерывные блоки двоичных данных, поэтому мой текущий код записывает все три канала и работает слишком медленно:

char * data = getDataFromCamera();
int dataSize = imageWidth * imageHeight * imageChannels;
std::ofstream output;
output.open( fileName, std::ios::out | std::ios::binary );
output.write( data, dataSize );

Я бы хотел иметь возможность заменить последнюю строку вызовом, подобным:

int skipSize = imageChannels;
output.write( data, dataSize, skipSize );

где skipSize приведет к тому, что write поместит в выходной файл только каждую треть. Однако я не смог найти ни одной функции, которая делает это.

Мне бы очень хотелось услышать любые идеи по быстрой записи одного канала на диск. Спасибо.

Ответы [ 6 ]

6 голосов
/ 20 июля 2010

Возможно, вам придется скопировать каждый третий элемент в буфер, а затем записать этот буфер на диск.

5 голосов
/ 20 июля 2010

Вы можете использовать фасет codecvt в локальной системе для фильтрации части вывода.
После создания вы можете наполнить любой поток подходящим локальным, и он будет видеть только каждый третий символ на входе.

#include <locale>
#include <fstream>
#include <iostream>

class Filter: public std::codecvt<char,char,mbstate_t>
{
    public:
   typedef std::codecvt<char,char,mbstate_t> MyType;
   typedef MyType::state_type          state_type;
   typedef MyType::result              result;

    // This indicates that we are converting the input.
    // Thus forcing a call to do_out()
    virtual bool do_always_noconv() const throw()   {return false;}

    // Reads   from -> from_end
    // Writes  to   -> to_end
    virtual result do_out(state_type &state,
             const char *from, const char *from_end, const char* &from_next,
             char       *to,   char       *to_limit, char*       &to_next) const
   {
       // Notice the increment of from
       for(;(from < from_end) && (to < to_limit);from += 3,to += 1)
       {
            (*to) = (*from);
       }
       from_next   = from;
       to_next     = to;

       return((to > to_limit)?partial:ok);
   }
};

Если у вас есть фасет, все, что вам нужно, это знать, как его использовать:

int main(int argc,char* argv[])
{
   // construct a custom filter locale and add it to a local.
   const std::locale filterLocale(std::cout.getloc(), new Filter());

   // Create a stream and imbue it with the locale
   std::ofstream   saveFile;
   saveFile.imbue(filterLocale);


   // Now the stream is imbued we can open it.
   // NB If you open the file stream first. 
   // Any attempt to imbue it with a local will silently fail.
   saveFile.open("Test");
   saveFile << "123123123123123123123123123123123123123123123123123123";

   std::vector<char>   data[1000];
   saveFile.write( &data[0], data.length() /* The filter implements the skipSize */ );
                                           // With a tinay amount of extra work
                                           // You can make filter take a filter size
                                           // parameter.

   return(0);
}
2 голосов
/ 20 июля 2010

Допустим, ваш буфер 24-битный RGB, и вы используете 32-битный процессор (поэтому операции с 32-битными объектами наиболее эффективны).

Для большей скорости давайте работать с 12-байтовым чанком за раз. В двенадцати байтах у нас будет 4 пикселя, вот так:

AAABBBCCCDDD

Это 3 32-битных значения:

AAAB
BBCC
CDDD

Мы хотим превратить это в ABCD (одно 32-битное значение).

Мы можем создать ABCD, применяя маску к каждому входу и ИЛИ.

ABCD = A000 | 0BC0 | 000D

В C ++, с процессором с прямым порядком байтов, я думаю, это будет:

unsigned int turn12grayBytesInto4ColorBytes( unsigned int buf[3] )
{
   return (buf[0]&0x000000FF) // mask seems reversed because of little-endianness
        | (buf[1]&0x00FFFF00)
        | (buf[2]&0xFF000000);
}

Вероятно, быстрее всего сделать это еще одно преобразование в другой буфер и затем сбросить на диск, вместо того, чтобы идти прямо на диск.

1 голос
/ 20 июля 2010

В стандартной библиотеке afaik такой функциональности нет.Решение Джерри Коффина будет работать лучше всего.Я написал простой фрагмент, который должен помочь:

const char * data = getDataFromCamera();
const int channelNum = 0;
const int channelSize = imageWidth * imageHeight;
const int dataSize    = channelSize * imageChannels;
char * singleChannelData = new char[channelSize];
for(int i=0; i<channelSize ++i)
    singleChannelData[i] = data[i*imageChannels];
try {
    std::ofstream output;
    output.open( fileName, std::ios::out | std::ios::binary );
    output.write( singleChannelData, channelSize );
}
catch(const std::ios_base::failure& output_error) {
    delete [] channelSize;
    throw;
}
delete [] singleChannelData;

РЕДАКТИРОВАТЬ: я добавил try..catch.Конечно, вы можете использовать std :: vector для более приятного кода, но он может быть немного медленнее.

0 голосов
/ 20 июля 2010

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

ostream& operator<< (ostream& out, struct data * s) {
    out.write(s->first);
}
0 голосов
/ 20 июля 2010

Во-первых, я бы сказал, что для максимизации скорости записи вы должны записывать буферы, кратные размеру сектора (например, 64 КБ или 256 КБ)

Чтобы ответить на ваш вопрос, вам нужно будет скопировать каждый третий элемент из ваших исходных данных в другой буфер, а затем записать это в поток.

Если я правильно помню Intel Performance Primitives имеет функции для копирования буферов, пропуская определенное количество элементов. Использование IPP, вероятно, даст более быстрые результаты, чем ваша собственная процедура копирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...