Nano Hash - криптовалюты, майнинг, программирование

Рисование мозаичных изображений в CGContext с преобразованием масштаба дает ошибки точности

Я хочу рисовать мозаичные изображения, а затем преобразовывать их с помощью обычных жестов панорамирования и масштабирования. Проблема, которая привела меня сюда, заключается в том, что всякий раз, когда я выполняю масштабирование большого количества знаков после запятой, в середине плитки появляется тонкая линия пикселей (1 или 2). Мне удалось изолировать проблему следующим образом:

CGContextSaveGState(UIGraphicsGetCurrentContext());

CGContextSetFillColor(UIGraphicsGetCurrentContext(), CGColorGetComponents([UIColor redColor].CGColor));
CGContextFillRect(UIGraphicsGetCurrentContext(), rect);//rect from drawRect:

float scale = 0.7;
CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(50, 50, 100, 100), testImage);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(150, 50, 100, 100), testImage);
CGContextRestoreGState(UIGraphicsGetCurrentContext());

При масштабе 0,7 два изображения отображаются правильно мозаично: масштаб 0,7

При масштабе 0,777777 (изменение строки 6 на «масштаб с плавающей запятой = 0,777777;») появляется визуальный артефакт:

0,777777 масштаб

Есть ли способ избежать этой проблемы? Это происходит с CGImage, CGLayer и примитивными формами, такими как прямоугольник. Это также происходит в MacOSx.

Спасибо за помощь!

редактировать: добавлено, что это также происходит с примитивной формой, такой как CGContextFillRect

edit2: Это также происходит в MacOSx!


  • Что, если вместо использования float вы используете CGFloat? Редактировать: неважно, это не должно иметь значения. 28.08.2012
  • Комментарии типа Android делают это нормально (имеется в виду, почему iOS такая отстойная!) не принесут вам здесь много друзей :-) 28.08.2012
  • удалил ссылку на Android, ничего не подразумевая, просто хотел дать как можно больше информации о том, что я пробовал. 28.08.2012

Ответы:


1

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

  1. Отрегулируйте коэффициент масштабирования так, чтобы все масштабированные координаты были целыми. Это не всегда возможно, особенно если вы рисуете много вещей.

  2. Отключите сглаживание для вашего графического контекста, используя CGContextSetShouldAntialias(UIGraphicsGetCurrentContext(), false);. Это приведет к четким границам пикселей, но все, кроме прямых линий, может выглядеть не очень хорошо.

28.08.2012
  • Это был антиалиас!!! Спасибо!! Раньше я пытался включить сглаживание, думал, что оно отключено по умолчанию... 28.08.2012
  • И, оглядываясь назад, я всегда был заинтригован тем, почему линия не была полностью красной, а была смешанной красной с белой... Я думаю, это был алгоритм, который смешал красный цвет с последними пикселями изображения при первом проходе, выдавая эту строчку на границе, она не имела ничего общего со вторым изображением. 28.08.2012

  • 2

    Когда все сказано и сделано, iOS имеет дело с дискретными пикселями на целочисленных границах. Когда ваши кадры уменьшаются на 0,7, 50 уменьшается до 35, прямо на границе пикселей. В 0,777777 это не так, поэтому iOS адаптируется и перемещает/сжимает/смешивает что угодно.

    У вас действительно есть два варианта. Если вы хотите использовать масштабирование контекста, округлите желаемое значение вверх или вниз, чтобы оно привело к целочисленным масштабированным значениям кадра (ваш код показывает 50 как стандартное значение умножения).

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

    РЕДАКТИРОВАТЬ: Если мое подозрение верно, для вас есть еще один вариант. Допустим, вам нужен масштабный коэффициент 0,77777 и кадр 50,50,100,100. Вы берете 50, умножаете его на шкалу, затем округляете возвращаемое значение вверх или вниз. Затем вы пересчитываете новый кадр, используя это значение, разделенное на 0,7777, чтобы получить некоторое дробное значение, которое при масштабировании на 0,7777 возвращает целое число. Quartz действительно хорошо понимает, что вы имеете в виду целочисленное значение, поэтому небольшие ошибки округления игнорируются. Могу поспорить, что все это будет работать просто отлично для вас.

    28.08.2012
  • Разве округление целых чисел не должно давать одинаковый результат на правой границе первого изображения и на левой границе второго изображения? Поскольку оба рассчитываются по шкале 100*, потеря точности все равно должна перекрываться. И получить масштабирование мне достаточно сложно, так как мой тайловый движок рисования получает контекст с предустановленной трансформацией. 28.08.2012
  • Мы можем спорить весь день, ЧТО такое правильное поведение, я пытаюсь сказать, что оно, вероятно, и есть. Для Apple крайне неэффективно выяснять, что рисовать в каком-то пикселе, когда ему нужно усреднить четыре пикселя. Я подозреваю, что они этого не делают, и в результате изображение выравнивается хотя бы по некоторым измерениям на целочисленных значениях. Запустите Pixie и внимательно посмотрите на зазор и посмотрите, что там находится — спорим, это тонкая красная линия в один пиксель. 28.08.2012
  • Я тестировал в приложении MacOSx, и происходит то же самое, я надеялся, что это связано с изменением 1 единицы на 2 пикселя с дисплеями сетчатки в iOS. Попробую вашу правку, как только смогу. Спасибо за помощь! 28.08.2012
  • Я попробовал ваше отредактированное решение, и оно не сработало. Я предполагаю, что вы имели в виду сделать что-то подобное для всех значений прямоугольника: floorf(value*scale)/scale; Тем временем omz решил это для меня, это было сглаживание, которое делало линию! 28.08.2012
  • Спасибо, что дал мне знать! Рад, что вы исправили это. 29.08.2012
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..