Обработка изображений в C ++ - PullRequest
1 голос
/ 11 сентября 2011

Я хочу прочитать необработанный файл, который имеет 3 чередования и имеет размер около (3,5 МБ) большого размера в трехмерном массиве ... код, который я использую для чтения файла:

ifile.open(argv[2], ios::in|ios::binary);
for(int i=0; i<1278; i++){
    for(int j=0; j<968; j++){
        for(int k=0; k<3; k++){
            Imagedata1[i][j][k]=ifile.get();
        }
    }
}

Дело в том, что этот массив не тот, который я ожидаю ... Мне нужно, чтобы 1278 была шириной изображения ... 968 - это высота, а 3 байта - значения RGB ... как я долженнаписать код для чтения из файла, чтобы массив был заполнен правильно. Спасибо.

Ответы [ 3 ]

2 голосов
/ 11 сентября 2011

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

ifile.open(argv[2], ios::in|ios::binary);
for(int j=0; j<968; j++){
    for(int i=0; i<1278; i++){
        for(int k=0; k<3; k++){
            Imagedata1[i][j][k]=ifile.get();
        }
    }
}

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

ifile.open(argv[2], ios::in|ios::binary);
for(int row=0; row<968; row++){
    for(int col=0; col<1278; col++){
        for(int color=0; color<3; color++){
            Imagedata1[col][row][color]=ifile.get();
        }
    }
}

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

#include <iostream>
#include <fstream>

class ColorValue {
 public:
   ColorValue(unsigned char r, unsigned char g, unsigned char b)
     : r_(r), g_(g), b_(b) {}
   ColorValue() : r_(0), g_(0), b_(0) {}

   unsigned char getR() const { return r_; }
   unsigned char getG() const { return g_; }
   unsigned char getB() const { return b_; }

 private:
   unsigned char r_, g_, b_;
};

void readrows(const char *fname, ColorValue imagedata[][1278])
{
   ::std::ifstream ifile;
   ifile.open(fname, ::std::ios::in|::std::ios::binary);
   for (int row = 0; row < 968; ++row) {
      for (int col = 0; col < 1278; ++col) {
         char r, g, b;
         ifile.get(r);
         ifile.get(g);
         ifile.get(b);
         imagedata[row][col] = ColorValue(r, g, b);
      }
   }
}

int main(int argc, const char *argv[])
{
   ColorValue (*imagedata)[1278] = new ColorValue[968][1278];
   readrows(argv[1], imagedata);
   delete[] imagedata;
}

Использование класса для ColorValue не позволяет вам иметь магические индексы повсюду в вашем коде для компонентов 'r', 'g' и 'b'. А выделение массива таким образом сохраняет всю память, используемую для изображения, непрерывной и удаляет несколько уровней ненужной косвенности. Они оба имеют свойство делать вашу программу намного более дружественной к кешу.

Я также нашел замечательную статью, которая представляет собой действительно комплексную обработку многомерных массивов в C ++ .

0 голосов
/ 11 сентября 2011

Пока вы всегда получаете доступ к своим данным через трехмерный массив, не имеет значения, как структура массива располагается в памяти.В вашем примере вы определяете первый индекс (i) как индекс столбца, индекс (j) как индекс строки и индекс (k) как индекс компонента пикселя.

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

ifile.open(argv[2], ios::in|ios::binary);
for(int i=0; i<1278; i++){
    for(int j=0; j<968; j++){
        for(int k=0; k<3; k++){
            Imagedata1[j][i][k]=ifile.get();
        }
    }
}

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

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

unsigned char Imagedata1[968][1278][3];

ifile.open(argv[2], ios::in|ios::binary);
for(int i=0; i<968; i++){
    for(int j=0; j<1278; j++){
        for(int k=0; k<3; k++){
            Imagedata1[i][j][k]=ifile.get();
        }
    }
}

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

unsigned char Imagedata1[968][1278][3];

Я бы вместо этого поместил его в кучу, например:

unsigned char* Imagedata1 = new unsigned char[968*1278*3];

Затем вы можете прочитать данные из файла с помощью:

if (fread(Imagedata1, 1278*3, 968, fd) != 968) {
    // handle error here
}

Обратите внимание, что числа, которые вы указываете как число и размер в вызове fread, не так важны, если эти дваумноженные числа равны ширине * высоте * компонентов.

Если вам необходимо получить доступ к этому изображению в виде трехмерного массива, я рекомендую вам создать вспомогательную функцию, что-то вроде этого:

unsigned char* getPixel(int col, int row)
{
    return Imagedata1 + row * 1278 * 3 + col * 3;
}

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

В качестве окончательного предложения, я рекомендую вам обернуть ваше изображениев классе, и добавьте переменные-члены, которые определяют ширину и высоту (и, возможно, количество цветовых плоскостей).Вы не хотите жестко кодировать 1278 и 968 повсюду в вашем коде!

Надеюсь, это поможет.

0 голосов
/ 11 сентября 2011

C массивы не работают так.

Допустим, вам нужен 2D 1024 * 768 пиксельный буфер с 4 байтами на пиксель. Вы бы сделали что-то вроде этого:

  unsigned int pixbuf[1024*768];

  for (int irow=0; irow < 1024; irow++)
    for (int icol=0; icol < 768; icol++)
      pixbuf[(irow*1024)+icol] = icolor;

Вот хорошая ссылка, которая объясняет далее:

http://c -faq.com / ~ SCS / cclass / INT / sx9.html

Надеюсь, это поможет!

...