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

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

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

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

4b9b3361

Ответ 1

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

Google это для 2-й библиотеки изображений. Magick++ может быть идеей как divideandconquer.se, но есть и другие.

Ответ 2

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

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

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

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

sx,sy = M(dx,dy)

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

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

Ответ 3

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

Отображение для изменения размера очень просто:

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

Отображение для вращения немного сложнее.

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

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

Ответ 4

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

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

Это еще не упоминалось, поэтому я хотел бы указать, что 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

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

Ответ 8

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;
}

Ответ 9

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

Ответ 10

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