拍摄的照片有垂直条纹

时间:2015-11-09 08:53:35

标签: c# windows-runtime windows-phone-8.1

我正在使用WinRT Mediacapture课程拍摄一张照片,但是当我拍摄照片时会发现奇怪的透明条纹,这很难解释,所以这里有一些照片:

拍摄照片之前(预览)

Before capturing picture (Previewing)

拍照后

After taking picture

我见过其他人在这里遇到同样的问题(比如here,但是他们的解决方案对我来说似乎没有用。(要么没有结果,要么照片搞砸了)

我用于设置分辨率的代码:

System.Collections.Generic.IEnumerable<VideoEncodingProperties> available_resolutions = captureManager.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo).Select(x => x as VideoEncodingProperties);

foreach (VideoEncodingProperties resolution in available_resolutions)
{
     if (resolution != null && resolution.Width == 640 && resolution.Height == 480) //(resolution.Width==1920 && resolution.Height==1080) //resolution.Width==640 && resolution.Height==480)
     {
           await captureManager.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, resolution);
     }
}

我用来拍摄照片的代码:

private async Task<BitmapImage> ByteArrayToBitmapImage(byte[] byteArray)
    {
        var bitmapImage = new BitmapImage();

        using (var stream = new InMemoryRandomAccessStream())
        {
            await stream.WriteAsync(byteArray.AsBuffer());
            stream.Seek(0);

            await bitmapImage.SetSourceAsync(stream);

            await stream.FlushAsync();
        }

        return bitmapImage;
    }

    /// <summary>
    /// Relayed Execute method for TakePictureCommand.
    /// </summary>
    async void ExecuteTakePicture()
    {
        System.Diagnostics.Debug.WriteLine("Started making picture");
        DateTime starttime = DateTime.Now;

        ImageEncodingProperties format = ImageEncodingProperties.CreateJpeg();

        using (var imageStream = new InMemoryRandomAccessStream())
        {
            await captureManager.CapturePhotoToStreamAsync(format, imageStream);

            //Compresses the image if it exceedes the maximum file size
            imageStream.Seek(0);

            //Resize the image if needed
            uint maxImageWidth = 640;
            uint maxImageHeight = 480;

            if (AvatarPhoto)
            {
                maxImageHeight = 200;
                maxImageWidth = 200;

                //Create a BitmapDecoder from the stream
                BitmapDecoder resizeDecoder = await BitmapDecoder.CreateAsync(imageStream);

                if (resizeDecoder.PixelWidth > maxImageWidth || resizeDecoder.PixelHeight > maxImageHeight)
                {
                    //Resize the image if it exceedes the maximum width or height
                    WriteableBitmap tempBitmap = new WriteableBitmap((int)resizeDecoder.PixelWidth, (int)resizeDecoder.PixelHeight);
                    imageStream.Seek(0);
                    await tempBitmap.SetSourceAsync(imageStream);
                    WriteableBitmap resizedImage = tempBitmap.Resize((int)maxImageWidth, (int)maxImageHeight, WriteableBitmapExtensions.Interpolation.Bilinear);
                    tempBitmap = null;

                    //Assign to imageStream the resized WriteableBitmap
                    await resizedImage.ToStream(imageStream, BitmapEncoder.JpegEncoderId);
                    resizedImage = null;
                }

                //Converts the final image into a Base64 String
                imageStream.Seek(0);
            }

            //Converts the final image into a Base64 String
            imageStream.Seek(0);

            BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream);

            PixelDataProvider pixels = await decoder.GetPixelDataAsync();
            byte[] bytes = pixels.DetachPixelData();

            //Encode image
            InMemoryRandomAccessStream encoded = new InMemoryRandomAccessStream();
            BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, encoded);

            encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, maxImageWidth, maxImageHeight, decoder.DpiX, decoder.DpiY, bytes);

            //Rotate the image based on the orientation of the camera
            if (currentOrientation == DisplayOrientations.Portrait)
            {
                encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise90Degrees;
            }
            else if (currentOrientation == DisplayOrientations.LandscapeFlipped)
            {
                encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise180Degrees;
            }

            if (FrontCam)
            {
                if (currentOrientation == DisplayOrientations.Portrait)
                {
                    encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise270Degrees;
                }
                else if (currentOrientation == DisplayOrientations.LandscapeFlipped)
                {
                    encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise180Degrees;
                }
            }

            await encoder.FlushAsync();
            encoder = null;

            //Read bytes
            byte[] outBytes = new byte[encoded.Size];
            await encoded.AsStream().ReadAsync(outBytes, 0, outBytes.Length);

            encoded.Dispose();
            encoded = null;

            //Create Base64
            image = await ByteArrayToBitmapImage(outBytes);
            System.Diagnostics.Debug.WriteLine("Pixel width: " + image.PixelWidth + " height: " + image.PixelHeight);
            base64 = Convert.ToBase64String(outBytes);

            Array.Clear(outBytes, 0, outBytes.Length);
            await imageStream.FlushAsync();
            imageStream.Dispose();
        }

        DateTime endtime = DateTime.Now;
        TimeSpan span = (endtime - starttime);

        //Kind of a hacky way to prevent high RAM usage and even crashing, remove when overal RAM usage has been lowered
        GC.Collect();

        System.Diagnostics.Debug.WriteLine("Making the picture took: " + span.Seconds + " seconds");

        if (image != null)
        {
            RaisePropertyChanged("CapturedImage");

            //Tell both UsePictureCommand and ResetCommand that the situation has changed.
            ((RelayedCommand)UsePictureCommand).RaiseCanExecuteChanged();
            ((RelayedCommand)ResetCommand).RaiseCanExecuteChanged();
        }
        else
        {
            throw new InvalidOperationException("Imagestream is not valid");
        }
    }

如果需要更多信息,请随时发表评论,我会尽快将其推出,感谢您的阅读。

1 个答案:

答案 0 :(得分:2)

预览的宽高比必须与捕获的照片的宽高比相匹配,否则您将在捕获中获得类似工件的工件(尽管它实际上取决于驱动程序的实现,因此它可能因设备而异)到设备)。

  1. 使用MediaCapture.VideoDeviceController.GetMediaStreamProperties()上的MediaStream.VideoPreview方法。
  2. 获取结果VideoEncodingProperties,并使用宽度和高度来计算宽高比。
  3. MediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties()上调用MediaStream.Photo,找出哪些广告系列的宽高比相匹配(我建议使用公差值,0.015f可能会很好)
  4. 在那些做的事情中,选择哪一个更适合您的需求,例如:通过注意总分辨率W * H
  5. 通过调用MediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync()上的MediaStream.Photo并传递所需的编码属性来应用您的选择。
  6. this thread中的更多信息。 SDK示例为available here