Jump to content

    

Сбор идей по повороту картинки

Всем доброго дня!

Ищутся мысли по поводу оптимальной реализации поворота картинки.

Что сделано:

Поворот картинки через CORDIC. Производится поворот координаты каждого пикселя (по конвейеру) на заданный угол, вычисляется адрес пикселя в читаемой (не повернутой) картинке, прочитанные пиксели выводятся последовательно в формате ITU656.  

Что не устраивает:

При повороте пиксели из исходной картинки читаются не через burst transfer, а по одному, т.к. при повороте получаем чтение не по последовательным, а по произвольным адресам. Поэтому шина ДДР сильно просаживается по производительности. Мало того что пиксели читаются по разным адресам, так еще из 32битного прочитанного слова мне надо только один пиксель, т.е. 8бит. 

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

Может кто-то как-то решал подобные проблемы неэффективного использования ДДР шины?

Реализация поворота полностью аппаратная.

 

Share this post


Link to post
Share on other sites

При повороте края обрезаются или картинка уменьшается и добавляются чёрные поля?

В одном случае считываемых точек больше - в другом записываемых...

 

И потом в ПЛИС обычно множественный доступ по чтению (например к кешу) будет быстрее  множественного доступа по записи (нужен мультиплексор).

Share this post


Link to post
Share on other sites
55 минут назад, _4afc_ сказал:

При повороте края обрезаются или картинка уменьшается и добавляются чёрные поля?

В одном случае считываемых точек больше - в другом записываемых...

 

И потом в ПЛИС обычно множественный доступ по чтению (например к кешу) будет быстрее  множественного доступа по записи (нужен мультиплексор).

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

Аппаратное чтение происходит без участия кэша (cyclone5 или zynq7000), да и весь кадр в кэш наверно не влезет. Аппаратный доступ к кэшу ЕМНИП,  начинается только у ultrascale+. Да и читающий мастер написан для чтения без участия кэша. Хотя я сомневаюсь, что будет сильно лучше, т.к. процессор во время поворота свое молотит, тоже приличные объемы данных ворочает, там весь кэш думаю будет забит. Нов случае с процессором кэш здорово вывозит.

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

Share this post


Link to post
Share on other sites
2 hours ago, alexPec said:

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

Можно сделать внутри FPGA буфер на восемь строк и сохранять во внешней памяти уже повернутые пиксели burst'ами по восемь пикселей за одно обращение к памяти.

Share this post


Link to post
Share on other sites

поворот на произвольный угол +-180гр? а то если углы ограничены небольшими градусами может можно обойтись внутренним буфером на несколько строк? и наоборот читать подряд, писать "под углом", но в буфер всего на несколько строк, и выдавать из него строку по заполнении.

ну или даже всё оставить как есть, но сделать промежуточный буфер на несколько строк соответствующих максимальному углу поворота, а не на всю картинку.

 

Share this post


Link to post
Share on other sites
Только что, blackfin сказал:

Можно сделать внутри FPGA буфер на восемь строк и сохранять во внешней памяти уже повернутые пиксели burst'ами по восемь пикселей за одно обращение к памяти.

Не понял как это. Например, берем (условно, для простоты квадратный экран 500х500) пиксели № (0,0), (1,0),(2,0),(3,0). Их читаем бастом. Поворачиваем их на 90 градусов - они оказываются на позициях (0,499), (0,498), (0,497), (0,496) - это все НЕ последовательные адреса. На 45 градусов, например, повернуть - вообще где попало в памяти после поворота окажутся.

4 минуты назад, _pv сказал:

поворот на произвольный угол +-180гр? а то если углы ограничены небольшими градусами может можно обойтись внутренним буфером на несколько строк? и наоборот читать подряд, писать "под углом", но в буфер всего на несколько строк, и выдавать из него строку по заполнении.

ну или даже всё оставить как есть, но сделать промежуточный буфер на несколько строк соответствующих максимальному углу поворота, а не на всю картинку.

 

Вообще хотелось бы +/- 90 градусов, но даже 30 градусов (меньше даже заморачиваться не стоит) было бы не плохо. Но даже при 30 строка даже в 640 пикс. при повороте займет tg(30)*640 = 369 пикс. по вертикали. Т.е. почти весь кадр 640*480.

Share this post


Link to post
Share on other sites
18 minutes ago, alexPec said:

Не понял как это.

Берем квадратный экран 500х500.

 

Читаем burst'ом во внутреннюю SRAM FPGA из внешней DDR пиксели:

 

1-ая строка: (0,0), (0,1),(0,2),(0,3),...,(0,499);

2-ая строка: (1,0), (1,1),(1,2),(1,3),...,(1,499);

3-я строка: (2,0), (2,1),(2,2),(2,3),...,(2,499);

...

8-ая строка: (7,0), (7,1),(7,2),(7,3),...,(7,499).

 

Пишем burst'ом по 8 beats во внешнюю DDR из внутренней SRAM пиксели:

 

