Russian Qt Forum
Март 29, 2024, 00:09 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Вычислить кадр мувика  (Прочитано 18013 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Май 22, 2017, 07:08 »

Добрый день

Задан диапазон кадров R[2], напр [5..10] (играть с 5-го по 10-й включительно) или [10..5] (играть в обратном порядке с 10-го по 5-й). После того как достигнут последний или первый кадр диапазона мувик должен проигрываться в обратном порядке, напр
5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 6...    

Требуется ф-ция которая возвращает любой следующий кадр от текущего
Код
C++ (Qt)
int NextFrame( int currentFrame, int step, .. );
Для последовательности кадров выше

NextFrame(9, 1) = 10
NextFrame(9, 2) = 9

Спасибо
« Последнее редактирование: Май 22, 2017, 07:09 от Igors » Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #1 : Май 22, 2017, 10:06 »

Набил на скорую руку, вроде работает
Код:
int NextFrame(int currentFrame, int step, int x0, int x1) {
    int dPosFirst = x1>x0? 1: -1; // направление в первой последовательности
    int size = abs(x1-x0)+1;

    int posCurrentFrame = (currentFrame - x0) * dPosFirst;
    if(posCurrentFrame >= size || posCurrentFrame<0) return 0; //TODO error: число не принадлежит последовательности

    posCurrentFrame += step; // new Frame;

    if(x0 == x1)return x0; // если один кадр
    int sizeWithBack = size*2 - 2; // размер последовательности включая обратную(не правильно считает для одного кадра x0==x1, но этот случай отсекли)
    posCurrentFrame -= (posCurrentFrame / sizeWithBack) * sizeWithBack; // теперь новый кадр будет лежать в диапазоне [0, sizeWithBack), так как данная последовательность повторяется

    return posCurrentFrame < size? x0 + posCurrentFrame * dPosFirst:
                                   x0 + (sizeWithBack - posCurrentFrame) * dPosFirst;
}
« Последнее редактирование: Май 22, 2017, 10:15 от deMax » Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #2 : Май 22, 2017, 10:22 »

если у вас может быть отрицательной позиция кадра, добавить после строки
posCurrentFrame -= (posCurrentFrame / sizeWithBack) * sizeWithBack;
строку:
if(posCurrentFrame<0) posCurrentFrame += sizeWithBack;


p.s. имхо, я бы разбил на 2 функции:

int nextFrame = pos2frame( frame2pos( currentFrame ) + step )

а если видео нужно гонять в цикле, то итератор подошел бы

class zzzz{int data, direction ... int operator ++() { data += direction; if(direction == x0 || direction == x1) direction = -direction; return data; } } // direction = +1 / -1, для x0==x1 direction=0;
« Последнее редактирование: Май 22, 2017, 10:35 от deMax » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #3 : Май 22, 2017, 13:28 »

Цитировать
Набил на скорую руку, вроде работает

Можно попроще
Код
C++ (Qt)
inline int NextFrame(int currentFrame, int step, int min, int max)
{
   const int T = 2*(max - min);
 
   auto toFrame = [&](int x)->int
   {
       return (x <= T/2) ? (min + x) : (T - x + min);
   };
 
   int x = currentFrame - min;
 
   int n = trunc(double(step)/T);
 
   return toFrame(x + step - T*n);
}
 

Цитировать
а если видео нужно гонять в цикле, то итератор подошел бы
Итераторы здесь, это больная тема  Улыбающийся
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #4 : Май 22, 2017, 13:49 »

Можно попроще
не спорю, но "int x = currentFrame - min;" некорректно, так как в условии " или [10..5] (играть в обратном порядке с 10-го по 5-й)"
нет проверки на диапазон, да и вообще она неверный результат на тесте выводит.

int n = trunc(double(step)/T); лучше floor - для отрицательных значений(из условия неясно могут ли кадры быть отрицательными) у trunc результат неверный будет
Вообще переводить в double, лишние операции, мой вариант проще Улыбающийся
« Последнее редактирование: Май 22, 2017, 14:01 от deMax » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #5 : Май 22, 2017, 13:54 »

Цитировать
но "int x = currentFrame - min;" некорректно, так как в условии " или [10..5] (играть в обратном порядке с 10-го по 5-й)"
Проверки на принадлежность к диапазону и на обратный порядок  - пускай igors делает) Я чисто концепт обозначил)

