在WPF中使用WriteableBitmap對(duì)接工業(yè)相機(jī)及常用操作
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
寫(xiě)作背景寫(xiě)這篇文章主要是因?yàn)楣I(yè)相機(jī)(???、大恒等)提供的.NET開(kāi)發(fā)文檔和示例程序都是用WinForm項(xiàng)目來(lái)說(shuō)明的,而在WPF項(xiàng)目中對(duì)圖像的使用和處理與在WinForm項(xiàng)目中有很大不同。在WinForm中用System.Drawing.Bitmap來(lái)處理圖像,而在WPF中是用System.Windows.Media.Imaging.WriteableBitmap來(lái)處理圖像的。 本文的主要內(nèi)容也是對(duì)WriteableBitmap類使用的介紹以及與使用Drawing.Bitmap的比較。 從相機(jī)中接收?qǐng)D像首先當(dāng)然要?jiǎng)?chuàng)建一個(gè)WriteableBitmap,這里以PixelFormats.Bgr24像素格式舉例說(shuō)明
雖然工業(yè)相機(jī)有多個(gè)品牌,但是獲取位圖像素?cái)?shù)據(jù)的方式基本有兩種: 1、代表位圖像素地址的IntPtr作為相機(jī)SDK方法的參數(shù),由SDK方法向該地址寫(xiě)入像素?cái)?shù)據(jù)。 2、相機(jī)SDK方法返回代表位圖像素地址的IntPtr。 針對(duì)第一種,將WBitmap.BackBuffer傳給SDK方法,BackBuffer代表的就是WriteableBitmap對(duì)象像素?cái)?shù)據(jù)的地址。 針對(duì)第二種,使用
WritePixels方法是專門用來(lái)修改一個(gè)矩形區(qū)域中像素?cái)?shù)據(jù)的方法,其中參數(shù)rect代表修改的區(qū)域,ppixel代表相機(jī)SDK方法返回的代表像素?cái)?shù)據(jù)的地址。 與Bitmap比較 在WinForm中使用Bitmap則有兩種方式接收?qǐng)D像。 針對(duì)第一種,使用Bitmap(int width, int height, PixelFormat format)創(chuàng)建Bitmap,然后調(diào)用LockBits方法獲得BitmapData對(duì)象,BitmapData的scan0屬性表示圖像像素?cái)?shù)據(jù)地址。 針對(duì)第二種,在創(chuàng)建Bitmap時(shí)使用Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0)構(gòu)造函數(shù),將ppixel作為scan0的值傳入。 圖像的顯示WriteableBitmap使用兩個(gè)緩沖區(qū),一個(gè)后端緩沖區(qū)和一個(gè)前端緩沖區(qū)(后端緩沖區(qū)用來(lái)處理圖像像素?cái)?shù)據(jù),前端緩沖區(qū)用來(lái)顯示圖像),所以一個(gè)WriteableBitmap對(duì)象存著圖像的兩份數(shù)據(jù)。 如果在【從相機(jī)中接收?qǐng)D像】中使用第一種方式創(chuàng)建WriteableBitmap,那么圖像數(shù)據(jù)存在后端緩沖區(qū)中(BackBuffer),而界面上Image控件顯示圖像用的是前端緩沖區(qū)中的圖像。 所以現(xiàn)在我們需要把后端緩沖區(qū)中的數(shù)據(jù)更新到前端緩沖區(qū)中去,然后傳給Image的Source屬性即可。
Lock鎖定后端緩沖區(qū),AddDirtyRect將后端緩沖區(qū)數(shù)據(jù)更新到前端緩沖區(qū),Unlock解鎖后端緩沖區(qū)。AddDirtyRect的使用模式是固定的,都是先Lock然后Unlock。 如果在前面【從相機(jī)中接收?qǐng)D像】使用的是方式二WritePixels方法,則在圖像顯示時(shí)只需要MyImage.Source = WBitmap即可,因?yàn)閃ritePixels的內(nèi)部已經(jīng)調(diào)用了AddDirtyRect方法。 與Bitmap比較 WinForm中使用PictureBox控件顯示圖像。使用方法是: Image showImage= Image.FromHbitmap(bitmap.GetHbitmap()); MyPictureBox.Image = showImage; 像素操作WriteableBitmap中的像素操作有兩種方式 1、使用像素地址 該方式涉及到代表像素地址的指針。在前面【從相機(jī)中接收?qǐng)D像】中方式一提到用一個(gè)指針地址去接受圖像, 所以圖像的所有像素?cái)?shù)據(jù)都保存在這個(gè)起始地址的內(nèi)存中,也就是后端緩沖區(qū)中。WBitmap.BackBuffer指向的就是坐標(biāo)(0,0)點(diǎn)的像素?cái)?shù)據(jù)。 下面以讀取(100,200)坐標(biāo)點(diǎn)的像素?cái)?shù)據(jù)舉例說(shuō)明,先介紹要用到的兩個(gè)屬性:WBitmap.BackBufferStride表示一行圖像數(shù)據(jù)的字節(jié)數(shù),WBitmap.Format.BitsPerPixel表示一個(gè)像素的位數(shù)。 首先計(jì)算(100,200)處的偏移量應(yīng)該是WBitmap.BackBufferStride*200 + WBitmap.Format.BitsPerPixel / 8*100,那么BackBuffer加上偏移量就是(100,200)處的地址 ,所以完整的讀取像素值的代碼如下:
或者使用System.Runtime.InteropServices.Marshal.ReadByte,不需要unsafe模式
像素修改也是同樣的方法,把讀取變成賦值即可,或者用Marshal.WriteByte寫(xiě)值。 2、使用WritePixels WritePixels方法適合修改一個(gè)特定矩形內(nèi)的像素。源像素?cái)?shù)據(jù)通常來(lái)自另一個(gè)已生成的圖像的數(shù)據(jù)。WritePixels方法接受IntPtr類型(數(shù)據(jù)地址)或byte[]類型(數(shù)據(jù)內(nèi)容)的值??蓞⒖记懊妗緩南鄼C(jī)中接收?qǐng)D像】的例子。 與Bitmap比較 使用Bitmap也有兩種方式操作像素。1:Bitmap提供GetPixel和SetPixel方法操作單個(gè)像素。2:調(diào)用LockBits方法獲得BitmapData對(duì)象,BitmapData對(duì)象的Scan0即像素?cái)?shù)據(jù)地址。 圖像的保存與Bitmap使用Save不同,WriteableBitmap需要使用Encoder編碼后才能保存成文件。
這里使用BmpBitmapEncoder編碼器來(lái)保存bmp圖像,要保存成其他格式則使用對(duì)應(yīng)的編碼器即可,如JpegBitmapEncoder等。 與Bitmap比較 調(diào)用Save方法即可。 注意事項(xiàng)1:工業(yè)相機(jī)的開(kāi)發(fā)也可以查看C/C++版本的開(kāi)發(fā)文檔,C#可以使用DllImport調(diào)用C/C++版SDK中的函數(shù)。 2:使用工業(yè)相機(jī)采圖一般都是使用回調(diào)函數(shù)的形式,所以在回調(diào)函數(shù)的多線程環(huán)境中要注意跨線程訪問(wèn)資源的問(wèn)題。 3:圖像保存用的是后端緩沖區(qū)中的數(shù)據(jù)(再次證明前端緩沖區(qū)只是用來(lái)在界面上展示的)。 作者:左眼水星 轉(zhuǎn)載請(qǐng)注明原文鏈接:https://www.cnblogs.com/yxllxy/p/18269391 該文章在 2024/9/7 10:45:58 編輯過(guò) |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |