图像亮度/对比度 - Xamarin iOS

时间:2015-12-11 14:32:53

标签: ios xamarin xamarin.ios core-image

Xamarin提供了一些示例代码,用于对iOS中的图像进行简单调整:

configuring the project's visibility

此代码仅在用户释放滑块旋钮时更新图像 - 而不是我们通常期望的连续更新。

然而,当我做出以下更改时,我可靠地在硬件上遇到SIGSEGV故障。

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

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

我希望这是"重载"代码以某种方式。您将如何实施避免此问题的图像调整?是否有较低级别的方法,或者其他应用只是使用低得多的rez版本的图像进行调整?

1 个答案:

答案 0 :(得分:2)

这是我所做的一个“更多”实时的快速版本(这是来自sim的录制,设备(6s)根据初始图像大小是平滑的。

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);
}

然后是三个滑块的更改处理程序。

在那些我'破解'繁忙的旗帜中,如果最后的变换没有完成,则跳过图像变换。如果我们不忙,那就等待我们的异步转换方法调用。

注意:我说' hack ',我的意思是,在最佳实践中,这应该将请求转换为队列,队列处理程序将汇总队列中的所有待处理项,冲洗它们并进行转换。

注意:我为生成的事件处理程序添加了“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,所以我们可以从主线程中获得这项工作,而不是阻止UI。这样滑块就不会在用户滑动手指时断断续续,但由于滑块处理程序中的“忙”标志/黑客,我们可能会跳过其中一些事件(我们应该添加处理程序触摸拖动退出,以便我们处理'最后'用户的请求值....)

// 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;
}

个人对于这种类型的实时图像转换,我更喜欢使用GPUImage通过OpenGL-ES来实现,因为屏幕在60z刷新率下的交互与黄油一样顺畅,但它比使用CoreImage过滤器要多得多。