Winform使用StretchDIBits显示图像

Winform中最常用的显示图像和视频的控件就是PictureBox,而常见的显示方式是直接对PictureBox的Image属性进行赋值,但该方式有个明显的缺点:若需要在主线程外的其他线程对PictureBox赋值,则需要将赋值需求Invoke到主线程,但过多的Invoke会影响主线程的界面更新,甚至有可能出现画面在流畅更新,但界面的其他更新不被响应的情况(用大恒相机回调连续图像采集时遇到过,不清楚什么原因,但是是这个现象)。

相比之下用StretchDIBits更为底层,更省性能。

之前在网上没找到有人这样用,就自己摸索着写了一下用StretchDIBits显示Bitmap和用StretchDIBits显示Mat的功能,没想到真能用,嘿嘿。

  • 前置条件

//与图像显示相关的成员
int m_nWidth;       //图像宽度
int m_nHeigh;       //图像高度   
CWin32Bitmaps.BITMAPINFO m_objBitmapInfo = new CWin32Bitmaps.BITMAPINFO();  //位图信息头数据
IntPtr m_pBitmapInfo = IntPtr.Zero;                                         //位图信息头指针
const uint DIB_RGB_COLORS = 0;      //使StretchDIBits函数处理24位位图
const uint SRCCOPY = 0x00CC0020;    //光栅操作模式代码,这个是“直接将源拷贝到目标区域”
byte[] m_byColorBuffer = null;      //图像数据
IntPtr m_pHDC = IntPtr.Zero;        //目标设备上下文指针,这里指向picturebox
const int COLORONCOLOR = 3;         //StretchDIBits拉伸图像的模式,这里是“删除像素。 此模式会删除所有已消除的像素线,而不会尝试保留其信息。”

初始化参数

//初始化bitmapInfo参数
BitmapInfoInit();
Marshal.StructureToPtr(m_objBitmapInfo, m_pBitmapInfo, false);
m_pHDC = m_pictureBox.CreateGraphics().GetHdc();
m_byColorBuffer = new byte[3 * m_nWidth * m_nHeigh];

用到的函数

/// <summary>
/// 初始化Bitmap文件头
/// </summary>
private void BitmapInfoInit()
{

    m_objBitmapInfo.bmiHeader.biSize = (uint)Marshal.SizeOf(typeof(CWin32Bitmaps.BITMAPINFOHEADER));
    m_objBitmapInfo.bmiHeader.biWidth = m_nWidth;
    m_objBitmapInfo.bmiHeader.biHeight = m_nHeigh;
    m_objBitmapInfo.bmiHeader.biPlanes = 1;
    m_objBitmapInfo.bmiHeader.biBitCount = 24;
    m_objBitmapInfo.bmiHeader.biCompression = 0;
    m_objBitmapInfo.bmiHeader.biSizeImage = 0;
    m_objBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
    m_objBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
    m_objBitmapInfo.bmiHeader.biClrUsed = 0;
    m_objBitmapInfo.bmiHeader.biClrImportant = 0;
    m_pBitmapInfo = Marshal.AllocHGlobal(2048);
}

最终结果1:使用StretchDIBits显示Bitmap图像

/// <summary>
/// 最终的画面显示函数
/// </summary>
/// <param name="_imgBmp"></param>
/// <param name="pictureBox"></param>
private void DispBitmap(Bitmap _imgBmp, Control pictureBox)
{
    BitmapData bmpData = _imgBmp.LockBits(new Rectangle(0, 0, _imgBmp.Width, _imgBmp.Height), ImageLockMode.ReadWrite, _imgBmp.PixelFormat);
    IntPtr pBufferColor = bmpData.Scan0;
    _imgBmp.UnlockBits(bmpData);
    m_pHDC = pictureBox.CreateGraphics().GetHdc();
    m_objBitmapInfo.bmiHeader.biWidth = _imgBmp.Width;
    m_objBitmapInfo.bmiHeader.biHeight = _imgBmp.Height;
    Marshal.StructureToPtr(m_objBitmapInfo, m_pBitmapInfo, false);
    Marshal.Copy(pBufferColor, m_byColorBuffer, 0, 3 * _imgBmp.Width * _imgBmp.Height);
    CWin32Bitmaps.SetStretchBltMode(m_pHDC, COLORONCOLOR);
    CWin32Bitmaps.StretchDIBits(
                m_pHDC,
                0,
                0,
                pictureBox.Width,
                pictureBox.Height,
                0,
                0,
                _imgBmp.Width,
                _imgBmp.Height,
                m_byColorBuffer,
                m_pBitmapInfo,
                DIB_RGB_COLORS,
                SRCCOPY);
}

最终结果2:使用StretchDIBits显示Mat表示的图像

private void DispMat(Mat mat, Control pictureBox)
{
    m_pHDC = pictureBox.CreateGraphics().GetHdc();
    m_objBitmapInfo.bmiHeader.biWidth = mat.Width;
    m_objBitmapInfo.bmiHeader.biHeight = mat.Height;
    Marshal.StructureToPtr(m_objBitmapInfo, m_pBitmapInfo, false);
    Marshal.Copy(mat.Data, m_byColorBuffer, 0, 3 * mat.Width * mat.Height);
    CWin32Bitmaps.SetStretchBltMode(m_pHDC, COLORONCOLOR);
    CWin32Bitmaps.StretchDIBits(
                m_pHDC,
                0,
                0,
                pictureBox.Width,
                pictureBox.Height,
                0,
                0,
                mat.Width,
                mat.Height,
                m_byColorBuffer,
                m_pBitmapInfo,
                DIB_RGB_COLORS,
                SRCCOPY);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值