[Назад] [Вся нить] [Первые 100 сообщений] [Последние 50 сообщений]
Ответ в нить [Последние 50 сообщений]
Имя
Captcha image [Д]
Animapcha image [@] [?] [Т]
Тема    ( ответ в 1000686)
Сообщение
flower
Предпросмотр
Файл 
Пароль  (для удаления файлов и сообщений)
Параметры   
140368429_p0.jpg - (2.48MB, 4000×4000)
1000686
No. 1000686  
Замечания и предложения по нему, а также их обсуждение.
Предыдущий тред тонет тут >>1000357.
108 сообщений пропущено. Показаны 50 последних сообщений
No. 1000832  
145751771_p2.jpg - (190.32KB, 640×696)
1000832
>>1000830
> я прошу как это будет выглядеть в некоем абстрактном MoveThreadService. Начиная с авторизации. С вызовами пересборки и прочая. Можно не кодом, а взаимодействующими сущностями.
Jawohl, ждите.

> Но впрочем костыли связанные с привязкой айпишника к конкретной доске уже сейчас видны
Если не нравится, давайте тогда, как сейчас, держать шифрованный IP прямо в posts, и делать SELECT DISTINCT по нему для поиска по подсети и числа уникальных клиентов, although это более медленные SELECT'ы.

> Не имеет смысла с точки зрения пользования. Что админ будет переносить треды не посмотрев на репорты сомнительно, а если и будет, удалять их не требуется, так как они не отсмотрены.
Удалять их требуется, если доска, на которую осуществляется перенос, не поддерживает репорты, чтобы не было orphan'ов.

А если поддерживает, то требуется обновить ID постов в репортах, чтобы пользователь, например, не мог отрепортить пост, помеченный модератором или админом, как не требующий вмешательства уже на новой доске.

Пускай база данных будет consistent, жалко что ли?

> Алсо, мускуль
?? Мы же на Postgres будем переходить. После решения #9 и прочих более насущных проблем в том, что есть.

> Ало, indices.
Аря? My bad.
No. 1000833  
>>1000832
Если постгря, то зачем last_post_id когда можно просто CREATE SEQUENCE?
No. 1000834  
>>1000833
Потому что у нас composite primary key (board_id, post_id). А sequence'ы, насколько я понимаю, не работают с composite pkey даже в Постре.
No. 1000835  
>>1000834
>composite primary key (board_id, post_id)
Да, не (board_id, last_post_id). Чем ручками его дёргать, nextval/curval/setval и по последовательности на доску.
No. 1000837  
139385864_p0.jpg - (6.35MB, 1718×2406)
1000837
>>1000835
Как-то так то бишь?
SELECT
  posts.id AS old_id,
  nextval(boards.post_id_sequence_name) AS new_id
FROM posts,boards
WHERE
  posts.board_id = :source_board_id AND
  posts.thread_id = :source_thread_id AND
  boards.id = :target_board_id

Ясно.
No. 1000838  
epi_cjs.png - (191.03KB, 506×468)
1000838
>>1000815
Inside (png+zip)-related.
Если перейдём на единую таблицу posts, можно будет взять ORM/Data Mapper/…. А пока так.

>>1000829
1. Отлаживать-поддерживать эту радость потом можно будет так же просто, как императивный код?
2. Мы уже прямо-таки собрались мигрировать на постгрес и единую таблицу posts?

>>1000831
> Тогда пока поставить на 'cookie_samesite' => 'Lax' и 'cookie_domain' => KU_DOMAIN, although, ЕМНИП, в браузере есть какие-то проверки/ограничения на соответствие домена, выставившего cookie, и домена, на который cookie отправляется, и 'cookie_domain' самостоятельно ставить не надо.
При этих ограничениях куки подставляются только в GET-запросы и только если запрос делается в результате клика. Но это не есть надлежащее решение: работать это будет до первой XSS или GET, меняющего состояние (у нас последнее, вроде как, сейчас присутствует).