Цитировать
она неверный результат на тесте выводит.
На каком именно тесте?
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Май 22, 2017, 14:07 »

В предложенные решения пока глубоко не вникал (просто это трудно несмотря на внешнюю простоту задачки), но хочу обратить Ваше внимание на такую деталь
5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 6...    
...
NextFrame(9, 1) = 10
NextFrame(9, 2) = 9
А "от какого" 9? Не вижу как это учтено в Ваших исходниках. Вводить доп переменные не запрещено, можно и просто переставить диапазон R. Но все равно спасибо за участие  Улыбающийся

Итераторы здесь, это больная тема  Улыбающийся
Здесь как раз нужен прямой доступ. Если мувик не укладывается в заданный FPS и включена стандартная опция "drop frames", то кадры должны пропускаться. Пример: на данный момент должно быть показано уже 10 кадров, а успели всего 6 - грузим 4-й кадр от текущего. Собсно за этим и нужна такая ф-ция.

Да, и в "геометрии" там задачка давно плачет по Вашему академическому образованию  Улыбающийся

  
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #7 : Май 22, 2017, 14:08 »

На каком именно тесте?

for(int i=-20; i<20; ++i) qDebug() << NextFrame(9,i,5,10); //
for(int i=-20; i<20; ++i) qDebug() << NextFrame(9,i,10,5); //

можно с нуля начинать, но так как автор не указал допустимы ли отрицательная позиция кадра, я начал с -20.
Мой пример выводит корректно, хотя я бы сам его переписал. х0,х1 диапазон 5 и 10, или 10 и 5 например(плохие имена переменных)

А "от какого" 9? Не вижу как это учтено в Ваших исходниках. Вводить доп переменные не запрещено, можно и просто переставить диапазон R. Но все равно спасибо за участие  Улыбающийся
[5 6 7 8 9 10] 9 8 7 6 5 6 7 ... - из основного диапазона (в скобках []) 9-ку брал, можно аргумент ввести если из следующего перевернутого брать
if(isReverseFind==true) posCurrentFrame = sizeWithBack - posCurrentFrame;

« Последнее редактирование: Май 22, 2017, 14:13 от deMax » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Май 23, 2017, 12:42 »

Мой вариант
Код
C++ (Qt)
int NextFrame( int curFrame, int step, int R[2] )
{
int relF = qAbs(curFrame - R[0]) + step; // frame to relative
int range = qAbs(R[1] - R[0]) + 1; // frame count
 
if (relF >= range) {   // if frame is out of range
relF %= range * 2 - 1; // skip period
if (relF >= range) { // flip direction
relF -= range - 1;
qSwap(R[0], R[1]);
}
}
 
return R[0] + ((R[0] < R[1]) ? relF : -relF); // frame to absolute
}
 
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #9 : Май 23, 2017, 20:34 »

Цитировать
Да, и в "геометрии" там задачка давно плачет по Вашему академическому образованию
Ну так Вы бы её академически сформулировали бы, что ли)
А так у меня сейчас голова забита совершенно другими задачками) Да и сессия на носу) 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #10 : Май 24, 2017, 10:25 »

Мой вариант
   int relF = qAbs(curFrame - R[0]) + step;   // frame to relative
А если R[10,5], то фрейм 8 окажеться на -2 месте, и следующий кадр укажет на 9, а не на 7.

Моя программа выводит:     
for(int i=-20; i<20; ++i)  qDebug() << NextFrame(9,i,5,10);
9 10 9 8 7 6 5 6 7 8 9 10 9 8 7 6 5 6 7 8 9 10 9 8 7 6 5 6 7 8 9 10 9 8 7 6 5 6 7 8
for(int i=-20; i<20; ++i)  qDebug() << NextFrame(9,i,10,5);
9 8 7 6 5 6 7 8 9 10 9 8 7 6 5 6 7 8 9 10 9 8 7 6 5 6 7 8 9 10 9 8 7 6 5 6 7 8 9 10

А вот данная программа выводит:
 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 5 6 7 8 9 10 9 8 7 6 5 5 6
29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 6 7 8 9 10 10 9 8 7 6 5 6 7 8 9

Ладно, пусть i<0 это наверное не нужно(кадры, возможно, не могут быть отрицательными), но вот 5 5 подряд вроде не должно быть? или я не понял что должна функция делать?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Май 24, 2017, 13:13 »

Ладно, пусть i<0 это наверное не нужно(кадры, возможно, не могут быть отрицательными), но вот 5 5 подряд вроде не должно быть? или я не понял что должна функция делать?
Параметр step (у Вас "i") это не кадр, а смещение кадра относительно текущего. Пример

currentFrame = 5;  // текущий кадр мувика = 5
step = 2;              // на какое число кадров сдвинуться? (на 2 собаки вперед)

Т.е. какой кадр мувика (лежащий в диапазоне R) станет текущим? При этом еcли смещение = периоду то следующий кадр будет тем же (напр 5). Отрицательное смещение не рассматривается - время-то идет только вперед  Улыбающийся
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #12 : Май 24, 2017, 14:50 »

Это понятно, просто при "i < -curFramePos" позиция в последовательности станет отрицательной.

>> Отрицательное смещение не рассматривается - время-то идет только вперед
Вам виднее, тогда uint step Подмигивающий

мне не известно и не интересно зачем вам гонять фрагмент видео. Я только написал рабочее решение для int step,
остальные программы работают неправильно Показает язык
Возможно нет смысла проверять currentFrame на принадлежность диапазону(уже проверенно).
« Последнее редактирование: Май 24, 2017, 14:54 от deMax » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #13 : Май 25, 2017, 13:15 »

Цитировать
остальные программы работают неправильно
Всё работает как надо) Слегка подправил для для обратного порядка и на проверку на диапазон.
Код
C++ (Qt)
inline int NextFrame(int currentFrame, int step, int x0, int x1) throw (std::logic_error)
{
   if ((currentFrame < std::min(x0, x1)) || (currentFrame > std::max(x0, x1)))
       throw std::logic_error("out of range");
 
   int sign = (x1 > x0) ? 1 : -1;
 
   const int T = 2*sign*(x1 - x0);
 
   auto toFrame = [&](int x)->int
   {
       return (x <= T/2) ? (x0 + sign*x) : (sign*(T - x) + x0);
   };
 
   int x = sign*(currentFrame - x0);
 
   return toFrame((x + step % T) % T);
}
 
По моему это гораздо проще и нагляднее)
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #14 : Май 25, 2017, 14:07 »

m_ax
теперь работает, но есть мелкие придирки
1. uint step - для отрицательных чисел у вас алгоритм вычисляет неправильно(автору не нужно)
2. при x0 == x1 у вас T == 0 -> %T сгенерирует ошибку и программа упадет без обработчика
3. Названия переменных T -> cycleSize, toFrame -> pos2numFrame, x -> pos
4. имхо, через деление выражение ((x + step % T) % T) быстрее будет
5. std::min и max тоже можно убрать повысив производительность, if((sign>0 && currentFrame<x0 ?&& currentFrame>x1) || (sign<0 && currentFrame<x1 ?&& currentFrame>x0)) throw std::logic_error("out of range");
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.146 секунд. Запросов: 23.