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

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

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

10 ответов


там нет "простой" способ acommplish, что. Как масштабирование, так и вращение не "тривиальной" procesis.

Google для библиотеки 2d-изображений. магия++ может быть идея как 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 сделать это для вас?


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

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

EDIT: ссылки выглядят нормально в предварительном просмотре, но нарушаются при публикации. Это странно. Перейдите в Google codesearch и запросите "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, используя интерполяции lanczos.

Я не так хорошо знаком с ротациями, но вот часть примера из одного из учебников на веб-сайте 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

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


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


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

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