目錄
- 前言
- 圖像轉換
- 1.相機取流轉VM對應類型圖像格式
- 1.1 相機采圖轉流程輸入(IoImage)、Group輸入(IoImage)
- 1.2 相機采圖轉圖像源SDK輸入(ImageBaseData)、子產品輸入(ImageBaseData)
- 1.3 相機采圖轉算子輸入(IMvdImage)
- 2.QImage取圖與VM對應圖像格式互轉
- 2.1 QImage轉流程輸入(IoImage)、Group輸入(IoImage)
- 2.2 QImage轉圖像源SDK輸入(ImageBaseData)、子產品輸入(ImageBaseData)
- 2.3 Qimage與算子圖像(IMvdImage)互轉
- 2.4 流程輸出(IoImage)轉QImage
- 3.Mat取圖與VM對應圖像格式互轉
- 3.1 Mat轉流程輸入(IoImage)、Group輸入(IoImage)
- 3.2 Mat轉圖像源SDK輸入(ImageBaseData)、子產品輸出(ImageBaseData)
- 3.3 Mat與算子圖像(IMvdImage)互轉
- 3.4 流程輸出(IoImage)轉Mat
- 4.Halcon與VM圖像格式互轉
- 4.1 Halcon圖像轉流程輸入(IoImage)、Group輸入(IoImage)
- 4.2 Halcon圖像轉圖像源SDK輸入(ImageBaseData)、子產品輸入(ImageBaseData)
- 4.3 Halcon圖像與算子圖像(IMvdImage)互轉
- 4.4 流程輸出(IoImage)轉Halcon圖像
- 5.流程圖像與算子圖像
- 5.1 流程圖像轉算子圖像
- 5.2 算子圖像轉流程圖像
- 6.算法子產品圖像與Mat、Halcon、算子圖像互轉的方法(C++)
- 6.1 HKA_IMAGE與Mat互轉
- 6.2 HKA_IMAGE與Halcon圖像互轉
- 6.3 HKA_IMAGE與算子圖像(CmvdImage)互轉
- 總結
前言
目前VM提供了VM算法平台、VM SDK開發、算子SDK開發和算子子產品開發四種開發模式兼顧各種開發族群。如何實作圖像的正确輸入是開發者在使用通用算法庫時經常遇到的首要問題,目前市面上又存在多種圖像格式,如Bitmap、Mat和Halcon中的圖像類型等,而VM這麼多種開發模式又分别有不同的圖像格式,本文将介紹如何實作這些圖像類型之間的互轉。本文是C++語言的示例代碼,C#語言示例代碼請參考上一篇文章。
注:本文章僅限VM4.2版本;
VM中對應的圖像類型如下:
- 相機:圖像資料流(此處圖像資料流類型是MyCamera.MV_FRAME_OUT,是來自MvCameraControl.Net.dll,即海康機器人工業相機SDK,在MVS SDK和算子SDK中都有這個dll;算子SDK的MVDCamera.Net.dll也可以進行相機取流,它是對MvCameraControl.Net.dll的二次封裝,用MVDCamera.Net.dll時,圖像資料流類型是IMvdImage);
- VM:腳本輸入圖像(圖像類型是ImageData);
- VM SDK:流程輸入圖像(IoImage)、Group輸入圖像(IoImage)、圖像源SDK輸入圖像(ImageBaseData)、子產品輸入圖像(ImageBaseData);
- 算子SDK:輸入圖像(IMvdImage);
- 算法子產品:輸入圖像(HKA_IMAGE)。
需要注意的是, 三通道圖像類型轉換時,Bitmap、Mat為BGR,VM和二次開發為RGB。
下面針對常用圖像轉換場景,提供對應的圖像轉換示例供大家參考(每種圖像轉換用函數表達,函數輸入某種圖像類型,傳回轉換後的某種圖像類型)。
圖像轉換
1.相機取流轉VM對應類型圖像格式
相機截取幀格式為MyCamera.MV_FRAME_OUT,以下為分别轉換為流程輸入圖像、Group輸入圖像、圖像源SDK輸入圖像、子產品輸入圖像、算子輸入圖像的示例代碼。
1.1 相機采圖轉流程輸入(IoImage)、Group輸入(IoImage)
//圖像轉換函數
IoImage MV_FRAME_OUTToProcedureIoImage(MV_FRAME_OUT stImageInfo)
{
// TODO: 在此處添加實作代碼.
IoImage ioImage{};
unsigned char* m_pSaveImageBuf = NULL;//建議在頭檔案聲明,控制釋放時機防止記憶體洩漏,寫在此處為了友善參考
m_pSaveImageBuf = (unsigned char*)malloc(sizeof(unsigned char) * stImageInfo.stFrameInfo.nFrameLen);
memcpy(m_pSaveImageBuf, stImageInfo.pBufAddr, stImageInfo.stFrameInfo.nFrameLen);
ioImage.stImage.Width = stImageInfo.stFrameInfo.nWidth;
ioImage.stImage.Height = stImageInfo.stFrameInfo.nHeight;
ioImage.stImage.DataLen = stImageInfo.stFrameInfo.nFrameLen;
ioImage.stImage.ImageData = m_pSaveImageBuf;
if (stImageInfo.stFrameInfo.enPixelType == PixelType_Gvsp_Mono8)
{
ioImage.stImage.Pixelformat = MvdPixelFormat::MVD_PIXEL_MONO_08;
}
else if (stImageInfo.stFrameInfo.enPixelType == PixelType_Gvsp_RGB8_Packed)
{
ioImage.stImage.Pixelformat = MvdPixelFormat::MVD_PIXEL_RGB_RGB24_C3;
}
return ioImage;
}
1.2 相機采圖轉圖像源SDK輸入(ImageBaseData)、子產品輸入(ImageBaseData)
//圖像轉換函數
ImageBaseData MV_FRAME_OUTToImageBaseData(MV_FRAME_OUT stImageInfo)
{
// TODO: 在此處添加實作代碼.
ImageBaseData imageBaseData{};
unsigned char* m_pSaveImageBuf = NULL;//建議在頭檔案聲明,控制釋放時機防止記憶體洩漏,寫在此處為了友善參考
m_pSaveImageBuf = (unsigned char*)malloc(sizeof(unsigned char) * stImageInfo.stFrameInfo.nFrameLen);
memcpy(m_pSaveImageBuf, stImageInfo.pBufAddr, stImageInfo.stFrameInfo.nFrameLen);
imageBaseData.Width = stImageInfo.stFrameInfo.nWidth;
imageBaseData.Height = stImageInfo.stFrameInfo.nHeight;
imageBaseData.DataLen = stImageInfo.stFrameInfo.nFrameLen;
imageBaseData.ImageData = m_pSaveImageBuf;
if (stImageInfo.stFrameInfo.enPixelType == PixelType_Gvsp_Mono8)
{
imageBaseData.Pixelformat = MvdPixelFormat::MVD_PIXEL_MONO_08;
}
else if (stImageInfo.stFrameInfo.enPixelType == PixelType_Gvsp_RGB8_Packed)
{
imageBaseData.Pixelformat = MvdPixelFormat::MVD_PIXEL_RGB_RGB24_C3;
}
return imageBaseData;
}
1.3 相機采圖轉算子輸入(IMvdImage)
//圖像轉換函數
IMvdImage* MV_FRAME_OUTToIMvdImage(MV_FRAME_OUT stImageInfo)
{
// TODO: 在此處添加實作代碼.
IMvdImage* iMvdImage = NULL;
unsigned char* m_pSaveImageBuf = NULL;//建議在頭檔案聲明,控制釋放時機防止記憶體洩漏,寫在此處為了友善參考
m_pSaveImageBuf = (unsigned char*)malloc(sizeof(unsigned char) * stImageInfo.stFrameInfo.nFrameLen);
memcpy(m_pSaveImageBuf, stImageInfo.pBufAddr, stImageInfo.stFrameInfo.nFrameLen);
MVD_IMAGE_DATA_INFO stImageData{ };
if (stImageInfo.stFrameInfo.enPixelType == PixelType_Gvsp_Mono8)
{
stImageData.stDataChannel[0].nRowStep = stImageInfo.stFrameInfo.nWidth;
stImageData.stDataChannel[0].nLen = stImageInfo.stFrameInfo.nFrameLen;
stImageData.stDataChannel[0].nSize = stImageInfo.stFrameInfo.nFrameLen;
stImageData.stDataChannel[0].pData = m_pSaveImageBuf;
iMvdImage->InitImage(stImageInfo.stFrameInfo.nWidth, stImageInfo.stFrameInfo.nHeight, VisionDesigner::_MVD_PIXEL_FORMAT_::MVD_PIXEL_MONO_08, stImageData);
}
else if (stImageInfo.stFrameInfo.enPixelType == PixelType_Gvsp_RGB8_Packed)
{
stImageData.stDataChannel[0].nRowStep = stImageInfo.stFrameInfo.nWidth*3;
stImageData.stDataChannel[0].nLen = stImageInfo.stFrameInfo.nFrameLen;
stImageData.stDataChannel[0].nSize = stImageInfo.stFrameInfo.nFrameLen;
stImageData.stDataChannel[0].pData = m_pSaveImageBuf;
iMvdImage->InitImage(stImageInfo.stFrameInfo.nWidth, stImageInfo.stFrameInfo.nHeight, VisionDesigner::_MVD_PIXEL_FORMAT_::MVD_PIXEL_BGR_BGR24_C3, stImageData);
}
return iMvdImage;
}
2.QImage取圖與VM對應圖像格式互轉
QImage轉流程輸入、Group輸入、圖像源SDK輸入、子產品輸入、算子輸入、流程輸出圖像互相轉換的示例代碼如下所示。
2.1 QImage轉流程輸入(IoImage)、Group輸入(IoImage)
IoImage QImageToIoImage(QImage qImage)
{
QString strReMsg = "";
IoImage ioImage;
switch (qImage.format())
{
case QImage::Format_Indexed8:
ioImage.stImage.Width=qImage.width();
ioImage.stImage.Height=qImage.height();
ioImage.stImage.DataLen=qImage.sizeInBytes();
ioImage.stImage.Pixelformat=_MvdPixelFormat_::MVD_PIXEL_MONO_08;
ioImage.stImage.ImageData=(void *)qImage.constBits();
//ioImage.stImage.ImageData=qImage.data_ptr();
//QImage(ioImage.stImage.ImageData,ioImage.stImage.Width,ioImage.stImage.Width,QImage::Format_RGB888);
break;
case QImage::Format_RGB888:
ioImage.stImage.Width=qImage.width();
ioImage.stImage.Height=qImage.height();
ioImage.stImage.DataLen=qImage.sizeInBytes();
ioImage.stImage.Pixelformat=_MvdPixelFormat_::MVD_PIXEL_RGB_RGB24_C3;
ioImage.stImage.ImageData=(void *)qImage.constBits();
break;
}
strReMsg = "QImageToIoImage s uccess.";
ui->textEdit->append(strReMsg);
return ioImage;
}
2.2 QImage轉圖像源SDK輸入(ImageBaseData)、子產品輸入(ImageBaseData)
ImageBaseData QImageToImageBaseData(QImage qImage)
{
ImageBaseData imageBaseData;
switch (qImage.format())
{
case QImage::Format_Indexed8:
imageBaseData.Width=qImage.width();
imageBaseData.Height=qImage.height();
imageBaseData.DataLen=qImage.sizeInBytes();
imageBaseData.Pixelformat=_MvdPixelFormat_::MVD_PIXEL_MONO_08;
imageBaseData.ImageData=(void *)qImage.constBits();
//ioImage.stImage.ImageData=qImage.data_ptr();
break;
case QImage::Format_RGB888:
imageBaseData.Width=qImage.width();
imageBaseData.Height=qImage.height();
imageBaseData.DataLen=qImage.sizeInBytes();
imageBaseData.Pixelformat=_MvdPixelFormat_::MVD_PIXEL_RGB_RGB24_C3;
imageBaseData.ImageData=(void *)qImage.constBits();
break;
}
return imageBaseData;
}
2.3 Qimage與算子圖像(IMvdImage)互轉
IMvdImage* QImageToIMvdImage(QImage qImage)
{
IMvdImage* iMvdImage;
CreateImageInstance(&iMvdImage);
MVD_IMAGE_DATA_INFO stImageData;
switch (qImage.format())
{
case QImage::Format_Indexed8:
stImageData.stDataChannel[0].nRowStep = qImage.width();
stImageData.stDataChannel[0].nLen = qImage.sizeInBytes();
stImageData.stDataChannel[0].nSize = qImage.sizeInBytes();
stImageData.stDataChannel[0].pData = (unsigned char*)qImage.constBits();
iMvdImage->InitImage(qImage.width(), qImage.height(),MVD_PIXEL_FORMAT::MVD_PIXEL_MONO_08, stImageData);
break;
case QImage::Format_RGB888:
stImageData.stDataChannel[0].nRowStep = qImage.width()*3;
stImageData.stDataChannel[0].nLen = qImage.sizeInBytes();
stImageData.stDataChannel[0].nSize = qImage.sizeInBytes();
stImageData.stDataChannel[0].pData = (unsigned char*)qImage.constBits();
iMvdImage->InitImage(qImage.width(), qImage.height(),MVD_PIXEL_FORMAT::MVD_PIXEL_RGB_RGB24_C3, stImageData);
break;
}
return iMvdImage;
}
//算子轉QImage
QImage IMvdImageToQImage(IMvdImage * iMvdImage)
{
if(iMvdImage->GetPixelFormat() == MVD_PIXEL_FORMAT::MVD_PIXEL_MONO_08)
{
//QImage qImage((const uchar*)iMvdImage->GetImageData(0)->pData,iMvdImage->GetWidth(),iMvdImage->GetHeight(),iMvdImage->GetImageData(0)->nLen/iMvdImage->GetHeight(),QImage::Format_Indexed8);
//QImage qImage(iMvdImage->GetImageData(0)->pData,iMvdImage->GetWidth(),iMvdImage->GetHeight(),iMvdImage->GetImageData(0)->nLen/iMvdImage->GetHeight(),QImage::Format_Indexed8);
QImage qImage((const uchar*)iMvdImage->GetImageData(0)->pData,iMvdImage->GetWidth(),iMvdImage->GetHeight(),QImage::Format_Grayscale8);//Format_Indexed8
return qImage;
}
if(iMvdImage->GetPixelFormat() == MVD_PIXEL_FORMAT::MVD_PIXEL_RGB_RGB24_C3)
{
QImage qImage((const uchar*)iMvdImage->GetImageData(0)->pData,iMvdImage->GetWidth(),iMvdImage->GetHeight(),QImage::Format_RGB888);
return qImage;
}
}
2.4 流程輸出(IoImage)轉QImage
QImage IoImageToQImage(IoImage inIoImage)
{
if(inIoImage.stImage.Pixelformat == _MvdPixelFormat_::MVD_PIXEL_MONO_08)
{
QImage qImage((const uchar*)inIoImage.stImage.ImageData,inIoImage.stImage.Width,inIoImage.stImage.Height,QImage::Format_Grayscale8);
return qImage;
}
if(inIoImage.stImage.Pixelformat == _MvdPixelFormat_::MVD_PIXEL_RGB_RGB24_C3)
{
QImage qImage((const uchar*)inIoImage.stImage.ImageData,inIoImage.stImage.Width,inIoImage.stImage.Height,QImage::Format_RGB888);
return qImage;
}
}
3.Mat取圖與VM對應圖像格式互轉
Mat與流程輸入、Group輸入、圖像源SDK輸入、子產品輸入、算子輸入、算子輸出、流程輸出、腳本圖像互轉代碼示例如下:
3.1 Mat轉流程輸入(IoImage)、Group輸入(IoImage)
IoImage MatToProcedureInputImage(Mat matInputImg)
{
if (matInputImg.empty())
{
throw IMVDException(MVD_MODUL_APP, MVD_E_PARAMETER_ILLEGAL);
}
if ((CV_8UC1 != matInputImg.type()) && (CV_8UC3 != matInputImg.type()))
{
throw IMVDException(MVD_MODUL_APP, MVD_E_SUPPORT);
}
IoImage m_pIoImage{};
uint dataLen = (uint)(matInputImg.cols * matInputImg.rows * matInputImg.channels());
CString strReMsg = _T("");
try
{
if (CV_8UC1 == matInputImg.type())
{
m_pIoImage.stImage.Width = matInputImg.cols;
m_pIoImage.stImage.Width = matInputImg.cols;
m_pIoImage.stImage.Height = matInputImg.rows;
m_pIoImage.stImage.DataLen = dataLen;
m_pIoImage.stImage.Pixelformat = _MvdPixelFormat_::MVD_PIXEL_MONO_08;
m_pIoImage.stImage.ImageData = matInputImg.ptr(0);
}
else if (CV_8UC3 == matInputImg.type())
{
cv::cvtColor(matInputImg, matInputImg, CV_BGR2RGB);
m_pIoImage.stImage.Width = matInputImg.cols;
m_pIoImage.stImage.Height = matInputImg.rows;
m_pIoImage.stImage.DataLen = dataLen;
m_pIoImage.stImage.Pixelformat = _MvdPixelFormat_::MVD_PIXEL_RGB_RGB24_C3;
m_pIoImage.stImage.ImageData = matInputImg.ptr(0);
}
}
catch (CVmException e)
{
strReMsg.Format(_T("%x"), e.GetErrorCode());
strReMsg = _T("0x") + strReMsg + _T(" == SaveProcedureToFile()");
}
return m_pIoImage;
}
3.2 Mat轉圖像源SDK輸入(ImageBaseData)、子產品輸出(ImageBaseData)
ImageBaseData MatToImageBaseData(Mat matInputImg)
{
if (matInputImg.empty())
{
throw IMVDException(MVD_MODUL_APP, MVD_E_PARAMETER_ILLEGAL);
}
if ((CV_8UC1 != matInputImg.type()) && (CV_8UC3 != matInputImg.type()))
{
throw IMVDException(MVD_MODUL_APP, MVD_E_SUPPORT);
}
ImageBaseData m_pImageBaseData{};
uint dataLen = (uint)(matInputImg.cols * matInputImg.rows * matInputImg.channels());
CString strReMsg = _T("");
try
{
if (CV_8UC1 == matInputImg.type())
{
m_pImageBaseData.Width = matInputImg.cols;
m_pImageBaseData.Height = matInputImg.rows;
m_pImageBaseData.DataLen = dataLen;
m_pImageBaseData.Pixelformat = _MvdPixelFormat_::MVD_PIXEL_MONO_08;
m_pImageBaseData.ImageData = matInputImg.ptr(0);
}
else if (CV_8UC3 == matInputImg.type())
{
cv::cvtColor(matInputImg, matInputImg, CV_BGR2RGB);
m_pImageBaseData.Width = matInputImg.cols;
m_pImageBaseData.Height = matInputImg.rows;
m_pImageBaseData.DataLen = dataLen;
m_pImageBaseData.Pixelformat = _MvdPixelFormat_::MVD_PIXEL_RGB_RGB24_C3;
m_pImageBaseData.ImageData = matInputImg.ptr(0);
}
}
catch (CVmException e)
{
strReMsg.Format(_T("%x"), e.GetErrorCode());
strReMsg = _T("0x") + strReMsg + _T(" == SaveProcedureToFile()");
}
return m_pImageBaseData;
}
3.3 Mat與算子圖像(IMvdImage)互轉
IMvdImage* MatToIMvdImage(Mat& matInputImg)
{
if (matInputImg.empty())
{
throw IMVDException(MVD_MODUL_APP, MVD_E_PARAMETER_ILLEGAL);
}
if ((CV_8UC1 != matInputImg.type()) && (CV_8UC3 != matInputImg.type()))
{
throw IMVDException(MVD_MODUL_APP, MVD_E_SUPPORT);
}
IMvdImage* pMvdImg = NULL;
uint dataLen = (uint)(matInputImg.cols * matInputImg.rows * matInputImg.channels());
try
{
int nRet = CreateImageInstance(&pMvdImg);
if (MVD_OK != nRet)
{
throw IMVDException(MVD_MODUL_IMAGE, nRet, "Failed to create image instance.");
}
if (CV_8UC1 == matInputImg.type())
{
MVD_IMAGE_DATA_INFO stImageData{ };
stImageData.stDataChannel[0].nRowStep = (uint)matInputImg.cols;
stImageData.stDataChannel[0].nLen = dataLen;
stImageData.stDataChannel[0].nSize = dataLen;
stImageData.stDataChannel[0].pData = matInputImg.ptr(0);
pMvdImg->InitImage((uint)matInputImg.cols, (uint)matInputImg.rows, VisionDesigner::_MVD_PIXEL_FORMAT_::MVD_PIXEL_MONO_08, stImageData);
}
else if (CV_8UC3 == matInputImg.type())
{
cv::cvtColor(matInputImg, matInputImg, CV_BGR2RGB);
MVD_IMAGE_DATA_INFO stImageData{ };
stImageData.stDataChannel[0].nRowStep = (uint)matInputImg.cols*matInputImg.channels();
stImageData.stDataChannel[0].nLen = dataLen;
stImageData.stDataChannel[0].nSize = dataLen;
stImageData.stDataChannel[0].pData = matInputImg.ptr(0);
pMvdImg->InitImage((uint)matInputImg.cols, (uint)matInputImg.rows, VisionDesigner::_MVD_PIXEL_FORMAT_::MVD_PIXEL_RGB_RGB24_C3, stImageData);
}
}
catch (IMVDException &ex)
{
if (NULL != pMvdImg)
{
DestroyImageInstance(pMvdImg);
pMvdImg = NULL;
}
throw ex;
}
return pMvdImg;
}
Mat IMvdImageToMat(IMvdImage* pMvdImg)
{
Mat stMatImg;
if (NULL == pMvdImg)
{
throw IMVDException(MVD_MODUL_APP, MVD_E_PARAMETER_ILLEGAL);
}
MVD_PIXEL_FORMAT enSrcPixelFormat = pMvdImg->GetPixelFormat();
if ((VisionDesigner::MVD_PIXEL_FORMAT::MVD_PIXEL_MONO_08 != enSrcPixelFormat) && (VisionDesigner::MVD_PIXEL_FORMAT::MVD_PIXEL_RGB_RGB24_C3 != enSrcPixelFormat))
{
throw IMVDException(MVD_MODUL_APP, MVD_E_SUPPORT);
}
// 根據傳入的ImvdImage圖像初始化mat
if (VisionDesigner::MVD_PIXEL_FORMAT::MVD_PIXEL_MONO_08 == enSrcPixelFormat)
{
stMatImg.create((int)pMvdImg->GetHeight(), (int)pMvdImg->GetWidth(), CV_8UC1);
}
else if (VisionDesigner::MVD_PIXEL_FORMAT::MVD_PIXEL_RGB_RGB24_C3 == enSrcPixelFormat)
{
stMatImg.create((int)pMvdImg->GetHeight(), (int)pMvdImg->GetWidth(), CV_8UC3);
}
if (stMatImg.empty())
{
throw IMVDException(MVD_MODUL_APP, MVD_E_RESOURCE);
}
// 上述方式為mat配置設定的記憶體一定是連續的
uchar* pdata = stMatImg.ptr<uchar>(0);
memcpy(pdata, pMvdImg->GetImageData(0)->pData, pMvdImg->GetImageData(0)->nLen);
if (CV_8UC3 == stMatImg.type())
{
cvtColor(stMatImg, stMatImg, CV_RGB2BGR);
}
return stMatImg;
}
3.4 流程輸出(IoImage)轉Mat
Mat IoImageToMat(IoImage m_pIoImage)
{
Mat stMatImg;
CString strReMsg = _T("");
try
{
MvdPixelFormat srcPixelFormat = m_pIoImage.stImage.Pixelformat;
if ((VisionMasterSDK::MvdPixelFormat::MVD_PIXEL_MONO_08 != srcPixelFormat) && (VisionMasterSDK::MvdPixelFormat::MVD_PIXEL_RGB_RGB24_C3 != srcPixelFormat))
{
throw CVmException(0xE0000503);
}
// 根據傳入的IoImage圖像初始化mat
if (VisionMasterSDK::MvdPixelFormat::MVD_PIXEL_MONO_08 == srcPixelFormat)
{
stMatImg.create((int)m_pIoImage.stImage.Height, (int)m_pIoImage.stImage.Width, CV_8UC1);
}
else if (VisionMasterSDK::MvdPixelFormat::MVD_PIXEL_RGB_RGB24_C3 == srcPixelFormat)
{
stMatImg.create((int)m_pIoImage.stImage.Height, (int)m_pIoImage.stImage.Width, CV_8UC3);
}
if (stMatImg.empty())
{
throw IMVDException(MVD_MODUL_APP, MVD_E_RESOURCE);
}
// 上述方式為mat配置設定的記憶體一定是連續的
uchar* pdata = stMatImg.ptr<uchar>(0);
memcpy(pdata, m_pIoImage.stImage.ImageData, m_pIoImage.stImage.DataLen);
if (CV_8UC3 == stMatImg.type())
{
cvtColor(stMatImg, stMatImg, CV_RGB2BGR);
}
}
catch (CVmException e)
{
strReMsg.Format(_T("%x"), e.GetErrorCode());
strReMsg = _T("0x") + strReMsg + _T(" == SaveProcedureToFile()");
}
return stMatImg;
}
4.Halcon與VM圖像格式互轉
Halcon圖像轉換為流程輸入圖像、Group輸入圖像、圖像源SDK輸入圖像、子產品輸入圖像、算子輸入圖像,算子輸出圖像轉Halcon圖像,流程輸出圖像轉換為Halcon圖像,互轉示例代碼如下 :
4.1 Halcon圖像轉流程輸入(IoImage)、Group輸入(IoImage)
IoImage HImageToIoImage(HImage image)
{
IoImage ioImage{};
ImageBaseData imageBaseData = HImageToImageBaseData(image);
ioImage.stImage = imageBaseData;
return ioImage;
}
4.2 Halcon圖像轉圖像源SDK輸入(ImageBaseData)、子產品輸入(ImageBaseData)
ImageBaseData HImageToImageBaseData(HImage image)
{
ImageBaseData imageBaseData{};
//擷取圖像通道位深度資訊
HString bitdepth = image.GetChannelInfo("type", 1);
assert(!strcmp(bitdepth.Text(), "byte"));
int channels = image.CountChannels();
assert(channels == 1 || channels == 3);
HString type;
Hlong width, height;
//單通道
if (channels == 1)
{
void* imagePtr = image.GetImagePointer1(&type, &width, &height);
imageBaseData.DataLen = width * height;
imageBaseData.Width = width;
imageBaseData.Height = height;
imageBaseData.Pixelformat = MvdPixelFormat::MVD_PIXEL_MONO_08;
imageBaseData.ImageData = imagePtr;
}
//3通道
if (channels == 3)
{
void* imageRedPtr;
void* imageGreenPtr;
void* imageBluePtr;
image.GetImagePointer3(&imageRedPtr, &imageGreenPtr, &imageBluePtr, &type, &width, &height);
byte* imageRedBuf = new byte[width * height];
byte* imageGreenBuf = new byte[width * height];
byte* imageBlueBuf = new byte[width * height];
memcpy(imageRedBuf, imageRedPtr, width * height);
memcpy(imageGreenBuf, imageGreenPtr, width * height);
memcpy(imageBlueBuf, imageBluePtr, width * height);
byte* imageBuf = new byte[width * height * 3];
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++, index += 3)
{
imageBuf[index] = imageRedBuf[row * width + col];
imageBuf[index + 1] = imageGreenBuf[row * width + col];
imageBuf[index + 2] = imageBlueBuf[row * width + col];
}
}
delete[] imageRedBuf;
delete[] imageGreenBuf;
delete[] imageBlueBuf;
imageBaseData.DataLen = width * height * 3;
imageBaseData.Width = width;
imageBaseData.Height = height;
imageBaseData.Pixelformat = MvdPixelFormat::MVD_PIXEL_RGB_RGB24_C3;
imageBaseData.ImageData = imageBuf;
}
return imageBaseData;
}
4.3 Halcon圖像與算子圖像(IMvdImage)互轉
IMvdImage* HImageToMvdImage(HImage image)
{
//擷取圖像通道位深度資訊
HString bitdepth = image.GetChannelInfo("type", 1);
assert(!strcmp(bitdepth.Text(), "byte"));
int channels = image.CountChannels();
assert(channels == 1 || channels == 3);
HString type;
Hlong width, height;
//單通道
if (channels == 1)
{
IMvdImage* pMvdImage;
CreateImageInstance(&pMvdImage);
void* imagePtr = image.GetImagePointer1(&type, &width, &height);
MVD_IMAGE_DATA_INFO imageDataInfo;
imageDataInfo.stDataChannel[0].nLen = width * height;
imageDataInfo.stDataChannel[0].nRowStep = width;
imageDataInfo.stDataChannel[0].nSize = width * height;
imageDataInfo.stDataChannel[0].pData = (byte*)imagePtr;
pMvdImage->InitImage(width, height, MVD_PIXEL_FORMAT::MVD_PIXEL_MONO_08, imageDataInfo);
return pMvdImage;
}
//3通道
else if (channels == 3)
{
IMvdImage* pMvdImage;
CreateImageInstance(&pMvdImage);
void* imageRedPtr;
void* imageGreenPtr;
void* imageBluePtr;
image.GetImagePointer3(&imageRedPtr, &imageGreenPtr, &imageBluePtr, &type, &width, &height);
long size = width * height * 3;
byte* imageRedBuf = new byte[width * height];
byte* imageGreenBuf = new byte[width * height];
byte* imageBlueBuf = new byte[width * height];
memcpy(imageRedBuf, imageRedPtr, width * height);
memcpy(imageGreenBuf, imageGreenPtr, width * height);
memcpy(imageBlueBuf, imageBluePtr, width * height);
byte* imageBuffer = new byte[size];
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++, index += 3)
{
imageBuffer[index] = imageRedBuf[row * width + col];
imageBuffer[index + 1] = imageGreenBuf[row * width + col];
imageBuffer[index + 2] = imageBlueBuf[row * width + col];
}
}
delete[] imageRedBuf;
delete[] imageGreenBuf;
delete[] imageBlueBuf;
MVD_IMAGE_DATA_INFO imageDataInfo{};
imageDataInfo.stDataChannel[0].nLen = width * height * 3;
imageDataInfo.stDataChannel[0].nRowStep = width * 3;
imageDataInfo.stDataChannel[0].nSize = width * height * 3;
imageDataInfo.stDataChannel[0].pData = imageBuffer;
try {
pMvdImage->InitImage(width, height, MVD_PIXEL_FORMAT::MVD_PIXEL_RGB_RGB24_C3, imageDataInfo);
}
catch (IMVDException* ex)
{
cout << ex->GetDescription() << ex->GetErrorCode() << endl;
}
return pMvdImage;
}
else
{
return nullptr;
}
}
HImage MvdImageToHImage(IMvdImage* pMvdImage)
{
HImage image;
MVD_IMAGE_DATA_INFO* imageDataInfo = pMvdImage->GetImageData();
if (pMvdImage->GetPixelFormat() == MVD_PIXEL_FORMAT::MVD_PIXEL_MONO_08)
{
image.GenImage1(
"byte",
pMvdImage->GetWidth(),
pMvdImage->GetHeight(),
imageDataInfo->stDataChannel[0].pData);
}
else if (pMvdImage->GetPixelFormat() == MVD_PIXEL_FORMAT::MVD_PIXEL_RGB_RGB24_C3)
{
int width = pMvdImage->GetWidth();
int height = pMvdImage->GetHeight();
long size = width * height * 3;
byte* imageRedBuf = new byte[(long)(width * height)];
byte* imageGreenBuf = new byte[(long)(width * height)];
byte* imageBlueBuf = new byte[(long)(width * height)];
byte* imageBuffer = new byte[size];
memcpy(imageBuffer, pMvdImage->GetImageData()->stDataChannel[0].pData, size);
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++, index += 3)
{
imageRedBuf[row * width + col] = imageBuffer[index];
imageGreenBuf[row * width + col] = imageBuffer[index + 1];
imageBlueBuf[row * width + col] = imageBuffer[index + 2];
}
}
delete[] imageBuffer;
image.GenImage3(
"byte",
pMvdImage->GetWidth(),
pMvdImage->GetHeight(),
imageRedBuf,
imageGreenBuf,
imageBlueBuf);
}
return image;
}
4.4 流程輸出(IoImage)轉Halcon圖像
HImage IoImageToHImage(IoImage ioImage)
{
HImage image;
if (ioImage.stImage.Pixelformat == MvdPixelFormat::MVD_PIXEL_MONO_08)
{
image.GenImage1("byte", ioImage.stImage.Width, ioImage.stImage.Height, ioImage.stImage.ImageData);
}
if (ioImage.stImage.Pixelformat == MvdPixelFormat::MVD_PIXEL_RGB_RGB24_C3)
{
int width = ioImage.stImage.Width;
int height = ioImage.stImage.Height;
long size = width * height * 3;
byte* imageRedBuf = new byte[(long)width * height];
byte* imageGreenBuf = new byte[(long)width * height];
byte* imageBlueBuf = new byte[(long)width * height];
byte* imageBuffer = new byte[size];
memcpy(imageBuffer, ioImage.stImage.ImageData, size);
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++, index += 3)
{
imageRedBuf[row * width + col] = imageBuffer[index];
imageGreenBuf[row * width + col] = imageBuffer[index + 1];
imageBlueBuf[row * width + col] = imageBuffer[index + 2];
}
}
delete[] imageBuffer;
image.GenImage3("byte", width, height, imageRedBuf, imageGreenBuf, imageBlueBuf);
}
return image;
}
5.流程圖像與算子圖像
VM SDK開發中流程輸入輸出圖像都是ImageBaseData_V2,算子SDK開發中算子輸入輸出圖像都是CmvdImage,兩者可以實作互轉。
5.1 流程圖像轉算子圖像
public CMvdImage ImageBaseData_V2ToCMvdImage(ImageBaseData_V2 ImageBaseDataV2)
{
VisionDesigner.CMvdImage cmvdImage = new VisionDesigner.CMvdImage();
VisionDesigner.MVD_IMAGE_DATA_INFO stImageData = new VisionDesigner.MVD_IMAGE_DATA_INFO();
if (VMPixelFormat.VM_PIXEL_MONO_08 == ImageBaseDataV2.Pixelformat)
{
stImageData.stDataChannel[0].nRowStep = (uint)ImageBaseDataV2.Width;
stImageData.stDataChannel[0].nLen = (uint)(ImageBaseDataV2.Width * ImageBaseDataV2.Height);
stImageData.stDataChannel[0].nSize = (uint)(ImageBaseDataV2.Width * ImageBaseDataV2.Height);
byte[] m_BufForDriver1 = new byte[ImageBaseDataV2.Width * ImageBaseDataV2.Height];
//資料Copy
Marshal.Copy(ImageBaseDataV2.ImageData, m_BufForDriver1, 0, ((int)ImageBaseDataV2.Width * ImageBaseDataV2.Height));
stImageData.stDataChannel[0].arrDataBytes = m_BufForDriver1;
//初始化CMvdImage
cmvdImage.InitImage((uint)ImageBaseDataV2.Width, (uint)ImageBaseDataV2.Height, MVD_PIXEL_FORMAT.MVD_PIXEL_MONO_08, stImageData);
}
else if (VMPixelFormat.VM_PIXEL_RGB24_C3 == ImageBaseDataV2.Pixelformat)
{
stImageData.stDataChannel[0].nRowStep = (uint)ImageBaseDataV2.Width * 3;
stImageData.stDataChannel[0].nLen = (uint)(ImageBaseDataV2.Width * ImageBaseDataV2.Height * 3);
stImageData.stDataChannel[0].nSize = (uint)(ImageBaseDataV2.Width * ImageBaseDataV2.Height * 3);
byte[] m_BufForDriver1 = new byte[3 * (ImageBaseDataV2.Width * ImageBaseDataV2.Height)];
//資料Copy
Marshal.Copy(ImageBaseDataV2.ImageData, m_BufForDriver1, 0, ((int)(ImageBaseDataV2.Width * ImageBaseDataV2.Height) * 3));
stImageData.stDataChannel[0].arrDataBytes = m_BufForDriver1;
//初始化CMvdImage
cmvdImage.InitImage((uint)ImageBaseDataV2.Width, (uint)ImageBaseDataV2.Height, MVD_PIXEL_FORMAT.MVD_PIXEL_RGB_RGB24_C3, stImageData);
}
return cmvdImage;
}
5.2 算子圖像轉流程圖像
public ImageBaseData_V2 CMvdImageToImageBaseData_V2(CMvdImage cmvdImage)
{
VM.PlatformSDKCS.ImageBaseData_V2 ImageBaseDataV2 = null;
if (MVD_PIXEL_FORMAT.MVD_PIXEL_MONO_08 == cmvdImage.PixelFormat)
{
var cmvdImageData = cmvdImage.GetImageData();
IntPtr imagedata = Marshal.AllocHGlobal(cmvdImageData.stDataChannel[0].arrDataBytes.Length);
Marshal.Copy(cmvdImageData.stDataChannel[0].arrDataBytes, 0, imagedata, cmvdImageData.stDataChannel[0].arrDataBytes.Length);
ImageBaseDataV2 = new ImageBaseData_V2(imagedata, (uint)cmvdImageData.stDataChannel[0].arrDataBytes.Length, (int)cmvdImage.Width, (int)cmvdImage.Height, VMPixelFormat.VM_PIXEL_MONO_08);
//使用結束後需要手動釋放
//Marshal.FreeHGlobal(imagedata);
//imagedata = IntPtr.Zero;
}
else if (MVD_PIXEL_FORMAT.MVD_PIXEL_RGB_RGB24_C3 == cmvdImage.PixelFormat)
{
var cmvdImageData = cmvdImage.GetImageData();
IntPtr imagedata = Marshal.AllocHGlobal(cmvdImageData.stDataChannel[0].arrDataBytes.Length);
Marshal.Copy(cmvdImageData.stDataChannel[0].arrDataBytes, 0, imagedata, cmvdImageData.stDataChannel[0].arrDataBytes.Length);
ImageBaseDataV2 = new ImageBaseData_V2(imagedata, (uint)cmvdImageData.stDataChannel[0].arrDataBytes.Length, (int)cmvdImage.Width, (int)cmvdImage.Height, VMPixelFormat.VM_PIXEL_RGB24_C3);
//使用結束後需要手動釋放
//Marshal.FreeHGlobal(imagedata);
//imagedata = IntPtr.Zero;
}
return ImageBaseDataV2;
}
6.算法子產品圖像與Mat、Halcon、算子圖像互轉的方法(C++)
算法子產品圖像與Mat、Halcon圖像、算子圖像實作互轉,自定義算法子產品開發時,在C++工程中,算法的圖像類型為HKA_IMAGE。
6.1 HKA_IMAGE與Mat互轉
Mat CAlgorithmModule::HKAImageToMat(HKA_IMAGE inputimage)
{
Mat mat, mat1;
if (inputimage.format == HKA_IMG_MONO_08)
{
mat = Mat(inputimage.height, inputimage.width, CV_8UC1, inputimage.data[0]);
}
else if (inputimage.format == HKA_IMG_RGB_RGB24_C3)
{
mat1 = Mat(inputimage.height, inputimage.width, CV_8UC3, inputimage.data[0]);
cvtColor(mat1, mat, COLOR_RGB2BGR);
}
return mat;
}
HKA_IMAGE CAlgorithmModule::MatToHKAImage(Mat mat)
{
HKA_IMAGE inputimage;
if (mat.channels() == 1)
{
inputimage = { HKA_IMG_MONO_08, 0 };
inputimage.width = mat.cols;
inputimage.height = mat.rows;
inputimage.format = HKA_IMG_MONO_08;
inputimage.step[0] = mat.cols;
inputimage.data[0] = (char*)malloc(inputimage.width * inputimage.height);
if (inputimage.data[0] != NULL)
{
memset(inputimage.data[0], 0, inputimage.width * inputimage.height);
memcpy_s(inputimage.data[0], inputimage.width * inputimage.height, mat.data, inputimage.width * inputimage.height);
}
}
else if (mat.channels() == 3)
{
cvtColor(mat, mat, COLOR_BGR2RGB);
inputimage = { HKA_IMG_RGB_RGB24_C3, 0 };
inputimage.width = mat.cols;
inputimage.height = mat.rows;
inputimage.format = HKA_IMG_RGB_RGB24_C3;
inputimage.step[0] = mat.cols * 3;
inputimage.data[0] = (char*)malloc(inputimage.width * inputimage.height * 3);
if (inputimage.data[0] != NULL)
{
memset(inputimage.data[0], 0, inputimage.width * inputimage.height * 3);
memcpy_s(inputimage.data[0], inputimage.width * inputimage.height * 3, mat.data, inputimage.width * inputimage.height * 3);
}
}
return inputimage;
}
6.2 HKA_IMAGE與Halcon圖像互轉
HImage CAlgorithmModule::HKAImageToHImage(HKA_IMAGE inputimage)
{
HImage himage;
if (HKA_IMG_MONO_08 == inputimage.format)
{
himage.GenImage1("byte", inputimage.width, inputimage.height, inputimage.data[0]);
}
if (HKA_IMG_RGB_RGB24_C3 == inputimage.format)
{
int width = inputimage.width;
int height = inputimage.height;
long size = width * height * 3;
byte* imageRedBuf = new byte[(long)width * height];
byte* imageGreenBuf = new byte[(long)width * height];
byte* imageBlueBuf = new byte[(long)width * height];
byte* imageBuffer = new byte[size];
memcpy(imageBuffer, inputimage.data[0], size);
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++, index += 3)
{
imageRedBuf[row * width + col] = imageBuffer[index];
imageGreenBuf[row * width + col] = imageBuffer[index + 1];
imageBlueBuf[row * width + col] = imageBuffer[index + 2];
}
}
delete[] imageBuffer;
himage.GenImage3("byte", width, height, imageRedBuf, imageGreenBuf, imageBlueBuf);
}
return himage;
}
HKA_IMAGE CAlgorithmModule::HImageToHKAIMAGE(HImage himage)
{
HKA_IMAGE inputimage;
HString type;
Hlong width, height;
if (himage.CountChannels() == 1)
{
inputimage = { HKA_IMG_MONO_08, 0 };
void* imagePtr = himage.GetImagePointer1(&type, &width, &height);
inputimage.width = width;
inputimage.height = height;
inputimage.format = HKA_IMG_MONO_08;
inputimage.step[0] = width;
inputimage.data[0] = (char*)malloc(inputimage.width * inputimage.height);
if (inputimage.data[0] != NULL)
{
memset(inputimage.data[0], 0, inputimage.width * inputimage.height);
memcpy_s(inputimage.data[0], inputimage.width * inputimage.height, imagePtr, inputimage.width * inputimage.height);
}
}
else if (himage.CountChannels() == 3)
{
inputimage = { HKA_IMG_RGB_RGB24_C3, 0 };
void* imageRedPtr;
void* imageGreenPtr;
void* imageBluePtr;
himage.GetImagePointer3(&imageRedPtr, &imageGreenPtr, &imageBluePtr, &type, &width, &height);
long size = width * height * 3;
byte* imageRedBuf = new byte[width * height];
byte* imageGreenBuf = new byte[width * height];
byte* imageBlueBuf = new byte[width * height];
memcpy_s(imageRedBuf, imageRedPtr, width * height);
memcpy_s(imageGreenBuf, imageGreenPtr, width * height);
memcpy_s(imageBlueBuf, imageBluePtr, width * height);
byte* imageBuffer = new byte[size];
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++, index += 3)
{
imageBuffer[index] = imageRedBuf[row * width + col];
imageBuffer[index + 1] = imageGreenBuf[row * width + col];
imageBuffer[index + 2] = imageBlueBuf[row * width + col];
}
}
delete[] imageRedBuf;
delete[] imageGreenBuf;
delete[] imageBlueBuf;
inputimage.width = width;
inputimage.height = height;
inputimage.format = HKA_IMG_RGB_RGB24_C3;
inputimage.step[0] = width * 3;
inputimage.data[0] = (char*)malloc(inputimage.width * inputimage.height * 3);
if (inputimage.data[0] != NULL)
{
memset(inputimage.data[0], 0, inputimage.width * inputimage.height * 3);
memcpy_s(inputimage.data[0], inputimage.width * inputimage.height * 3, imageBuffer, inputimage.width * inputimage.height * 3);
}
delete[] imageBuffer;
}
return inputimage;
}
6.3 HKA_IMAGE與算子圖像(CmvdImage)互轉
IMvdImage* CAlgorithmModule::HKAImageToIMvdImage(HKA_IMAGE inputimage)
{
IMvdImage* iMvdImage = NULL;
CreateImageInstance(&iMvdImage);
MVD_IMAGE_DATA_INFO stImageData;
if (inputimage.format == HKA_IMG_MONO_08)
{
uint dataLen = (uint)(inputimage.width * inputimage.height);
stImageData.stDataChannel[0].nRowStep = inputimage.width;
stImageData.stDataChannel[0].nLen = dataLen;
stImageData.stDataChannel[0].nSize = dataLen;
stImageData.stDataChannel[0].pData = (unsigned char*)malloc(inputimage.width * inputimage.height);
memset(stImageData.stDataChannel[0].pData, 0, inputimage.width * inputimage.height);
stImageData.stDataChannel[0].pData = (unsigned char*)inputimage.data[0];
iMvdImage->InitImage(inputimage.width, inputimage.height, MVD_PIXEL_MONO_08, stImageData);
}
else if (inputimage.format == HKA_IMG_RGB_RGB24_C3)
{
uint dataLen = (uint)(inputimage.width * inputimage.height * 3);
stImageData.stDataChannel[0].nRowStep = inputimage.width * 3;
stImageData.stDataChannel[0].nLen = dataLen;
stImageData.stDataChannel[0].nSize = dataLen;
stImageData.stDataChannel[0].pData = (unsigned char*)malloc(inputimage.width * inputimage.height * 3);
memset(stImageData.stDataChannel[0].pData, 0, inputimage.width * inputimage.height);
stImageData.stDataChannel[0].pData = (unsigned char*)inputimage.data[0];
iMvdImage->InitImage(inputimage.width, inputimage.height, MVD_PIXEL_RGB_RGB24_C3, stImageData);
}
return iMvdImage;
}
HKA_IMAGE CAlgorithmModule::IMvdImageToHKA_IMAGE(IMvdImage* iMvdImage)
{
HKA_IMAGE inputimage;
if (iMvdImage->GetPixelFormat() == MVD_PIXEL_MONO_08)
{
inputimage = { HKA_IMG_MONO_08, 0 };
inputimage.width = iMvdImage->GetWidth();
inputimage.height = iMvdImage->GetHeight();
inputimage.format = HKA_IMG_MONO_08;
inputimage.step[0] = iMvdImage->GetWidth();
inputimage.data[0] = (char*)malloc(inputimage.width * inputimage.height);
if (inputimage.data[0] != NULL)
{
memset(inputimage.data[0], 0, inputimage.width * inputimage.height);
memcpy_s(inputimage.data[0], inputimage.width * inputimage.height, iMvdImage->GetImageData()->stDataChannel[0].pData, inputimage.width * inputimage.height);
}
}
else if (iMvdImage->GetPixelFormat() == MVD_PIXEL_RGB_RGB24_C3)
{
inputimage = { HKA_IMG_RGB_RGB24_C3, 0 };
inputimage.width = iMvdImage->GetWidth();
inputimage.height = iMvdImage->GetHeight();
inputimage.format = HKA_IMG_RGB_RGB24_C3;
inputimage.step[0] = iMvdImage->GetWidth() * 3;
inputimage.data[0] = (char*)malloc(inputimage.width * inputimage.height * 3);
if (inputimage.data[0] != NULL)
{
memset(inputimage.data[0], 0, inputimage.width * inputimage.height * 3);
memcpy_s(inputimage.data[0], inputimage.width * inputimage.height * 3, iMvdImage->GetImageData()->stDataChannel[0].pData, inputimage.width * inputimage.height * 3);
}
}
return inputimage;
}
總結
以上基本包含大部分圖像類型和VM圖像類型互轉的方法,其實本質上都是圖像資料(位址或byte數組)、圖像寬高及像素格式的指派及拷貝操作,其它圖像類型的轉換可以參考這些方式實作。