UWP/C#中的图像散列,图像在缩放和变灰后水平重复 [英] Image hashing in UWP/C#, the image repeats horizontally after scaling and graying

查看:13
本文介绍了UWP/C#中的图像散列,图像在缩放和变灰后水平重复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在关注

这是我的代码产生的输出:

它正在缩放和变灰.但我不明白为什么图像水平重复??

这是呈现图像的 XAML 代码:

以及设置图片来源的C#代码:

StorageFile userPickedFile = ...;//代码被忽略.myImage.Source = await ProcessImageAsync(userPickedFile);

我做错了什么?处理后的图像看起来有些可疑..我从这里迷路了......我应该如何继续使用哈希?有什么帮助吗?

解决方案

您的 ConvertToGrayAsync 方法应该只返回转换后的 WriteableBitmap.循环内部的像素转换代码也可以简化,该方法不需要对源缓冲区和目标缓冲区进行操作.它也可以就地操纵像素值.

私有异步任务ConvertToGrayAsync(WriteableBitmap srcBitmap){var pixel = srcBitmap.PixelBuffer.ToArray();for (int i = 0; i 

以下方法加载具有预定义大小的 WriteableBitmap:

私有异步任务LoadWriteableBitmapAsync(StorageFile 文件,int 宽度,int 高度){使用 (var fileStream = await file.OpenReadAsync())使用 (var memoryStream = new InMemoryRandomAccessStream()){vardecoder = await BitmapDecoder.CreateAsync(fileStream);var 变换 = 新的 BitmapTransform{ScaledWidth = (uint)width,ScaledHeight = (uint)height,InterpolationMode = BitmapInterpolationMode.Cubic};var pixelData = awaitdecoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8、BitmapAlphaMode.Straight、变换、ExifOrientationMode.RespectExifOrientation,ColorManagementMode.ColorManageToSRgb);var pixel = pixelData.DetachPixelData();var 编码器 = 等待 BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, memoryStream);编码器.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight,(uint)width, (uint)height, 96, 96, 像素);等待encoder.FlushAsync();memoryStream.Seek(0);var bitmap = new WriteableBitmap(width, height);等待位图.SetSourceAsync(memoryStream);返回位图;}}

您的 ProcessImageAsync 方法现在看起来像这样:

私有异步任务ProcessImageAsync(StorageFile 文件,int 宽度,int 高度){返回等待 ConvertToGrayAsync(等待 LoadWriteableBitmapAsync(file, width, height));}

I am following this tutorial on image hashing.

So far I have achieved the following:

Code:

    private async Task<ImageSource> ProcessImageAsync(StorageFile ImageFile)
    {
        if (ImageFile == null)
            throw new ArgumentNullException("ImageFile cannot be null.");

        //The new size of processed image.
        const int side = 300; //300 is for clarity. Should be 8 or 16 px.

        //Initialize bitmap transformations to be applied to the image.
        var transform = new BitmapTransform() { ScaledWidth = side, ScaledHeight = side, InterpolationMode = BitmapInterpolationMode.Cubic };

        //Get image pixels.
        var stream = await ImageFile.OpenStreamForReadAsync();
        var decoder = await BitmapDecoder.CreateAsync(stream.AsRandomAccessStream());
        var pixelData = await decoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, transform, ExifOrientationMode.RespectExifOrientation, ColorManagementMode.ColorManageToSRgb);
        var pixels = pixelData.DetachPixelData();

        //Initialize writable bitmap.
        var wBitmap = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
        await wBitmap.SetSourceAsync(stream.AsRandomAccessStream());

        //Make it gray
        var grayBitmapBuffer = await ConvertToGrayAsync(wBitmap);

        //Create a software bitmap from the writable bitmap's pixel buffer.
        var sBitmap = SoftwareBitmap.CreateCopyFromBuffer(wBitmap.PixelBuffer, BitmapPixelFormat.Bgra8, side, side, BitmapAlphaMode.Premultiplied);

        //Create software bitmap source.
        var sBitmapSource = new SoftwareBitmapSource();
        await sBitmapSource.SetBitmapAsync(sBitmap);

        return sBitmapSource;
    }

    private async Task<IBuffer> ConvertToGrayAsync(WriteableBitmap srcBitmap)
    {
        // Get the source bitmap pixels
        byte[] srcPixels = new byte[4 * srcBitmap.PixelWidth * srcBitmap.PixelHeight];

        using (Stream pixelStream = srcBitmap.PixelBuffer.AsStream())
        {
            await pixelStream.ReadAsync(srcPixels, 0, srcPixels.Length);
        }

        // Create a destination bitmap and pixels array
        WriteableBitmap dstBitmap = new WriteableBitmap(srcBitmap.PixelWidth, srcBitmap.PixelHeight);
        byte[] dstPixels = new byte[4 * dstBitmap.PixelWidth * dstBitmap.PixelHeight];


        for (int i = 0; i < srcPixels.Length; i += 4)
        {
            double b = (double)srcPixels[i] / 255.0;
            double g = (double)srcPixels[i + 1] / 255.0;
            double r = (double)srcPixels[i + 2] / 255.0;

            byte a = srcPixels[i + 3];

            double e = (0.21 * r + 0.71 * g + 0.07 * b) * 255;
            byte f = Convert.ToByte(e);

            dstPixels[i] = f;
            dstPixels[i + 1] = f;
            dstPixels[i + 2] = f;
            dstPixels[i + 3] = a;

        }

        // Move the pixels into the destination bitmap
        using (Stream pixelStream = dstBitmap.PixelBuffer.AsStream())
        {
            await pixelStream.WriteAsync(dstPixels, 0, dstPixels.Length);
        }
        dstBitmap.Invalidate();

        // Display the new bitmap
        return dstBitmap.PixelBuffer;
    }

