2015-12-11 7 views
1

Xamarin предоставляет некоторые примеры кода для выполнения простых корректировки изображения в прошивкой:Изображение Яркость/контрастность - Xamarin IOS

https://github.com/xamarin/recipes/blob/master/ios/media/coreimage/adjust_contrast_and_brightness_of_an_image/color_controls_pro/ImageViewController.cs

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

Однако, когда я делаю следующее изменение, я надежно получаю ошибки SIGSEGV на оборудовании.

//sliderC.TouchUpInside += HandleValueChanged; 
    //sliderS.TouchUpInside += HandleValueChanged; 
    //sliderB.TouchUpInside += HandleValueChanged; 

    sliderC.ValueChanged += HandleValueChanged; 
    sliderS.ValueChanged += HandleValueChanged; 
    sliderB.ValueChanged += HandleValueChanged; 

Я ожидаю, что это «перегрузка» кода в некотором роде. Как бы вы реализовали корректировки изображений, которые избегают этой проблемы? Есть ли подход более низкого уровня, или другие приложения просто используют гораздо более низкую версию изображения для настроек?

+0

Выполнение этого способа, вероятно, приведет к тому, что HandleValue изменится так, чтобы его вызывали несколько раз одновременно, вызывая сбои. Если вы добавите какую-то логику для предотвращения параллельного выполнения этого метода, она, вероятно, будет работать лучше. – Jason

+0

Спасибо Джейсону. Ваш отзыв заставил меня экспериментировать и придумать что-то не слишком далеко от принятого ответа ниже. –

ответ

2

Вот беглая версия, которую я сделал, что это «больше» в реальное время (Это запись с сим, устройство (6с) является гладким в зависимости от исходного размера изображения.

enter image description here

Создать . один ViewController IOS приложение из шаблона и добавить UIImageView и три ползунка на раскадровку, так это выглядит, как живой GIF

Я создал простой класс для хранения значений ColorCtrl (яркость, контрастность, насыщенность:

public class ColorCtrl 
{ 
    public float s; 
    public float b; 
    public float c; 
} 

чем в методе ViewDidLoad, сделать некоторые настройки:

public override void ViewDidLoad() 
{ 
    base.ViewDidLoad(); 

    string filePath = Path.Combine (NSBundle.MainBundle.BundlePath, "hero.jpg"); 
    originalImage = new CIImage (new NSUrl (filePath, false)); 

    colorCtrls = new CIColorControls(); 
    colorCtrls.Image = originalImage; 

    // Create the context only once, and re-use it 
    var contextOptions = new CIContextOptions(); 
    contextOptions.UseSoftwareRenderer = false; // gpu vs. cpu 
    // On save of the image, create a new context with highqual attributes and re-apply the filter... 
    contextOptions.HighQualityDownsample = false; 
    contextOptions.PriorityRequestLow = false; // high queue order it 
    contextOptions.CIImageFormat = (int)CIFormat.ARGB8; // use 32bpp, vs. 64|128bpp 
    context = CIContext.FromOptions (contextOptions); 
} 

Тогда для обработчиков изменить три ползунка.

Внутри этих я «взломаю» флаг занятости, чтобы пропустить преобразование изображения, если последнее преобразование не выполнено. Если мы не заняты, тогда вызовите вызов нашего метода преобразования async.

Примечание: Я сказал: «взломать», я имею в виду это, в наилучшей практике, как это должно перекачивать преобразование запросов в очереди и обработчик очереди будет суммировать все ожидающие элементов в очереди, промойте их и сделать преобразование.

Примечание. Я добавил «асинхронный вызов» к сгенерированным обработчикам событий, чтобы преобразовать изображение в await.

Примечание. Обработчики трех ползунков являются одинаковыми, за исключением значения, которое они назначают; colorCtrlV.b | colorCtrlV.s | colorCtrlV.c

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

async partial void brightnessChange (UISlider sender) 
{ 
    if (!busy) { 
     busy = true; 
     colorCtrlV.b = sender.Value; 
     this.imageView.Image = await FilterImageAsync (colorCtrlV); 
     busy = false; 
    } 
} 

Итак, теперь для фактического преобразования достаточно простая Run.Task, чтобы мы могли выполнить эту работу с основного потока и НЕ блокировать пользовательский интерфейс. Таким образом, слайдеры не будут заикаться, поскольку пользователь скользит пальцем, НО из-за «загруженного» флага/взлома в обработчике слайдера мы можем пропустить некоторые из этих событий (мы должны должно добавить обработчик для касания перетаскивания, чтобы мы обработать «последнее» запрошенное пользователем значение ....)

// async Task.Run() - not best practice - just a demo 
async Task<UIImage> FilterImageAsync (ColorCtrl value) 
{ 
    if (transformImage == null) 
     transformImage = new Func<UIImage>(() => { 
      colorCtrls.Brightness = colorCtrlV.b; 
      colorCtrls.Saturation = colorCtrlV.s; 
      colorCtrls.Contrast = colorCtrlV.c; 
      var output = colorCtrls.OutputImage; 
      var cgImage = context.CreateCGImage (output, originalImage.Extent); 
      var filteredImage = new UIImage (cgImage); 
      return filteredImage; 
     }); 
    UIImage image = await Task.Run<UIImage>(transformImage); 
    return image; 
} 

Лично Для этого типа в реальном времени преобразования изображения я предпочитаю делать это с помощью OpenGL-ES с помощью GPUImage как взаимодействие экрана со скоростью обновления 60Z так гладко, как сливочное масло, но это намного больше чем использование фильтров CoreImage.

+0

отличный ответ! В то же время мои собственные эксперименты привели к несколько схожим (хотя и гораздо менее всеобъемлющим) подходам с использованием флага занятости и задержки 100 мс между действиями фильтра. Это привело меня к тому, что разрывы сегов прекратились. Теперь я попробую ваше решение и сравню. –

+0

@SteveMacdonald Прохладный, рад помочь ... Позвольте мне знать, как это происходит ... – SushiHangover