Как сохранить качество изображения после поворота в C #?

#c# #image #rotation

#c# #изображение #вращение #поворот

Вопрос:

мой лектор потребовал, чтобы я написал программу, которая может поворачивать изображение без каких-либо функций преобразования, предоставляемых библиотекой C #, это означает, что я просто мог использовать метод, который предоставляется по ссылке this wiki . Моя проблема в том, что после поворота качество изображения стало очень плохим, как показано на рисунке ниже.

изображение с левой стороны является источником

И вот мой код, первая часть — создание нового растрового изображения для изображения после поворота:

             double sin = Math.Abs(Math.Sin(ratio * (Math.PI / 180.0)));
            double cos = Math.Abs(Math.Cos(ratio * (Math.PI / 180.0)));
            bmpOut = new Bitmap((int)(sin * bmpIn.Width   cos * bmpIn.Height), (int)(sin * bmpIn.Height   cos * bmpIn.Width));
  

И вот код, который поворачивает изображение

         int intHeight = bitmapOri.Height;
        int intWidth = bitmapOri.Width;

        double x_cen = intWidth / 2.0;
        double y_cen = intHeight / 2.0;

        unsafe
        {
            for (int j = 0; j < intWidth; j  )
            {
                for (int i = 0; i < intHeight; i  )
                {
                    double x_new = x_cen   (double)((j - x_cen) * Math.Cos(ratio) - (i - y_cen) * Math.Sin(ratio));
                    double y_new = y_cen   (double)((j - x_cen) * Math.Sin(ratio)   (i - y_cen) * Math.Cos(ratio));
                    if (x_new < 0 || y_new < 0 || x_new >= bitmapRes.Width || y_new >= bitmapRes.Height)
                        continue;
                    bitmapRes.SetPixel((int)x_new, (int)y_new, bitmapOri.GetPixel(j, i));
                }
            }
        }
  

Не могли бы вы сказать мне, что такое мошенничество в моем коде, что с ним не так, большое спасибо за вашу помощь.

Комментарии:

1. при повороте необходимо учитывать отношение высоты к ширине. если вы повернете изображение шириной 4 и высотой 3 на 90 градусов без регулировки, вы в конечном итоге превратите 4 в 3 и разложите 3 на 4. так что либо отрегулируйте способ поворота, либо найдите способ повернуть объект, в котором находится изображение, а не само изображение.

2. Корень проблемы в вашем кастинге. Когда вы поворачиваете точку вокруг начала координат, точка в подавляющем большинстве случаев приводит к десятичному числу, но когда вы приводите координаты к (int), вы отбрасываете эту информацию. Это приводит к тому, что некоторые пиксели устанавливаются более одного раза, в то время как другие не устанавливаются вообще. Простым решением является округление, а не усечение, но более надежным решением является ответ ZenWu.

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

4. Другой вопрос. что происходит с моей функцией поворота, когда изображение не вращается по центру?

Ответ №1:

проблема

операция double to int может привести к тому, что некоторые пиксели будут установлены более одного раза, а некоторые пиксели не будут установлены

решение

попробуйте противоположный способ

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

Подробные сведения

как вычислить местоположение в исходном изображении

  1. пусть ось поворота равна O, рассматривая точку A как пиксель в целевом изображении

  2. OA может быть записан как t * rotate(alpha, OX). OX — это нормализованный вектор, начинающийся с точки O. это означает, что вектор OA можно рассматривать как (или получить) повернутый на альфа-угол от OA, и он может иметь специальную длину (t). И реальное значение OA будет (t * cos (альфа), t * sin (альфа))

  3. предположим, что OA был фактически повернут OB, поскольку он находится в целевом изображении, повернутом по сравнению с исходным изображением, поэтому OB можно записать как t * rotate (альфа бета, X). Это означает, что OA была одной операцией поворота, отличной от OB. Это немного странно. Но это правильно и полезно.

  4. давайте сделаем настоящую работу сейчас. Фактическое значение OB равно (t * cos (альфа бета), t * sin(альфа бета)).

  5. давайте сосредоточимся на координате X, которая равна t * cos (альфа) * sin (бета) t * sin (альфа) t * cos (бета), и вернемся к просмотру OA coordinate. из этого следует, что X (OB) = sin (бета) * X (OA) cos (бета) * Y (OA). Координата Y такая же.

Комментарии:

1. Технический термин для шага 3 — «билинейная интерполяция».

2. Какая формула может помочь мне найти местоположение на исходном изображении на шаге 2?

3. @iamatsundere181 просто обратная функция вашей формулы, попробуйте сами, может быть, так как это упражнение

4. Другой вопрос. что происходит с моей функцией поворота, когда изображение не вращается по центру?

5. @iamatsundere181 Мне так жаль, что я действительно не проверил вашу формулу поворота. Я отредактировал ответ и добавил некоторые подробности о шаге 2. Также упоминался поворот поворота