Масштабирование и поворот изображения в C / C ++

Как лучше всего масштабировать массив 2D-изображений? Например, предположим, что у меня есть изображение размером 1024 x 2048 байтов, каждый из которых является пикселем. Каждый пиксель представляет собой уровень оттенков серого от 0 до 255. Я хотел бы иметь возможность масштабировать это изображение с произвольным коэффициентом и получать новое изображение. Итак, если я масштабирую изображение с коэффициентом 0,68, я должен получить новое изображение размером 0,68 * 1024 x 0,68 * 2048. некоторые пиксели будут свернуты друг на друга. И, если я масштабирую с коэффициентом, скажем, 3,15, я получу более крупное изображение с дублированными пикселями. Итак, как лучше всего этого добиться?

Затем я хотел бы иметь возможность вращать изображение на произвольный угол в диапазоне от 0 до 360 градусов (0 - 2Pi). Обрезка изображения после поворота не является проблемой. Как лучше всего это сделать?


person kafuchau    schedule 18.11.2008    source источник


Ответы (9)


Нет простого способа добиться этого. Ни масштабирование, ни вращение не являются тривиальными процессами.

Поэтому рекомендуется использовать библиотеку 2D-изображений. Идея Magick ++ может быть идеей, но есть и другие.

person Pablo Herrero    schedule 18.11.2008

Есть много способов масштабировать и вращать изображения. Самый простой способ масштабирования:

dest[dx,dy] = src[dx*src_width/dest_width,dy*src_height/dest_height]

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

Для поворота местоположение src-пикселя можно рассчитать с помощью матрицы поворота:

sx,sy = M(dx,dy)

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

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

person Skizz    schedule 18.11.2008

Что вы делаете, так это сопоставляете набор входных точек с набором выходных точек. Первая часть проблемы - определить отображение для изменения размера или поворота; вторая часть предназначена для обработки точек, которые не лежат точно на границе пикселя.

Сопоставление для изменения размера очень просто:

x' = x * (width' / width)
y' = y * (height' / height)

Составить карту для вращения немного сложнее.

x' = x * cos(a) + y * sin(a)
y' = y * cos(a) - x * sin(a)

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

person Mark Ransom    schedule 18.11.2008

Вы хотите делать грязную работу самостоятельно или можете ImageMagick сделать это за вас?

person activout.se    schedule 18.11.2008

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

Взгляните на функцию Resamples wxWidgets. Он работает со всеми видами изображений, не только в оттенках серого, но вы должны иметь возможность адаптировать его к своим потребностям. Также есть код передискретизации из VirtualDub. Google Codesearch может выявить больше связанного кода.

РЕДАКТИРОВАТЬ: ссылки выглядят нормально в предварительном просмотре, но не работают при публикации. Это странно. Перейдите в google codesearch и запросите «wxwidgets resamplebicubic» и «virtualdub resample» соответственно, чтобы получить те же результаты.

person user38329    schedule 18.11.2008

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

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

Используя OpenCV, масштабирование можно сделать так:

float scaleFactor = 0.68f;
cv::Mat original = cv::imread(path);
cv::Mat scaled;
cv::resize(original, scaled, cv::Size(0, 0), scaleFactor, scaleFactor, cv::INTER_LANCZOS4);
cv::imwrite("new_image.jpg", scaled);

Это уменьшает изображение с коэффициентом 0,68 с использованием интерполяции Ланцоша.

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

/// Compute a rotation matrix with respect to the center of the image
Point center = Point(original.size().width / 2, original.size().height / 2);
double angle = -50.0;
double scale = 0.6;

/// Get the rotation matrix with the specifications above
Mat rot_mat( 2, 3, CV_32FC1 );
rot_mat = getRotationMatrix2D(center, angle, scale);

/// Rotate the image
Mat rotated_image;
warpAffine(src, rotated_image, rot_mat, src.size());

Веб-сайт OpenCV

У них тоже есть очень хорошая документация.

person Meta    schedule 30.08.2016
comment
Хорошая точка зрения. Я добавил несколько примеров, так что теперь это более реальный ответ. - person Meta; 31.08.2016

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

person peterchen    schedule 18.11.2008
comment
Хотя теоретически это может дать ответ на вопрос, было бы предпочтительнее включить сюда основные части ответа и предоставить ссылку для справки. . - person Toby Speight; 31.08.2016

Методы изменения размера CxImage дают странный результат. Я использовал функции Resample и Resample2 со всеми доступными вариантами методов интерполяции с тем же результатом. Например, попробуйте изменить размер изображения 1024 x 768, залитого белым цветом, до размера 802 x 582. Вы обнаружите, что на изображении есть пиксели, цвет которых отличается от белого! Вы можете проверить это: откройте изображение с измененным размером в Windows Paint и попробуйте залить его черным цветом. Результат наверняка вас развеселит.

person izogfif    schedule 19.08.2010

Ознакомьтесь с примитивами производительности Intel. Я использовал его раньше, и он дает почти оптимальную производительность на x86. Также есть тестовая программа, которая позволяет поиграть с различными алгоритмами.

person Jon Clegg    schedule 15.02.2012
comment
Хотя теоретически это может дать ответ на вопрос, было бы предпочтительнее включить сюда основные части ответа и предоставить ссылку для справки. . - person Toby Speight; 31.08.2016