Покритикуйте библиотеку для работы с изображениями
От: syomin  
Дата: 05.09.07 16:00
Оценка:
Добрый день! Заранее извиняюсь за объем сообщения, сокращал как мог.

Возникла задача разработать библиотеку на языке C++ для обработки растровых изображений. Специфика задачи такова, что приходится иметь дело с различными цветовыми пространствами. Минимум — grayscale и binary, в дальнейшем, возможно, появится RGB.

Для примера смотрел на Qt4, System.Drawing из .Net и java.awt.Graphics.

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

template<class T>
class Image {
public:
    // Тип данных, используемый для хранения сведений об отдельном пикселе
    // изображения.
    typedef T Pixel;

    // Конструктор копирования и оператор присваивания.
    Image(const Image &rhs);
    Image<Pixel> &operator=(const Image &rhs);

    // Возвращает true, если ширина и высота изображения равны 0.
    bool isNull() const throw();

    // Получить размеры изображения.
    const Size &getSize() const throw();
    int getWidth() const throw();
    int getHeight() const throw();

    // Получить пиксел с заданными координатами.
    Pixel getPixel(const Point &point) const;
    Pixel getPixel(int x, int y) const;

    // Изменить пиксел с заданными координатами.
    void setPixel(const Point &point, Pixel pixel);
    void setPixel(int x, int y, Pixel pixel);

protected:
    // Конструкторы.
    Image() {}
    explicit Image(const Size &size);
    Image(int width, int height);

private:
    Size size_;
    std::vector<Pixel> pixels_;
};


От него наследуется класс для работы с полутоновыми изображениями:
// Класс "Полутоновое изображение".
class GrayImage : public Image<unsigned char> {
public:
    // Конструкторы.
    GrayImage() {}
    explicit GrayImage(const Size &size) : Image<Pixel>(size) {}
    GrayImage(int width, int height) : Image<Pixel>(width, height) {}
    explicit GrayImage(const std::string &filename);

    // Сохранить изображение в файл.
    void save(const std::string &filename);
};


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

Что касается классов Point и Size, то выглядят они так:
// Класс, описывающий координаты точки на плоскости.
class Point {
public:
    // Конструкторы.
    Point() throw() : x_(0), y_(0) {}
    Point(int x, int y) throw() : x_(x), y_(y) {}

    // Получить координаты точки.
    int getX() const throw();
    int getY() const throw();

    // Изменить координаты точки.
    void setX(int x) throw();
    void setY(int y) throw();
    void setXY(int x, int y) throw();

    // Декрементировать координаты точки.
    void decX() throw() { --x_; }
    void decY() throw() { --y_; }

    // Инкрементировать координаты точки.
    void incX() throw() { ++x_; }
    void incY() throw() { ++y_; }

private:
    int x_;
    int y_;
};

bool operator==(const Point &lhs, const Point &rhs) throw();
bool operator!=(const Point &lhs, const Point &rhs) throw();


// Класс, описывающий размеры двумерного объекта на плоскости (чаще всего -
// прямоугольника).
class Size {
public:
    // Конструкторы.
    Size() throw() : width_(0), height_(0) {}
    Size(int width, int height) { setSize(width, height); }

    // Возвращает true, если ширина и высота объекта равны 0.
    bool isNull() const throw();

    // Получить размер объекта.
    int getWidth() const throw();
    int getHeight() const throw();

    // Изменить ширину объекта.
    void setWidth(int width);

    // Изменить высоту объекта.
    void setHeight(int height);

    // Изменить размер объекта.
    void setSize(int width, int height);

private:
    int width_;
    int height_;
};

inline bool operator==(const Size &lhs, const Size &rhs) throw();
inline bool operator!=(const Size &lhs, const Size &rhs) throw();


Для тех, кто все-таки добрался до этого места, у меня есть ряд вопросов:
1. Какие есть минусы схемы с наследованием от Image<>? Мне пока ничего такого найти не удалось, поэтому и возникают некоторые сомнения — почему я такого больше нигде не видел?
2. Стоит ли овчинка выделки применительно к классам Point и Size? Может лучше отказаться от них, а при вызове методов Image<> отдельно указывать x и y (или width и height)?
3. Ну и вообще, как вам дизайн?

Заранее благодарю за ответы по существу.
Re: Покритикуйте библиотеку для работы с изображениями
От: korzh.pavel Россия  
Дата: 05.09.07 16:16
Оценка:
Здравствуйте, syomin, Вы писали:

