Search code examples
c#wpfwritablebitmap

Why AccessViolationException occurs when accessing pixels in WriteableBitmap Image?


I have a video stream from a camera to an Image in a WPF. I am trying to access the WritableBitMap Image pixel by pixel before displaying it. As a test I am trying to set the whole image to white or black. In both cases however, I get the AccessViolationException error.

I checked other posts and it seems that this error is very wide and not specific to my case. I can't seem to know why I am not getting this working.

So what is the best way to play with the pixels in my case? or why this is not working? Any help is appreciated

     private async void UpdateMasterCameraPreview(IdsFrame frame)
    {
        if (masterImage != null)
            frame.Image.CopyTo(masterImage);
        else
            masterImage = frame.Image.ToWriteableBitmap();

        //BitmapImage temp = ConvertWriteableBitmapToBitmapImage(masterImage);
        WriteableBitmap temp = masterImage;

        // Here I get the exception, on every pixel access
        for (int y = 0; y < temp.PixelHeight; y++)
            for (int x = 0; x < temp.PixelWidth; x++)
                temp.SetPixel(x, y, 255);

        masterImage = temp;

        masterImage.Lock();
        masterImage.AddDirtyRect(new Int32Rect(0, 0, masterImage.PixelWidth, masterImage.PixelHeight));
        masterImage.Unlock();

        if (OnMasterFrameCaptured != null)
            OnMasterFrameCaptured(this, new CameraFrameCapturedArgs(CameraType.Master, masterImage));
    }

Solution

  • I ended up using the answer of this post. I now can edit raw pixel data of any WriteableBitmap image before sending it to image control in WPF. Below is what I exactly used but here I just convert every frame to some transparency under a condition:

            public void ConvertImage(ref WriteableBitmap Wbmp)
        {
            int width = Wbmp.PixelWidth;
            int height = Wbmp.PixelHeight;
            int stride = Wbmp.BackBufferStride;
            int bytesPerPixel = (Wbmp.Format.BitsPerPixel + 7) / 8;
    
            unsafe
            {
                byte* pImgData = (byte*)Wbmp.BackBuffer;
    
                // set alpha to transparent for any pixel with red < 0x88 and invert others
                int cRowStart = 0;
                int cColStart = 0;
                for (int row = 0; row < height; row++)
                {
                    cColStart = cRowStart;
                    for (int col = 0; col < width; col++)
                    {
                        byte* bPixel = pImgData + cColStart;
                        UInt32* iPixel = (UInt32*)bPixel;
    
                        if (bPixel[2 /* bgRa */] < 0x44)
                        {
                            // set to 50% transparent
                            bPixel[3 /* bgrA */] = 0x7f;
                        }
                        else
                        {
                            // invert but maintain alpha
                            *iPixel = *iPixel ^ 0x00ffffff;
                        }
    
                        cColStart += bytesPerPixel;
                    }
                    cRowStart += stride;
                }
            }
        }
    

    And the routine of using it is like this:

            masterImage.Lock();
            ConvertImage(ref masterImage);
            masterImage.AddDirtyRect(new Int32Rect(0, 0, masterImage.PixelWidth, masterImage.PixelHeight));
            masterImage.Unlock();