Baumer GAPI ve OpenCV
Yazılım örneği Baumer GAPI v2.9.0
Bu kılavuzda, Baumer GAPI çerçeve tamponlarından görüntüleri alıp, bunları daha fazla işleme için OpenCV’ye nasıl aktaracağınızı öğreneceksiniz.
Baumer kamerayı kurmak ve görüntüleri belleğe almak için Baumer GAPI SDK’sını kullanacağız. Daha sonra bellekteki görüntüleri OpenCV’ye aktararak sabit diske kaydedeceğiz. OpenCV’ye aktarıldıktan sonra, kütüphaneyi kullanarak görüntüleri ihtiyaçlarınıza göre daha fazla işleyebilirsiniz.
Görüntüleri Baumer GAPI’den OpenCV’ye aktarma
Baumer GAPI’de görüntü verilerini aldıktan sonra, bu veriler aşırı yüklenmiş yapıcı (constructor) kullanılarak bir OpenCV matrisi (Mat) ile ilişkilendirilebilir:
new cv::Mat::Mat(int _rows, int _cols, int _type, void * _data, size_t _step = 0Ui64);
new Emgu.CV.Mat.Mat(int rows, int cols, Emgu.CV.CvEnum.DepthType type,
int channels, IntPtr data, int step);
Baumer GAPI bellek arabelleğindeki veriler kopyalanmaz, bunun yerine bir işaretçi OpenCV matrisine geçirilir. OpenCV matrisi, ardından cv::imwrite() kullanılarak diske kaydedilebilir. Kaydettikten sonra, OpenCV matrisini silebilir veya yeniden kullanabilir ve Baumer GAPI belleğini yeniden sıraya alarak yeni bir görüntü yakalamak için kullanabilirsiniz.
Baumer GAPI arabelleğini OpenCV matrisine klonlama, kopyalama ve dönüştürme
Baumer GAPI Bellek verileriyle çalışmak için OpenCV’nin Clone(), Copy() veya ConvertTo() yöntemlerini kullanabilirsiniz. Kopyalama işleminden sonra, Baumer GAPI Belleği yeniden sıraya alınabilir ve kopyalanan veriler OpenCV kullanılarak daha fazla işlenebilir.
Dikkat edilmesi gereken nokta, OpenCV matrisinin genişlik, yükseklik ve tür (CV_8UC1, CV_8UC3, CV_16UC1, CV_16UC3) bilgilerini içerirken, Baumer GAPI belleğinin Buffer.FrameID, Buffer.PixelFormat, Buffer.XOffset, Buffer.YOffset gibi ek yararlı bilgiler yanı sıra parça (chunk) verileri de sağladığıdır. Gerekirse bu bilgileri de kopyalamanız gerekebilir.
pDevice->GetRemoteNode("PixelFormat")->SetString("Mono8");
BGAPI2::Buffer* pBufferFilled = pDataStream->GetFilledBuffer(1000);
if (pBufferFilled->GetPixelFormat() == "Mono8")
{
cv::Mat* imOriginal = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_8UC1,
(char *)pBufferFilled->GetMemPtr());
// 3 methods to copy
cv::Mat imClone = imOriginal->clone();
cv::Mat* imCopy = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_8UC1);
imOriginal->copyTo(*imCopy);
cv::Mat* imConvert = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_8UC1);
imOriginal->convertTo(*imConvert, CV_8UC1, 1.0);
delete imOriginal;
pBufferFilled->QueueBuffer();
// Use copied images
cv::imwrite("cv_image_Clone.png", imClone);
cv::imwrite("cv_image_Copy.png", *imCopy);
cv::imwrite("cv_image_Convert.png", *imConvert);
delete imCopy;
delete imConvert;
}
mDevice.RemoteNodeList["PixelFormat"].Value = "Mono8";
BGAPI2.Buffer mBufferFilled = mDataStream.GetFilledBuffer(1000);
if (mBufferFilled.PixelFormat == "Mono8")
{
Emgu.CV.Mat imOriginal = new Emgu.CV.Mat((int)mBufferFilled.Height,
(int)mBufferFilled.Width,
Emgu.CV.CvEnum.DepthType.Cv8U, 1,
(IntPtr)mBufferFilled.MemPtr,
(int)mBufferFilled.Width * 1);
// 3 methods to copy
Emgu.CV.Mat imClone = imOriginal.Clone();
Emgu.CV.Mat imCopy = new Emgu.CV.Mat((int)mBufferFilled.Height,
(int)mBufferFilled.Width,
Emgu.CV.CvEnum.DepthType.Cv8U, 1);
imOriginal.CopyTo(imCopy);
Emgu.CV.Mat imConvert = new Emgu.CV.Mat((int)mBufferFilled.Height,
(int)mBufferFilled.Width,
Emgu.CV.CvEnum.DepthType.Cv8U, 1);
imOriginal.ConvertTo(imConvert, Emgu.CV.CvEnum.DepthType.Cv8U, 1.0);
mBufferFilled.QueueBuffer();
// Use copied image
Emgu.CV.CvInvoke.Imwrite("cv_image_Clone.png", imClone);
Emgu.CV.CvInvoke.Imwrite("cv_image_Copy.png", imCopy);
Emgu.CV.CvInvoke.Imwrite("cv_image_Convert.png", imConvert);
}
PixelFormat’ları Anlama
Baumer kameralar, Mono8, Mono12, BGR8 gibi çeşitli PixelFormat’ları destekler ve bunların, ilgili OpenCV formatlarıyla eşleştirilmesi gerekir. Aşağıdaki tabloda, eşleşen OpenCV Matris Türlerini görebilirsiniz.
| Baumer formatı | OpenCV formatı |
|---|---|
| Mono8 | CV_8UC1, (8 bit, 1 kanal) |
| Mono10 | Mono16’ya dönüştür (bit-kaydırma) |
| Mono12 | Mono16’ya dönüştür (bit-kaydırma) |
| Mono16 | CV_16UC1, (16 bit, 1 kanal) |
| BGR8 | CV_8UC3, (8 bit, 3 kanal) |
| BGR10 | BGR16’ya dönüştür (bit-kaydırma) |
| BGR12 | BGR16’ya dönüştür (bit-kaydırma) |
| BGR16 | CV_16UC3, (16 bit, 3 kanal (BGR)) |
| RGB8 | cv::cvtColor kullanarak BGR8’e dönüştür |
| RGB10 | BGR16’ya bit-kaydırma ve cv::cvtColor ile dönüştür |
| RGB12 | BGR16’ya bit-kaydırma ve cv::cvtColor ile dönüştür |
| RGB16 | cv::cvtColor kullanarak BGR16’ya dönüştür |
| BayerGB8, BayerRG8, BayerGR8, BayerBG8 | cv::cvtColor kullanarak BGR8’e dönüştür |
| BayerGB10, BayerRG10, BayerGR10, BayerBG10 | BGR16’ya bit-kaydırma ve cv::cvtColor ile dönüştür |
| BayerGB12, BayerRG12, BayerGR12, BayerBG12 | BGR16’ya bit-kaydırma ve cv::cvtColor ile dönüştür |
Dönüşüm gerektirmeyen PixelFormat’lardaki görüntülerle çalışmak oldukça basittir, aşağıdaki örneklerde bunu görebilirsiniz.
Örnek: Mono8
pDevice->GetRemoteNode("PixelFormat")->SetString("Mono8");
BGAPI2::Buffer * pBufferFilled = pDataStream->GetFilledBuffer(1000);
if (pBufferFilled->GetPixelFormat() == "Mono8")
{
cv::Mat* imOriginal = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_8UC1,
(char *)pBufferFilled->GetMemPtr();
cv::imwrite("cv_Mono8_image.png", *imOriginal);
delete imOriginal;
}
pBufferFilled->QueueBuffer();
mDevice.RemoteNodeList["PixelFormat"].Value = "Mono8";
BGAPI2.Buffer mBufferFilled = mDataStream.GetFilledBuffer(1000);
if (mBufferFilled.PixelFormat == "Mono8")
{
Emgu.CV.Mat imOriginal = new Emgu.CV.Mat((int)mBufferFilled.Height,
(int)mBufferFilled.Width,
Emgu.CV.CvEnum.DepthType.Cv8U, 1,
(IntPtr)mBufferFilled.MemPtr,
(int)mBufferFilled.Width * 1);
Emgu.CV.CvInvoke.Imwrite("cv_Mono8_image.png", imOriginal);
}
mBufferFilled.QueueBuffer();
Örnek: BGR8
OpenCV’deki standart renkli PixelFormat, her renk kanalı için 8 bit olan BGR formatıdır (CV_8UC3). Kamerada bu formata uyması için PixelFormat’i BGR8 olarak ayarlayabilirsiniz (BGR8Packed de kullanılabilir).
pDevice->GetRemoteNode("PixelFormat")->SetString("BGR8");
BGAPI2::Buffer * pBufferFilled = pDataStream->GetFilledBuffer(1000);
if ((pBufferFilled->GetPixelFormat() == "BGR8") ||
(pBufferFilled->GetPixelFormat() == "BGR8Packed"))
{
cv::Mat* imOriginal = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_8UC3,
(char *)pBufferFilled->GetMemPtr());
cv::imwrite("cv_BGR8_image.png", *imOriginal);
delete imOriginal;
}
pBufferFilled->QueueBuffer();
mDevice.RemoteNodeList["PixelFormat"].Value = "BGR8";
BGAPI2.Buffer mBufferFilled = mDataStream.GetFilledBuffer(1000);
if ((mBufferFilled.PixelFormat == "BGR8") ||
(mBufferFilled.PixelFormat == "BGR8Packed"))
{
Emgu.CV.Mat imOriginal = new Emgu.CV.Mat((int)mBufferFilled.Height,
(int)mBufferFilled.Width,
Emgu.CV.CvEnum.DepthType.Cv8U,
3,
(IntPtr)mBufferFilled.MemPtr,
(int)mBufferFilled.Width * 3);
Emgu.CV.CvInvoke.Imwrite("cv_BGR8_image.png", imOriginal);
}
mBufferFilled.QueueBuffer();
PixelFormat’ları 16 Bit OpenCV Matris Tipine Dönüştürme
Bazı kameralar 12 bit (Mono12, RGB12) gibi PixelFormat’ları destekler. Bu verileri 16 bit OpenCV Matris Tipinde saklamak, beklenenden çok daha karanlık bir çıktı-görüntüsüne yol açabilir. 12 bit PixelFormat’ları 16 bit OpenCV Matris Tipine eşlemek için, Baumer GAPI bellek verilerinin 4 bit kaydırılması (16 ile çarpılması) gerekir. Bu işlem OpenCV ConvertTo() komutu kullanılarak yapılabilir.
Benzer şekilde, 10 bit PixelFormat’ları (örneğin Mono10), verileri 2 bit kaydırarak veya 64 ile çarparak dönüştürülebilir.
Uyarı: Baumer GAPI bellek verilerine doğrudan bir işaretçi geçirildiği için, orijinal veri değiştirilir.
pDevice->GetRemoteNode("PixelFormat")->SetString("Mono12");
BGAPI2::Buffer * pBufferFilled = pDataStream->GetFilledBuffer(1000);
if (pBufferFilled->GetPixelFormat() == "Mono12")
{
cv::Mat* imOriginal = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_16UC1,
(char *)pBufferFilled->GetMemPtr());
imOriginal.ConvertTo(imOriginal, Emgu.CV.CvEnum.DepthType.Cv16U, 64.0);
cv::imwrite("cv_Mono12_as_Mono16_image.png", *imOriginal);
delete imOriginal;
}
pBufferFilled->QueueBuffer();
mDevice.RemoteNodeList["PixelFormat"].Value = "Mono12";
BGAPI2.Buffer mBufferFilled = mDataStream.GetFilledBuffer(1000);
if (mBufferFilled.PixelFormat == "Mono12")
{
Emgu.CV.Mat imOriginal = new Emgu.CV.Mat((int)mBufferFilled.Height,
(int)mBufferFilled.Width,
Emgu.CV.CvEnum.DepthType.Cv16U,
1,
(IntPtr)mBufferFilled.MemPtr,
(int)mBufferFilled.Width * 2);
imOriginal.ConvertTo(imOriginal, Emgu.CV.CvEnum.DepthType.Cv16U, 16.0);
Emgu.CV.CvInvoke.Imwrite("cv_Mono12_as_Mono16_image.png", imOriginal);
}
mBufferFilled.QueueBuffer();
Bayer PixelFormat’ları ile Çalışma