1-ый столбец: (0,0), (1,0),(2,0),(3,0),...,(7,0);

2-ой столбец: (0,1), (1,1),(2,1),(3,1),...,(7,1);

...

459-ый столбец: (0,459), (1,459),(2,459),(3,459),...,(7,459).

 

Повторяем эту операцию для всех 500 строк.

 

Читаем burst'ом из внешней DDR полученные пиксели по строкам и выводим их во внешний порт..

Share this post


Link to post
Share on other sites
12 minutes ago, alexPec said:

Не понял как это. Например, берем (условно, для простоты квадратный экран 500х500) пиксели № (0,0), (1,0),(2,0),(3,0). Их читаем бастом. Поворачиваем их на 90 градусов - они оказываются на позициях (0,499), (0,498), (0,497), (0,496) - это все НЕ последовательные адреса. На 45 градусов, например, повернуть - вообще где попало в памяти после поворота окажутся.

внутреннему буферу на 8 строк при записи наплевать что адреса оказались непоследовательными, а вот прочитали-то вы их бурстом 8 штук последовательно.

Share this post


Link to post
Share on other sites

Да, туплю что-то.

 

Согласен.

Надо только аппаратно высчитать начало и конец баста ( в смысле адреса). Ну и еще наложится логика маскирования начала записываемого участка и конца, т.к. начало и конец часто не будут совпадать с границами записываемого слова. Но в части оптимизации обращения к ДДР выглядит сильно лучше.

Спасибо!

Share this post


Link to post
Share on other sites

При любом угле - можно уйти от рандомности так:

1 переводим картинку в полярную систему координат с минимальным нужным шагом угла

2 переводим картинку из полярной системы координат начиная с нужного угла.

 

PS: Если исходная картинка статичная - в памяти достаточно иметь результат 1 действия

и совершать над ним только второе...

 

Я так спрайт на экране делал в виде кораблика который поворачивался на тот градус куда корабль повёрнут...

Share this post


Link to post
Share on other sites
6 часов назад, _4afc_ сказал:

При любом угле - можно уйти от рандомности так:

1 переводим картинку в полярную систему координат с минимальным нужным шагом угла

2 переводим картинку из полярной системы координат начиная с нужного угла.

 

PS: Если исходная картинка статичная - в памяти достаточно иметь результат 1 действия

и совершать над ним только второе...

 

Я так спрайт на экране делал в виде кораблика который поворачивался на тот градус куда корабль повёрнут...

не совсем понял мысль. Картинка с матрицы (с камеры) идет в построчно. В память ее лучше всего ложить тоже построчно - бастами. Непонятно как перевод в полярную систему позволит решить проблему рандомного обращения к памяти. Даже если мы ее переведем (запишем по порядку, так сказать, "лучи" из центра экрана к периферии с разными углами), то сама запись в таком формате - это то же рандомные обращения к памяти. Весь кадр меняется каждые 20 мс. Ну а если картинка статичная - то можно и один раз преобразовать, потратить время на рандомную запись.

 

Хотя натолкнули меня на мысль сделать предвычисления по началам/концам бастов  и маскам при дискретных углах и забивать их в таблицу, которой будет пользоваться "вращалка". 

Share this post


Link to post
Share on other sites
1 hour ago, alexPec said:

не совсем понял мысль. Картинка с матрицы (с камеры) идет в построчно. В память ее лучше всего ложить тоже построчно - бастами. Непонятно как перевод в полярную систему позволит решить проблему рандомного обращения к памяти. Даже если мы ее переведем (запишем по порядку, так сказать, "лучи" из центра экрана к периферии с разными углами), то сама запись в таком формате - это то же рандомные обращения к памяти. Весь кадр меняется каждые 20 мс. Ну а если картинка статичная - то можно и один раз преобразовать, потратить время на рандомную запись.

Я хотел сказать, что при таком подходе (через полярное преобразование) уходит зависимость от угла в вычислениях, хоть и требуются 2 этапа.

А раз так - проще их оптимизировать по отдельности, по вычислениям.

 

У меня нет опыта решения в лоб вашей задачи, да ещё под ДМА и БУРСТ.  Здесь уже ваш опыт...

Share this post


Link to post
Share on other sites

С точки зрения памяти запись наиболее проблемное место.

Посмотрите в описании сколько максимально (размер слова) читается/пишется за один запрос памяти, это будет ширина буфера, далее читайте вниз по памяти до заполнения квадрата и потом обратно в память.

 

P.S. расположение картинки может быть как 1D, линейное, так и 2D. По сути также линейное, но размер по ширине ограничивается размером страйда.

Share this post


Link to post
Share on other sites
33 minutes ago, lexx said:

С точки зрения памяти запись наиболее проблемное место.

С чего это вдруг?

 

Вот диаграммы чтения и записи burst'ами по 8 слов типовой DDR3 памяти Micron'а:

Read.jpg

Write.jpg

 

Никаких особых проблем ни на чтении, ни на записи не видно..

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now