Ответ 1
Нет простого способа сделать это. Как масштабирование, так и вращение не "тривиальный" процесс.
Google это для 2-й библиотеки изображений. Magick++ может быть идеей как divideandconquer.se, но есть и другие.
Каков наилучший способ масштабирования массива 2D-изображений? Например, предположим, что у меня есть изображение размером 1024 x 2048 байт, причем каждый байт является пикселем. Каждый пиксель - это оттенок серого от 0 до 255. Я хотел бы иметь возможность масштабировать это изображение произвольным фактором и получать новое изображение. Итак, если я масштабирую изображение в 0,68, я должен получить новое изображение размером 0,68 * 1024 x 0,68 * 2048. некоторые пиксели будут свернуты друг на друга. И, если я масштабируюсь в 3,1 раза, я бы получил увеличенное изображение с дублирующимися пикселями. Итак, какой лучший способ это сделать?
Затем я хотел бы иметь возможность поворачивать изображение на произвольный угол в диапазоне от 0 до 360 градусов (0 - 2Pi). Обрезка изображения после вращения не является проблемой. Какой был бы лучший способ сделать это?
Нет простого способа сделать это. Как масштабирование, так и вращение не "тривиальный" процесс.
Google это для 2-й библиотеки изображений. Magick++ может быть идеей как divideandconquer.se, но есть и другие.
Существует множество способов масштабирования и поворота изображений. Самый простой способ масштабирования:
dest[dx,dy] = src[dx*src_width/dest_width,dy*src_height/dest_height]
но это приводит к блочным эффектам при увеличении размера и потери деталей при уменьшении размера. Существуют способы получения улучшенных результатов, например билинейная фильтрация.
Для вращения местоположение пикселя src можно вычислить с помощью матрицы вращения:
sx,sy = M(dx,dy)
где M - матрица, которая отображает пиксели назначения в исходное изображение. Опять же, вам нужно сделать интерполяцию для получения неблокированных результатов.
Но есть много доступных библиотек, если вы не хотите попасть в математику обработки изображений.
То, что вы делаете, - это сопоставление набора входных точек с множеством точек вывода. Первая часть проблемы заключается в определении отображения для вашего изменения размера или вращения; вторая часть - обрабатывать точки, которые не лежат точно на границе пикселя.
Отображение для изменения размера очень просто:
x' = x * (width' / width)
y' = y * (height' / height)
Отображение для вращения немного сложнее.
x' = x * cos(a) + y * sin(a)
y' = y * cos(a) - x * sin(a)
Метод определения значения пикселей, которые лежат вне сетки, называется интерполяцией. Существует множество таких алгоритмов, которые широко варьируются по скорости и качеству конечного изображения. Некоторые из них в порядке возрастания качества/времени являются ближайшими соседними, билинейными, бикубическими и фильтрами Sinc.
Вы хотите сделать свою грязную работу самостоятельно или можете ImageMagick сделать это за вас?
Дублирование или отбрасывание пикселей - это не лучший способ или изменение размера изображения, так как в результате будут отображаться пикселизация и неровность. Для достижения наилучших результатов вы должны перепрограммировать изображение, что придаст результирующему изображению гораздо более плавный вид. Существует множество способов передискретизации, таких как билинейный, бикубический, lanczos и т.д.
Посмотрите на функцию BicubicResample из wxWidgets. Он будет работать со всеми видами изображений, а не только с оттенками серого, но вы должны быть в состоянии адаптировать его к вашим потребностям. Затем также выполняется передискретизация кода из VirtualDub. Google Codesearch может выявить более сопутствующий код.
РЕДАКТИРОВАТЬ: ссылки отлично смотрятся в предварительном просмотре, но нарушаются при публикации. Это странно. Для получения одинаковых результатов перейдите к кодовому поиску google и запросите "wxwidgets resamplebicubic" и "virtualdub resample" соответственно.
CxImage - бесплатная библиотека для обработки изображений, которая может делать то, что вы хотите. Я лично не использовал его, кроме тривиальных вещей, но я неоднократно видел его.
Это еще не упоминалось, поэтому я хотел бы указать, что 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());
point scaling(point p,float sx,float sy) {
point s;
int c[1][3];
int a[1][3]={p.x,p.y,1};
int b[3][3]={sx,0,0,0,sy,0,0,0,1};
multmat(a,b,c);
s.x=c[0][0];
s.y=c[0][1];
return s;
}
Методы изменения размера CxImage дают странный результат. Я использовал функции Resample и Resample2 со всеми доступными вариациями методов интерполяции с одинаковым результатом. Например, попробуйте изменить размер изображения 1024 x 768, заполненного белым цветом, до размера 802 x 582. Вы увидите, что на изображении, имеющем цвет different, есть пиксели белого цвета! Вы можете проверить это: открыть изображение с уменьшенным размером в Windows Paint и попытаться заполнить его черным цветом. Результат наверняка поразит вас.
Ознакомьтесь с Примитивами производительности Intel. Я использовал его раньше, и он дает почти оптимальную производительность на x86. Существует также тестовая программа, которая позволяет играть с различными алгоритмами.