Быстрый алгоритм искажения изображения - PullRequest
3 голосов
/ 06 декабря 2011

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

Код, который я использую, следующий: для каждой точки (x, y) в области назначения я вычисляю соответствующий пиксель (sourceX, sourceY) в исходном изображении для извлечения.

Но этот подход неловко медленен, в моем тесте для обработки sunset.jpg (800 * 600) требуется более 1500 мсек, если я уберу математические / тригонометрические вычисления, для вызова только cvGet2D и cvSet2D потребуется более 1200 мс.

Есть ли лучший способ сделать это? Я использую Emgu CV (библиотека-оболочка .NET для OpenCV), но примеры на другом языке тоже в порядке.

private static void DistortSingleImage()
{
    System.Diagnostics.Stopwatch stopWatch = System.Diagnostics.Stopwatch.StartNew();
    using (Image<Bgr, Byte> origImage = new Image<Bgr, Byte>("sunset.jpg"))
    {
        int frameH = origImage.Height;
        using (Image<Bgr, Byte> distortImage = new Image<Bgr, Byte>(2 * frameH, 2 * frameH))
        {
            MCvScalar pixel;
            for (int x = 0; x < 2 * frameH; x++)
            {
                for (int y = 0; y < 2 * frameH; y++)
                {
                    if (x == frameH && y == frameH) continue; 
                    int x1 = x - frameH;
                    int y1 = y - frameH;
                    if (x1 * x1 + y1 * y1 < frameH * frameH) 
                    {
                        double radius = Math.Sqrt(x1 * x1 + y1 * y1);
                        double theta = Math.Acos(x1 / radius);
                        int sourceX = (int)(theta * (origImage.Width - 1) / Math.PI);
                        int sourceY = (int)radius;
                        pixel = CvInvoke.cvGet2D(origImage.Ptr, sourceY, sourceX);
                        CvInvoke.cvSet2D(distortImage, y, x, pixel);
                    }
                }
            }
            distortImage.Save("Distort.jpg");
        }
        Console.WriteLine(stopWatch.ElapsedMilliseconds);
    }
}

The desired distortion

1 Ответ

2 голосов
/ 06 декабря 2011

Исходя из моего личного опыта, я занимался вопросами стереоскопического зрения, лучший способ общения с openCV - через собственную оболочку, вы можете поместить свой метод в c ++ и вызвать его из c #, что даст вам 1 вызов native. более быстрый код, и потому что Emgu хранит данные OpenCV, также возможно создать изображение с помощью emgu, обработать его естественным образом и снова наслаждаться обработанным изображением в c #.

Методы get / set выглядят как методы Gdi GetPixel / SetPixel, и, согласно документации, они «медленные, но безопасные».

Для того, чтобы остаться только с Emgu, в документации сказано, что если вы хотите выполнить итерации по пикселям, вы должны получить доступ к свойству .Data:

Безопасный (медленный) путь

Предположим, вы работаете над изображением. Вы можете получить пиксель в y-й строке и x-м столбце, вызвав Bgr color = img [y, x]; Установить пиксель в y-й строке и x-м столбце также просто img [y, x] = цвет;

Быстрый путь

Значения пикселей изображения хранятся в свойстве Data, трехмерном массиве. Используйте это свойство, если вам нужно перебрать значения пикселей изображения.

...