This is the original image which user selects:

And this is the output produced by my code:

It is getting scaled and grayed all-right. But I don't understand why is the image repeating horizontally??

Here is the XAML code that renders the image:

<Image x:Name="myImage" Stretch="None" />

And the C# code that sets the image source:

StorageFile userPickedFile = ...; //code ignored.
myImage.Source = await ProcessImageAsync(userPickedFile);

What am I doing wrong? Something looks fishy about the processed image.. I am lost from here... How should I move ahead with Hashing? Any help?

解决方案

Your ConvertToGrayAsync method should simply return the converted WriteableBitmap. The pixel conversion code inside the loop could also be simplified, and the method does not need to operate on a source and destination buffer. It could as well manipulate the pixel values in place.

private async Task<WriteableBitmap> ConvertToGrayAsync(WriteableBitmap srcBitmap)
{
    var pixels = srcBitmap.PixelBuffer.ToArray();

    for (int i = 0; i < pixels.Length; i += 4)
    {
        var b = pixels[i];
        var g = pixels[i + 1];
        var r = pixels[i + 2];
        var f = (byte)(0.21 * r + 0.71 * g + 0.07 * b);
        pixels[i] = f;
        pixels[i + 1] = f;
        pixels[i + 2] = f;
    }

    var dstBitmap = new WriteableBitmap(srcBitmap.PixelWidth, srcBitmap.PixelHeight);

    using (var pixelStream = dstBitmap.PixelBuffer.AsStream())
    {
        await pixelStream.WriteAsync(pixels, 0, pixels.Length);
    }

    return dstBitmap;
}

The following method loads a WriteableBitmap with a predefined size:

private async Task<WriteableBitmap> LoadWriteableBitmapAsync(
    StorageFile file, int width, int height)
{
    using (var fileStream = await file.OpenReadAsync())
    using (var memoryStream = new InMemoryRandomAccessStream())
    {
        var decoder = await BitmapDecoder.CreateAsync(fileStream);
        var transform = new BitmapTransform
        {
            ScaledWidth = (uint)width,
            ScaledHeight = (uint)height,
            InterpolationMode = BitmapInterpolationMode.Cubic
        };
        var pixelData = await decoder.GetPixelDataAsync(
            BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, transform,
            ExifOrientationMode.RespectExifOrientation,
            ColorManagementMode.ColorManageToSRgb);
        var pixels = pixelData.DetachPixelData();

        var encoder = await BitmapEncoder.CreateAsync(
            BitmapEncoder.PngEncoderId, memoryStream);

        encoder.SetPixelData(
            BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight,
            (uint)width, (uint)height, 96, 96, pixels);

        await encoder.FlushAsync();
        memoryStream.Seek(0);

        var bitmap = new WriteableBitmap(width, height);
        await bitmap.SetSourceAsync(memoryStream);
        return bitmap;
    }
}

Your ProcessImageAsync method would now look like this:

private async Task<WriteableBitmap> ProcessImageAsync(
    StorageFile file, int width, int height)
{
    return await ConvertToGrayAsync(
        await LoadWriteableBitmapAsync(file, width, height));
}

这篇关于UWP/C#中的图像散列,图像在缩放和变灰后水平重复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