S>Добрый день! Заранее извиняюсь за объем сообщения, сокращал как мог.


S>Возникла задача разработать библиотеку на языке C++ для обработки растровых изображений. Специфика задачи такова, что приходится иметь дело с различными цветовыми пространствами. Минимум — grayscale и binary, в дальнейшем, возможно, появится RGB.


Особо не вглядывался. Первый возникший вопрос: имеем 32 битные пиксели, как учитывается различный порядок компонент (rgba, argb, abgr,bgra) ?
Re[2]: Покритикуйте библиотеку для работы с изображениями
От: syomin  
Дата: 05.09.07 16:26
Оценка:
Добрый день!

KP>Особо не вглядывался. Первый возникший вопрос: имеем 32 битные пиксели, как учитывается различный порядок компонент (rgba, argb, abgr,bgra) ?

Насколько я понимаю, в такой постановке задача возникает при работе с изображениями, получаемыми от каких-то железок, при условии ограниченности ресурсов (например, обработка в реальном времени картинки с камеры). В моем случае время работы системы не критично, поэтому самый подходящий вариант — работать только с (A)RGB, а все остальное приводить к этому формату. Хотя можно пойти по такому пути:


class RgbaPixel {
public:
...
private:
        int32 r_, g_, b_, a_;
};

class RgbaImage : public Image<RgbaPixel> {...};


class ArgbPixel {
...
private:
        int32 a_, r_, g_, b_;
};

class ArgbImage : public Image<RgbaPixel> {...};


Только нужно отключить выравнивание для классов *Pixel.
Re[3]: Покритикуйте библиотеку для работы с изображениями
От: korzh.pavel Россия  
Дата: 05.09.07 16:45
Оценка:
Здравствуйте, syomin, Вы писали:

S>Добрый день!


KP>>Особо не вглядывался. Первый возникший вопрос: имеем 32 битные пиксели, как учитывается различный порядок компонент (rgba, argb, abgr,bgra) ?

S>Насколько я понимаю, в такой постановке задача возникает при работе с изображениями, получаемыми от каких-то железок, при условии ограниченности ресурсов (например, обработка в реальном времени картинки с камеры).

да нет. Просто хочу на десктопе работать с bmp (bgra)

KP>>В моем случае время работы системы не критично, поэтому самый подходящий вариант — работать только с (A)RGB, а все остальное приводить к этому формату.


тоже конечно вариант

KP>>Хотя можно пойти по такому пути:


S>[...]


ну ладно, тогда ещё такой случай: надо обрабатывать bgra у которого каждая scanline должна иметь word-alignment, что тогда делать?

Ещё заводить один класс class BgraImageWithWordAlignment ?

В общем критикую я твой дизайн, тока без обид

советую посмотреть:
antigrain.com
http://opensource.adobe.com/gil/html/gildesignguide.html
Re[4]: Покритикуйте библиотеку для работы с изображениями
От: syomin  
Дата: 05.09.07 16:59
Оценка:
KP>ну ладно, тогда ещё такой случай: надо обрабатывать bgra у которого каждая scanline должна иметь word-alignment, что тогда делать?

KP>Ещё заводить один класс class BgraImageWithWordAlignment ?


KP>В общем критикую я твой дизайн, тока без обид


Какие тут обиды — наоборот, конструктивная критика это всегда хорошо . По большому счету, тут многое зависит от постановки задачи. В моем случае нужно загрузить изображение из файла (форматы могут быть разные), выполнить его обработку по определенному алгоритму, вывести результаты (в текстовом виде). В некоторых случаях (в частности для отладки) может потребоваться сохранять изображения. Я уже говорил, что время работы программы некритично, поэтому если мне придется-таки работать с RGB, то я буду преобразовывать все к одному формату. В вашем случае все может быть совсем по-другому.

KP>советую посмотреть:

KP>antigrain.com
KP>http://opensource.adobe.com/gil/html/gildesignguide.html

Спасибо. Antigrain завтра посмотрю, но мне кажется, что это несколько не то — заточено на ренденеринг. GIL я видел — как-то сложно на первый взгляд. Честно говоря, больше всего понравилось System.Drawing из .Net'а — как раз из-за простоты использования.
Re: Покритикуйте библиотеку для работы с изображениями
От: Sealcon190 Соломоновы острова  
Дата: 05.09.07 17:02
Оценка:
Здравствуйте, syomin, Вы писали:

S>
S>private:
S>    Size size_;
S>    std::vector<Pixel> pixels_;
S>};
S>



Как я понял в GetPixel у тебя будет что-то типа этого:
return pixels_[y*size.width + x];

Так вот если пользователю понадобится изображение обрабатывать, то использование GetPixel и SetPixel приведет к страшным тормозам. Или предусмотри возможность прямого доступа к буферу данных типа void* GetDataPtr(), или хотя бы заведи массив указателей на начало каждой строки, чтобы в GetPixel и SetPixel делать так:
return *(ptr_vect[y]+x);
Re[2]: Покритикуйте библиотеку для работы с изображениями
От: Sealcon190 Соломоновы острова  
Дата: 05.09.07 17:16
Оценка:
Да и еще в догонку.

Использование такого навороченного класса CPoint мне кажется надуманным ходом. ИМХО это будет и медленнее, и неудобнее, и менее прозрачно чем старая добрая структура из двух интов. Это тот самый случай когда инкапсуляция нафиг не нужна.
Re[2]: Покритикуйте библиотеку для работы с изображениями
От: syomin  
Дата: 05.09.07 18:17
Оценка:
Добрый вечер!

S>Так вот если пользователю понадобится изображение обрабатывать, то использование GetPixel и SetPixel приведет к страшным тормозам. Или предусмотри возможность прямого доступа к буферу данных типа void* GetDataPtr(), или хотя бы заведи массив указателей на начало каждой строки, чтобы в GetPixel и SetPixel делать так:

S>return *(ptr_vect[y]+x);

Пожалуй, соглашусь, хотя тут тоже все не так однозначно. Если алгоритмы обработки таковы, что вызовы GetPixel() и SetPixel() происходят относительно часто, то, действительно, накладные расходы на вычисление смещения пиксела относительно начала массива (вектора) могут оказаться существенными. В этом случае лучшее решение проблемы — механизм итераторов — он не нарушает инкапсуляцию и предоставляет прямой доступ к элементам. Странно, что ни в Qt4, ни в .Net ни в Java итераторы для доступа к пикселам не применяются.
Re: Покритикуйте библиотеку для работы с изображениями
От: Хитрик Денис Россия RSDN
Дата: 05.09.07 20:56
Оценка:
Здравствуйте, syomin, Вы писали:

S>Возникла задача разработать библиотеку на языке C++ для обработки растровых изображений. Специфика задачи такова, что приходится иметь дело с различными цветовыми пространствами. Минимум — grayscale и binary, в дальнейшем, возможно, появится RGB.


Что значит "обработка растровых изображений"? Какие задачи вообще стоят?

S>Для примера смотрел на Qt4, System.Drawing из .Net и java.awt.Graphics.


На CxImage смотрели? А что понравилось/не понравилось в указанных библиотеках? Почему решили велосипед писать?
Ещё есть Intel Performance Primitives — там часть библиотеки занимается как раз обработкой изображений.
Правила нашего с вами форума.
Как правильно задавать вопросы. © 2001 by Eric S. Raymond; перевод: © 2002 Валерий Кравчук.
Re[3]: Покритикуйте библиотеку для работы с изображениями
От: Trean Беларусь http://axamit.com/
Дата: 05.09.07 21:18
Оценка:
Здравствуйте, syomin, Вы писали:

S>Добрый вечер!


S>>Так вот если пользователю понадобится изображение обрабатывать, то использование GetPixel и SetPixel приведет к страшным тормозам. Или предусмотри возможность прямого доступа к буферу данных типа void* GetDataPtr(), или хотя бы заведи массив указателей на начало каждой строки, чтобы в GetPixel и SetPixel делать так:

S>>return *(ptr_vect[y]+x);

S>Пожалуй, соглашусь, хотя тут тоже все не так однозначно. Если алгоритмы обработки таковы, что вызовы GetPixel() и SetPixel() происходят относительно часто, то, действительно, накладные расходы на вычисление смещения пиксела относительно начала массива (вектора) могут оказаться существенными. В этом случае лучшее решение проблемы — механизм итераторов — он не нарушает инкапсуляцию и предоставляет прямой доступ к элементам. Странно, что ни в Qt4, ни в .Net ни в Java итераторы для доступа к пикселам не применяются.


