LINUX.ORG.RU

Аффинные преобразования в OpenCV и MXNet

 , , , ,


2

4

Привет всем!

Есть, значит, у меня картинка и матрица аффинных преобразований для неё. Нужно исказить картинку и обрезать под требуемый размер. Сейчас это делается так:

result = cv2.warpAffine(img, affine_matrix, (target_w, target_h), borderValue=0.0)
и всё работает. Но не быстро, т.к. на процессоре. В приложении много где используется фреймворк MXNet, который может ускоряться на GPU. Прямого аналога для warpAffine я там не нахожу. Результаты гугления по теме очень скудны, нашлось только немного документации c одним примером. В принципе, это то, что нужно, замена выглядит как-то так:
grid = mx.ndarray.GridGenerator(data=affine_matrix, transform_type='affine', target_shape=(original_h, original_w))
img_nchw = mx.ndarray.array(img)
img_nchw = img_nchw.transpose((2, 0, 1))
img_nchw = mx.ndarray.expand_dims(img_nchw, 0)
result = mx.ndarray.BilinearSampler(img_nchw, grid)
(Понятно, что картинку потом надо превести к прежнему виду, сделать transpose, squeeze...)

Но есть большая проблема: GridGenerator надо передавать совсем не такую матрицу, как в warpAffine. Некоторые элементы матрицы достаточно понятно преобразуются в вид для GridGenerator. Например, в warpAffine увеличение в два раза задаётся как 2, а для GridGenerator - 0.5. Это работает, если задавать только данные элементы, без искажений. А вот с коэффициентами для искажений не понятно совсем, подобрать их не получается.

Может быть кому-то попадалась внятная документация по mx.ndarray.GridGenerator с примерами?

P.S.: Да, можно найти другие варианты, вместо MXNet для издевательств над картинками силами GPU. Но не хочется увеличивать количество зависимостей. Кроме того, MXNet используется много для чего и важно сохранить контекст размещения данных, т.е. чтобы массивы не надо было пересоздавать.

★★★★★

Последнее исправление: ls-h (всего исправлений: 1)
Ответ на: комментарий от ymn

в opencv для аффинных преобразований можно использовать gpu

Похоже, что да. Осталось выяснить, нормально ли массив преобразуется в MXNet, прямо в видеопамяти.

ls-h ★★★★★
() автор топика

Но есть большая проблема: GridGenerator надо передавать совсем не такую матрицу, как в warpAffine

Не знаю ни opencv, ни mxnet. Но в приведенной тобой документации написано:

The usage of the operator is very similar to remap function in OpenCV, except that the operator has the backward pass

То есть надо использовать обратную матрицу преобразования. https://en.wikipedia.org/wiki/Affine_transformation#Groups

anonymous
()
Ответ на: комментарий от anonymous

Не знаю ни opencv, ни mxnet. Но в приведенной тобой документации написано

Спасибо! Слона-то я и не заметил. Остался один нюанс: в OpenCV начало координат в левом верхнем углу, а в MXNet все трансформации вокруг центра.
UPD
Хотя нет, разница не только в этом. Смещение как-то по-разному работает. В случае OpenCV изменение последнего столбца матрицы соответствует смещение на такое число пикселей, а в MXNet как-то иначе...

ls-h ★★★★★
() автор топика
Последнее исправление: ls-h (всего исправлений: 1)
Ответ на: комментарий от anonymous

То есть надо использовать обратную матрицу преобразования.

Вроде движение в нужном направлении получается, но всё равно разница есть: https://i.imgur.com/aNIjIVk.png и https://i.imgur.com/X2Z2LWu.png
Матрица:

[[1, .5, 0],
 [.5, 1, 0],
 [ 0, 0, 1]]

ls-h ★★★★★
() автор топика
Ответ на: комментарий от ls-h

Матрица:

И что это за матрица? Где обратная матрица, которая требуется для mxnet?

Обычно аффиннные преобразования - это комбинация(композиция) простых (перемещение, вращение, сдвиг, отражение). И для каждого простого преобразования достаточно легко найти обратное преобразование и из обратных составить обратную матрицу.

Вот что это за матрица, что за композиция простых преобразований? Или это случайная матрица, которая взбрела тебе в голову? И ты не можешь также случайно подбрать для него обратную, потому что, вообще, не знаешь теорию? (Для матрицы 2 на 2 достаточно легко найти обратную.) Ты даже не можешь проверить, что opencv или mxnet делают то что надо? Обезьяна с гранатой, не знаешь как это работает и пытаешься что-то с этим сделать.

anonymous
()
Ответ на: комментарий от anonymous

Обезьяна с гранатой, не знаешь как это работает и пытаешься что-то с этим сделать.

Спасибо! Мне прямо помогло очень!

И что это за матрица?

Это матрица от балды, да. Обратную я получаю вот так:

np.linalg.inv(affine_matrix)
. Извиняюсь, что сразу про это не написал. Конечно, в MXNet я передаю обратную матрицу. Когда я передавал изначальную, то результат был совсем другой, не похожий на OpenCV (ну, оно и понятно, так и должно быть). Почему матрица от балды? Матрица, по которой нужно изменить картинку, это результат вот этого кода
skimage.transform.SimilarityTransform()[br]tform.estimate(dst, src)
, где dst, src это массивы точек, а код выше вычисляет матрицу преобразований, необходимую для наложения точек dst на точки src. Т.е., можно считать, что я получаю извне некую произвольную матрицу. Возможно, стоит разобрать на простые преобразования (надо нагуглить, как).
Вот пример реальной матрицы:
[[1.89834978e+00, 4.19957029e-01, -5.55334733e+02],
[-4.19957029e-01, 1.89834978e+00, -5.16924291e+01],
[0, 0, 1]]

ls-h ★★★★★
() автор топика
Последнее исправление: ls-h (всего исправлений: 4)
Ответ на: комментарий от ls-h

Спасибо! Мне прямо помогло очень!

Ясно. Троллинг или эльфинг тупостью. Что есть одно и тоже в рамках аффиного преобразования - отражение. Успехов, малыш!

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.