Подтвердить что ты не робот

Как сделать высококачественное масштабирование изображения?

Я пишу код для масштабирования 32-битного изображения RGBA в C/С++. Я написал несколько попыток, которые были несколько успешными, но они медленны, а главное качество изображения не приемлемо.

Я сравнивал одно и то же изображение, масштабируемое OpenGL (то есть моя видеокарта), и моя рутина, и она была немного отличается качеством. Я искал Google Code, просматривал исходные деревья всего, что, как я думал, прольет свет (SDL, Allegro, wxWidgets, CxImage, GD, ImageMagick и т.д.), Но обычно их код либо запутан и разбросан по всему месту, либо пронизан сборщиком и небольшими комментариями или без комментариев. Я также читал несколько статей в Википедии и в других местах, и я просто не нашел ясного объяснения того, что мне нужно. Я понимаю основные понятия интерполяции и выборки, но я изо всех сил пытаюсь получить алгоритм правильно. Я НЕ хочу полагаться на внешнюю библиотеку для одной подпрограммы и должен конвертировать в свой формат изображения и обратно. Кроме того, я хотел бы знать, как это сделать в любом случае.:)

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

Вот что я ищу:

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

Моя процедура по существу принимает следующий вид:

DrawScaled(uint32 *src, uint32 *dst, 
      src_x, src_y, src_w, src_h, 
      dst_x, dst_y, dst_w, dst_h );

Спасибо!

ОБНОВЛЕНИЕ: Чтобы уточнить, мне нужно что-то более продвинутое, чем перемасштабирование коробки для уменьшения масштаба, что слишком сильно размывает изображение. Я подозреваю, что я хочу, это какой-то бикубический (или другой) фильтр, который в некотором роде обращен к бикубическому алгоритму масштабирования (т.е. Каждый пиксель назначения вычисляется из всех исходных пикселей источника в сочетании с алгоритмом взвешивания, который сохраняет четкость.

Пример

Вот пример того, что я получаю от алгоритма wxWidgets BoxResample по сравнению с тем, что я хочу, на растровом изображении 256x256, масштабированном до 55x55.

  • www.free_image_hosting.net/uploads/1a25434e0b.png

И наконец:

  • www.free_image_hosting.net/uploads/eec3065e2f.png

исходное изображение 256x256

4b9b3361

Ответ 1

Я нашел, что реализация wxWidgets довольно проста для изменения, если требуется. Это все С++, поэтому проблем с переносимостью там нет. Единственное отличие заключается в том, что их реализация работает с unsigned char массивами (которые, как мне кажется, проще всего обрабатывать изображения) с байтовым порядком RGB и альфа-компонентом в отдельном массиве.

Если вы ссылаетесь на файл "src/common/image.cpp" в дереве исходных данных wxWidgets, есть функция сэмплирования вниз, которая использует метод выборки ящиков "wxImage:: ResampleBox" и функцию масштабирования, называемую "wxImage:: ResampleBicubic".

Ответ 2

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

Ответ 3

Возможно ли, что OpenGL делает масштабирование в векторном домене? Если это так, нет никакого способа, чтобы какое-либо масштабирование на основе пикселей было рядом с ним по качеству. Это большое преимущество векторных изображений.

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

Изменить: Это была работа Митчелла-Нетравали, о которой я думал, на которую ссылается внизу этой ссылки:

http://www.cg.tuwien.ac.at/~theussl/DA/node11.html

Вы также можете изучить повторную выборку Lanczos в качестве альтернативы бикубическому.

Ответ 4

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

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

Ответ 5

Статьи CodeProject, обсуждающие и использующие исходный код для масштабирования изображений:

Ответ 6

Попробуйте использовать Adobe Generic Image Library (http://opensource.adobe.com/wiki/display/gil/Downloads), если вы хотите что-то готовое и не только алгоритм.


Выдержка из: http://www.catenary.com/howto/enlarge.html#c

Увеличить или уменьшить - исходный код C Требуется библиотека обработки изображений Виктора для 32-разрядной версии Windows версии 5.3 или выше.


int enlarge_or_reduce(imgdes *image1)
{
   imgdes timage;
   int dx, dy, rcode, pct = 83; // 83% percent of original size

   // Allocate space for the new image
   dx = (int)(((long)(image1->endx - image1->stx + 1)) * pct / 100);
   dy = (int)(((long)(image1->endy - image1->sty + 1)) * pct / 100);
   if((rcode = allocimage(&timage, dx, dy,
      image1->bmh->biBitCount)) == NO_ERROR) {
      // Resize Image into timage
      if((rcode = resizeex(image1, &timage, 1)) == NO_ERROR) {
         // Success, free source image
         freeimage(image1);
         // Assign timage to image1
         copyimgdes(&timage, image1);
         }
      else // Error in resizing image, release timage memory
         freeimage(&timage);
      }
   return(rcode);
}

Этот пример изменяет размер области изображения и заменяет исходное изображение новым изображением.

Ответ 8

Intel имеет библиотеки IPP, которые обеспечивают высокоскоростные алгоритмы интерполяции, оптимизированные для процессоров семейства Intel. Это очень хорошо, но это не бесплатно. Взгляните на следующую ссылку:

Intel IPP

Ответ 9

Похоже на то, что вы действительно испытываете трудности с пониманием, - это дискретный → непрерывный → дискретный поток, задействованный в правильной передискретизации изображения. Хороший технический отчет, который может помочь вам понять, что вам нужно, это Alvy Ray Smith Пиксель - это не маленький квадрат.

Ответ 10

Посмотрите ImageMagick, который выполняет все виды фильтров масштабирования.

Ответ 11

В качестве продолжения, Джереми Радд разместил эту статью выше. Он реализует фильтрованное изменение размера двух проходов. Источниками являются С#, но это выглядит достаточно ясно, что я могу его портировать, чтобы попробовать. Вчера я нашел очень похожий код C, который было намного сложнее понять (очень плохие имена переменных). Я получил его на работу, но он был очень медленным и не давал хороших результатов, что заставило меня поверить, что в моей адаптации была ошибка. Возможно, мне удастся написать это с нуля с этой ссылкой, которую я попробую.

Но учитывая, как работает алгоритм с двумя проходами, я задаюсь вопросом, не существует ли более быстрый способ сделать это, возможно, даже за один проход?