Убийца предсказателей переходов
lexa - 16/Дек/2010 18:54
if (cr2_slice[0]) {
jidx = jrow*jwide + jcol;
i = jidx / (cr2_slice[1]*jh.high);
if ((j = i >= cr2_slice[0]))
i = cr2_slice[0];
jidx -= i * (cr2_slice[1]*jh.high);
row = jidx / cr2_slice[1+j];
col = jidx % cr2_slice[1+j] + i*cr2_slice[1];
}
jidx = jrow*jwide + jcol;
i = jidx / (cr2_slice[1]*jh.high);
if ((j = i >= cr2_slice[0]))
i = cr2_slice[0];
jidx -= i * (cr2_slice[1]*jh.high);
row = jidx / cr2_slice[1+j];
col = jidx % cr2_slice[1+j] + i*cr2_slice[1];
}
- Этот кусок зовется на каждый пиксел и рассчитывает, куда именно поместить распакованный из CR2 пиксель (там не так просто все).
- jidx - номер пикселя в потоке, плавно возрастает.
- Изображение поделено на cr2_slice[0] полос шириной cr2_slice[1] и одну полосу шириной cr2_slice[2].
- cr2_slice[0] - небольшое число, 1-3-5
- j - соответственно - 0 или 1.
На 15 мегапикселях - 330 миллисекунд. Разворот if правильный (чтобы было не 1+j, а честно 1 или 2) - минус 70 миллисекунд. Замена на таблицу с заранее насчитанными оффсетами - минус 200 миллисекунд. Но все равно много, перемудрили в кэноне. Главное, их "слайсы" вполне можно было бы распаковывать впараллель (как они жмутся параллельными Digic-ами), если бы в RAW были бы смещения начал. Ан нет.
Comments
А строчки 3 и 4 ещё оптимизировать не получится? Я так понял
А строчки 3 и 4 ещё оптимизировать не получится? Я так понял, что jidx делится нацело на cr2_slice[1]*jh.high и получается ноль или 1. В таком разе можно в стр. 3 попробовать i = ( jidx > cr2_slice[1]*jh.high ).
Нет, не нацело. Там как устроено в CR2: K слайсов шириной L
Нет, не нацело. Там как устроено в CR2: K слайсов шириной L и один шириной M. Высота у всех H.
Вот картинка: http://lclevy.free.fr/cr2/#lossless
Если мы номер пикселя делим на H*L, то мы получаем номер слайса. Он может быть ошибочным (если M много меньше L) и его надо округлить до K+1.
Уф.
Но все это почти неважно т.к. можно прекалькулировать оффсеты (по числу строк т.е таблица получается размером (K+1)*H (10-20 тыс). А внутри одной строчки слайса - просто декрементировать и все.
Мда. Кодом проще написать. Следите за апдейтами LibRaw.
А, понял. Хитро, однако. Спасибо, полезная ссылка.
А, понял. Хитро, однако.
Спасибо, полезная ссылка.
Ссылка полезная, а сама схема - идиотская. Лучше бы сделали
Ссылка полезная, а сама схема - идиотская. Лучше бы сделали тайлами с известными началами-концами бинарных данных, как в DNG.
Это да. Интересно, по столбцам нарезано, ибо в сенсоре так
Это да.
Интересно, по столбцам нарезано, ибо в сенсоре так считывание устроено? Какая-то схема ну очень неудобная для эффективного раскодирования.
Нет, считывание идет по столбцам. А кодирование дальше - по
Нет, считывание идет по столбцам. А кодирование дальше - по строкам.
Т.е. выливают в какой-то буфер(ы) и их кодируют. В промежуточные буфера, которые потом склеивают.
В-принципе, если хранить дальше в нескольких буферах, а не в одном, то тоже удобно. Гы :)
Вообще же jpeg-овское кодирование, которое потоком, хоть и с маркерами рестарта, но все одно - переменной битности, это зло ужасное в век многоядерности.
щито? оно независимыми блоками 8x8 идет. сколько у тебя карт
щито?
оно независимыми блоками 8x8 идет.
сколько у тебя картинка, 4000x5000? можешь на 300000 ядер паралелить.
ну ладно, столько перебор, но на десяток -- можно.
Але, это dct можно параллелить. Который lossy jpeg. А хаф
Але,
это dct можно параллелить. Который lossy jpeg.
А хаффман - который под ним лежит - нормально нельзя. И у меня - этот самый lossless jpeg, выше никаких блоков 8x8 и прочей хрени - нету.
Точнее, если там есть рестарты, то можно их искать и от них распаковывать, надеясь потом распихать по нужным местам.
<q>это dct можно параллелить.</q> ну. тебе мало? <q>А хаффм
это dct можно параллелить.
ну. тебе мало?
А хаффман - который под ним лежит - нормально нельзя.
и? чтение с диска тоже не паралелится.
и при этом регулярно раздаются крики "сжатие данных повышает трансфер с диска". так что одно ядро на хафмане накормит стояптьсот dct.
И у меня - этот самый lossless jpeg, выше никаких блоков 8x8 и прочей хрени - нету.
а? что?
еще раз. jpeg это:
переходим в другое цветовое пространство
разбиваем картинку 8x8
dct каждого блока 8x8
отбрасываем хвосты (ну если у тебя lossless -- не отбрасываем)
кодируемся по хафману.
при декодировании все тоже самое в обратном порядке. ну только хвосты пришивать не надо.
Параллелить DCT мне мало, потому что в моих данных нету DCT.
Параллелить DCT мне мало, потому что в моих данных нету DCT. Нечего параллелить.
Я же говорю, SOF3. Еще бывает SOF7, SOF11 и SOF15, тоже без DCT.
Закон парных случаев -- у
Закон парных случаев -- у меня вот на руках файл с расширением JPG и JIFI но SOF 0xc3 -- какой-то loseless. И его даже djpeg из libjpeg не берёт. Чем бы расшифровать? Википедия как-то молчит, и гугл скорее тоже.
c3 - это и есть SOF3, в
c3 - это и есть SOF3, в чистом виде lossless с хаффманом.
Можно основу выдрать из RawSpeed. Собственно, у меня есть тестовый декодер, но он может ниасилить сложную структуру заголовка. Хотя с чистыми CR2-данными, выдранными из кэноновского файла - вроде справляется.
Черкни на мыло - пришлю.
Я может щас всем известное
Я может щас всем известное напишу или глупость какую.
К jpeg 6b существовал патч, гуглится по "pvrg jpeg ijg". Кусок из его реадме "This software implements JPEG baseline, extended-sequential, progressive
! and lossless compression processes.". Может поможет?
Плюс есть libjpeg-turbo на основе jpeg 6b c simd инструкциями, порченная и под 64 бита тоже. В свое время много юзал его японского прародителя. Давал существенный прирост в скорости против оригинального libjpeg, просто заменой shared библиотек. Но вот хаффмана там по моему не трогали.
Вспомнил петушиное слово: SOF3
Вспомнил петушиное слово: SOF3
А нельзя ли несколько
А нельзя ли несколько видоизменить задачу? Т.е. вместо вычислений координат назначения по индексу источника вычислять индекс перебирая координаты.
Т.е. нечто вроде (псевдокод):
int col;
int row;
int iLastSliceX0 = width - cr2_slice[2];
for(row=0;row
А нельзя ли несколько
А нельзя ли несколько видоизменить задачу? Т.е. вместо вычислений координат назначения по индексу источника вычислять индекс перебирая координаты.
Т.е. нечто вроде (псевдокод):
int col;
int row;
int iLastSliceX0 = width - cr2_slice[2];
for(row=0;row
Такая штука должа параллелится как из пушки.
Там ошибочки у меня, похоже,
Там ошибочки у меня, похоже, при расчете offset но суть думаю понятна.
A.. так там хаффман. Сорри,
A.. так там хаффман. Сорри, был не прав. Вспылил. :-)
Хаффман там ниже. Обсуждаемый
Хаффман там ниже.
Обсуждаемый код - это распихивание строки, уже раскодированной из Хаффмана.
Скажем, в DNG, где внизу тот же хаффман может быть, выше сделано по уму - или сплошным куском все или Tiles с известными координатами (и известными длинами, каждый тайл можно отдельно распаковывать).
А в CR2 - вот такой вот ужаснах.
Т.е теоретически все-таки
Т.е теоретически все-таки можно раскидать слайсы в destination order? Тогда можно и порасходовать дополнительно память в обмен на скорость (если эта скорость будет, конечно)
В смысле "можно"? У CR2 -
В смысле "можно"?
У CR2 - нельзя, как я понимаю. Там просто поток данных переменной битности, а индексов для хождения "в середину" (в начало слайса 3) - нету.
У DNG - при том же способе компрессии, другая организация данных.
Пожалуй, чуть поподробнее
Пожалуй, чуть поподробнее напишу.
Вот допустим у меня картинка 4000x3000. Слайсы, к примеру, шириной 1600,1600,800 и высотой 3000. И 4 компонента, т.е. раскодируя одну "строку" слайса я на самом деле раскодирую их 4.
Вот когда я раскодировал строку номер 752 - это я на самом деле раскодировал строки "слайсов" номер 3008-3011. В destination это прямоугольник 1600-7-3199-15 (считая с нуля).
Тут проблема в том, что
Тут проблема в том, что порядок поступления пикселов - он по слайсам (слева направа, внутри слайса - сверху вниз), причем желания делать отдельный битмэп на всю картинку (Src в вашей нотации) - никакого нет, это еще мегабайт 40 (для 20Mpix), хочется ограничиться буфером на строку (а в дальнейшем - прямо in-place раскодировать, все-таки копирование жрет прилично).
А ваш код - предполагает обход в порядке пикселов destination.
Решение, которое я спер в RawSpeed заключается в том, что для каждой строки слайса мы рассчитываем смещение в destination, а дальше просто линейно идем.
Тоже не бог весть что, так как если компонентов в JPEG больше одного, то буфере будет несколько строк слайса, но достаточно эффективно, чтобы на время забыть: из 330мс стало 80. А, скажем, чтение по-байтам с пропуском маркеров - 250мс и теперь надо оптимизировать его.
Добрый вечер. Вопрос не по
Добрый вечер.
Вопрос не по теме. :)
Насколько я себе представляю, сенсор камеры выдает одни и те же(условно) данные при одинаковых снимках, но на разном ISO. А само усиление сигнала делает АЦП, так вот вопрос, почему нельзя делать копии сигнала с усилением и без сразу же? Или повысить битность(?) АЦП, что бы он записывал с большей точностью данные, что бы потом можно было усиление делать на компьютере.
Где я не прав? :)
Не факт, что усилитель и АЦП
Не факт, что усилитель и АЦП - это одна микросхема.
Более разрядный АЦП - это больше данных, сам АЦП дороже и все такое. При том, что реальный диапазон используемых значений меньше, чем разрядность АЦП, в D3 вот даже есть два режима, 12 бит и 14.