UWP/C#中的图像散列,图像在缩放和变灰后水平重复 [英] Image hashing in UWP/C#, the image repeats horizontally after scaling and graying
问题描述
我正在关注
这是我的代码产生的输出:
它正在缩放和变灰.但我不明白为什么图像水平重复??
这是呈现图像的 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屋!