> Насколько я понимаю, оно заставляет так поступать конкретно с phpsessid печенькой, к которой management действия привязаны, а другим печенькам можно ставить политику as neeed.
> Разве нельзя на 0l4chan.org целиком MitM'ить соединение меж клиентом и подлинным 014chan.org-сервером?
My point was that, если администратор будет вынужден логиниться заново при переходе по ссылке с другого сайта, то он может и забыть проверить, что это домен не фишинговый. А без strict он просто не будет вынужден логиниться заново в таком случае.

И, если уж совсем вредничать, у нас faptcha_type в $_SESSION хранится.
No. 1000839  
Энивей, до 19го я ПР рассматривать не могу.
No. 1000856  
phash_dupes.png - (283.53KB, 419×867)
1000856
>>1000775
Вы забыли про 7x7 box blur в phash. Я реализовал phash. Обнаружилось только два легитимных false-positive (см. пик). А ваша ранее не обнаруженная Роко нашлась.

Для исключения первого можно хэшировать цветовую компоненту в дополнение к grayscale.

Это на 19k Булочных картинках.
No. 1000858  
162283373169.webp - (1.50MB, 2108×3274)
1000858
>>1000856
Пожалуйста, опубликуйте вашу реализацию же.
> А ваша ранее не обнаруженная Роко
Чего? В реализации, которую я здесь опубликовал и про которую говорил в >>/b/1006362
, она обнаруживается на расстоянии 0 (равные хэши). Неужели совсем позапускать-посмотреть неинтересно было?
No. 1000860  
>>1000718-пост можете disregard'нуть entirely. Там, ЕМНИП, была некая серьёзная ошибка в реализации. Точно не вспомню, какая.
No. 1000866  
Файл
удалён
>>1000858
Результаты на ваших примерах:
Дубликаты:
> 16/512 — расстояние меж https://ii.yakuji.moe/b/src/1705971491904.jpg и https://ii.yakuji.moe/b/src/1688504889304.jpg
2/64
> 28/512 — меж >>9388 и >>9496
6/64
> 40/512 — меж https://ii.yakuji.moe/b/src/1648398268154.jpg и https://ii.yakuji.moe/b/src/1572851490178.jpg
2/64

Похожие, но не идентичные:
> Для сравнения, на расстоянии 40/512 можно обнаружить https://ii.yakuji.moe/b/src/1681308511905.jpg и https://ii.yakuji.moe/b/src/1683280427230.jpg.
2/64

Scaling/сдвиг/padding:
> 138/512 — >>15995 и >>18833
4/64
> 148/512 — >>3380 и >>9520
8/64
> Например, https://ii.yakuji.moe/b/src/1673088974447.jpg, 1674079476839.jpg, 1676900847615.jpg, 1678044547885.jpg, 1695834706311.jpg, 1708415679326.jpg. Хотя меж некоторыми парами картинок из набора прямое расстояние и меньше 100/512, связным граф становится только при предельном прямом расстоянии меж индивидуальными хэшами-нодами 171/512
Pic related.
Последняя и предпоследняя имеют одинаковый хэш.

Вариации/частичные изменения содержимого:
> меж >>3681 и >>4892 36/512
2/64
> >>8513 >>8614 76/512
4/64
> >>5390 >>5455 116/512
26/64
> >>6377 >>6379 140/512
12/64
> >>14826 >>14826
(Во втором вы имели в виду >>14827)
12/64
> >>16709 >>16721 192/512
12/64
No. 1000868  
myPhash_zipjpeg.jpg - (585.85KB, 2337×3098)
1000868
>>1000858
> Пожалуйста, опубликуйте вашу реализацию же.
Here. Пример на PHP included. Хотя логичнее уж запускать отдельный процесс каждый раз.

Caveats:
  • вся прозрачность переводится в чёрный цвет, это можно поправить;
  • stb_image не умеет в webp, можно взять любую другую библиотеку, на неё ничего не завязано особо;
  • convo в 3-4 раза медленне, чем могло бы быть (separable kernel).
