文章目录
本文主要实现基于c++做一个视觉定位识别的功能,调用halcon的dll来实现二次开发,下边从头开始设置。
编程环境:MFC
C++
halcon
IDE: VisualStudio 2010
备注:IDE环境可以根据自己电脑已经安装的内容进行使用即可,IDE环境不限制
本次项目的效果视频:
基于c++的MFC框架实现halcon版的多模板匹配

1、Calibration.h、Calibration.cpp:主要是标定界面的逻辑函数
2、CallMe.h、CallMe.cpp:软件里边有个联系我们的按钮,这里是联系我们的界面及事件
3、CameraSetting.h、CameraSetting.cpp:主要是相机设置界面的逻辑函数
4、ModelSetting.h、ModelSetting.cpp:这里主要是模板函数,也就是模板的功能
5、MainFrm.h、MainFrm.cpp:这两个是MFC框架的源文件,主要是MFC程序启动时的一些初始窗体的设置
6、ImageMatchingView.h、ImageMatchingView.cpp:这两个是MFC框架的源文件,主要是MFC程序的试图工作
7、ImageMatchingDoc.h、ImageMatchingDoc.cpp:这两个是MFC框架的源文件,本次项目没有修改此文件
8、ImageMatching.h、ImageMatching.cpp:这两个文件时MFC框架的源文件,可以理解为主软件入口
这里先打开MFC的框架的资源文件入口,如图:

双击之后进入:

注意在新工程中不一定有这些配置,只需新建即可
菜单栏设置入口:

打开后一次按照一下图片进行设置菜单栏








从菜单栏上可以看出,本视觉软件所具有的功能。
先上图,只需要按照这个来设置即可:

从界面上可以看出,本相机设置具有的功能。
先上图,只需要按照这个来设置即可:

从界面上可以看出,本标定设置具有的功能。
先上图,只需要按照这个来设置即可:

从界面上可以看出,本标定设置具有的功能。
先上图,只需要按照这个来设置即可:

这里主要是只放了一个label,用来放图片
这里主要是相机的设置,包括搜索相机,打开相机,连续采集等功能
public:
afx_msg void OnBnClickedButtonSearchimage();
afx_msg void OnBnClickedCameraconnect();
afx_msg void OnBnClickedGetoneimage();
afx_msg void OnBnClickedStartReadimage();
afx_msg void OnCbnSelchangeCameratype();
afx_msg void OnCbnSelchangeRgbzone();
afx_msg void OnNMCustomdrawExposure(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnNMCustomdrawGain(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnBnClickedAutobalance();
afx_msg void OnBnClickedAtuoexposure();
afx_msg void OnBnClickedTen();
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnBnClickedRoisetting();
这里显示查找相机函数
void CameraSetting::OnBnClickedButtonSearchimage()
{
// TODO: 在此添加控件通知处理程序代码
if(OpenCameraFlag == true)
{
OnBnClickedCameraconnect();
Sleep(1000);
}
HTuple Information, ValueList;
HTuple hv_Length;
m_CameraList.ResetContent();
m_CameraZone.ResetContent();
const HTuple deviceNames[] = { "GigEVision","DirectShow","GenICamTL" };
for each (const HTuple name in deviceNames)
{
HalconCpp::InfoFramegrabber(name, "device", &Information, &ValueList);
HalconCpp::TupleLength(ValueList, &hv_Length);
int length1 = (int)hv_Length[0];
for (int i = 0; i<length1; i++)
{
char strDevice[128];
memset(strDevice, 0, 128);
try {
sprintf_s(strDevice, HTuple(ValueList[i]).S());
}
catch (HTupleAccessException e) {
continue;
}
if (strcmp(strDevice, "default") == 0)
{
break;
}
CString fill_name = name.ToString() + _T(":") + strDevice;
m_CameraList.AddString(fill_name);
}
}
if (m_CameraList.GetCount() > 0)
{
m_CameraList.SetCurSel(0);
OnBnClickedCameraconnect();
}
return VOID();
}
这里显示打开关闭相机函数
//打开相机
void CameraSetting::OnBnClickedCameraconnect()
{
// TODO: 在此添加控件通知处理程序代码
CString Btn_Name = _T("");
GetDlgItemText(IDC_CAMERACONNECT,Btn_Name);
if(Btn_Name == _T("连接"))
{
CString Camera_Name;
m_CameraList.GetLBText(m_CameraList.GetCurSel(), Camera_Name);
CStringArray* Data = DivString(Camera_Name,_T(":"));
CString type = Data->GetAt(0);
CString name = Data->GetAt(1);
type.Replace(_T("\""), _T(""));
CAMERA_TYPE = type;
CString ColorStr;
if (m_CameraZone.GetCount() <=0)
{
if (type == _T("DirectShow"))
{
ColorStr = _T("gray");
}
else if (type == _T("GigEVision") || type == _T("GenICamTL"))
{
ColorStr = _T("default");
}
else
{
ColorStr = _T("default");
}
}
else
{
m_CameraZone.GetLBText(m_CameraZone.GetCurSel(), ColorStr);
}
HTuple Information, ValueList;
InfoFramegrabber(HTuple(CStringToChar(type)), "defaults", &Information, &ValueList);
OpenFramegrabber(HTuple(CStringToChar(type)), ValueList[0], ValueList[1], ValueList[2], ValueList[3], ValueList[4], ValueList[5], ValueList[6], ValueList[7], HTuple(CStringToChar(ColorStr))/*ValueList[8]*/, ValueList[9], ValueList[10], ValueList[11], HTuple(CStringToChar(name)), 0, ValueList[13], &hv_AcqHandle);
//初始化图像大小
GrabImageStart(hv_AcqHandle, -1);
GrabImageAsync(&ho_Image, hv_AcqHandle, -1);
GetImageSize(ho_Image,&m_Width, &m_Height);
SetPart(hv_WindowHandle,0, 0, m_Height - 1, m_Width - 1);
GetCarmerInfo(type);
OpenCameraFlag = true;
EnableCamera(OpenCameraFlag);
SetDlgItemText(IDC_CAMERACONNECT,_T("断开"));
return;
}
else
{
CString Btn_Name2 = _T("");
GetDlgItemText(IDC_START_READIMAGE,Btn_Name2);
if(Btn_Name2 == _T("停止预览"))
{
OnBnClickedStartReadimage();
}
CloseCamera();
SetDlgItemText(IDC_CAMERACONNECT,_T("连接"));
}
}
//关闭相机
void CameraSetting::CloseCamera()
{
OpenCameraFlag = false;
EnableCamera(OpenCameraFlag);
CloseFramegrabber(hv_AcqHandle);
hv_AcqHandle = HTuple();
return;
}
void CameraSetting::GetCarmerInfo(CString CameraType)
{
//像素格式
try
{
HTuple hv_Value, hv_Length;
GetFramegrabberParam(hv_AcqHandle, "PixelFormat", &hv_Value);
TupleLength(hv_Value, &hv_Length);
int length = (int)hv_Length[0];
for (int i = 0; i < length; i++)
{
char strch[128];
memset(strch, 0, 128);
try {
sprintf_s(strch, HTuple(hv_Value[i]).S());
}
catch (HTupleAccessException e) {
continue;
}
CString fill_name = CString(strch);
m_CameraFormat.AddString(fill_name);
}
if (m_CameraFormat.GetCount() > 0)
{
m_CameraFormat.SetCurSel(0);
}
}
catch(...)
{
}
//颜色空间
try{
HTuple Information, ValueList,hv_Length;
if (m_CameraZone.GetCount() <= 0)
{
HalconCpp::InfoFramegrabber(HTuple(CStringToChar(CameraType)), "color_space", &Information, &ValueList);
HalconCpp::TupleLength(ValueList, &hv_Length);
int length1 = (int)hv_Length[0];
for (int i = 0; i < length1; i++)
{
char strch[128];
memset(strch, 0, 128);
try {
sprintf_s(strch, HTuple(ValueList[i]).S());
}
catch (HTupleAccessException e) {
continue;
}
CString fill_name = CString(strch);
m_CameraZone.AddString(fill_name);
}
if (m_CameraZone.GetCount() > 0)
{
m_CameraZone.SetCurSel(0);
}
}
}catch(...){}
//曝光时间
try {
HTuple hv_Value;
if(CameraType == _T("DirectShow"))
{
SetFramegrabberParam(hv_AcqHandle, "exposure", "auto");
//设置滑动条范围
CSliderCtrl *pSlidCtrl = (CSliderCtrl*)GetDlgItem(IDC_EXPOSURE);
pSlidCtrl->SetRange(-13, -1, TRUE);
pSlidCtrl->SetPos(-1);
CString mes;
mes.Format(_T("%d"), -1);
SetDlgItemText(IDC_STATIC_EXP, mes);
((CButton*)GetDlgItem(IDC_AtuoExpoSure))->SetCheck(true);
((CButton*)GetDlgItem(IDC_AtuoExpoSure))->EnableWindow(true);
pSlidCtrl->EnableWindow(false);
}
if(CameraType == _T("GigEVision"))
{
GetFramegrabberParam(hv_AcqHandle,"ExposureTime", &hv_Value);
int extime = int(hv_Value[0].D());
//设置滑动条范围
CSliderCtrl *pSlidCtrl = (CSliderCtrl*)GetDlgItem(IDC_EXPOSURE);
pSlidCtrl->SetRange(0, 200000, TRUE);
pSlidCtrl->SetPos(extime);
CString mes;
mes.Format(_T("%d"), extime);
SetDlgItemText(IDC_STATIC_EXP, mes);
((CButton*)GetDlgItem(IDC_AtuoExpoSure))->SetCheck(false);
((CButton*)GetDlgItem(IDC_AtuoExpoSure))->EnableWindow(false);
pSlidCtrl->EnableWindow(true);
}
}
catch (...) {
}
//增益
try
{
HTuple hv_Value;
GetFramegrabberParam(hv_AcqHandle, "Gain", &hv_Value);
int gain = hv_Value[0].D();
//设置滑动条范围
CSliderCtrl *pSlidCtrl = (CSliderCtrl*)GetDlgItem(IDC_GAIN);
pSlidCtrl->SetRange(0, 24, TRUE);
pSlidCtrl->SetPos(gain);
CString mes;
mes.Format(_T("%d"), gain);
SetDlgItemText(IDC_STATIC_GAIN, mes);
pSlidCtrl->EnableWindow(true);
}
catch(...)
{
}
}
设置曝光时间
void CameraSetting::OnNMCustomdrawExposure(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
int pos = ((CSliderCtrl *)GetDlgItem(IDC_EXPOSURE))->GetPos();
if (oldSlid1 == pos)
return;
oldSlid1 = pos;
CString mes;
mes.Format(_T("%d"), pos);
SetDlgItemText(IDC_STATIC_EXP, mes);
if (OpenCameraFlag == true)
{
try {
if (CAMERA_TYPE == _T("GigEVision"))
SetFramegrabberParam(hv_AcqHandle, "ExposureTime", pos);
else if(CAMERA_TYPE == _T("DirectShow"))
SetFramegrabberParam(hv_AcqHandle, "exposure", pos);
}
catch (...)
{
}
}
*pResult = 0;
}
设置增益
void CameraSetting::OnNMCustomdrawGain(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
int pos = ((CSliderCtrl *)GetDlgItem(IDC_GAIN))->GetPos();
if (oldSlid2 == pos)
return;
oldSlid2 = pos;
CString mes;
mes.Format(_T("%d"), pos);
SetDlgItemText(IDC_STATIC_GAIN, mes);
if (OpenCameraFlag == true)
{
try {
SetFramegrabberParam(hv_AcqHandle, "Gain", pos);
}
catch (...)
{
}
}
*pResult = 0;
}
设置自动曝光
void CameraSetting::OnBnClickedAtuoexposure()
{
// TODO: 在此添加控件通知处理程序代码
if (((CButton*)GetDlgItem(IDC_AtuoExpoSure))->GetCheck()) //选中
{
try {
SetFramegrabberParam(hv_AcqHandle, "exposure", "auto");
}
catch (...) {
}
}
}
设置白平衡
void CameraSetting::OnBnClickedAutobalance()
{
// TODO: 在此添加控件通知处理程序代码
if (((CButton*)GetDlgItem(IDC_AUTOBALANCE))->GetCheck()) //选中
{
try {
SetFramegrabberParam(hv_AcqHandle, "white_balance", "auto");
}
catch (...) {
}
}
}
这里是模板设置的一些标准信息
包括设置模板的起始角度、角度范围、识别分数、识别个数、是否变形等参数的设置
重要代码如下:
void ModelSetting::OnBnClickedSavemodel()
{
// TODO: 在此添加控件通知处理程序代码
CString MesTip=_T("");
MesTip.Format(_T("是否保存 模版%d 的参数?"),m_ModelNumCom.GetCurSel()+1);
if (MessageBox(MesTip, _T("提示"), MB_YESNO | MB_ICONWARNING) == IDNO)
{
return;
}
CString mes;
GetDlgItemText(IDC_ShowStartAngle,mes);
MyModelCom[m_ModelNumCom.GetCurSel()].startAngle = _ttoi(mes);
GetDlgItemText(IDC_ShowEndAngle,mes);
MyModelCom[m_ModelNumCom.GetCurSel()].endAngle = _ttoi(mes);
GetDlgItemText(IDC_ShowLevelNum,mes);
if(((CButton*)GetDlgItem(IDC_CHECK_AutoLeval))->GetCheck())
MyModelCom[m_ModelNumCom.GetCurSel()].Level = -1;
else
MyModelCom[m_ModelNumCom.GetCurSel()].Level = _ttoi(mes);
GetDlgItemText(IDC_ShowScore,mes);
MyModelCom[m_ModelNumCom.GetCurSel()].Score = _ttoi(mes);
MyModelCom[m_ModelNumCom.GetCurSel()].DeformationNum = m_Deformation.GetCurSel();
MyModelCom[m_ModelNumCom.GetCurSel()].MatchNum = m_FindNum.GetCurSel();
GetDlgItemText(IDC_FindModelTimeOut,mes);
MyModelCom[m_ModelNumCom.GetCurSel()].FindModelTimeOut = _ttoi(mes);
::PostMessage(ctu_Hwnd,CtuVision_MESSAGE_EVENT,0,0);
}
这里主要是相机像素与机器人坐标系的标定和转换
void Calibration::AffineTran(int CurrentNum)
{
HTuple concat = NULL, concat1 = NULL, concat2 = NULL, concat3 = NULL;
try
{
for(int i=0;i<MyCalib[CurrentNum].Num;i++)
{
concat = concat.TupleConcat(MyCalib[CurrentNum].MyAllPoint[i].Image_X);
concat1 = concat1.TupleConcat(MyCalib[CurrentNum].MyAllPoint[i].Image_Y);
concat2 = concat2.TupleConcat(MyCalib[CurrentNum].MyAllPoint[i].Robot_X);
concat3 = concat3.TupleConcat(MyCalib[CurrentNum].MyAllPoint[i].Robot_Y);
}
RobotHommat[CurrentNum].VectorToHomMat2d(concat, concat1, concat2, concat3);
MyCalib[CurrentNum].RobotHommatFlag = true;
SetDlgItemText(IDC_OK_NG,_T("OK"));
}
catch(...)
{
DeletePoint(CurrentNum);
SetDlgItemText(IDC_OK_NG,_T("NG"));
}
}
bool Calibration::PixelToRobot(int Num, double img_x,double img_y,double* robot_x,double* robot_y)
{
*robot_x = *robot_y = -1.0;
if (MyCalib[Num].RobotHommatFlag == true)
{
try
{
*robot_x = RobotHommat[Num].AffineTransPoint2d(img_x, img_y, robot_y);
return true;
}
catch(...) //(Exception e)
{
return false;
}
}
return false;
}
一个管理整个流程的一个变量的结构体,变量的意义在代码块解析
struct CurrentControl
{
HTuple hv_WindowHandle; //软件窗体的变量
HObject ho_Image; //软件窗体的图像变量
HTuple ho_Hight; //图像高度
HTuple ho_Width; //图像宽度
int ROIRunType; //ROI运算:并集、交集、差集
HObject ROITemp; //当前窗体的ROI变量
int ModelNum; //当前软件使用的模板号
int FindModelFun; //单钱软件使用的匹配算法
double setPartPosition; //图像在窗体显示的位置
int CurrentBarCodeType; //二维码识别类型
int CurrentDataCodeType; //条形码识别类型
//结构体里边的,用来初始化变量
CurrentControl()
{
hv_WindowHandle = -1;
ho_Hight = -1;
ho_Width = -1;
ho_Image.GenEmptyObj();
ROITemp.GenEmptyObj();
ROIRunType = 0;
ModelNum = 0;
FindModelFun=0;
setPartPosition=0.0;
CurrentBarCodeType = 6;
CurrentDataCodeType = 0;
}
};
视觉定位识别的结果的结构体
struct VisionPoint
{
double x; //识别的像素x
double y; //识别的像素y
double r; //识别的角度r
double score; //最终识别的分数
VisionPoint()
{
x=0;
y=0;
r=0;
score=0;
}
};
识别条形码、二维码、OCR的结构体
struct CodeModel
{
HObject BarCodeROI; # 条形码搜索区域
bool BarCodeROIFlag; # 是否已经设置条形码搜索区域
HObject QRCodeROI; # 二维码搜索区域
bool QRCodeROIFlag; # 是否已经设置了二维码搜索区域
HObject OCRCodeROI; # OCR的搜索区域
bool OCRCodeROIFlag; # 是否设置了OCR搜索区域
CodeModel()
{
BarCodeROI.GenEmptyObj();
BarCodeROIFlag = false;
QRCodeROI.GenEmptyObj();
QRCodeROIFlag = false;
OCRCodeROI.GenEmptyObj();
OCRCodeROIFlag = false;
}
};
结构体设置完成之后,下边开始整个软件的初始化,包括界面变量以及模板变量的初始化
//view的构造函数
CImageMatchingView::CImageMatchingView()
{
// TODO: 在此处添加构造代码
GetMoreImageTimerFlag = false;
DrawFlag = false;
FilePath = GetWorkDir() + _T("\VisionModel");
if(!PathIsDirectory(FilePath))
CreateDirectory(FilePath,NULL);
camSet = new CameraSetting;
camSet->Create(IDD_CAMERASETTING);
modelSet = new ModelSetting;
modelSet->Create(IDD_ModelSetting);
calib = new Calibration(NULL,FilePath);
calib->Create(IDD_CALIBTION);
callme = new CallMe;
callme->Create(IDD_CALLME);
ReadModel(0,MaxModelNum);
ReadCodeROI();
}
//view的析构函数
CImageMatchingView::~CImageMatchingView()
{
delete camSet;
delete modelSet;
delete calib;
delete callme;
}
窗体初始化,这里我写在了OnInitialUpdate函数
void CImageMatchingView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: 在此添加专用代码和/或调用基类
CRect cli;
GetClientRect(&cli);
SetSystem("clip_region", "false");
SetCheck("~father");
SetWindowAttr("background_color","gray");
OpenWindow(cli.top, cli.left, cli.Width(), cli.Height(), (Hlong)(this->GetSafeHwnd()), "visible", "", &MyCurrentControl.hv_WindowHandle);
SetCheck("father");
SetColor(MyCurrentControl.hv_WindowHandle,"red");
SetDraw(MyCurrentControl.hv_WindowHandle,"margin");
载入图像功能
//载入图像
void CImageMatchingView::OnOpenimage()
{
// TODO: 在此添加命令处理程序代码
CString StrFile;
CString defExe("bmp");
CString defFileName("");
CString defFilter("Image Files(*.bmp *.jpg *.png *.tiff)|*.*|");
CFileDialog dlg(true,defExe,defFileName,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,defFilter);
dlg.m_ofn.lpstrInitialDir= _T(".\\");
if(dlg.DoModal()==IDOK)
{
StrFile = dlg.GetPathName();
USES_CONVERSION;
ReadImage(&MyCurrentControl.ho_Image, T2A(StrFile));
MySetPart();
DispObj(MyCurrentControl.ho_Image, MyCurrentControl.hv_WindowHandle);
}
}
保存图像功能
//保存图像
void CImageMatchingView::OnSaveImage()
{
if(HObjectIsNull(MyCurrentControl.ho_Image))
return;
// TODO: 在此添加命令处理程序代码
CString StrFile;
CString defExe("bmp");
CString fileDefaultName = GetTimeMes();
fileDefaultName.Append(_T(".bmp"));
USES_CONVERSION;
CString defFileName(T2A(fileDefaultName));
CString defFilter("Image Files(*.bmp)|*.*|");
CFileDialog dlg(false,defExe,defFileName,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,defFilter);
dlg.m_ofn.lpstrInitialDir= _T(".\\");
if(dlg.DoModal()==IDOK)
{
StrFile = dlg.GetPathName();
USES_CONVERSION;
WriteImage(MyCurrentControl.ho_Image,"bmp",0,T2A(StrFile));
}
}
绘制ROI区域
void CImageMatchingView::OnRectangle1action()
{
// TODO: 在此添加命令处理程序代码
if(HObjectIsNull(MyCurrentControl.ho_Image))
return;
HTuple hv_Row1, hv_Column1, hv_Row2, hv_Column2;
HObject ROITemp;
SetColor(MyCurrentControl.hv_WindowHandle,"red");
DrawRectangle1(MyCurrentControl.hv_WindowHandle, &hv_Row1, &hv_Column1, &hv_Row2, &hv_Column2);
GenRectangle1(&ROITemp, hv_Row1, hv_Column1, hv_Row2, hv_Column2);
if(HObjectIsNull(MyCurrentControl.ROITemp))
MyCurrentControl.ROITemp = ROITemp;
else
RunROI(ROITemp);
ShowRunROI();
}
创建模板主入口
void CImageMatchingView::OnCreatemodelaction()
{
// TODO: 在此添加命令处理程序代码
if (modelSet->MyModelCom[MyCurrentControl.ModelNum].EffectiveFlag == true)
{
CString MesTip=_T("");
MesTip.Format(_T("已经存在模板%d,是否替换?"),MyCurrentControl.ModelNum+1);
if (MessageBox(MesTip, _T("提示"), MB_YESNO | MB_ICONWARNING) == IDNO)
{
MyCurrentControl.ROITemp.GenEmptyObj();
return;
}
}
if (HObjectIsNull(MyCurrentControl.ho_Image) || HObjectIsNull(MyCurrentControl.ROITemp))
{
AfxMessageBox(_T("无图或者无ROI"));
return;
}
//清空当前模板,相当于初始化
//InitModel(MyCurrentControl.ModelNum, MyCurrentControl.ModelNum + 1); //删除当前模板
//数据保存
modelSet->MyModelCom[MyCurrentControl.ModelNum].h_img = MyCurrentControl.ho_Image.Clone();
modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi = MyCurrentControl.ROITemp.Clone();
modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm = MyCurrentControl.FindModelFun;
modelSet->MyModelCom[MyCurrentControl.ModelNum].modelNum = MyCurrentControl.ModelNum;
bool Res = false;
if (MyCurrentControl.FindModelFun == 0)
Res = Create_ShapeModel();
else if (MyCurrentControl.FindModelFun == 1)
Res = Create_GrayModel();
else if (MyCurrentControl.FindModelFun == 2)
Res = Create_NCCModel();
else if (MyCurrentControl.FindModelFun == 3)
Res = Create_ChangeShapeModel();
else{}
if(Res ==false)
{
//模模板创建失败
InitModel(MyCurrentControl.ModelNum,MyCurrentControl.ModelNum+1);
MyCurrentControl.ROITemp.GenEmptyObj();
ShowStatusMes(_T("模板创建失败!"));
return;
}
else
{
ShowStatusMes(_T("模板创建成功!"));
}
WriteData(MyCurrentControl.ModelNum);
WriteImageROI(MyCurrentControl.ModelNum);
}
以灰度模板算法为例
bool CImageMatchingView::Create_GrayModel()
{
if (HObjectIsNull(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_img) || HObjectIsNull(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi))
return false;
HObject hv_ImageReduced;
HTuple hv_Orgin_Area;
HTuple hv_pi = HTuple(0.0).TupleAcos() * 2;
//裁减模板
ReduceDomain(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_img, modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi, &hv_ImageReduced);
try{
CreateTemplateRot(hv_ImageReduced, 4, HTuple(modelSet->MyModelCom[MyCurrentControl.ModelNum].startAngle).TupleRad(), HTuple(modelSet->MyModelCom[MyCurrentControl.ModelNum].endAngle).TupleRad(), 0.0982, "sort", "original", &modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_ModelID);
}catch(...)
{
return false;
}
//清空显示
ClearWindow(MyCurrentControl.hv_WindowHandle);
DispObj(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_img,MyCurrentControl.hv_WindowHandle);
AreaCenter(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi, &hv_Orgin_Area, &modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_Orgin_Row, &modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_Orgin_Column);
SetColor(MyCurrentControl.hv_WindowHandle,"blue");
DispObj(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi,MyCurrentControl.hv_WindowHandle);
SetColor(MyCurrentControl.hv_WindowHandle,"green");
DispCross(MyCurrentControl.hv_WindowHandle, modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_Orgin_Row, modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_Orgin_Column, MyCurrentControl.ho_Width[0].I()/24, 0);
MyCurrentControl.ROITemp.GenEmptyObj();
modelSet->MyModelCom[MyCurrentControl.ModelNum].EffectiveFlag = true;
return true;
}
查找模板的主入口
void CImageMatchingView::OnRunmodelaction()
{
// TODO: 在此添加命令处理程序代码
if(modelSet->MyModelCom[MyCurrentControl.ModelNum].EffectiveFlag == false)
{
MessageBox(_T("当前模板号无模板"), _T("提示"), MB_YESNO | MB_ICONWARNING);
return;
}
std::queue<VisionPoint> EachRes;
if (modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm == 0)
EachRes = FindModel_Shape(MyCurrentControl.ModelNum);
else if(modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm == 1)
EachRes = FindModel_Gray(MyCurrentControl.ModelNum);
else if(modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm == 2)
EachRes = FindModel_NCC(MyCurrentControl.ModelNum);
else if(modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm == 3)
EachRes = FindModel_ChangeShape(MyCurrentControl.ModelNum);
else{}
if(EachRes.size() == 0)
{
ShowStatusMes(_T("模板匹配失败!"));
CString mes=_T("");
mes.Format(_T("模板匹配结果:%f,%f,%f,%f"),-1.0,-1.0,-1.0,-1.0);
CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd();
pFrame->m_wndStatusBar.SetPaneText(0, mes);//修改原有的状态栏上就绪一栏的信息
}
else
{
ShowStatusMes(_T("模板匹配成功!"));
VisionPoint p = EachRes.front();
CString mes=_T("");
mes.Format(_T("模板匹配结果:%f,%f,%f,%f"),p.x,p.y,p.r,p.score);
CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd();
pFrame->m_wndStatusBar.SetPaneText(0, mes);//修改原有的状态栏上就绪一栏的信息
}
}
以灰度模板匹配为例找模板
std::queue<VisionPoint> CImageMatchingView::FindModel_Gray(int ModelNum)
{
std::queue<VisionPoint> pp;
if(HObjectIsNull(MyCurrentControl.ho_Image) || modelSet->MyModelCom[ModelNum].hv_ModelID == -1)
return pp;
HTuple hv_RowCheck = NULL, hv_ColumnCheck = NULL, hv_AngleCheck = NULL, hv_Error = NULL;
HTuple hMat2D = NULL;
HObject ho_ImageAffinTrans;
double Score = modelSet->MyModelCom[ModelNum].Score / 100.0;
HObject hv_img = MyCurrentControl.ho_Image;
if(modelSet->MyModelCom[ModelNum].SearchROIFlag)
ReduceDomain(hv_img, modelSet->MyModelCom[ModelNum].h_SearchROI, &hv_img);
BestMatchRotMg(hv_img, modelSet->MyModelCom[ModelNum].hv_ModelID, HTuple(modelSet->MyModelCom[ModelNum].startAngle).TupleRad(), HTuple(modelSet->MyModelCom[ModelNum].endAngle).TupleRad(), 100 - Score, "true", 4, &hv_RowCheck, &hv_ColumnCheck, &hv_AngleCheck, &hv_Error);
if (int(hv_Error.TupleLength()[0].D()) > 0)
{
if (Score*100 > (100 - hv_Error[0].D()))
return pp;
if (modelSet->MyModelCom[ModelNum].TargetFlag == true)
{
HTuple RowTrans = NULL, ColumnTrans = NULL;
VectorAngleToRigid(modelSet->MyModelCom[ModelNum].hv_Orgin_Row, modelSet->MyModelCom[ModelNum].hv_Orgin_Column, 0, hv_RowCheck[0].D(), hv_ColumnCheck[0].D(), hv_AngleCheck[0].D(), &hMat2D);
AffineTransPixel(hMat2D, modelSet->MyModelCom[ModelNum].hv_Target_Row, modelSet->MyModelCom[ModelNum].hv_Target_Column, &RowTrans, &ColumnTrans);
SetColor(MyCurrentControl.hv_WindowHandle,"green");
DispCross(MyCurrentControl.hv_WindowHandle, RowTrans[0].D(), ColumnTrans[0].D(), MyCurrentControl.ho_Width[0].I()/24, hv_AngleCheck[0].D());
AffineTransRegion(modelSet->MyModelCom[ModelNum].h_roi, &ho_ImageAffinTrans, hMat2D, "constant");
SetColor(MyCurrentControl.hv_WindowHandle,"blue");
DispObj(ho_ImageAffinTrans,MyCurrentControl.hv_WindowHandle);
VisionPoint tempPoint;
tempPoint.x = RowTrans[0].D();
tempPoint.y = ColumnTrans[0].D();
tempPoint.r = hv_AngleCheck[0].D() * 57.3;
tempPoint.score = 100 - hv_Error[0].D();
pp.push(tempPoint);
}
else
{
SetColor(MyCurrentControl.hv_WindowHandle, "green");
DispCross(MyCurrentControl.hv_WindowHandle, hv_RowCheck[0].D(), hv_ColumnCheck[0].D(), MyCurrentControl.ho_Width[0].I()/24, hv_AngleCheck[0].D());
VectorAngleToRigid(modelSet->MyModelCom[ModelNum].hv_Orgin_Row, modelSet->MyModelCom[ModelNum].hv_Orgin_Column, 0, hv_RowCheck[0].D(), hv_ColumnCheck[0].D(), hv_AngleCheck[0].D(), &hMat2D);
AffineTransRegion(modelSet->MyModelCom[ModelNum].h_roi, &ho_ImageAffinTrans, hMat2D, "constant");
SetColor(MyCurrentControl.hv_WindowHandle, "blue");
DispObj(ho_ImageAffinTrans,MyCurrentControl.hv_WindowHandle);
VisionPoint tempPoint;
tempPoint.x = hv_RowCheck[0].D();
tempPoint.y = hv_ColumnCheck[0].D();
tempPoint.r = hv_AngleCheck[0].D() * 57.3;
tempPoint.score = 100 - hv_Error[0].D();
pp.push(tempPoint);
}
}
//显示搜索区域
if (modelSet->MyModelCom[ModelNum].SearchROIFlag)
{
SetColor(MyCurrentControl.hv_WindowHandle, "orange");
DispObj(modelSet->MyModelCom[ModelNum].h_SearchROI,MyCurrentControl.hv_WindowHandle);
}
return pp;
}
条形码识别
CString CImageMatchingView::ReadBarCode()
{
if (HObjectIsNull(MyCurrentControl.ho_Image))
return _T("Code:-1");
HTuple hv_BarCodeHandle = -1, hv_DecodedDataStrings = -1, hv_BarCodeResults1 = -1,hv_DecodedDataTypes = -1;
HObject ho_SymbolRegions;
HObject hv_img = MyCurrentControl.ho_Image;
if(MyCodeCom.BarCodeROIFlag)
ReduceDomain(hv_img, MyCodeCom.BarCodeROI, &hv_img);
try{
CreateBarCodeModel(HTuple(), HTuple(), &hv_BarCodeHandle);
SetBarCodeParam(hv_BarCodeHandle, "element_size_min", 1);
FindBarCode(hv_img, &ho_SymbolRegions, hv_BarCodeHandle, "auto", &hv_DecodedDataStrings);
GetBarCodeResult(hv_BarCodeHandle, "all", "orientation", &hv_BarCodeResults1);
GetBarCodeResult(hv_BarCodeHandle, "all", "decoded_types", &hv_DecodedDataTypes);
ClearBarCodeModel(hv_BarCodeHandle);
}catch(...)
{
return _T("Code:-1");
}
if(MyCodeCom.BarCodeROIFlag)
{
SetColor(MyCurrentControl.hv_WindowHandle,"orange");
DispObj(MyCodeCom.BarCodeROI,MyCurrentControl.hv_WindowHandle);
}
SetColor(MyCurrentControl.hv_WindowHandle,"green");
DispObj(ho_SymbolRegions,MyCurrentControl.hv_WindowHandle);
CString Code = _T("");
int num = int(hv_DecodedDataStrings.TupleLength()[0].D());
if(num>0)
{
double Angle = hv_BarCodeResults1[0].D();
char CodeType[128];
memset(CodeType, 0, 128);
try {
sprintf_s(CodeType, HTuple(hv_DecodedDataTypes[0]).S());
}
catch (HTupleAccessException e) {
}
char CodeStr[128];
memset(CodeStr, 0, 128);
try {
sprintf_s(CodeStr, HTuple(hv_DecodedDataStrings[0]).S());
}
catch (HTupleAccessException e) {
}
CString ang;
ang.Format(_T("%f"),Angle);
Code = _T("") + CString(CodeType) + _T(":")+ CString(CodeStr) + _T(",") + ang;
}
if(Code == "")
Code = _T("Code:-1");
return Code;
}
二维码识别
CString CImageMatchingView::ReadQRCode()
{
if(HObjectIsNull(MyCurrentControl.ho_Image))
return _T("Code:-1");
HObject hv_img = MyCurrentControl.ho_Image;
if(MyCodeCom.QRCodeROIFlag)
ReduceDomain(hv_img, MyCodeCom.QRCodeROI, &hv_img);
try
{
HObject ho_SymbolXLDs;
HTuple hv_DataCodeHandle, hv_ResultHandles, hv_DecodedDataStrings;
CreateDataCode2dModel("QR Code", HTuple(), HTuple(), &hv_DataCodeHandle);
FindDataCode2d(hv_img, &ho_SymbolXLDs, hv_DataCodeHandle, HTuple(), HTuple(), &hv_ResultHandles, &hv_DecodedDataStrings);
ClearDataCode2dModel(hv_DataCodeHandle);
if(MyCodeCom.QRCodeROIFlag)
{
SetColor(MyCurrentControl.hv_WindowHandle,"orange");
DispObj(MyCodeCom.QRCodeROI,MyCurrentControl.hv_WindowHandle);
}
SetColor(MyCurrentControl.hv_WindowHandle,"green");
DispObj(ho_SymbolXLDs,MyCurrentControl.hv_WindowHandle);
CString Code = _T("");
int num = int(hv_DecodedDataStrings.TupleLength()[0].D());
if(num>0)
{
char CodeType[128];
memset(CodeType, 0, 128);
try {
sprintf_s(CodeType, HTuple(hv_DecodedDataStrings[0]).S());
}
catch (HTupleAccessException e) {
}
Code = _T("QR Code:") + CString(CodeType);
}
if(Code == "")
Code = _T("Code:-1");
return Code;
}
catch(...)
{
return _T("Code:-1");
}
}
OCR识别
CString CImageMatchingView::ReadOCRCode()
{
if (HObjectIsNull(MyCurrentControl.ho_Image))
return _T("Code:-1");
try{
HObject ho_Region2, ho_ConnectedRegions1,ho_SelectedRegions1,ho_SortedRegions;
HTuple hv_UsedThreshold2, hv_OCRHandle,hv_Class,hv_Confidence;
HObject hv_img = MyCurrentControl.ho_Image;
if(MyCodeCom.OCRCodeROIFlag)
ReduceDomain(hv_img, MyCodeCom.OCRCodeROI, &hv_img);
BinaryThreshold(hv_img, &ho_Region2, "max_separability", "dark", &hv_UsedThreshold2);
Connection(ho_Region2, &ho_ConnectedRegions1);
SelectShape(ho_ConnectedRegions1, &ho_SelectedRegions1, "area", "and", 150, 99999);
SortRegion(ho_SelectedRegions1, &ho_SortedRegions, "character", "true", "row");
ReadOcrClassMlp("./genicam/Industrial.omc", &hv_OCRHandle);
DoOcrMultiClassMlp(ho_SortedRegions, hv_img, hv_OCRHandle, &hv_Class, &hv_Confidence);
ClearOcrClassMlp(hv_OCRHandle);
if(MyCodeCom.OCRCodeROIFlag)
{
SetColor(MyCurrentControl.hv_WindowHandle,"orange");
DispObj(MyCodeCom.OCRCodeROI,MyCurrentControl.hv_WindowHandle);
}
int num = int(hv_Class.TupleLength()[0].D());
CString Code = _T("Code:");
for(int i=0;i<num;i++)
{
char temp[128];
memset(temp, 0, 128);
try {
sprintf_s(temp, HTuple(hv_Class[i]).S());
}
catch (HTupleAccessException e) {
}
Code = Code + CString(temp);
}
if(Code == "")
Code = _T("Code:-1");
return Code;
}
catch(...)
{
return _T("Code:-1");
}
}
该工程篇幅比较多,不过具体的函数在文章中已经表标明,具体的查看源码使用。
mfc调用halcon只需要理解整个目录结构和功能板块即可完成此模板匹配功能
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复