UWP / C#中的图像哈希处理后,缩放和灰色化后图像会水平重复 [英] Image hashing in UWP/C#, the image repeats horizontally after scaling and graying

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

问题描述

我遵循



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



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



以下是呈现图像的XAML代码:

 < Image x:Name =myImageStretch =None/> 

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

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

我做错了什么?有些东西看起来很腥,关于处理后的图像..我从这里失去了......我应该如何推进哈希?任何帮助?

解决方案您的 ConvertToGrayAsync 方法应该简单地返回转换后的WriteableBitmap 。循环内的像素转换代码也可以简化,并且该方法不需要在源和目标缓冲区上操作。

 私人异步任务< 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 =像素[i + 2];
var f =(byte)(0.21 * r + 0.71 * g + 0.07 * b);
像素[i] = f;
像素[i + 1] = f;
像素[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;

$ / code>

以下方法使用预定义大小加载一个WriteableBitmap:

  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);
等待bitmap.SetSourceAsync(memoryStream);
返回位图;




$ b $ ProcessImageAsync 方法现在看起来像这样:

  private async Task< WriteableBitmap> ProcessImageAsync(
StorageFile文件,int宽度,int高度)
{
return await ConvertToGrayAsync(
await 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天全站免登陆