Можете скомпилировать в wasm, rewrite it in Rust, сделать аналог для JavaScript, удолить и забыть.

Нужна libstb. Компилирвать через ./build.sh. Запускать так:
$ ./myphash /tmp/mypics/1572851490178.jpg
8976a19847e827f6


> Чего? В реализации, которую я здесь опубликовал и про которую говорил в >>/b/1006362, она обнаруживается на расстоянии 0 (равные хэши). Неужели совсем позапускать-посмотреть неинтересно было?
Таки где ваша последняя реализация? В >>1000775? А то запутаться можно. Её я и смотрел.
No. 1000869  
> convo в 3-4 раза медленне, чем могло бы быть (separable kernel).
Хотя оно уже раза в 2-3 быстрее, чем pHash, который на гитхабе, лол.
No. 1000871  
mpl_2.png - (10.28KB, 548×447)
1000871
>>1000866
Вот корректный пик. Gomen.
No. 1000872  
512 and 64.webp - (24.22KB, 2189×474)
1000872
>>1000868
Спасибо, потестирую. Может, тоже попробую поприменять blur.

> В >>1000775?
Она самая. Но находит пару картинок с той девочкой она на расстоянии 0. У вас не так?
No. 1000875  
Хочу добавить, что мой код сам реализует извлечение luma-канала и масштабирование. То есть после того, как у нас есть массив RGB, никакие зависимости нам не нужны. Это решает проблему с «там разные алгоритмы приведения к grayscale и масштабирования». Его можно скомпилировать в wasm или даже написать копию на JavaScript.

>>1000872
> Она самая. Но находит пару картинок с той девочкой она на расстоянии 0. У вас не так?
Конкретно на этой не запускал. Ориентировался на то, что вы написали. А оказалось, что это устарело.
No. 1000886  
>>1000856
Потестил вашу реализацию по всем JPEG и PNG из своих булочных картинок. Было бы неплохо, если бы выложили список, по которому тестируете, чтобы синхронизировать. CSV с результатами моей и вашей реализации в архиве.

На расстоянии 0 находятся ещё два "false positive" про незначительные вариации, кроме вами упомянутых: (>>/b/2996, >>/b/2997) и (>>/b/8825, >>/b/18633).

Первые серьёзные false positive появляются на расстоянии 6: (>>/b/8242, >>/b/16575), (>>/b/3908, >>/b/23698). Всего 2 таких пары среди 12 новых/обновлённых кластеров.

А вот на расстоянии 8, из 30 свежих кластеров где-то половина — пары нерелевантных картинок.

Моя реализация на длине хэша в 64 бита (threshold 72) и размере sample'а 32x32 начинает деградировать на тех же 6 и 8 расстояниях. Однако на расстоянии 0 находит больше дубликатов: например (>>/b/8637, >>/b/25626), (>>/b/18011, >>/b/18312) у меня 0/64, у вас 4/64. Количество недубликатов на расстоянии 0 такое же, но недубликаты немного другие: (>>/b/11092, >>/b/11456), (>>/b/6224, >>/b/6226) и (>>/b/3154, >>/b/3161) вместо (>>/b/2996, >>/b/2997), (>>/b/7767, >>/b/19060) и (>>/b/8825, >>/b/18633).

На больших расстояних какая-то совсем большая разница в количестве найденного, но там уже совсем месиво по большей части, скорее всего, так что я не смотрел.

В целом, поскольку уже на расстоянии 8/64 где-то половина найденного — лабуда, но не без интересностей, я и начал пробовать большие длины хэша и размерности сэмпла: при длине в почти 512 бит (threshold 617) и размере сэмпла 128x128 первый серьёзный false positive находится на 172/512, и до его наступления интересных похожестей находится больше, чем до 8/64 включительно. Поэтому хочу сделать phash не в 8, а в 64 байта а-ля SHA-512.