Bayer deseni, CCD ve CMOS kameralarında yaygın olarak kullanılır. Bu desen, R, G ve B piksellerinin (belirli bir bileşenin sensörleri) aşağıdaki resimde gösterildiği gibi birbirine geçecek şekilde tek bir düzlemden renkli görüntüler elde etmenizi sağlar.
Bir pikselin çıkış RGB bileşenleri, aynı renge sahip 1, 2 veya 4 komşu pikselden enterpolasyon yoluyla elde edilir. Yukarıdaki desenin, deseni bir piksel sola ve/veya bir piksel yukarı kaydırarak elde edilebilecek birkaç modifikasyonu vardır. CV_Bayer C1C2 2BGR ve CV_Bayer C1C2 2RGB dönüşüm sabitlerindeki iki harf C1 ve C2, belirli desen türünü gösterir. Bunlar sırasıyla ikinci satırdaki ikinci ve üçüncü sütunlardaki bileşenlerdir. Örneğin, yukarıdaki desen çok popüler bir “BG” türüne sahiptir.
OpenCV’de ‘cvtColor’ Kullanarak Renk Dönüşümü
Renkli kameralar, BayerBG8, BayerGB8, BayerGR8 ve BayerRG8 gibi ham PixelFormat’ları içerir. Bu formatların, daha fazla görüntü işleme için BGR8 formatına dönüştürülmesi gereklidir.
Baumer kameraları, Bayer desenlerini görüntünün ilk satırındaki ilk iki piksele göre adlandırır. Buna karşılık, OpenCV adlandırması, görüntünün ikinci satırındaki ikinci ve üçüncü piksele bağlıdır, bu da farklı bir adlandırmaya yol açar:
- Baumer BayerGB OpenCV’de BayerGR ile eşleşir.
- Baumer BayerRG OpenCV’de BayerBG ile eşleşir.
- Baumer BayerGR OpenCV’de BayerGB ile eşleşir.
- Baumer BayerBG OpenCV’de BayerRG ile eşleşir.
pDevice->GetRemoteNode("PixelFormat")->SetString("BayerRG8");
BGAPI2::Buffer * pBufferFilled = pDataStream->GetFilledBuffer(1000);
if (pBufferFilled->GetPixelFormat() == "BayerRG8")
{
cv::Mat* imOriginal = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_8UC1,
(char *)pBufferFilled->GetMemPtr());
cv::Mat* imTransformBGR8 = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_8UC3);
//Baumer: RGrgrg >> OpenCV: rgrgrg
// gbgbgb gBGbgb
cv::cvtColor(*imOriginal, *imTransformBGR8, CV_BayerBG2BGR); //to BGR
delete imOriginal;
pBufferFilled->QueueBuffer();
cv::imwrite("cv_BayerRG8_as_BGR8_image.png", *imTransformBGR8);
delete imTransformBGR8;
}
mDevice.RemoteNodeList["PixelFormat"].Value = "BayerRG8";
BGAPI2.Buffer mBufferFilled = mDataStream.GetFilledBuffer(1000);
if (mBufferFilled.PixelFormat == "BayerRG8")
{
Emgu.CV.Mat imOriginal = new Emgu.CV.Mat((int)mBufferFilled.Height,
(int)mBufferFilled.Width,
Emgu.CV.CvEnum.DepthType.Cv8U, 1,
(IntPtr)mBufferFilled.MemPtr,
(int)mBufferFilled.Width * 1);
Emgu.CV.Mat imTransformBGR8 = new Emgu.CV.Mat();
//Baumer: RGrgrg >> OpenCV: rgrgrg
// gbgbgb gBGbgb
Emgu.CV.CvInvoke.CvtColor(imOriginal, imTransformBGR8,
Emgu.CV.CvEnum.ColorConversion.BayerBg2Bgr);
mBufferFilled.QueueBuffer();
Emgu.CV.CvInvoke.Imwrite("cv_BGR8_image.png", imTransformBGR8);
}
Bayer’den BGR16’ya Dönüşüm
Bazı ham PixelFormat’lar, Bayer görüntüsünde daha fazla bit kullanır, örneğin BayerBG12, BayerGB12, BayerGR12 ve BayerRG12. Bu ham verilerin önce 12 bitten 16 bite dönüştürülmesi gerekir. Ardından, 16 bit değer cvtColor kullanılarak 48 bit formatında (her renk kanalı için 16 bit) BGR16’ya dönüştürülebilir.
10 bit formatlar (örneğin, BayerBG10, BayerGB10, BayerGR10 veya BayerRG10) için ise bunları 16 bit Bayer formatına dönüştürmek amacıyla 16.0 yerine 64.0’lık bir ölçekleme faktörü kullanmalısınız.
pDevice->GetRemoteNode("PixelFormat")->SetString("BayerGB12");
BGAPI2::Buffer * pBufferFilled = pDataStream->GetFilledBuffer(1000);
if (pBufferFilled->GetPixelFormat() == "BayerGB12")
{
cv::Mat* imOriginal = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_16UC1,
(char *)pBufferFilled->GetMemPtr());
cv::Mat* imConvert = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_16UC1);
//convert with scaling of 16.0 to convert 12-Bit to 16-Bit
imOriginal->convertTo(*imConvert, CV_16UC1, 16.0);
delete imOriginal;
pBufferFilled->QueueBuffer();
cv::Mat* imTransformBGR16 = new cv::Mat((int)pBufferFilled->GetHeight(),
(int)pBufferFilled->GetWidth(),
CV_16UC3);
//Baumer: GBgbgb >> OpenCV: gbgbgb
// rgrgrg rGRgrg
cv::cvtColor(*imConvert, *imTransformBGR16, CV_BayerGR2BGR); //to BGR
delete imConvert;
cv::imwrite("cv_BayerGB12_as_BGR16_image.png", *imTransformBGR16);
delete imTransformBGR16;
}
mDevice.RemoteNodeList["PixelFormat"].Value = "BayerGB12";
BGAPI2.Buffer mBufferFilled = mDataStream.GetFilledBuffer(1000);
if (mBufferFilled.PixelFormat == "BayerGB12")
{
Emgu.CV.Mat imOriginal = new Emgu.CV.Mat((int)mBufferFilled.Height,
(int)mBufferFilled.Width,
Emgu.CV.CvEnum.DepthType.Cv16U, 1,
(IntPtr)mBufferFilled.MemPtr,
(int)mBufferFilled.Width * 2);
Emgu.CV.Mat imConvert = new Emgu.CV.Mat((int)mBufferFilled.Height,
(int)mBufferFilled.Width,
Emgu.CV.CvEnum.DepthType.Cv16U, 1);
//convert with scaling of 16.0 to convert 12-Bit to 16-Bit
imOriginal.ConvertTo(imConvert, Emgu.CV.CvEnum.DepthType.Cv16U, 16.0);
mBufferFilled.QueueBuffer();
Emgu.CV.Mat imTransformBGR16 = new Emgu.CV.Mat();
//Baumer: GBgbgb >> OpenCV: gbgbgb
// rgrgrg rGRgrg
Emgu.CV.CvInvoke.CvtColor(imConvert, imTransformBGR16,
Emgu.CV.CvEnum.ColorConversion.BayerGr2Bgr);
Emgu.CV.CvInvoke.Imwrite("cv_BayerGB12_as_BGR16_image.png", imTransformBGR16);
}
İndirmeler
Yazılım Örnekleri
Baumer GAPI ve OpenCV