Самый быстрый способ прямой доступ к памяти — по указателю, без всяких итераторов и прочих оберток. По большей части, работа с изображениями, подобна работе с матрицами, т.е. блочная по идеологии. Т.е. удобнее работать ограниченным набором алгоритмических примитивов, вроде свертки, корреляции и т.д. Такие примитивы можно реализовать один раз и очень эффективно с точки зрения использования ресурсов.
Съэкономьте себе время, используйте IPP, OpenCV или JAI, или аналогичные библиотеки. Люди которые их проектировали "в теме", очень многие важные вопросы хорошо продуманы (абстрагирование от цветовых пространств, ROI, фильтры, маски, трансформации изображений, выравнивание в памяти и кэширование). Разумеется, речь идет о серьезном использовании, а не простой отрисовке чего-то поверх картинки.
Re[2]: Покритикуйте библиотеку для работы с изображениями
От: syomin  
Дата: 06.09.07 05:44
Оценка:
Денис, доброе утро!

ХД>Что значит "обработка растровых изображений"? Какие задачи вообще стоят?

Фильтрация, бинаризация, выделение связанных областей.

ХД>На CxImage смотрели? А что понравилось/не понравилось в указанных библиотеках? Почему решили велосипед писать?

В CxImage неустраивает хотя бы вот это: "It is not a MFC library, altogether it's a windows library", т.к. Linux у меня — основная платформа. Что касается Qt4, System.Drawing и чего-то там из Java, то главный, на мой взгляд, недостаток этих библиотек в том, что вне зависимости от того, в каком цветовом пространстве мы работаем, используется один и тот же класс Bitmap. В VIGRA, например, используется именно такой подход.
ХД>Ещё есть Intel Performance Primitives — там часть библиотеки занимается как раз обработкой изображений.
Re[3]: Покритикуйте библиотеку для работы с изображениями
От: GlebZ Россия  
Дата: 06.09.07 07:03
Оценка:
Здравствуйте, syomin, Вы писали:

S>Пожалуй, соглашусь, хотя тут тоже все не так однозначно. Если алгоритмы обработки таковы, что вызовы GetPixel() и SetPixel() происходят относительно часто, то, действительно, накладные расходы на вычисление смещения пиксела относительно начала массива (вектора) могут оказаться существенными. В этом случае лучшее решение проблемы — механизм итераторов — он не нарушает инкапсуляцию и предоставляет прямой доступ к элементам. Странно, что ни в Qt4, ни в .Net ни в Java итераторы для доступа к пикселам не применяются.

Функция SetPixel/GetPixel, которая является вызовом апишной, практически нигде не применяется в силу своей огромной тормознутости. При вызове проходит большое кол-во проверок. А поскольку с пикселями придется работать вплотную, применимость очень скромная.
Re: Покритикуйте библиотеку для работы с изображениями
От: GlebZ Россия  
Дата: 06.09.07 07:12
Оценка:
Здравствуйте, syomin, Вы писали:

S>Для тех, кто все-таки добрался до этого места, у меня есть ряд вопросов:

S>1. Какие есть минусы схемы с наследованием от Image<>? Мне пока ничего такого найти не удалось, поэтому и возникают некоторые сомнения — почему я такого больше нигде не видел?
Если использовать Image только как контейнер — никаких. Для доступа к пикселям — нужны другие классы. Еще, судя по твоим задачам — тебе скорее всего понадобится раздельная работа по каналам.
S>2. Стоит ли овчинка выделки применительно к классам Point и Size? Может лучше отказаться от них, а при вызове методов Image<> отдельно указывать x и y (или width и height)?
Стоит — удобная структуры. Только стоит их сделать максимально открытыми для использования. Практически без инкапсуляции.
S>3. Ну и вообще, как вам дизайн?
Судя по всему — это только малая толика того дизайна которые тебе понадобится.
Re: Покритикуйте библиотеку для работы с изображениями
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 06.09.07 14:01
Оценка: +1
Здравствуйте, syomin, Вы писали:

S>1. Какие есть минусы схемы с наследованием от Image<>? Мне пока ничего такого найти не удалось, поэтому и возникают некоторые сомнения — почему я такого больше нигде не видел?

Думаю, Вы согласитесь с тем, что библиотеки пишутся для того, чтобы выполнять некоторые функции. Это означает, что у библиотеки должны быть некоторые обязанности. Какими обязанностями обладает Ваш класс Image? Если посмотреть внимательно, то никакими. Функции установки и получения пикселя, как уже справедливо писали коллеги, будут работать слишком медленно. А кроме этих функций никакого другого API у класса по существу нет.

