[Назад] [Вся нить] [Первые 100 сообщений] [Последние 50 сообщений]
Ответ в нить [Последние 50 сообщений]
Имя
Captcha image [Д]
Animapcha image [@] [?] [Т]
Тема    ( ответ в 1000686)
Сообщение
flower
Предпросмотр
Файл 
Пароль  (для удаления файлов и сообщений)
Параметры   
140368429_p0.jpg - (2.48MB, 4000×4000)
1000686
No. 1000686  
Замечания и предложения по нему, а также их обсуждение.
Предыдущий тред тонет тут >>1000357.
142 сообщений пропущено. Показаны 50 последних сообщений
No. 1000929  
>>1000921
It's up.
No. 1000930  
И >>1000909 тоже.
No. 1000931  
phash_plot_v3.png - (147.24KB, 1000×800)
1000931
>>1000929
Thx. Через несколько дней продолжу открывать PR с фиксами очевидного.

>>1000912
А нам, собственно, для чего нужно оптимизировать хэш?

Устроены все результаты, которые у меня получились, одинаково (пикрелейтед). x — threshold (в % от длины хэша), y — сколько новых картинок находятся при очередном увеличении threshold. Пояснения нарисованы для красного графика, но форма у всех графиков одинаковая. Чисто визуально по графику какой-либо вариации можно определить (1) и (2), всё, что между, нужно смотреть глазами. Всякие редкие масштабированные/растянутые/обрезанные продолжают существовать в промежутке между (1) и (2).

И вот, собственно, мой вопрос — как нам оценивать разные вариации? Чтобы как можно больше дубликатов/масштабированных/растянутых/обрезанных находилось до границы (1)? Или до границы (2)? Или просто нужно как можно больше найденных картинок в какой-то точке между (1) и (2), где оно ещё находит только related-картинки (для красного графика — около 15%)? Если последнее, то нужно опасаться overfitting’а для конкретного датасета.
No. 1000932  
brk.png - (80.28KB, 1481×747)
1000932
Штмл поломался.
No. 1000933  
>>1000932
fixed
No. 1000934  
119580783_p0.webp - (627.95KB, 2048×1443)
1000934
>>1000931
В идеале дубликаты/масштабирования/растягивания/обрезки должны строго на меньших расстояниях, чем средние/серьёзные изменения. Но с обрезками и сдвигами, увы, у меня не получилось.

> Или просто нужно как можно больше найденных картинок в какой-то точке между (1) и (2)
Я оценивал по количеству найденного до точки, когда начинаются серьёзные false positives (начинает путать девочек и помидоры), и до точки, когда false positives по сравению с true positives становится слишком много. Последняя упомянутая точка определялась на глаз.

В меньшей степени по характеру найденного (потому что с этим удач особых не было): скажем, одна из вариаций хэша по DCT zoom cube'а находила (>>/b/4173, >>/b/6116) на расстоянии 196/512, а do_round_phash.php на 223/512 (когда, если смотреть в общем, граф уже давно целиком связный и hamming_evo.py бесполезен).

По-хорошему нужно было бы
> единый список «как-то связаных между собой» картинок, которые должны находиться.
Построить такой список можно, выстроив пары в порядке возрастания phash или SSIM, присваивая вручную парам со схожим содержимым некий действительный similarity score. И даже так это очень много работы. Как вариант, посмотреть, что в OpenCV есть более современное и тяжёлое, чем эту работу можно упростить.

Или пока не заморачиваться, найти менее трудозатратными средствами вмещающийся в 512 бит вариант, и пусть будет MVP. И когда-нибудь если захочется заняться длинными серьёзными исследованиями или появится настоящий CV сварщик, то пытаться лучше.
No. 1000935  
>>1000934
Кажется saucenao/ascii2d/wait до сих пор не умеют в кропы и сдвиги, так что всё равно GJ.
c:hanako
No. 1000937  
aoba_maki.jpg - (258.74KB, 1448×2048)
1000937
Представляю вам на суд вариант
blur=gauss_dyn[alpha=0.8,beta=4],scale=nn,S=64,post_blur=gauss[ksize=3,sigma=0.333333],hash=phash[Z=16,mask=circle],post_sobel=1.
Размер хэша 193 бит (да, на единицу больше, чем 128+64, но это не специально), предлагаемое безопасное расстояние — 40〜42 бит (Hamming).

В репозитории https://codeberg.org/aoba/my_phash — со всеми bells and whistles, в архиве в прикреплённой картинке — минимум, нужный для компиляции хешера и скрипт для сборки. Теперь нужна SDL2_Image вместо stb, оно умеет в webp.

Мои выводы:

✳ Перед скейлингом нужно делать динамический прямоугольный Gaussian blur (размеры ядра считаются из размеров изображения, но ядро не больше 255x255, чтобы не DoS'или).
Ланцош плохо даунскейлит некоторые картинки: https://codeberg.org/aoba/my_phash/raw/commit/10507d8d7b1e996020568fb4484d86b6c96675b6/_demo/lanczos.png, потому что оно зависит только от маленькой доли всех пикселей исходного изображения (1.5% для 1024x1024 → 128x128).
Нам не нужно считать свертку blur'а в каждом пикселе исходного изображения, а только в тех, которые требуются алгоритмом масштабирования.
Для скорости (уменьшения количества точек, в которых нужно считать свёртку) можно использовать nearest-neighbour, после блюра нет разницы.

✳ Нужно также блюрить Гауссом после скейлинга: ядро 3x3, сигма 1/3 выглядят оптимальными (для 64x64, для 128x128 нужно больше).

✳ Обозначение: Z — сторона верхней левой подматрицы DCT, которую мы принимаем во внимание.
Вообще все варианты с Z=8, включая канонический phash, выдают один и тот же хэш на bad1.png, bad2.jpg, bad3.jpg (путают bad1 и bad2/bad3). Это картинки из архива Ычана 1614714858949.png, 1610896340790.jpg, 1610895433020.jpg. Копии можно найти в том же репозитории в _demo/.
Z=32 и даже Z=24 — это слишком много, начинает хуже находить legitimate дубликаты. Я остановился на Z=16.

✳ Нужно применять фильтр Собеля после скейлинга и размытия, иначе плохо отличает те же bad1.png vs bad2.jpg/bad3.jpg.
У некотрых вариантов с post_sobel=1 тоже есть failure mode: плохо отличают 1755031272746.jpg vs 1757275052034.jpg vs bad3.jpg.
Но представленный мной вариант отличает их с огромным запасом (расстояние около 40%).

✳ Безопасное расстояние для вашего хэша составляет не больше 139 бит. Были найдены следующие false-positives, первый из которых совсем unrelated:

# img1 img2 distance_in_bits
1610895433020.jpg 1693216927545.png 140
1712238432772.png 1470588477270.png 142
1595774788245.png 1588697792032.png 142
1641455194459.png 1623844005270.png 148
1556647751230.png 1557674602249.png 152
...

Про сравнение моего варианта и вашего будет в последующем посте.
No. 1000938  
aoba_sincos.png - (393.43KB, 900×1128)
1000938
“a” обозначает ваш вариант, “p” — мой.

Ваши примеры (исключая простые случаи, где оба выдают очень маленький процент; и исключая heavy padding, где ни один ни справляются):

https://014.cdn.ganbaranai.moe/b/src/170370140818.jpg vs https://014.cdn.ganbaranai.moe/b/src/168217548738.jpg:
a => 23.828%, p => 15.544%

https://014.cdn.ganbaranai.moe/b/src/163730500889.jpg vs https://014.cdn.ganbaranai.moe/b/src/158460154167.jpg:
a => 30.469%, p => 24.870%

https://ii.yakuji.moe/b/src/1673088974447.jpg vs https://ii.yakuji.moe/b/src/1674079476839.jpg:
a => 17.578%, p => 9.326%

Из архива Ычана были случайно выбраны 2000 изображений, у которых ширина и высота >= 500.
Они были подвергнуты следующим преобразованиям: даунскейлинг в 50%, 25%, 13%; кроп 5% сверху+снизу, справа+слева, со всех сторон; паддинг 5% чёрным сверху+снизу.
Затем вычислялось расстояние с исходным.
threshold для вашего был взят 27% (138 бит), для моего — 22% (42 бита).


# variant transform_index min max 90% average median num_caught_at_thres num_caught_at_90%_thres
# transforms: 0 => scale 50%, 1 => scale 25%, 2 => scale 13%, 3 => crop top+bottom, 4 => crop left+right, 5 => crop all, 6 => pad top+bottom

a 0 0.000% 51.953% 0.781% 0.501% 0.391% 1997 1997
p 0 0.000% 33.161% 2.073% 1.355% 1.036% 1997 1996

a 1 0.000% 51.953% 1.562% 0.886% 0.391% 1996 1996
p 1 0.000% 34.197% 4.145% 2.507% 2.073% 1995 1991

a 2 0.000% 51.953% 7.812% 4.728% 5.859% 1994 1993
p 2 0.000% 34.197% 7.254% 4.091% 3.109% 1988 1985

a 3 7.031% 51.953% 32.422% 27.404% 27.344% 938 431
p 3 0.000% 51.813% 24.870% 19.930% 19.689% 1466 1079

a 4 4.688% 54.688% 32.031% 26.402% 26.562% 1091 624
p 4 0.000% 36.269% 24.870% 19.134% 18.653% 1553 1212

a 5 8.594% 57.812% 44.922% 38.923% 39.062% 29 8
p 5 0.000% 63.212% 35.233% 29.402% 29.016% 134 55

a 6 8.984% 53.125% 30.078% 25.304% 25.391% 1394 822
p 6 0.000% 44.560% 23.834% 19.544% 19.689% 1559 1182

0〜2 можно игнорировать, с ними отлично справляются оба.

max значительно меньше на всех, кроме 5 (но с 5 вообще оба плохо справляются).
average и median значительно меньше на всех 3〜6.

num_caught_at_thres и num_caught_at_90%_thres в процентах от 2000 (исключая 0〜2, где везде >99%):
<= threshold:     47% → 73%, 55% → 78%, 1% → 7%, 70% → 78%.
<= 0.9*threshold: 22% → 54%, 31% → 61%, 0% → 3%, 41% → 59%.

Изменение ratio тоже пробовалось, но результаты такие же, как у 0〜2.

Код этого эксперимента и список файлов выложу позже.
No. 1000940  
aoba_aji.png - (655.54KB, 926×1348)
1000940
> И когда-нибудь если захочется заняться длинными серьёзными исследованиями или появится настоящий CV сварщик, то пытаться лучше.
А чего вообще в теории можно сделать-то?
В проекте pHash есть ещё хэш на интегралах Радона — его затратно считать, там O(n_rays * W * H), n_rays = 180.
Ещё там есть волночки (wavelet) — я не верю, что они существенно лучше, чем DCT.
CNN-based (как в https://github.com/idealo/imagededup) — как-то слишком круто для нас.
Average hash — оче плохой.
dhash, dhash-over-DCT, zigzag и прочее тоже работает хуже, чем DCT.

Только автоматическое убирание паддинга можно ещё сделать.

> Построить такой список можно
Ну я сделаль убирание кластеров из очень похожих изображений (mean_error.c и utils/hide_genuine_clusters.py) и viewer/. В том же репозитории.
No. 1000941  
> Код этого эксперимента и список файлов выложу позже.
In the repo now (_eval/).
No. 1000942  
94706770_p0.jpg - (1.24MB, 2676×3360)
1000942
>>1000937
Приятные результаты у вас. Детально посмотрю в воскресенье. Have been в разъездах.%

Пока, читаючи на смартфоне замечено, что по-прежнему включаете DC (то бишь, block[0]) в хэш. Так и задумано?
No. 1000943  
aoba_poI.png - (332.65KB, 703×1145)
1000943
>>1000942
> Пока, читаючи на смартфоне замечено, что по-прежнему включаете DC (то бишь, block[0]) в хэш. Так и задумано?
Во-первых, один бит из 193 не повлияет заметно на результат.
Во-вторых, имеет смысл выбросить буквально любой бит, кроме DC.

Обозначения: N — длина хэша, DC = hash[0], AC = hash[1:N].

Утверждение: при определённом допущении*, parity(AC) 【a.k.a. popcount(AC)%2】 есть функция от DC и N: parity(AC) = f(DC, N). Таким образом, мы можем выбрать любой бит из AC и отбросить его: его можно реконструировать как b = parity(AC_without_b) XOR f(DC, N).

* Допущение: либо изображение полностью одноцветное и hash состоит только из нулевых бит (и, следовательно, DC=0), либо DC=1 и у нас ровно половина (исключая саму медиану, если N-1 нечётное) элементов больше медианы (popcount(AC) = floor((N-1) / 2)).

Это допущение выполняется для всех изображений в архиве Ычана, допущение DC=1 — не выполняется для 19 из 95031.

Пруф запощу завтра.
No. 1000946  
Пруф: разберите все восемь вариантов ⟨N%4, DC⟩. Получится
def f(DC, N):
  if N % 4 == 0 or N % 4 == 3:
    return DC
  else:
    return 0
No. 1000947  
>Pr. 95
Про картинки уже обсуждалось, решается ограничением по макс. ширине/высоте.
Видео... Ну, в целом, такие лимиты сервер съест.
No. 1000949  
>>1000947
Понятно, что настолько продвинутый желающий навредить так или иначе найдёт способ, но конкретно это легко поправить: добавить к ffmpeg’у опцию -max_pixels 100M. Этого должно быть достаточно, но хорошо бы ещё запускать сам ffmpeg, предварительно сделав ulimit -v 20971520 (20G виртуальной памяти) и ulimit -t 30 (30 секунд чистого CPU time). Поскольку exec() в PHP уже запускает команду под /bin/sh -c ..., для этого даже не нужно создавать никаких новых процессов или что-то переделывать.
No. 1000950  
>>1000942
Прошу прощения за просрочку в неделю. Ждите к этому воскресенью тогда.
No. 1000951  
equalized_aoba+my_phash.webp - (23.98KB, 256×256)
1000951
>>1000950
Собственно, пробовать предлагается уже другое. Но можете и старое попробовать.

По какой-то причине, blur&scale ⇒ histogram equalization ⇒ blur ⇒ DCT работает значительно лучше, чем blur&scale ⇒ blur ⇒ Sobel ⇒ DCT.

Предлагаемое безопасное расстояние не изменилось: 40〜42 бит.

Изменения в результатах по сравнению с моим прошлым вариантом:

<= threshold:     73% → 86%, 78% → 88%, 7% → 12%, 78% → 83%.
<= 0.9*threshold: 54% → 69%, 61% → 73%, 3% → 5%,  59% → 65%.

Новых false-positives не обнаружено.

В архиве в картинке — опять же, минимум, нужный для компиляции нового хешера и скрипт для сборки.

(А ещё был найден более вопиющий пример плохого даунскейлинга Ланцошом: https://codeberg.org/aoba/my_phash/raw/commit/484ed9ad07056888a98db9ae44673c46deaf1d71/_demo/lanczos_another.png)
No. 1000953  
192.webp - (43.47KB, 1995×3496)
1000953
>>1000951
Посмотрел. Давайте остановимся на текущем варианте?
Который blur=gauss_dyn[alpha=0.8,beta=4],scale=nn,S=64,post_blur=gauss[ksize=3,sigma=0.333333],hash=phash[Z=16,mask=circle],post_histeq=1. On the other hand, проверьте, как волночки справляются, раз уже закомитили.

Если брать текущий вариант, то за тем, исключением, что DC я бы всё-таки не включал. Во-первых, поскольку для большинства изображений в наших данных DC бит равен 1, DC бит не несёт различительной силы. Да, выброшенный AC бит можно восстановить, но покуда он выброшен, он не участвует в расчёте расстояния, и уж он-то точно может разниться. Поэтому, и потому, что если брать только AC, получается естественным образом определить 192-битный хэш — целое число байтов.

Ещё я бы попробовал (и, наверное, попробую) реализовать текущий вариант с blur и histeq vips'овыми функциями, доступными PHP-обёртке.

> А чего вообще в теории можно сделать-то?
Наверное, много чего, особенно с большей-то длинной. С 64 битами, уже на расстоянии 16/64, скорее всего, вероятность коллизий между двумя случайными изображениями достаточно высокая для того, чтобы на dataset'е в 10**4 картинок они likely были. А вот с 192 битами и 42/192 эта вероятность на порядок меньше. А значит, есть куда расти. Другой вопрос, как.

Есть radon transform и log-polar transform. O(n_rays * W * H) вряд ли страшно, если это про уменьшенную копию и простые операции: матричное умножение сейчас — это O(S**3).
Вроде существуют алгоритмы, позволяющие вместо синусов-косинусов построить для специфичного dataset'а более подходящий набор базисных векторов.
Есть scattering wavelet transform, которое бывает используется для нейронок. Там генерируется несколько проекций-матриц, и оно довольно толстое и медленное, и не понятно, как его в phash.
Есть SIFT и подобные алгоритмы для feature extraction. Применимы ли они в нашем деле, не знаю.
Можно подумать о некой функции, меняющей местами пиксели, то бишь об преобразовании координат из (x, y) в (p, q), даже не обязательно биективном, таком что основанные на DCT phash'ы картинок после преобразования более инвариантны относительно crop'ов и padding'ов. Думается, например, о том, чтобы найти некий saliency point в картинке, принять координаты этого пикселя за (p=0, q=0), а значения для остальных пикселей считать по удалению от этого (p, q). Но может быть можно придумать что-то куда более робастное.

Хотя мы для оценки мы берём безопасное расстояние 42, где нет false positives, но на практике будет при поиске за него стоит забегать, поскольку некоторые (например, 15139:160754327348.png и 17616:160805964719.jpg 50/192) важные сопоставления находятся за его приделами. Писать что-то вроде "похожее изображение могло быть опубликовано здесь" вместо "похожее изображение было опубликовано здесь".

По-прежнему нахожу очень странным, что ваша реализация иногда несколько хуже справляется с простыми переужатиями. 14/192 (3369:176383346733.png, 3381:176686056329.jpg) найденный максимум. Совсем не понимаю, почему.
No. 1000965  
stretched_aoba.png - (327.56KB, 745×468)
1000965
> Посмотрел. Давайте остановимся на текущем варианте?
> Который blur=gauss_dyn[alpha=0.8,beta=4],scale=nn,S=64,post_blur=gauss[ksize=3,sigma=0.333333],hash=phash[Z=16,mask=circle],post_histeq=1.
Давайте.

> On the other hand, проверьте, как волночки справляются, раз уже закомитили.
Очень плохо они справляются. Реализация корректная, на всех уровнях «пайплайна» смотрел результаты, найденные «похожие» тоже смотрел — plausible. Meh.

> Если брать текущий вариант, то за тем, исключением, что DC я бы всё-таки не включал. Во-первых, поскольку для большинства изображений в наших данных DC бит равен 1, DC бит не несёт различительной силы. Да, выброшенный AC бит можно восстановить, но покуда он выброшен, он не участвует в расчёте расстояния, и уж он-то точно может разниться. Поэтому, и потому, что если брать только AC, получается естественным образом определить 192-битный хэш — целое число байтов.
Agreed. Выпилил DC.

> А значит, есть куда расти. Другой вопрос, как.
Можно завести два-три индекса по разным хешам, например, текущий, предыдущий (с sobel) и dhash. Запрашивать похожие по всем и объединять результаты.

> Есть radon transform и log-polar transform. O(n_rays W H) вряд ли страшно, если это про уменьшенную копию и простые операции:
Нет, не про уменьшенную копию. И в библиотеке pHash оно выдаёт не биты, которые можно сравнивать по Hamming distance или Jaccard distance, а 40 байт, которые нужно сравнивать с помощью, эм, “circular cross-corelation”.

> Вроде существуют алгоритмы, позволяющие вместо синусов-косинусов построить для специфичного dataset'а более подходящий набор базисных векторов.
> Есть scattering wavelet transform, которое бывает используется для нейронок. Там генерируется несколько проекций-матриц, и оно довольно толстое и медленное, и не понятно, как его в phash.
> Есть SIFT и подобные алгоритмы для feature extraction. Применимы ли они в нашем деле, не знаю.
Слишком сложно, ИМХО.

> Можно подумать о некой функции, меняющей местами пиксели, то бишь об преобразовании координат из (x, y) в (p, q), даже не обязательно биективном, таком что основанные на DCT phash'ы картинок после преобразования более инвариантны относительно crop'ов и padding'ов. Думается, например, о том, чтобы найти некий saliency point в картинке, принять координаты этого пикселя за (p=0, q=0), а значения для остальных пикселей считать по удалению от этого (p, q). Но может быть можно придумать что-то куда более робастное.
Так вы хотите выпячивать важные куски (как на pic related)? Или затемнять неважные? Я не понял.

> Хотя мы для оценки мы берём безопасное расстояние 42, где нет false positives, но на практике будет при поиске за него стоит забегать, поскольку некоторые (например, 15139:160754327348.png и 17616:160805964719.jpg 50/192) важные сопоставления находятся за его приделами. Писать что-то вроде "похожее изображение могло быть опубликовано здесь" вместо "похожее изображение было опубликовано здесь".
Ну dhash’ы выдают маленькое (для них — там threshold в процентах гораздо больше) расстояние на этих картинках, но нужно будет глазами опять посмотреть, где у них безопасное расстояние по факту.
No. 1000974  
> Ну dhash’ы выдают маленькое (для них — там threshold в процентах гораздо больше) расстояние на этих картинках, но нужно будет глазами опять посмотреть, где у них безопасное расстояние по факту.
Нет, эти расстояния далеко за пределами «находится совсем не связанная между собой ерунда».
Конкретно эти картинки можно найти на расстоянии 38, если применить агрессивный unsharp mask на оригиналы. Но искать фильтры для каждой пары картинок, которая не находится, — странное занятие какое-то.
No. 1000975  
>>1000965
>stretched_aoba.png
Чем и как такое забавное сгенерировано?
No. 1000978  
>>1000975
gimp, Filters → Distorts → Lens Distortion. Подбирать параметры.
No. 1001000  
Автор форматтера приглашается для ревью https://codeberg.org/yakui-lover/fbe-410/pulls/19
No. 1001001  
Пока посмотрел код на телефоне. Я не автор rec_node_format.
> // Currently there's a bug here: it produces 15 lines instead of 16 (compare with <br> above).
Разве в контексте предложенного алгоритма !20:<li>x</li>: не корректнее сравнивать с !20:<br>x:, чем с !20:x<br>?

Всегда ли ли <ul><li> означает новую строку? Или если в самом начале сообщения или сразу после <br>, то переноса строки не будет? I wonder.
No. 1001002  
>>1001001
Э… там какой-то майндфак вообще. Требует изучения. А я подозревал, что вырезание <body> и </body> по индексам это нехорошо.
No. 1001005  
Ну, видимо, дело в моей версии PHP или чём-то ещё. Здесь не воспроизводится.
По существу заданных мне вопросов могу пояснить следующее:

// This is correct (there is a line break after "Begin", even two of them):
testcase(my_expand('Begin<ul>!20:<li>x</li>:</ul>End'), my_expand('Begin<ul>!15:<li>x</li>:</ul>'));
// This is incorrect (15 lines total, not 16):
testcase(my_expand('<ul>!20:<li>x</li>:</ul>'), my_expand('<ul>!15:<li>x</li>:</ul>'));
No. 1001006  
Поскольку автор форматтера не объявился, давайте рассмотрим PR в его отсутствие.

И это, так а чего, будем прикручивать поиск картинок? Для этого постгрес не нужен: вот это отрабатывает в MySQL за 40 мс:

SELECT filename, hash0, hash1, hash2
FROM images
WHERE id BETWEEN 3 AND 199997
ORDER BY BIT_COUNT(hash0 ^ %s) + BIT_COUNT(hash1 ^ %s) + BIT_COUNT(hash2 ^ %s) ASC
LIMIT 30

(После

CREATE TABLE images (
  id       INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  filename VARCHAR(32) NOT NULL,
  hash0    BIGINT UNSIGNED NOT NULL,
  hash1    BIGINT UNSIGNED NOT NULL,
  hash2    BIGINT UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

и вставки 200k записей со случайными хешами).
Вроде бы даже «на холодную» столько же времени требуется.

А хэшер скомпилировать в WASM и запускать на сервере и на клиенте — оказывается, синусы-косинусы-корни зависят от платформы, IEEE 754 не определяет результат до последнего бита. А WASM определяет. Да и сишкой тыкать в живой интерпретатор PHP как-то небезопасно.
No. 1001007  
148054363_p0.jpg - (608.36KB, 2000×3038)
1001007
>>1001006
> И это, так а чего, будем прикручивать поиск картинок?
Всё не могу пока включиться в работу. Так что прошу, если можете, взять дело в свои руки.

> BIT_COUNT(hash0 ^ %s) + BIT_COUNT(hash1 ^ %s) + BIT_COUNT(hash2 ^ %s)
С Постгресом, как минимум, можно обойтись одним bit(192) столбцом вместо трёх. Но если есть желание вскорости увидеть рабочий вариант... Решайтесь.
No. 1001008  
>>1001007
Хорошо.

Из последних упражнений:
  1. Можно заставить выделять памяти максимум 6 байт на пиксель. Это вместе с преобразованием прозрачности в чёрное или белое в зависимости от weighted luma, как у вас. imagemagick, вроде, максимум 4 байта на пиксель может потреблять, ffmpeg — 12.
  2. Center crop на 87.5% хорошо работает, результаты лучше.
  3. Выглядит интересным https://github.com/manjunath5496/ML-Papers/blob/main/Saliency Detection A Spectral Residual Approach.pdf,но у авторов большие проблемы с выражением своих мыслей формализмами — большинство формул и формулировок означают не то, что можно подумать)
Но #2 и #3 это на потом.

> С Постгресом, как минимум, можно обойтись одним bit(192) столбцом вместо трёх.
Ну, в MySQL тоже есть BINARY(192). Только BIT_COUNT с ним не работает (он обрезает входное значение до 64 бит). И, почему-то, даже с BIT_COUNT(whole_hash), что неправильно, оно работает медленнее.

Да и какая разница, если 40 мс?
No. 1001009  
> BIT_COUNT(whole_hash)
BIT_COUNT(whole_hash ^ UNHEX(%s)), конечно же.
No. 1001014  
Будет ли принята фича с поиском похожих картинок, если таковая будет реализована? Там на сервере нужно будет запускать только ffmpeg и мою штуку через что-то типа wasmtime с максимальными ограничениями (без доступа к сети, ФС, etc, с лимитами на память и время работы — настраивается в wasmtime), чтобы было безопасно.
No. 1001015  
>>1001014
>wasmtime
Нет. Пишите на языке кодобазы.
No. 1001016  
kaga.gif - (290.38KB, 320×240)
1001016
>>1001015
На языке кодобазы это будет непрактично, поскольку подход требует обработки изображений, которую у меня не получается выразить в терминах libvips или чего-либо ещё.
Ну и мы планировали это дело на клиенте ещё запускать — там-то точно нужен будет васм, лол.

В общем, weird. Ну может кто-то, не я, сделает версию без блюра на PHP. Но зачем дублировать то, что на клиенте будет.

Васмтайм, оказывается, нет в репозиториях дебиана. Но есть wasmedge и wazero. Чем они-то не угодили?
No. 1001017  
>>1001016
На языке отличным от кодобазы это будет непрактично, потому что сопровождающему тогда придётся знать 2-2.5 языка вместо 1.5.
Пишите отдельный продукт в отдельной репе. А дальше если это можно вызывать через exec, то и славно.
No. 1001019  
eva_com.jpg - (397.03KB, 2048×1902)
1001019
>>1001017
OK. Этот отдельный продукт может требовать для запуска на сервере какой-либо рантайм WASI (wasmtime/wasmedge/whatever)? Без этого можно, но нужно будет заморачиваться с изоляцией (ну и детерминизм потеряется, хотя, опять же, nobody cares).
Запускать какой-то сишный код без изоляции на сервере кажется плохой идеей даже мне, автору кода.
No. 1001022  
139443861_p0.webp - (11.48MB, 4961×7016)
1001022
>>1001019
> детерминизм потеряется
Проблему с синусами-косинусами-корнями разве нельзя решить, захардкодив матрицы преобразования?
> спойлер
Кто он, safe и blazing fast? Верно, дети. Это Rust!

>>1001016
> подход требует обработки изображений, которую у меня не получается выразить в терминах libvips
Какие конкретно моменты не получется? Попробую в субботу посмотреть-таки.
No. 1001023  
>>1001019
У нас там magic и ffmpeg уже запускаются от апача, какая ещё изоляция? Я-то могу что-нибудь настроить, но в случае Соуса, думаю будет проще какой-нибудь просто Докер обернуть.
No. 1001024  
тыктыктык.gif - (486.87KB, 720×720)
1001024
>>1001022
> Проблему с синусами-косинусами-корнями разве нельзя решить, захардкодив матрицы преобразования?
Нет, потому что там ещё exp в blur_gauss_dyn. А вообще, если мы не компилируемся в WASM и не включаем в себя всю лабуду для декодирования изображений, то не имеет смысла заботиться о каком-то детерминизме: всё равно RGBA, которые надекодирует библиотека, может отличаться от платформы к платформе (минимальные пары есть), и уж точно от того, что надекодирует браузер, если мы на клиенте собираемся использовать его возможности для декодирования, а не полагаться на WASM, в котором всё нужное для декодирования уже есть.

> Кто он, safe и blazing fast? Верно, дети. Это Rust!
Ну вот тут не вполне понятно, какой от него прок. Быстрее, чем текущее под bwrap, точно не будет.

> Какие конкретно моменты не получется?
Момент blur_gauss_dyn & scale_nn. Там нужно считать свёртку. Не во всех пикселях, а только в тех, которые нужны scale_nn. Свёртка прямоугольная.

>>1001023
> У нас там magic и ffmpeg уже запускаются от апача
magic и ffmpeg написаны понятно кем, их код всегда под пристальным присмотром, они есть в репозиториях всех крупных дистрибутивов, etc. Поэтому их не должно быть страшно запускать.
Вот эту мою хреновину — должно быть.

> , какая ещё изоляция?
bwrap. Или firejail. Или Podman/Docker/что-то там в systemd завезли.

$ ffmpeg -hide_banner -loglevel error -i картинка.jpg -vf format=rgba -f image2pipe -vcodec pam - | bwrap --ro-bind /usr/bin/busybox /usr/bin/busybox --unshare-all /usr/bin/busybox sha1sum
eb3609abf7df96a19edf40c059bb2f15f2bf5911  -
$

(Для повторения нужен busybox-static, наш хэшер будет тоже статически слинкован, если будет просто читать PAM из stdin.)
Это изоляция вообще всего, включая сеть, ФС, user namespace, etc.

Ну или не через пайп, а использовать ту же SDL2_Image, и прокидывать всё нужное-слинкованное тоже через bwrap.

> Я-то могу что-нибудь настроить, но в случае Соуса, думаю будет проще какой-нибудь просто Докер обернуть.

Можно. Но не знаю, зачем заморачиваться с чем-то ещё, если bwrap умеет всё, что нужно, и есть в репозиториях.
No. 1001026  
> bwrap
Я тут обнаружил, что systemd-run --scope ещё лучше: даже не нужно устанавливать отдельный пакет, и оно работает везде, где есть системд, а bwrap в таком виде не работает на каких-то хентайных hardened-версиях дистрибутивов.

«Если у вас не systemd, делайте bwrap. Если у вас не bwrap, сделайте chmod u+s /usr/bin/bwrap или обращайтесь к нам за помощью, если мы ещё живы.»
No. 1001028  
126222408_p0.jpg - (12.47MB, 5300×3600)
1001028
>>1001024
> Момент blur_gauss_dyn & scale_nn
И правда, крайне неудобно, если возможно.

Судя по всему, в libvips нету условного reduce. Поэтому в терминах php-vips для подсчёта значения в заблюреном пикселе надо будет делать extract_area вокруг него и multiply'ить её на ядро, потом брать у результата avg (sum нету) и умножать среднее на количество элементов в матрице. extract_area не копирует память, а вот multiply, как я понимаю, будет. Что не есть эффективно. И ещё проблема с clamp.

В чём-то побыстрее и понизкоуровнее PHP вроде есть воспользоваться более низкоуровневым Vips.Region и обращаться к пикселям по указателю.

> uint32_t rgba = f(f_userdata, x, y);
На всякий случай. Grayscale, как Соусная "Неправда", и 16-битные цвета, как в некоторых PNG аниме-скриншотах, обрабатываются корректно?
No. 1001029  
RGB565 ещё.
No. 1001031  
phash_haha.png - (130.74KB, 728×755)
1001031
>>1001028
> На всякий случай. Grayscale, как Соусная "Неправда", и 16-битные цвета, как в некоторых PNG аниме-скриншотах, обрабатываются корректно?
Sure thing. Это же SDL2 этим занимается, а нам просто предоставляет SDL_GetRGBA() и количество байт на пиксель (bpp). Мы читаем bpp байт по нужному смещению, передаём результат и SDL_PixelFormat *format в SDL_GetRGBA(), она декодирует в rgba.
format->format может принимать одно из большого списка значений SDL_PIXELFORMAT_*.

У меня готов образец, который читает PAM из ffmpeg’а. И даже прозрачность выставляет в чёрное или белое в зависимости от средней люмы (в основной ветке это пока не реализовано). Ветка prod. Сделать ./build_main_pam.sh и запускать так

ffmpeg -hide_banner -loglevel error -i PICTURE.jpg -vf format=rgba -f image2pipe -vcodec pam - | ./main_pam
No. 1001032  
kosozu_at_computer.png - (1.06MB, 800×800)
1001032
(На картинке была демонстрация корректность обработки grayscale старым хэшером с SDL2_Image.)

Статическая сборка (CC="gcc -static -s" ./build_main_pam.sh) даёт бинарник в 747 кб, что вполне. Его нужно будет потом просто запускать под systemd-run --scope (...какие-то_опции...).

Осталось код на PHP и фронтенд написать.
No. 1001033  
639874d21003300f29ad786214873413.jpg - (130.34KB, 1123×1576)
1001033
>>1001031
>>1001032
Замечательно.

> ffmpeg
Хм. Там такая проблема вроде, что он отказывается картинки, превосходящие где-то 20000 (?) пикселей по одной стороне. С одной стороны, релевантно для сшивок манги. С другой, вряд ли есть польза от phashing'а таких сшивок.
No. 1001037  
c1.png - (85.16KB, 1000×1000)
1001037
>>1001033
> Там такая проблема вроде, что он отказывается картинки, превосходящие где-то 20000 (?) пикселей по одной стороне.
Всё гораздо интересней. Ограничения такие:
  • (8×W + 1024)×(H + 128) < 2147483647;
  • W < 65536;
  • H < 65536.
На практике это означает W×H < ≈260'000'000 (на самом деле верхний предел 259M〜264M в зависимости от aspect ratio).

При этом приведённая мной команда ffmpeg выделяет 8 байт на один пиксель. А наша программа ещё допольнительно 2 байта на пиксель.
Если мы хотим, чтобы всё вместе это потребляло не больше, скажем, 1G (лимит по умолчанию у imagemagick), то площадь (W×H) должна быть < ≈107'000'000. То есть ffmpeg’у нужно передавать именно те самые -max_pixels 100M, про которые мной говорилось в >>1000949.

А ≈107M (ограничение по памяти, которую дозволительно скушать) это меньше, чем ≈260M (техническое ограничение ffmpeg’а).

Мне кажется, получилось неплохо: для компиляции, кроме build-essential, ничего не нужно; собранный бинарник не может сломаться после обновлений, ибо статический; systemd-run даже не нужно устанавливать.
No. 1001038  
1. Должна ли функциональность «похожие картинки» находиться за [кф]апчей?
2. Название пуродакуто®©? Изначально не хотелось название.
No. 1001039  
>>1001038
  1. Под похожие, может быть, а под почти идентичные, думаю, нет.

    Я как это себе представлял: пользователь выбирает картинку для прикрепления, её хэш тут же отправляется серверу, а сервер возвращает, есть ли likely идентичные картинки. Если есть, показывается в status bar'е о том уведомление и reflink на одну из.

    Но это про почти идентичные. А под похожие, наверное, окно вроде «Избранные нити» или отдельную страницу? На которую в уведомлении давать ссылку, если почти идентичные или похожие были обнаружены.

  2. You decide. Я бы на чём-то совсем утилитарном остановился вроде round_phash.
No. 1001040  
>>1001039
Вы понимаете, что такое захочется трогать даже не только для того чтоб постить - а чтоб найти что-то милое?
No. 1001041  
146735452_p0.jpg - (853.25KB, 1240×1754)
1001041
>>1001040
Ну, я из соображений отказоустойчивости и хотел HNSW индекс.

Но будут ли желающие? Ведь iqdb вроде не трогают для целей поиска милоты, и вряд ли iqdb для таких целей сколь-нибудь удовлетворительно. И надолго ли желания у желающих хватит? Скажем, если похожие картинки бывают редко: сделать поиск без капчи вплоть до расстояния, где false positive rate < 0.001). Более глубокий пока отключить вовсе, а потом спрятать за капчу. Сейчас, мне кажется, менять-возиться с капчесистемой будет нецелесообразно муторно в рамках MVP.

Как альтернативу капче можно потом rate limiter.
Удалить сообщение []
Пароль  
[Mod]