>>1000868
Ещё, такая заметка. Покуда нам нужно только левое верхнее 8x8 окно из 32x32 DCT матрицы, не обязательно считать всю 32x32 матрицу, а можно посчитать только это окно, сделав матрицы коэффицентов прямоугольными: 8x32 и 32x8--транспонированная. (32 * 32 * 32 * 2) / (32 * 32 * 8 + 32 * 8 * 8) — в 6.4 раза быстрее расчёт будет, когда окно меньше sample'а по стороне в 4 раза. Although, по сравнению со scale'ингом это, наверное, мелочь.
No. 1000894  
aoba_oueo•myphash_zipjpeg.jpg - (839.88KB, 694×1000)
1000894
> Было бы неплохо, если бы выложили список, по которому тестируете, чтобы синхронизировать. CSV с результатами моей и вашей реализации в архиве.
В архиве (misc/*). Названия у вас, скорее всего, другие, поэтому сделал csv md5,filename.

> На расстоянии 0 находятся ещё два "false positive" про незначительные вариации, кроме вами упомянутых:
Понятно. Ну, я чисто визуально смотрел. Мне кажется, что если человек не может увидеть разницу на 150x150 — то phash тем более не может/не должен/не предназначен для такого.

Это был просто proof-of-concept, что можно без сложностей написать оригинальный phash. Идей для улучшения у меня много, но мне сначала нужно написать/улучшить свои скрипты для визуализации. И было бы хорошо, если бы у нас был единый список «как-то связаных между собой» картинок, которые должны находиться. Тогда можно будет автоматически оценивать.

Замена nearest-neighbour interpolation на bicubic сделала только хуже. А вот изменение размера блюра с 7 до 11 — сделала лучше (меньше Hamming distance у «как-то связанных между собой» картинок). А если выставить HASH_TYPE => HASH_TYPE_RADIAL (при тех C=>11, S=32, S1=>8), получается ещё лучше. Даже некоторые масштабированные находятся на расстоянии 0, которые раньше не. Каких-то false positives, которые не связаны между собой очевидным образом, нет.

Там в архиве новая версия. Можно играться с параметрами в core/params.h. Например, вашему будет примерно соответствовать C => 1, S => 128, S1 => 23, HASH_TYPE => HASH_TYPE_RADIAL. Только у меня масштабирование через nearest-neighbour interpolation, а у вас, вроде бы, lanczos3?

> Although, по сравнению со scale'ингом это, наверное, мелочь.
Scaling тоже мелочь (оно ведь O(S^2)). Узкое место — в свёртке (блюре). И оно сейчас O(W * H * C^2), а можно сделать O(W * H * C). Только пока руки не доходят.

Пора открывать /dev/?
No. 1000895  
found_banner.png - (47.90KB, 392×221)
1000895
>>1000894
> Даже некоторые масштабированные находятся на расстоянии 0, которые раньше не
Пример.
No. 1000905  
c.png - (15.92KB, 615×79)
1000905
>>1000894
> спойлер
Капча согласна.
А надо ли? Devочкотреда хватит наверное.
No. 1000912  
stack.webp - (2.34MB, 773×1386)
1000912
Как ваши дела, Аоба-сан?

>>1000894
> сделал csv md5,filename
Принято. Я решил исключить дубликаты, для которых RGB пикселей целиком совпадают, оставив только один экземпляр. Иначе слишком много Ханю.

> А если выставить HASH_TYPE => HASH_TYPE_RADIAL (при тех C=>11, S=32, S1=>8), получается ещё лучше
Когда R2_THRESHOLD = 64, хэш получается длиной 57 битов. Возможно, из-за меньшей длины.

Чтобы входило то же количество AC, то есть 64, нужно S1=10 и R2_THRESHOLD=72. Если соответствующим образом обновить parameters.h и phash_of_dct.h, то в вашей реализации (C => 7) не получается результатов, как в моей с тем же threshold.

Тестировалось только по JPG и PNG.

Для aoba_phash_32_8_8 из недубликатов на расстоянии 0 ранее не был упомянут (1871, 1872): https://014.yakuji.moe/b/res/25313.html#25341 и рядом. ID перед ':' не совпадают с ID поста. Сделать совпадающими?
Для aoba_phash_32_72 из недубликатов на расстоянии 0 оказывается (16614, 16658)[>>/b/7767], (4666, 12320)[>>/b/8825], (13602, 16347)[>>/b/5852], (4886, 16708), (2237, 17041).
do_round_phash.php 32 72 находит больше дубликатов на расстоянии 0. Недубликаты те же, что описаны в >>1000886.
CSV в архиве.

> Только у меня масштабирование через nearest-neighbour interpolation, а у вас, вроде бы, lanczos3?
Насколько я понимаю, lancoz3. Хотя я ещё буду опробывать shrink-on-load фичи + lancoz3.
Также, у меня DC не участвует в хэше, а у вас, хотя не участвует в выборе медианы, в расчёте хэша участвует.

Меня libvips привлекает помимо матричной арифметики тем, что там реализовано последовательное чтение картинки для форматов, которые это поддерживают: не нужно грузить всю картинку в память. Поэтому я хочу использовать его. BTW, я как-то пропустил это обстоятельство, но есть wasm-libvips. https://www.libvips.org/2020/09/01/libvips-for-webassembly.html Где-то 5 MiB весит. И тогда можно его же на клиенте крутить.
No. 1000913  
124370018_p0.jpg - (373.71KB, 1215×1920)
1000913
> Ну, я чисто визуально смотрел.
Так я тоже. Только не на 150x150 thumbnail'ы, а на оригиналы или их уменьшенные до вмещения в 15.6'' QHD монитор копии.

> Мне кажется, что если человек не может увидеть разницу на 150x150 — то phash тем более не может/не должен/не предназначен для такого.
So desu ka? Как по мне, phash всё-таки про картинки, а не про их уменьшенные копии, хоть те и берутся для его вычисления. Да и thumbnail'ы у нас не 150x150, а 200x200 на страницах.
No. 1000916  
> нужно S1=10 и R2_THRESHOLD=72
> S1=10
На самом деле нет и достаточно S1=9.
No. 1000917  
> lancoz3
Это ж надо было дважды имя Ланцоша так искаверкать. Прошу прошу прощения.
No. 1000918  
aoba_danoso.jpg - (1.06MB, 1975×3508)
1000918
>>1000912
Аобе нужен ещё день-два на эксперименты, десу.

1. Осозналось, что не нужно считать свёртку (будь то box blur, Gaussian blur или что-либо ещё) в каждом пикселе исходного изображения. Если у нас nearest-neighbor или lanczos, там вообще очень мало точек, в которых нужно её посчитать.

2. Появилась гипотеза, что лучше делать Gaussian blur. Причём прямоугольный и с динамически выбираемыми размерами свёртки. Ну, 1024x1024 нужно блюрить с большим радиусом, чем 32x32.

3. Пробоваю dhash (difference hash). Но там свои особенности: если использовать Hamming distance, то там большой кластер в районе <все нолики> будет. Ну, в теории ещё и во <все единички>, но на практике последнего кластера не образуется. В pgvector для битовых векторов, кроме Hamming distance есть ещё Jaccard distance. И вот тут уже оно работает хорошо. Только оно не спасает от теоретического кластера в районе <все единички>, нужно просто инвертировать хэш, если единичек получилось >66%.

4. Внезапно, Jaccard distance с phash тоже хорошо работает. По первым впечатлениям даже лучше, чем Hamming distance. Но нужно пристальнее смотреть.

5. Можно считать хэш от медианы от несколько меньшего квадрата/четверть-окружности и приписывать его копию несколько раз.

Это только то, что уже закожено.
No. 1000919  
104645504_p0.webp - (3.75MB, 6000×8000)
1000919
>>1000918
> Внезапно, Jaccard distance с phash тоже хорошо работает
В случае с нашим медианным phash, jaccard_distance — это монотонно возрастающая функция от hamming_distance. Поэтому работает в точности также.

jaccard_distance(a, b) = hash_length - hash_length * popcnt(a & b) / popcnt(a | b)
= hash_length * (popcnt(a | b) - popcnt(a & b)) / popcnt(a | b)
= hash_length * popcnt(a ^ b) / popcnt(a | b)
= popcnt(a ^ b) * hash_length / popcnt(a | b)
= popcnt(a ^ b) * hash_length / {[popcnt(a) + popcnt(b) + popcnt(a ^ b)] / 2}
= popcnt(a ^ b) * hash_length / {[hash_length / 2 + hash_length / 2 + popcnt(a ^ b)] / 2}

..потому что половина битов в a и в b еденица, потому что хэш по медиане.

Получаем
jaccard_distance(a, b)
= 2 * popcnt(a ^ b) * hash_length / [hash_length + popcnt(a ^ b)]
= {2 * popcnt(a ^ b) * hash_length + 2 * hash_length**2 - 2 * hash_length**2} / [popcnt(a ^ b) + hash_length]
= -2 * hash_length**2 / [hamming_distance(a, b) + hash_length] + 2 * hash_length


Такая вот прямая зависимость.
No. 1000920  
> прямая зависимость
Или гиперболическая. Не знаю, как правильно.
No. 1000921  
ping -c1 yakui-lover (regarding PRs).

>>1000919
Correct. Проблема была в моей методика подсчёта порога, когда появляются false positives. И зависимость действительно нелинейная.

Справедливости ради, в результате DCT могут получиться равные элементы. Но на ычанских картинках такое бывает, только если изображения полностью чёрные — там получаются все нули, и хэш — все нолики.
No. 1000923  
a_fruitless_experiment.webp - (17.53KB, 1499×460)
1000923
>>1000921
Не совсем related, но как вариант, можно попробовать dhash не по самой картинке, а по DCT. И по нему уже Jaccard distance.

>>1000918
> Можно считать хэш от медианы от несколько меньшего квадрата/четверть-окружности и приписывать его копию несколько раз.
Тоже пробовал было делать для phash подобное, и увы у меня толку особо не вышло, если вышло вообще. В round_phash.php именно посекторный обход в частности в связи с этими попытками.
No. 1000924  
Phash_CC.png - (299.98KB, 641×700)
1000924
Лучше всего себя показывает
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]
с threshold в 36 бит (не overfitting, вычислено как 0.6 × когда_количество_дубликатов_начинает_превышать_80k).

Конфигурация должна быть понятна, кроме gauss_dyn[alpha=0.8,beta=4]. Там по каждой размерности вычисляется sigma = size_orig / size_scaled * alpha, kernel_size = ceil(sigma * beta) | 1. Здесь | 1 значит «прибавить 1, если чётное».

Оно находит всё то, что вы привели в качестве примеров того, что не находит, хотя получено в результате scaling/padding/crop.

Вот примеры из ычанских картинок.

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

>>1000923
> Не совсем related, но как вариант, можно попробовать dhash не по самой картинке, а по DCT. И по нему уже Jaccard distance.
Тогда уж кодировать знак разницы между соседними в zig-zag order в матрице, которая результат DCT. Но оно показывает себя чуть хуже.
No. 1000925  
Ах да, на этой конфигурации false positives нет. А для gauss_dyn установлен максимум на kernel_size в 255. Там всё равно узкое место в декодировании. Даже с нормальными библиотеками.
No. 1000926  
>>1000921
Сегодня посмотрю.
No. 1000927  
>>1000926
codeberg лежит \shrug
No. 1000928  
codebernd
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 ..., для этого даже не нужно создавать никаких новых процессов или что-то переделывать.
Удалить сообщение []
Пароль  
[Mod]