Конечно, с помощью шаблона Вы смогли абстрагироваться от типа пикселя. Пиксель может быть представлен байтом, словом, двойным словом. Но такое абстрагирование бесполезно, т.к. непонятно, как алгоритмы будут использовать подобную абстракцию — функции GetPixel() и SetPixel() использовать нельзя.

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

S>2. Стоит ли овчинка выделки применительно к классам Point и Size? Может лучше отказаться от них, а при вызове методов Image<> отдельно указывать x и y (или width и height)?

Стоит, если у них есть обязанности.

S>3. Ну и вообще, как вам дизайн?

На мой взгляд, есть еще над чем поработать.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re: Покритикуйте библиотеку для работы с изображениями
От: minorlogic Украина  
Дата: 06.09.07 14:26
Оценка:
Посмотрите GIL от адоба , в ее создании принимал участие Степанов , автор СТЛ
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: Покритикуйте библиотеку для работы с изображениями
От: syomin  
Дата: 07.09.07 16:34
Оценка:
Может, кому-то будет интересно:
http://kogs-www.informatik.uni-hamburg.de/~koethe/papers/handbook.ps.gz
http://kogs-www.informatik.uni-hamburg.de/~koethe/papers/GenericProg2DC++Report.ps.gz
Re: Покритикуйте библиотеку для работы с изображениями
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 18.09.07 08:51
Оценка:
Здравствуйте, syomin, Вы писали:

S>Добрый день! Заранее извиняюсь за объем сообщения, сокращал как мог.


S>Возникла задача разработать библиотеку на языке C++ для обработки растровых изображений. Специфика задачи такова, что приходится иметь дело с различными цветовыми пространствами. Минимум — grayscale и binary, в дальнейшем, возможно, появится RGB.


S>Заранее благодарю за ответы по существу.


Покопайтесь в AGG для разнообразия.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
HgLab: Mercurial Server and Repository Management for Windows
Re[2]: Покритикуйте библиотеку для работы с изображениями
От: adontz Грузия http://adontz.wordpress.com/
Дата: 26.09.07 23:10
Оценка:
Здравствуйте, Нахлобуч, Вы писали:

Н>Покопайтесь в AGG для разнообразия.


Если туда основательно зарыться, то потом уже вылезти не удастся.
A journey of a thousand miles must begin with a single step © Lau Tsu
Re: Покритикуйте библиотеку для работы с изображениями
От: syomin  
Дата: 28.09.07 19:56
Оценка:
Добрый день!

Решил добавить класс Rectangle для работы с прямоугольными областями изображения. Прямоугольник будет задаваться координатой верхнего левого угла (класс Point) и размерами (класс Size). Определенный интерес представляют методы, возвращающие координаты правого нижнего угла прямоугольника (нужно, например, для обхода всех пикселей области в цикле). Порывшись встретил два варианта:
1. правый нижний угол имеет координаты (left + width — 1, top + height — 1);
2. правый нижний угол имеет координаты (left + width, top + height).

Первый способ используется в Qt4 (класс QRect), второй — опять же в Qt4 (класс QRectF) и GDI+. Честно говоря, первый вариант мне кажется более "концептуально целостным" что ли, но почему в GDI+ сделали по-другому? Может, тут есть какие-то тонкости, связанные с переходом к вещественным координатам?
Re[2]: Покритикуйте библиотеку для работы с изображениями
От: adontz Грузия http://adontz.wordpress.com/
Дата: 28.09.07 20:06
Оценка:
Здравствуйте, syomin, Вы писали:

S>1. правый нижний угол имеет координаты (left + width — 1, top + height — 1);

S>2. правый нижний угол имеет координаты (left + width, top + height).
S>Первый способ используется в Qt4 (класс QRect), второй — опять же в Qt4 (класс QRectF) и GDI+. Честно говоря, первый вариант мне кажется более "концептуально целостным" что ли, но почему в GDI+ сделали по-другому? Может, тут есть какие-то тонкости, связанные с переходом к вещественным координатам?

Первый способ хорош для целых чисел, второй для вещественных.
Почему? Подумай о реализации базовых операций.
A journey of a thousand miles must begin with a single step © Lau Tsu
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.