問(wèn)題描述
我有 Basler acA3800 USB 相機(jī).
IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException);//圖片抓取成功?如果(grabResult.GrabSucceeded){byte[] buffer = grabResult.PixelData as byte[];ImageWindow.DisplayImage(0, grabResult);pictureBox1.Image = ImageFromRawBgraArray(buffer,3840,2748,PixelFormat.Format8bppIndexed);MessageBox.Show(grabResult.PixelTypeValue.ToString());}
此代碼部分顯示圖像自身窗口.
我有捕獲圖像的像素?cái)?shù)據(jù).原始圖像很好,但是當(dāng)我將其轉(zhuǎn)換為圖像時(shí),它已損壞.這是我的轉(zhuǎn)換函數(shù).
public Image ImageFromRawBgraArray(byte[] arr, int width, int height, PixelFormat pixelFormat){var output = new Bitmap(width, height, pixelFormat);var rect = new Rectangle(0, 0, width, height);var bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat);//逐行復(fù)制var arrRowLength = 寬度 * Image.GetPixelFormatSize(output.PixelFormat)/8;var ptr = bmpData.Scan0;for (var i = 0; i <高度; i++){Marshal.Copy(arr, i * arrRowLength, ptr, arrRowLength);ptr += bmpData.Stride;}輸出.UnlockBits(bmpData);返回輸出;}
我認(rèn)為這與像素類型有關(guān).我選擇了 PixelFormat.Format8bppIndexed 的像素格式.其他的不工作.
MessageBox.Show(grabResult.PixelTypeValue.ToString());
這個(gè)消息框給了我像素類型.上面寫(xiě)著B(niǎo)ayerBG8".這是什么意思?我應(yīng)該怎么做才能獲得清晰的圖像?
你得到的奇怪顏色是因?yàn)?Format8bppIndexed
是調(diào)色板,你從不編輯調(diào)色板,這意味著它保留了默認(rèn)生成的 Windows調(diào)色板.但在您的情況下,此調(diào)色板無(wú)關(guān)緊要,因?yàn)閳D像 不是 8 位索引格式;需要對(duì)其進(jìn)行處理以將其轉(zhuǎn)換為 RGB.
BayerBG8 的快速 google 找到了我介紹這些內(nèi)容的一般處理方式,但 .
請(qǐng)注意,上面的去馬賽克方法非常基本,并且會(huì)顯示 許多預(yù)期的工件.有更先進(jìn)的方法可以分析數(shù)據(jù)并根據(jù)圖像的拍攝方式獲得更準(zhǔn)確的結(jié)果,但您可能需要進(jìn)行大量研究才能弄清楚所有這些并自己實(shí)施.
這是我做的一個(gè)小測(cè)試,從 我在網(wǎng)上找到的經(jīng)過(guò)拜耳過(guò)濾的圖像(第一張圖像),我將其轉(zhuǎn)換為 8 位數(shù)組(此處顯示為灰度;第二張圖像).如您所見(jiàn),我自己的去馬賽克(第三張圖片)遠(yuǎn)不如他們從中得到的校正版本(第四張圖片)準(zhǔn)確,而且,值得注意的是,它小了一個(gè)像素,因此顯示為白色邊框.
(請(qǐng)注意,與上面的示例不同,此圖像以綠色像素開(kāi)頭,這意味著必須調(diào)整解碼參數(shù))
I have Basler acA3800 USB camera.
IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException);
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
byte[] buffer = grabResult.PixelData as byte[];
ImageWindow.DisplayImage(0, grabResult);
pictureBox1.Image = ImageFromRawBgraArray(buffer,3840,2748,PixelFormat.Format8bppIndexed);
MessageBox.Show(grabResult.PixelTypeValue.ToString());
}
This code section shows image self window.
I have pixel data of captured image. Original image is good but when I convert it to Image, it corrupt. And here is my conversion function.
public Image ImageFromRawBgraArray(byte[] arr, int width, int height, PixelFormat pixelFormat)
{
var output = new Bitmap(width, height, pixelFormat);
var rect = new Rectangle(0, 0, width, height);
var bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat);
// Row-by-row copy
var arrRowLength = width * Image.GetPixelFormatSize(output.PixelFormat) / 8;
var ptr = bmpData.Scan0;
for (var i = 0; i < height; i++)
{
Marshal.Copy(arr, i * arrRowLength, ptr, arrRowLength);
ptr += bmpData.Stride;
}
output.UnlockBits(bmpData);
return output;
}
I think it is about pixel type. I have selected pixel format of PixelFormat.Format8bppIndexed. The others is not working.
MessageBox.Show(grabResult.PixelTypeValue.ToString());
This messagebox gives me the pixeltype. and it says "BayerBG8". What does it mean? What should I do to get clear image?
The odd colours you are getting are because Format8bppIndexed
is paletted, and you never edit the palette, meaning it retains the default generated Windows palette. But in your case, this palette is irrelevant, because the image is not an 8-bit indexed format; it needs to be processed to convert it to RGB.
A quick google for BayerBG8 got me this page. The Bayer section there shows it's a rather peculiar transformation to use specifically patterned indices on the image as R, G and B.
Wikipedia has a whole article on how this stuff is generally processed, but this YouTube video shows the basics:
Note that this is a sliding window; for the first pixel, the colours are
R G G B
but for the second pixel, they'll be
G R B G
and for one row down, the first one will use
G B R G
You'll end up with an image that is one pixel less wide and high than the given dimensions, since the last pixel on each row and all pixels on the last row won't have the neighbouring data needed to get their full pixel data. There are apparently more advanced algorithms to get around that, but for this method I'll just go over the basic sliding window method.
public static Byte[] BayerToRgb(Byte[] arr, ref Int32 width, ref Int32 height, ref Int32 stride, Boolean greenFirst, Boolean blueRowFirst)
{
Int32 actualWidth = width - 1;
Int32 actualHeight = height - 1;
Int32 actualStride = actualWidth*3;
Byte[] result = new Byte[actualStride*actualHeight];
for (Int32 y = 0; y < actualHeight; y++)
{
Int32 curPtr = y*stride;
Int32 resPtr = y*actualStride;
Boolean blueRow = y % 2 == (blueRowFirst ? 0 : 1);
for (Int32 x = 0; x < actualWidth; x++)
{
// Get correct colour components from sliding window
Boolean isGreen = (x + y) % 2 == (greenFirst ? 0 : 1);
Byte cornerCol1 = isGreen ? arr[curPtr + 1] : arr[curPtr];
Byte cornerCol2 = isGreen ? arr[curPtr + stride] : arr[curPtr + stride + 1];
Byte greenCol1 = isGreen ? arr[curPtr] : arr[curPtr + 1];
Byte greenCol2 = isGreen ? arr[curPtr + stride + 1] : arr[curPtr + stride];
Byte blueCol = blueRow ? cornerCol1 : cornerCol2;
Byte redCol = blueRow ? cornerCol2 : cornerCol1;
// 24bpp RGB is saved as [B, G, R].
// Blue
result[resPtr + 0] = blueCol;
// Green
result[resPtr + 1] = (Byte) ((greenCol1 + greenCol2)/2);
// Red
result[resPtr + 2] = redCol;
curPtr++;
resPtr+=3;
}
}
height = actualHeight;
width = actualWidth;
stride = actualStride;
return result;
}
The parameters greenFirst
and blueRowFirst
indicate whether green is the first encountered pixel on the image, and whether the blue pixels are on the first or second row. For your "BG" format, both of these should be false.
From the result of this, with the adjusted width, height and stride, you can convert that to a new image using the method you already used, but with Format24bppRgb
as pixel format.
Personally I use a somewhat more advanced method that takes the input stride into account and can handle indexed content. If you're interested, that method can be found here.
Note that the demosaicing method above is very basic, and will show many of the expected artifacts. There are more advanced methods out there to analyse the data and get more accurate results based on how the image was taken, but it'll probably cost you quite some research to figure all that out and implement it yourself.
Here's a little test I did, starting from a Bayer-filtered image I found online (first image) which I converted to an 8-bit array (shown here as grayscale; second image). As you can see, my own demosaicing (third image) is far less accurate than the corrected version they got out of it (fourth image), and, notably, is one pixel smaller and thus shows a white border.
(Note that, unlike the examples above, this image starts with a green pixel, meaning the parameters to decode it had to be adjusted)
這篇關(guān)于Basler USB Camera字節(jié)緩沖區(qū)到圖像的轉(zhuǎn)換的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!