3:QT联合HALCON编程—海康相机SDK二次程序开发
思路:
1.定义带UI界面的主函数类
1.1在主函数中包含其它所有类头文件,进行声明和实例化;使用相机时,是用公共相机的接口在某一个具体函数中去实例化具体的海康相机对象。
1.2设计界面:连接相机,单次采集,连续采集,停止采集,关闭相机
1.3在连续采集中,开始启用线程。需要在线程类中采集图像,通过信号与槽在主函数中接收并显示图像。
2.定义公共相机接口类
3.定义海康相机类
4.定义线程类
4.1里面包含:接收海康相机的函数,在主函数中可以直接调用线程里面的这个函数,并通过指针传参。
4.2定义run函数,在函数里面采集图像,并发送信号。
4.3定义if语句判断线程状态,控制线程启停。
4.4定义bool变量去结合if进行判断
5.定义日志类
6.定义加载保存参数,公共结构体类
7.定义其它图像处理功能类
7.1例如:测量,匹配,检测等...............
1.主目录框架
列表中含有:
1.src里面是图像处理的各种模块功能以及公共文件(日志和参数加载)
2.相机的公共接口类
3.Halcon类
4.海康相机类
5.主函数
6.线程类
2.定义公共相机接口(camerainterface)
camerainterface.h
#ifndef CAMERAINTERFACE_H
#define CAMERAINTERFACE_H#include "HalconCpp.h"
#include "HDevThread.h"
using namespace HalconCpp;
#include"iostream"
class CameraInterface
{
public:CameraInterface();~CameraInterface();//关闭相机采集 // ch:连接设备virtual int connectCamera(int id)=0;//设置是否为触发模式virtual int setTriggerMode(unsigned int TriggerModeNum)=0;//开启相机采集virtual int startCamera()=0;virtual int stopCamera()=0;//关闭相机virtual int closeCamera()=0;//软触发virtual int softTrigger()=0;//读取buffervirtual int ReadBuffer(HObject &image)=0;//设置图像高度virtual int setHeight(unsigned int height)=0;//设置图像ROI宽度virtual int setWidth(unsigned int width)=0;//获取图像高度值virtual int getHeight()=0;//获取图像宽度值virtual int getWidth()=0;//获取相机曝光时间virtual float getExposureTime()=0;//设置图像水平偏移OffsetXvirtual int setOffsetX(unsigned int offsetX)=0;//设置图像竖直偏移OffsetYvirtual int setOffsetY(unsigned int offsetY)=0;//设置触发源virtual int setTriggerSource(unsigned int TriggerSourceNum)=0;//设置帧率控制使能virtual int setFrameRateEnable(bool comm)=0;//设置心跳时间virtual int setHeartBeatTime(unsigned int time)=0;//设置曝光时间virtual int setExposureTime(float ExposureTimeNum)=0;//设置增益virtual int setGain(float Gain)=0;//关闭自动曝光virtual int setExposureAuto(bool exposureAutoFlag)=0;//关闭自动增益virtual int setGainAuto(bool gainAutoFlag)=0;//virtual int setGain(float Gain)=0;//清理相机缓存virtual void clearBuffer()=0;
};#endif // CAMERAINTERFACE_H
3.定义海康相机类(hikvisionsdk)
1.hikvisionsdk.h文件,海康相机功能函数声明(包含公共相机头文件)
#ifndef HIKVISIONSDK_H
#define HIKVISIONSDK_H
#include"camerainterface.h"
#include"MvCameraControl.h"
#include "HalconCpp.h"
#include "HDevThread.h"
#include <QImage>
using namespace HalconCpp;
class HikvisionSDK:public CameraInterface
{
public:HikvisionSDK();~HikvisionSDK();// ch:连接设备//int connectCamera(std::string id);int connectCamera(int id);//设置是否为触发模式int setTriggerMode(unsigned int TriggerModeNum);//开启相机采集int startCamera();//关闭相机采集int stopCamera();//关闭相机int closeCamera();//软触发int softTrigger();//读取bufferint ReadBuffer(HObject &image);//设置图像高度int setHeight(unsigned int height);//设置图像ROI宽度int setWidth(unsigned int width);//获取图像高度值int getHeight();//获取图像宽度值int getWidth();//获取相机曝光时间float getExposureTime();//设置图像水平偏移OffsetXint setOffsetX(unsigned int offsetX);//设置图像竖直偏移OffsetYint setOffsetY(unsigned int offsetY);//设置触发源int setTriggerSource(unsigned int TriggerSourceNum);//设置帧率控制使能int setFrameRateEnable(bool comm);//设置心跳时间int setHeartBeatTime(unsigned int time);//设置曝光时间int setExposureTime(float ExposureTimeNum);//设置增益int setGain(float Gain);//关闭自动曝光int setExposureAuto(bool exposureAutoFlag);//关闭自动增益int setGainAuto(bool gainAutoFlag);//清理相机缓存void clearBuffer();bool QImage2HObject(QImage &qImg, HObject &hImg);private:void* m_hDevHandle;
public:// 用于保存图像的缓存unsigned int m_nBufSizeForSaveImage;// 用于从驱动获取图像的缓存unsigned int m_nBufSizeForDriver;
};#endif // HIKVISIONSDK_H
2.hikvisionsdk.cpp文件(海康相机各功能实现)
在读图相机中图像函数里面有个事件,此时需要找到自己相机的型号才能执行,要不然程序容易闪退
#include "hikvisionsdk.h"MV_CC_DEVICE_INFO_LIST m_stDevList; // ch:设备信息列表结构体变量,用来存储设备列表
MV_CC_DEVICE_INFO* m_Device=NULL; //设备对象#include <QDebug>
#include <QString>
#include <QDebug>
HikvisionSDK::HikvisionSDK()
{m_hDevHandle = NULL;
}HikvisionSDK::~HikvisionSDK()
{if (m_hDevHandle){MV_CC_DestroyHandle(m_hDevHandle);m_hDevHandle = NULL;}
}//连接相机
int HikvisionSDK::connectCamera(int id)
{// Enum deviceMV_CC_DEVICE_INFO_LIST stDeviceList;memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));int nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);if (nRet!=0){qDebug()<<"nRet:="<<nRet;return -1;}if (stDeviceList.nDeviceNum > 0){for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++){MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];if (NULL == pDeviceInfo){break;}}}else{return -1;}unsigned int nIndex = 0;// Select device and create handlenRet = MV_CC_CreateHandle(&m_hDevHandle, stDeviceList.pDeviceInfo[nIndex]);if (nRet!=0){//printf("Create Handle fail! nRet [0x%x]\n", nRet);return -1;}// open devicenRet = MV_CC_OpenDevice(m_hDevHandle);if (nRet!=0){//printf("Open Device fail! nRet [0x%x]\n", nRet);return -1;}return 0;
}//启动相机采集
int HikvisionSDK::startCamera()
{int tempValue=MV_CC_StartGrabbing(m_hDevHandle);if(tempValue!=0){return -1;}else{return 0;}
}//停止相机采集
int HikvisionSDK::stopCamera()
{int tempValue=MV_CC_StopGrabbing(m_hDevHandle);if(tempValue!=0){return -1;}else{return 0;}
}//关闭相机
int HikvisionSDK::closeCamera()
{if (NULL == m_hDevHandle){return -1;}MV_CC_CloseDevice(m_hDevHandle);int tempValue = MV_CC_DestroyHandle(m_hDevHandle);m_hDevHandle = NULL;if(tempValue!=0){return -1;}else{return 0;}
}//发送软触发
int HikvisionSDK::softTrigger()
{int tempValue= MV_CC_SetCommandValue(m_hDevHandle, "TriggerSoftware");if(tempValue!=0){return -1;}else{return 0;}
}//读取相机中的图像
int HikvisionSDK::ReadBuffer(HObject &halconImage)
{//Mat* getImage=new Mat();unsigned int nRecvBufSize = 0;MVCC_INTVALUE stParam;qDebug()<<"enter3";memset(&stParam, 0, sizeof(MVCC_INTVALUE));int tempValue = MV_CC_GetIntValue(m_hDevHandle, "PayloadSize", &stParam);qDebug()<<"enter4";if (tempValue != 0){return -1;}//分配一个指针的内存大小 , c语言的库函数 malloc;nRecvBufSize = stParam.nCurValue;//指针 图像接收数据的指针unsigned char* pDate;pDate=(unsigned char *)malloc(nRecvBufSize);qDebug()<<"enter41";//句柄 指针 nRecvBufSize 700 , 输出 (指针和图像信息的结构体)stImageInfo。MV_FRAME_OUT_INFO_EX stImageInfo = {0};tempValue= MV_CC_GetOneFrameTimeout(m_hDevHandle, pDate, nRecvBufSize, &stImageInfo, 700);if(tempValue!=0){return -1;}
// m_nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
// unsigned char* m_pBufForSaveImage;
// m_pBufForSaveImage = (unsigned char*)malloc(m_nBufSizeForSaveImage);qDebug()<<"enter42";bool isMono;//HObject halconImage;//stImageInfo.enPixelType//像素格式 的 stImageInfo ,switch 调整,switch (stImageInfo.enPixelType){case PixelType_Gvsp_Mono8:case PixelType_Gvsp_Mono10:case PixelType_Gvsp_Mono10_Packed:case PixelType_Gvsp_Mono12:case PixelType_Gvsp_Mono12_Packed:case 17301512:isMono=true;break;default:isMono=false;break;}if(isMono){//*getImage=Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC1,pDate);//imwrite("d:\\测试opencv_Mono.tif", image);qDebug()<<" stImageInfo.nHeight:"<< stImageInfo.nHeight;qDebug()<<" stImageInfo.nWidth:"<< stImageInfo.nWidth;qDebug()<<"pDate:"<<pDate;GenImage1(&halconImage, "byte", stImageInfo.nWidth,stImageInfo.nHeight,(Hlong)(pDate));//转换为hoject
// GenImage1(&hImg, "byte", tFrameInfo.iWidth, tFrameInfo.iHeight, (Hlong)m_pchImgBuffer[camId]);
// qDebug()<<"pDate11:"<<pDate;//WriteImage(halconImage, "png", 0, "./picture/halcon_Mono.png");}else{//转换图像格式为BGR8MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));stConvertParam.nWidth = stImageInfo.nWidth; //ch:图像宽 | en:image widthstConvertParam.nHeight = stImageInfo.nHeight; //ch:图像高 | en:image height//stConvertParam.pSrcData = m_pBufForDriver; //ch:输入数据缓存 | en:input data bufferstConvertParam.pSrcData = pDate; //ch:输入数据缓存 | en:input data bufferstConvertParam.nSrcDataLen = stImageInfo.nFrameLen; //ch:输入数据大小 | en:input data sizestConvertParam.enSrcPixelType = stImageInfo.enPixelType; //ch:输入像素格式 | en:input pixel formatstConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed; //ch:输出像素格式 | en:output pixel format 适用于OPENCV的图像格式//stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed; //ch:输出像素格式 | en:output pixel format//stConvertParam.pDstBuffer = m_pBufForSaveImage; //ch:输出数据缓存 | en:output data bufferstConvertParam.nDstBufferSize = m_nBufSizeForSaveImage; //ch:输出缓存大小 | en:output buffer sizeMV_CC_ConvertPixelType(m_hDevHandle, &stConvertParam);QImage img = QImage((const uchar*)pDate, stImageInfo.nWidth,stImageInfo.nHeight, QImage::Format_RGB888);QImage2HObject(img, halconImage);//QImage2HObject(img, hImg);//halconImage 输出 rgb hobject 格式的图像 。//因为 这里没有 图片 输出 所以 代码就奔溃了。//*getImage=Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC3,m_pBufForSaveImage);//imwrite("d:\\测试opencv_Color.tif", image);}//CopyImage(halconImage, &image);free(pDate);//free(m_pBufForSaveImage);return 0;
}//Qimage 转换成 hobject image
bool HikvisionSDK::QImage2HObject(QImage &qImg, HObject &hImg)
{try{if (qImg.isNull()) return false;int width = qImg.width();int height = qImg.height();QImage::Format format = qImg.format();if (format == QImage::Format_RGB32 ||format == QImage::Format_ARGB32 ||format == QImage::Format_ARGB32_Premultiplied){GenImageInterleaved(&hImg, Hlong(qImg.bits()), "bgrx", width, height, 0, "byte", width, height, 0, 0, 8, 0);}else if (format == QImage::Format_RGB888){GenImageInterleaved(&hImg, Hlong(qImg.bits()), "bgr", width, height, 0, "byte", width, height, 0, 0, 8, 0);}else if (format == QImage::Format_Grayscale8 || format == QImage::Format_Indexed8){GenImage1Extern(&hImg, "byte", width, height, Hlong(qImg.bits()), NULL);}}catch (const std::exception&){return false;}return true;
}//获取图像高度值
int HikvisionSDK::getHeight()
{MVCC_INTVALUE stParam;memset(&stParam, 0, sizeof(MVCC_INTVALUE));int tempValue=MV_CC_GetIntValue(m_hDevHandle, "Height", &stParam);int value= stParam.nCurValue;if(tempValue!=0){return -1;}else{return value;}
}//获取图像宽度值
int HikvisionSDK::getWidth()
{MVCC_INTVALUE stParam;memset(&stParam, 0, sizeof(MVCC_INTVALUE));int tempValue=MV_CC_GetIntValue(m_hDevHandle, "Width", &stParam);int value= stParam.nCurValue;if(tempValue!=0){return -1;}else{return value;}
}//获取相机曝光时间
float HikvisionSDK::getExposureTime()
{MVCC_FLOATVALUE stParam;memset(&stParam, 0, sizeof(MVCC_INTVALUE));int tempValue=MV_CC_GetFloatValue(m_hDevHandle, "ExposureTime", &stParam);float value= stParam.fCurValue;if(tempValue!=0){return -1;}else{return value;}
}//设置图像ROI高度
int HikvisionSDK::setHeight(unsigned int height)
{int tempValue=MV_CC_SetIntValue(m_hDevHandle, "Height", height);if(tempValue!=0){return -1;}else{return 0;}
}//设置图像ROI宽度
int HikvisionSDK::setWidth(unsigned int width)
{int tempValue=MV_CC_SetIntValue(m_hDevHandle, "Width", width);if(tempValue!=0){return -1;}else{return 0;}
}//设置图像水平偏移OffsetX
int HikvisionSDK::setOffsetX(unsigned int offsetX)
{int tempValue=MV_CC_SetIntValue(m_hDevHandle, "OffsetX", offsetX);if(tempValue!=0){return -1;}else{return 0;}
}//设置图像竖直偏移OffsetY
int HikvisionSDK::setOffsetY(unsigned int offsetY)
{int tempValue=MV_CC_SetIntValue(m_hDevHandle, "OffsetY", offsetY);if(tempValue!=0){return -1;}else{return 0;}
}//设置是否为触发模式
int HikvisionSDK::setTriggerMode(unsigned int TriggerModeNum)
{//0:Off 1:Onint tempValue= MV_CC_SetEnumValue(m_hDevHandle,"TriggerMode", TriggerModeNum);if(tempValue!=0){return -1;}else{return 0;}
}//设置触发源
int HikvisionSDK::setTriggerSource(unsigned int TriggerSourceNum)
{//0:Line0 1:Line1 7:Softwareint tempValue= MV_CC_SetEnumValue(m_hDevHandle,"TriggerSource", TriggerSourceNum);if(tempValue!=0){return -1;}else{return 0;}
}//设置帧率控制使能
int HikvisionSDK::setFrameRateEnable(bool comm)
{int tempValue =MV_CC_SetBoolValue(m_hDevHandle, "AcquisitionFrameRateEnable", comm);if (tempValue != 0){return -1;}else{return 0;}
}//设置心跳时间
int HikvisionSDK::setHeartBeatTime(unsigned int time)
{//心跳时间最小为500msif(time<500)time=500;int tempValue=MV_CC_SetIntValue(m_hDevHandle, "GevHeartbeatTimeout", time);if(tempValue!=0){return -1;}else{return 0;}
}//设置曝光时间
int HikvisionSDK::setExposureTime(float ExposureTimeNum)
{int tempValue= MV_CC_SetFloatValue(m_hDevHandle, "ExposureTime",ExposureTimeNum );if(tempValue!=0){return -1;}else{return 0;}
}//设置曝光时间
int HikvisionSDK::setGain(float Gain)
{int tempValue= MV_CC_SetFloatValue(m_hDevHandle, "Gain",Gain);if(tempValue!=0){return -1;}else{return 0;}
}//关闭自动曝光
int HikvisionSDK::setExposureAuto(bool exposureAutoFlag)
{int tempValue= MV_CC_SetEnumValue(m_hDevHandle,"ExposureAuto", exposureAutoFlag);if (tempValue != 0){return -1;}else{return 0;}
}//关闭自动增益
int HikvisionSDK::setGainAuto(bool gainAutoFlag)
{int tempValue= MV_CC_SetEnumValue(m_hDevHandle,"GainAuto", gainAutoFlag);if (tempValue != 0){return -1;}else{return 0;}
}//清理相机缓存
void HikvisionSDK::clearBuffer()
{//stopCamera();//startCamera();
}
4.在主程序相机实例化
1.首先包含公共相机和海康相机的头文件
2.用公共相机接口去实例化海康相机
.h主文件
private:
//相机指针CameraInterface * camera=NULL;
.cpp主文件
camera=new HikvisionSDK();用公共相机接口实例化海康相机类
析构函数中
if(camera!=NULL){delete camera;camera=NULL;}
5.连接相机
1.在IU界面下添加连接相机按钮转到槽函数
//连接相机
void MainWindow::on_btn_Connect_clicked()
{//初始化相机句柄if(camera!=NULL){delete camera;camera=NULL;}qDebug()<<111;if(camera==NULL){qDebug()<<112;InitCam();//连接相机函数//控制按钮是否可以按下ui->btn_Close->setEnabled(false);ui->btn_Connect->setEnabled(false);ui->btn_Trigger->setEnabled(true);ui->lxcj->setEnabled(true);ui->StopAcquisition->setEnabled(true);}}
2.连接相机函数实现
注意:次函数是实例化具体的相机(因为在项目中可能用到不同类型的相机,所以在头文件首先用公共相机接口)然后在具体的连接相机下面去实例化具体的相机类型对象。
最后一行程序,是把这个具体的海康相机对象通过传参,传入到线程类中去。
void MainWindow::InitCam()
{camera=new HikvisionSDK();此时用到了上面提到的海康相机实例化//连接相机//std::cout<<"Connect: "<<camera->connectCamera(1)<<std::endl;int ret=camera->connectCamera(1);if(ret!=0){//失败//QMessageBox::warning()}//设置为触发模式 打开std::cout<<"TriggerMode: "<<camera->setTriggerMode(1)<<std::endl;//设置触发源为软触发std::cout<<"TriggerSource: "<<camera->setTriggerSource(7)<<std::endl;//设置曝光时间std::cout<<"SetExposureTime: "<<camera->setExposureTime(40000)<<std::endl;//开启相机采集std::cout<<"StartCamera: "<<camera->startCamera()<<std::endl;myThread->getCameraPtr(camera);//把实例化后的海康相机类传入到线程中去//myThread->getImagePtr(myImage);}
6.定义线程类(mythread)
1.在线程里面需要包含公共相机的头文件
#include "QThread"//线程
#include "camerainterface.h"//公共相机接口
#include <QImage>
2.头文件定义接收海康相机类的函数
void getCameraPtr(CameraInterface* camera);
3..cpp文件具体实现
//析构函数
MyThread::~MyThread()
{if(cameraPtr==NULL){delete cameraPtr;}
}//具体实现
void MyThread::getCameraPtr(CameraInterface *camera)
{cameraPtr=camera;
}
7.单次采集
1.在IU界面添加单次采集按钮转跳槽函数
2.需要在主头文件中,private: 下面去声明 bool IsRun = false;(目的是为了更好的调节相机采图启停,方便后续操作(在这里可以不用))
3.转到线程中,去执行停止线程工作内容(因为单次采集不需要启动线程)
//单次采集
void MainWindow::on_btn_Trigger_clicked()
{HObject image;HTuple hv_Width,hv_Height;IsRun =true;//单次采图状态myThread->ChangeCloseStatus();//线程状态启停std::cout<<"TriggerMode: "<<camera->setTriggerMode(1)<<std::endl;std::cout<<"SoftTrigger: "<<camera->softTrigger()<<std::endl;//读取Mat格式的图像qDebug()<<"enter1";camera->ReadBuffer(image); //相机类里面的读图函数CopyImage(image, &halconImage);if(ui->checkBox_saveImage->isChecked()){//保存图像QString path="./data/"+QString::number(ui->sB_Num->value())+".png";WriteImage(halconImage, "png", 0, HTuple(path.toLatin1().data()));}GetImageSize(image, &hv_Width, &hv_Height);SetPart(WindowHandle, 0, 0, hv_Height,hv_Width); // 1944 2592qDebug()<<"enter2";DispObj(halconImage, WindowHandle);//其它图像处理功能//m_pMeasure01->OutMeasure01(halconImage);
}
4.在线程类中,.h的public:下定义 bool Status=false;
同时定义线程状态启停函数
void ChangeCloseStatus();//关闭void ChangeOpenStatus();//打开.cpp文件void MyThread::ChangeCloseStatus()
{Status=false;//qDebug()<<"Status:="<<Status;
}void MyThread::ChangeOpenStatus()
{Status=true;//qDebug()<<"Status:="<<Status;
}
8.连续采集
1.此时需要利用线程进行连续图像采集,需要在主程序中实例化线程类(应该在一开始就实例化)
//线程对象MyThread* myThread=NULL;
// 线程对象实例化myThread = new MyThread();
if(myThread!=NULL){delete myThread;myThread=NULL;}
2.在IU界面上添加连续采集按钮转到槽函数
void MainWindow::on_lxcj_clicked()
{std::cout<<"TriggerMode: "<<camera->setTriggerMode(0)<<std::endl;myThread->ChangeOpenStatus();//打开线程工作内容if(!IsRun)//判断单次采集是否打开{IsRun = false;关闭单次采集myThread->start();//开启连续彩图线程}else{IsRun = false;//关闭单次采集myThread->start();//开启连续彩图线程}
}
3.在线程类里面
.h文件
void run();//定义run函数(线程里的工作内容)void display( HObject imagePtr);//(用来其它作用显示)signals:void CaptureImage(HObject);//定义一个发送图像的信号
.cpp文件
void MyThread::run()
{if(cameraPtr==NULL){return;}while(!isInterruptionRequested()){if(Status) //判断是否停止的状态{qDebug()<<"thread current" <<currentThread();std::cout<<"Thread_Trigger:"<<cameraPtr->softTrigger()<<std::endl;HObject image;//读取Mat格式的图像cameraPtr->ReadBuffer(image);emit CaptureImage(image);//发送图像信号msleep(100);}}
}
void MyThread::display( HObject imagePtr)
{//qDebug()<<"Enter2";//std::cout<<"so"<<std::endl;//判断是黑白、彩色图像DispObj((imagePtr), WindowHandle);QString path="./picture/halcon"+QString::number(1)+".png";//WriteImage((*imagePtr), "png", 0, HTuple(path.toLatin1().data()));//int num=ui->sB_Num->value();//ui->sB_Num->setValue(num+1);
}
4.在线程中发送图像信号之后,需要在主函数中去接收这个图像信号
//信号与槽connect(myThread,SIGNAL(CaptureImage(HObject)),this,SLOT(ImageProcess01(HObject)),\Qt::BlockingQueuedConnection);//信号槽函数 。必须display 是slot
private slots://显示连续图像,接收槽函数void ImageProcess01(HObject image); //信号槽函数 --收到图像之后的 图像处理槽函数
//槽函数接收显示图像
void MainWindow::ImageProcess01(HObject halconImage)
{HTuple hv_Width,hv_Height;qDebug()<<"Enter1";GetImageSize(halconImage, &hv_Width, &hv_Height);SetPart(WindowHandle, 0, 0, hv_Height,hv_Width); // 1944 2592display(halconImage);m_pMeasure01->OutMeasure01(halconImage); //输出一个宽度//tuple -length ,length ==1 识别 成功//TCP 服务器 发给客户端 ,一个字符串。myThread->ChangeOpenStatus();//采图 收到图像处理完的信号,可以启动继续采图。同步采集!qDebug()<<"Enter2";}
9.停止采集
void MainWindow::on_StopAcquisition_clicked()
{myThread->ChangeCloseStatus();//停止线程状态ui->btn_Close->setEnabled(true);if(IsRun){myThread->requestInterruption();myThread->wait();//线程等待IsRun =false;//单次采集关闭// camera->stopCamera();// camera->closeCamera();}
}
10.关闭相机
void MainWindow::on_btn_Close_clicked()
{ui->btn_Trigger->setEnabled(false);ui->lxcj->setEnabled(false);ui->StopAcquisition->setEnabled(false);if(camera!=NULL){myThread->requestInterruption();camera->closeCamera();}//ui->Image_Label->clear();ui->btn_Connect->setEnabled(true);}
11.保存图像
void MainWindow::on_saveImage_clicked()
{QString filePath ="./data/picture/"+ QDateTime::currentDateTime().toString("yyyy-MM-dd");HTuple file1=HTuple(filePath.toStdString().c_str());WriteImage(halconImage, "bmp", 0, file1);//ui->textBrowser_log->append("write image success.");
}
12.设置曝光、增益
//曝光
void MainWindow::on_pB_exposTime_clicked()
{int exposTime=ui->sB_exposure->value();int ret=camera->setExposureTime(exposTime);qDebug()<<"ret:="<<ret;
}//增益
void MainWindow::on_pB_setGain_clicked()
{int Gain =ui->sB_Gain->value();int ret=camera->setGain(Gain);qDebug()<<"ret:="<<ret;
}
13.保存参数
//把界面的参数 固化 到 本地文件
void Measure01::on_pB_saveParameters_clicked()
{/*AmplitudeThreshold = 23;RoiWidthLen = 67;Alpha1 = 3.4;LineRowStart = 879.281;LineColumnStart = 1436.34;LineRowEnd = 1769.58;LineColumnEnd = 3055.55;*///把界面的参数 赋值 给局部作用域的变量MeasureParam01.AmplitudeThreshold=ui->SpinBox_AmpThre->value();MeasureParam01.Alpha1=ui->SpinBox_Alpha1->value();MeasureParam01.RoiWidthLen=ui->SpinBox_RoiWidthLen->value();MeasureParam01.LineRowStart=ui->SpinBox_LineRowStart->value();MeasureParam01.LineColumnStart=ui->SpinBox_LineColumnStart->value();MeasureParam01.LineRowEnd=ui->SpinBox_LineRowEnd->value();MeasureParam01.LineColumnEnd=ui->SpinBox_LineColumnEnd->value();//再通过qsetting的方法 把参数保存到qt 本地的 文件中去SaveSetting(CONFIG_FILEPATH,"Measure01","AmplitudeThreshold",\QVariant(MeasureParam01.AmplitudeThreshold));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","Alpha1",\QVariant(MeasureParam01.Alpha1));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","RoiWidthLen",\QVariant(MeasureParam01.RoiWidthLen));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","LineRowStart",\QVariant(MeasureParam01.LineRowStart));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","LineColumnStart",\QVariant(MeasureParam01.LineColumnStart));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","LineRowEnd",\QVariant(MeasureParam01.LineRowEnd));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","LineColumnEnd",\QVariant(MeasureParam01.LineColumnEnd));//AmpThre}
14.加载参数
构造函数里面
// //把界面的参数 赋值 给局部作用域的变量//double AmpThre=ui->SpinBox_AmpThre->value();//再通过qsetting的方法 把参数保存到qt 本地的 文件中去//SaveSetting(CONFIG_FILEPATH,"Measure01","AmplitudeThreshold",QVariant(AmpThre));//AmpThreQVariant ValueAmpThre;QVariant ValueAlpha1;QVariant ValueRoiWidthLen;QVariant ValueRowStart;QVariant ValueColumnStart;QVariant ValueRowEnd;QVariant ValueColumnEnd;LoadSetting(CONFIG_FILEPATH,"Measure01","AmplitudeThreshold",ValueAmpThre);LoadSetting(CONFIG_FILEPATH,"Measure01","Alpha1",ValueAlpha1);//AmpThreLoadSetting(CONFIG_FILEPATH,"Measure01","RoiWidthLen",ValueRoiWidthLen);//AmpThreLoadSetting(CONFIG_FILEPATH,"Measure01","LineRowStart",ValueRowStart);//AmpThreLoadSetting(CONFIG_FILEPATH,"Measure01","LineColumnStart",ValueColumnStart);//AmpThreLoadSetting(CONFIG_FILEPATH,"Measure01","LineRowEnd",ValueRowEnd);//AmpThreLoadSetting(CONFIG_FILEPATH,"Measure01","LineColumnEnd",ValueColumnEnd);//AmpThre//把QVariant 类型 转换 double 类型MeasureParam01.AmplitudeThreshold=ValueAmpThre.toDouble();MeasureParam01.Alpha1=ValueAlpha1.toDouble();MeasureParam01.RoiWidthLen=ValueRoiWidthLen.toDouble();MeasureParam01.LineRowStart=ValueRowStart.toDouble();MeasureParam01.LineColumnStart=ValueColumnStart.toDouble();MeasureParam01.LineRowEnd=ValueRowEnd.toDouble();MeasureParam01.LineColumnEnd=ValueColumnEnd.toDouble();ui->SpinBox_AmpThre->setValue(MeasureParam01.AmplitudeThreshold);ui->SpinBox_Alpha1->setValue(MeasureParam01.Alpha1);ui->SpinBox_RoiWidthLen->setValue(MeasureParam01.RoiWidthLen);ui->SpinBox_LineRowStart->setValue(MeasureParam01.LineRowStart);ui->SpinBox_LineColumnStart->setValue(MeasureParam01.LineColumnStart);ui->SpinBox_LineRowEnd->setValue(MeasureParam01.LineRowEnd);ui->SpinBox_LineColumnEnd->setValue(MeasureParam01.LineColumnEnd);ui->SpinBox_AmpThre->setStyleSheet("background-color: green");
15.日志类(lxlog)
.h
#ifndef __LX_LOG_H__
#define __LX_LOG_H__#include<QString>
#include <QTextBrowser>void WriteLog(QString LogType, QString str);
void MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);#endif
.cpp
#include "lxlog.h"
#include "paramsconfig.h"
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QTextBrowser>extern QTextBrowser * g_pTb;void WriteLog(QString LogType, QString str)
{//文件名QString filePath = QString(LOG_PATH) + '/'+ QDateTime::currentDateTime().toString("yyyy-MM-dd")+".log";//时间QString strToWrite = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");//类型strToWrite.append(QString(" %1 ").arg(LogType));//信息strToWrite.append(QString("%1").arg(str));QFile file(filePath);file.open(QIODevice::WriteOnly | QIODevice::Append);QTextStream text_stream(&file);text_stream << strToWrite << "\r\n";file.flush();file.close();g_pTb->append(strToWrite);
}void MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{QString txtMessage = "";QString messageType = "";switch (type) {case QtDebugMsg: //调试信息提示messageType = "Debug";txtMessage = QString("Debug: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);break;case QtInfoMsg:messageType = "Info";txtMessage = QString("Warning: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);break;case QtWarningMsg: //一般的warning提示messageType = "Waring";txtMessage = QString("Warning: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);break;case QtCriticalMsg: //严重错误提示messageType = "Critical";txtMessage = QString("Critical: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);//PostErrorMessage(txtMessage, messageType);break;case QtFatalMsg: //致命错误提示messageType = "Fatal";txtMessage = QString("Fatal: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);abort();}WriteLog(txtMessage, messageType);
}
16.公共参数、结构体类(paramsconfig)
.h
#ifndef PARAMSCONFIG_H
#define PARAMSCONFIG_H#include <QString>
#include <QVariant>#define SYS_CONFIG_FILE "./data/sysConfig/params.ini"
#define USER_CONFIG_PATH "./data/userConfig"
#define LOG_PATH "./data/log"
#define TRAIN_FILEPATH "./data/train"
#define CALIB_DATA_PATH "data/calib"
#define IMG_DEPETH_FILEPATH "data/imageDepth"
#define IMG_RAW_FILEPATH "data/imageRaw"
#define MODEL_FILEPATH "data/model"
#define SENCE_FILEPATH "data/sence"
#define CONFIG_FILEPATH "data/config/params.ini"
#define CONFIG_Main_FILEPAT "data/config/my.ini"
#define CONFIG_Face_FILEPAT "data/config/Face.ini"
#define CONFIG_Box_FILEPAT "data/config/Box.ini"
#define CONFIG_CreatModel_FILEPAT "data/config/CreatModel.ini"#define POSE_TO_HTUPLE(pose, hTuple) {hTuple[0] = pose.x; hTuple[1] = pose.y; hTuple[2] = pose.z; hTuple[3] = pose.rx; hTuple[4] = pose.ry; hTuple[5] = pose.rz; hTuple[6] = 0.0;}
#define HTUPLE_TO_POSE(hTuple, pose) {pose.x = hTuple[0]; pose.y = hTuple[1]; pose.z = hTuple[2]; pose.rx = hTuple[3]; pose.ry = hTuple[4]; pose.rz = hTuple[5];}#define KD_PI 3.141592653
#define LENGTH_UNIT "mm"
#define LX_STATIONS_NUM 3 // 相机数量#include "HalconCpp.h"
using namespace HalconCpp;/*** measure*/
typedef struct
{double AmplitudeThreshold;double RoiWidthLen;double Alpha1;double LineRowStart;double LineColumnStart;double LineRowEnd;double LineColumnEnd;
}MeasureParam;/*** pose*/
typedef struct {double x; ///X偏移double y; ///Y偏移double z; ///Z偏移double rx; ///X旋转double ry; ///Y旋转double rz; ///Z旋转int type; ///姿态类型
} KD_POSE;/*** point select*/
typedef struct {double xMin; ///X范围double xMax; ///X范围double yMin; ///Y范围double yMax; ///Y范围double zMin; ///Z范围double zMax; ///Z范围int type; ///备用
} KD_POINT_SELECT;/*** 机械臂工具类型*/
typedef enum {ROT_TOOL_SUCKER = 0, ///吸盘ROT_POSE_GRIPPER_PNEUMATIC, ///夹具气动ROT_POSE_GRIPPER_ELECTRIC, ///夹具电动
}ROT_TOOL_TYPE;/*** 三维点云控制参数*/
typedef struct {KD_POSE calibPose; ///校正PoseKD_POINT_SELECT potSelc; ///范围限定
} KD_3D_CTRL; ///三维控制参数/*** 三维物体参数*/
typedef struct {KD_POSE * pObjChangePose; ///偏移poseunsigned int surfaceNum; ///面数double objGuideHigh; ///物体抓取引导高度
} KD_OBJECT_CTRL; ///三维控制参数/*** 3d匹配参数*/
typedef struct {double objectMaxLength; ///物体最大长度double sampleDis; ///采样距离double keyPotFraction; ///特征点最小得分double minScore; ///最小得分QString * modelFileName; ///模型文件名KD_POSE toolInFlangeCenter; ///工具在法兰盘中心(由机械臂标定得出)KD_POSE camInBase; ///相机在基础 (由halcon手眼标定得出)KD_POSE toolInObj; ///工具在物体 (由halcon手眼标定得出)KD_3D_CTRL bgInfo; ///背景抽取参数
} KD_SURFACE_MATCH_CTRL;/*** 机械臂参数*/
typedef struct {int speed; ///速度(测试用)double jointVelc; ///角速度double jointAcc; ///角加速度double lineVelc; ///线速度double lineAcc; ///线加速度int colliClass; ///防撞等级KD_POSE toolInFlangeCenter; ///工具在法兰盘中心
} KD_ROBOT_CTRL;/*** 机械臂码垛参数*/
typedef struct {KD_POSE oriPose; ///起始码垛姿态KD_POSE offsetPose; ///偏移码垛姿态int palletNum; ///码垛数量double palletSize; ///工件尺寸
} KD_ROBOT_PALLET_CTRL;/*** 机械臂运动参数*/
typedef struct {double doorHigh; ///门型高度int ioId; ///吸盘、夹具IO口int moveTime; ///机械臂从抓取到放置位置延时时间int doorUpDownTime; ///门型上下移动延时时间int suctionTime; ///吸盘、夹具延时时间KD_POSE halfWayPose; ///中途路点KD_ROBOT_PALLET_CTRL pallet; ///码垛参数ROT_TOOL_TYPE toolType; ///工具类型
} KD_ROBOT_MOVE_CTRL;typedef enum {UNINIT, //还未初始化RUNNING, //运行STOP //停止
}PROGRAM_STATUS;/**
* DO输出0
*/
typedef enum {KEY_RELEASE = 0,KEY1 = 1,KEY2 = 2,KEY3 = 4,KEYS = 8,KEYU = 16,KEYD = 32
}HC_KEY_TYPE;/**
* DO输出1
*/
typedef enum {DO_NONE = 0,DO_GUIDE1 = 1, // 推进DO_GUIDE2 = 2, // 推出DO_BUZZER = 4,DO_LIGHT = 8,DO_BACKUP1 = 16,DO_BACKUP2 = 32
}HC_DO_TYPE;/**
* DI输入
*/
typedef enum {DI_GUIDE1 = 1, // 推进状态DI_GUIDE2 = 2, // 推出状态DI_START = 4,DI_RESET = 8,DI_STOP = 16,DI_BACKUP = 32
}HC_DI_TYPE;/*** 矩形*/
typedef struct {int x;int y;int w;int h;
} LX_RECT;/*** 识别参数*/
typedef struct {LX_RECT roiRect; ///ROI区域int erosionVal; ///腐蚀参数int dilationVal; ///膨胀参数int noiseArea; ///噪声面积(小于该面积都被认为是噪声)int decimalPointArea; ///小数点面积double confidence; ///最低置信率QString trainFile; ///训练文件QString usrconfigFile; ///测试项目配置文件
} LX_RECOGNISE_CTRL;//LX_RECOGNISE_CTRL LX_RECOGNISE_CTRL1;
//LX_RECOGNISE_CTRL LX_RECOGNISE_CTRL2;
/*** 相机参数*/
typedef struct {int exposureTime;int exposureTimeMin;int exposureTimeMax;int gain;int gainMin;int gainMax;
// bool bMiroH;
// bool bMiroV;
} LX_CAMERA_CTRL;/*** io*/
typedef struct {QString key1Do; //io口IDQString key2Do; //io口IDQString key3Do; //io口IDQString keySDo; //io口IDQString keyUpDo; //io口IDQString keyDownDo; //io口IDQString keyBuzzerDo; //io口IDQString keyStartDi; //io口IDQString keyResetDi; //io口IDQString keyStopDi; //io口ID
} LX_IO_CTRL;/*** 初始化参数*/
typedef struct {int pressTime; ///按下时间QString defaultVal; ///初始值
} HC_INIT_CTRL;/*** 公英制参数*/
typedef struct {int unit; ///0为公制值, 1为英制
} HC_METRIC_IMPERIAL_CTRL;/*** 数字缺失*/
typedef struct {QString defaultVal; ///预设值
} HC_NUM_MISS_CTRL;/*** 记忆位*/
typedef struct {int pressTime; ///单次上升时间
} HC_MEMORY_POS_CTRL;/*** 陀螺仪*/
typedef struct {QString defaultVal; ///陀螺仪预设等级
} HC_GYRO_CTRL;/*** 上升下降锁*/
typedef struct {int pressTime; ///按下时间
} HC_LOCK_CTRL;/*** 异常码*/
//typedef struct {
// int pressTimeE05; ///E05按下时间
//}HC_EXCEPTION_CTRL;/*** 手控器检测和预设参数*/
typedef struct {HC_INIT_CTRL initCtrl;HC_METRIC_IMPERIAL_CTRL metricImperialCtrl;HC_NUM_MISS_CTRL numMisCtrl;HC_MEMORY_POS_CTRL memoryPosCtrl;HC_GYRO_CTRL gyroCtrl;HC_LOCK_CTRL lockCtrl;int testItem; //测试项int workStationId;
} LX_HC_CTRL;/***2d模板匹配的预设参数*/typedef struct {double OffsetRow;double OffsetColumn;double TPhi;double TLength1;double TLength2;int m_nModecase; // =1HTuple ModelID;HObject ShapeModel;
} LX_MATCH_CTRL;//保存加载配置
void SaveSetting(QString fileName, QString group, QString key, QVariant value);
void LoadSetting(QString fileName, QString group, QString key, QVariant &value);//保存加载识别配置
void SaveRecogniseCtrl(QString fileName, QString group, LX_RECOGNISE_CTRL recCtrl);
void LoadRecogniseCtrl(QString fileName, QString group, LX_RECOGNISE_CTRL &recCtrl);//保存加载IO配置
void SaveIoCtrl(QString fileName, QString group, LX_IO_CTRL ioCtrl);
void LoadIoCtrl(QString fileName, QString group, LX_IO_CTRL &ioCtrl);//保存加载相机配置
void SaveCameraCtrl(QString fileName, QString group, LX_CAMERA_CTRL camCtrl);
void LoadCameraCtrl(QString fileName, QString group, LX_CAMERA_CTRL &camCtrl);//保存加载手控器配置
void SaveHandCtrlerCtrl(QString fileName, QString group, LX_HC_CTRL hcCtrl);
void LoadHandCtrlerCtrl(QString fileName, QString group, LX_HC_CTRL &hcCtrl);//保存相机的 产品唯一序列号和工位
void SaveCameraAscn(QString fileName, QString Key,QString CameraNumber );
void LoadCameraAscn(QString fileName, QString Key,QString &CameraNumber );double AngleToRad(double angle);
double RadToAngle(double rad);//保存pose
void SavePose(QString group, KD_POSE pose);//加载pose
void LoadPose(QString group, KD_POSE &pose);class paramsConfig
{
public:paramsConfig();
};#endif // PARAMSCONFIG_H
.cpp
#include "paramsconfig.h"
#include <QSettings>
#include <QDebug>paramsConfig::paramsConfig()
{}void SaveRecogniseCtrl(QString fileName, QString group, LX_RECOGNISE_CTRL recCtrl)
{}void SaveCameraCtrl(QString fileName, QString group, LX_CAMERA_CTRL camCtrl)
{ // 淇濆瓨鍔犺浇鐩告満閰嶇疆SaveSetting(fileName, group, "exposureTime", QVariant(camCtrl.exposureTime));SaveSetting(fileName, group, "gain", QVariant(camCtrl.gain));SaveSetting(fileName, group, "gainMin", QVariant(camCtrl.gainMin));SaveSetting(fileName, group, "gainMax", QVariant(camCtrl.gainMax));SaveSetting(fileName, group, "exposureTimeMin", QVariant(camCtrl.exposureTimeMin));SaveSetting(fileName, group, "exposureTimeMax", QVariant(camCtrl.exposureTimeMax));
}void LoadCameraCtrl(QString fileName, QString group, LX_CAMERA_CTRL &camCtrl)
{ // 鍔犺浇鐩告満閰嶇疆QVariant qexposureTime;QVariant qexposureTimeMin;QVariant qexposureTimeMax;QVariant qGain;QVariant qGainMin;QVariant qGainMax;LoadSetting(fileName, group, "exposureTime", qexposureTime);LoadSetting(fileName, group, "exposureTimeMin", qexposureTimeMin);LoadSetting(fileName, group, "exposureTimeMax", qexposureTimeMax);LoadSetting(fileName, group, "gain", qGain);LoadSetting(fileName, group, "gainMin", qGainMin);LoadSetting(fileName, group, "gainMax", qGainMax);camCtrl.exposureTime = qexposureTime.toInt();camCtrl.exposureTimeMin = qexposureTimeMin.toInt();camCtrl.exposureTimeMax = qexposureTimeMax.toInt();camCtrl.gain = qGain.toInt();camCtrl.gainMin = qGainMin.toInt();camCtrl.gainMax = qGainMax.toInt();
// qDebug()<<"camCtrl.gain"<<camCtrl.gain;
// qDebug()<<"camCtrl.qexposureTime:+"<<camCtrl.exposureTime;
}void SaveHandCtrlerCtrl(QString fileName, QString group, LX_HC_CTRL hcCtrl)
{}void LoadCameraAscn(QString fileName, QString Key, QString &CameraNumber)
{QString group = "CameraManage";QVariant ValueCameraNumber;LoadSetting(fileName,group,Key,ValueCameraNumber);CameraNumber = ValueCameraNumber.toString();qDebug() << "CameraName:= " << CameraNumber;
}void LoadSetting(QString fileName, QString group, QString key, QVariant &value)
{QSettings settings(fileName,QSettings::IniFormat);if(group.size() != 0){settings.beginGroup(group);}value = settings.value(key);if(group.size() != 0){settings.endGroup();}
}void SaveSetting(QString fileName, QString group, QString key, QVariant value)
{QSettings settings(fileName, QSettings::IniFormat);if (group.size() != 0) {settings.beginGroup(group);}settings.setValue(key, value);if (group.size() != 0) {settings.endGroup();}
}void SavePose(QString group, KD_POSE pose)
{}
已经看到这里了,点个赞和关注吧!
刚开始写文章,如有不足请多多包含;之后会持续更新关于(halcon学习,VS联合编程,QT联合编程,C++,C#,Opencv图像处理库,三维点云库pcl,相机以及机器人的二次开发)等系统化学习文章。
相关文章:
3:QT联合HALCON编程—海康相机SDK二次程序开发
思路: 1.定义带UI界面的主函数类 1.1在主函数中包含其它所有类头文件,进行声明和实例化;使用相机时,是用公共相机的接口在某一个具体函数中去实例化具体的海康相机对象。 1.2设计界面:连接相机,单次采集&a…...
图论---LCA(倍增法)
预处理 O( n logn ),查询O( log n ) #include<bits/stdc.h> using namespace std; typedef pair<int,int> pii; const int N40010,M2*N;//是无向边,边需要见两边int n,m; vector<int> g[N]; //2的幂次范围 0~15 int depth[N],fa[N][1…...
Bento4的安装和简单转码
1.下载Bento4 2解压复制到安装位置 3配置环境变量 在path下配置 5.视频转码为Dash 视频分片化 mp4fragment --track video --fragment-duration 4000 C:\Users\zcc\Downloads\Video\gg.mp4 C:\Users\zcc\Downloads\Video\out3\input_fragmented.mp4分片化的视频转码为dash…...
用python写一个相机选型的简易程序
最近有点忙,上来写的时间不多。 今天就把之前写的一个选型的简易程序,供大家参考。 代码: import sys from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QLabel, QLineEdit, QPushButton, QGro…...
论人际关系发展的阶段
朋友关系的建立和发展是一个渐进的过程,通常需要经历情感积累、信任磨合和价值观融合等阶段。以下是朋友关系发展的详细阶段划分及核心特征: 一、表层接触阶段(社交试探期) 核心特征:以信息交换为主,关系停…...
2软考系统架构设计师:第一章系统架构概述 - 练习题附答案及超详细解析
第一章系统架构概述综合知识单选题 每道题均附有答案解析: 1. 系统架构的核心定义是什么? A. 系统代码的实现细节 B. 系统组件、组件关系及与环境交互的高层次设计蓝图 C. 用户界面的设计规范 D. 数据库表结构的详细设计 答案:B 解析&…...
华为OD机试真题——素数之积RSA加密算法(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录…...
k8s中资源的介绍及标准资源namespaces实践
文章目录 第1章 k8s中的资源(resources)介绍1.1 k8s中资源(resouces)的分类1.2 k8s中资源(resources)的级别1.3 k8s中资源(resources)的API规范1.4 k8s中资源(resources)的manifests 第2章 k8s中的标准资源之namespaces的实践2.1 基本介绍2.2 编写相关ns资源对象的manifests2.3…...
k8s学习记录(四):节点亲和性
一、前言 在上一篇文章里,我们了解了 Pod 中的nodeName和nodeSelector这两个属性,通过它们能够指定 Pod 调度到哪个 Node 上。今天,我们将进一步深入探索 Pod 相关知识。这部分内容不仅信息量较大,理解起来也有一定难度࿰…...
联想笔记本电脑在Windows下通过联想驱动实现风扇控制
概述 本文旨在解决部分联想笔记本电脑无法使用主流的风扇控制工具(如Fan Control, SpeedFan)控制风扇的问题。主流的风扇控制工具在这些电脑上会因无法找到控制风扇的EC寄存器而无法发挥作用。但这是不是就意味着没办法控制风扇了呢?答案是否…...
Java单链表题目
Java链表题目练习 移除链表元素反转单链表链表的中间节点返回倒数第K个节点合并两个有序列表判断链表是否回文 学习了知识,就要进行其检验自己是否真正学会,练习题目来加强对知识的理解,今天就来练习一下链表题目 移除链表元素 目的ÿ…...
springboot入门-controller层
在 Spring Boot 中,Controller 层是处理 HTTP 请求的核心组件,负责接收客户端请求、调用业务逻辑(Service 层)并返回响应。其核心原理基于 Spring MVC 框架,通过注解驱动的方式实现请求的路由和参数绑定。以下是 Contr…...
游戏引擎学习第245天:wglChoosePixelFormatARB
Blackboard: PBO(像素缓冲对象) 我们将一起编写一个完整的游戏。老实说,我原本以为我们会花更长时间来实现异步纹理上传,结果我们只用了两天时间,主要原因是我们没有设置标志来真正告诉程序下载纹理,所以这…...
中国大陆DNS服务选择指南:阿里云VS AWS,合规性与最佳实践
导语 在中国大陆开展互联网业务时,DNS服务的选择不仅关乎性能,更涉及合规性问题。本文将深入探讨DNS服务商选择的自由度、阿里云与AWS DNS服务的优劣势,以及如何在确保合规的同时优化您的域名解析策略。无论您是初创公司还是跨国企业,这份指南都将助您在复杂的中国互联网环境中…...
LLaMa Factory大模型微调
LLaMa Factory大模型微调 大模型微调平台&硬件LLaMA-Factory安装hfd下载hugging face模型自我认知微调Alpaca数据集指令监督微调断点续训 大模型微调 微调自我认知微调特定领域数据集。 平台&硬件 Ubuntu20.04显卡:M40 24G 2080TI 22G微调框架ÿ…...
git和github的使用指南
目录 1.git初始化本地仓库 2.远程仓库 3.如何将自己的代码上传到远程仓库的某一个分支 1.git初始化本地仓库 在项目目录中初始化 Git 仓库: cd your-project-directory git init 将文件添加到暂存区: git add . //添加所有文件 git add <fi…...
如何快速轻松地恢复未保存的 Word 文档:简短指南
文字处理器已经存在了几十年,其中许多已经变得非常擅长防止问题。丢失未保存的数据是一个常见问题,因此办公软件通常带有恢复文件的方法。在本文中,我们将介绍如何恢复 Word 文档,即使您尚未保存它。 确保数据安全的最佳方法是保…...
【Linux网络】打造初级网络计算器 - 从协议设计到服务实现
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
基于STM32定时器中断讲解(HAL库)
基于STM32定时器中断讲解(HAL库) 1、定时器简单介绍 以STM32F103C8T6中几个定时器为例: TIM1:这是一个高级定时器,不仅具备基本的定时中断功能,还拥有内外时钟源选择、输入捕获、输出比较、编码器接口以…...
《Vue3学习手记5》
pinia 共享的数据交给集中状态管理 引入与使用 //main.ts // 引入Pinia import {createPinia} from "pinia"const piniacreatePinia() app.use(pinia)案例: <template><div class"count"><h2>当前和为:{{ sum…...
MySQL多查询条件下深度分页性能优化技巧及示例总结
深度分页(Deep Pagination)是MySQL中常见的性能瓶颈问题,特别是在多查询条件下,当offset值很大时,查询性能会急剧下降。本文将总结多种优化技巧,并提供实际示例。 一、深度分页的性能问题分析 当执行类似SELECT * FROM table WHERE condition1 AND condition2 LIMIT 1000…...
3、初识RabbitMQ
界面上的导航栏共分6部分,分别代表不同的意思 一、Producer和Consumer Producer: 生产者, 是RabbitMQ Server的客户端, 向RabbitMQ发送消息 Consumer: 消费者, 也是RabbitMQ Server的客⼾端, 从RabbitMQ接收消息 Broker:其实就是RabbitMQ Server, 主要…...
量子计算与GPU的异构加速:基于CUDA Quantum的混合编程实践
一、量子模拟的算力困境与GPU破局 量子计算模拟面临指数级增长的资源需求:n个量子比特的态向量需要存储2^n个复数。当n>30时,单机内存已无法承载(1TB需求)。传统CPU模拟器(如Qiskit Aer)在n28时计算…...
在Spring Boot项目中实现Word转PDF并预览
在Spring Boot项目中实现Word转PDF并进行前端网页预览,你可以使用Apache POI来读取Word文件,iText或Apache PDFBox来生成PDF文件,然后通过Spring Boot控制器提供文件下载或预览链接。以下是一个示例实现步骤和代码: 1. 添加依赖 …...
Windows怎样使用curl下载文件
安装curl 从官网下载:访问curl官方网站,根据系统位数(32 位或 64 位)选择相应的版本进行下载。下载完成后,双击安装程序并按照提示进行安装。也可以选择自定义安装路径,记住安装路径,后续配置环…...
priority_queue的学习
priority_queue的介绍 优先级队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。优先队列被…...
浅谈Java 内存管理:栈与堆,垃圾回收
在Java编程世界里,内存管理是一项极为关键的技能,它就像程序运行背后的“隐形守护者”,默默影响着程序的性能与稳定性。今天,咱们就来简单学习一下Java内存管理中的两大核心要点:栈与堆的内存分配机制,以及…...
windows下查看idea运行的进程占的JVM情况工具
jconsole 查看JVM 查看线程数 自己测试时,可以先不把线程关闭查效果。 也可以用这工具查下是不是有线程一直在增加。...
【新技术】微软 Azure Test Impact Analyzer (TIA) 全面解析
目录 一、什么是 Azure Test Impact Analyzer?二、核心功能与优势三、如何掌握 Azure TIA?四、工作中的典型应用场景五、最佳实践与注意事项六、总结 一、什么是 Azure Test Impact Analyzer? Azure Test Impact Analyzer (TIA) 是微软 Azur…...
JAVA服务内存缓慢上涨,年轻代GC正常但Full GC频繁,如何定位?
1. 分析 : 年轻代GC正常,说明年轻代的对象回收没有问题,可能大部分对象都是朝生夕死的,所以Minor GC能有效清理。但Full GC频繁,通常意味着老年代空间不足,导致频繁进行Full GC来回收老年代。而内存缓慢上…...
浏览器界面无显示,提示“代理服务器可能有问题”,这是怎么回事呢?
前言 🌟🌟本期讲解浏览器代理服务器解决办法介绍~~~ 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 🔥 你的点赞就是小编不断更新的最大动力 🎆那么废话不…...
C#中的弱引用使用
弱引用(Weak Reference)是一种特殊的引用类型,它允许你引用一个对象,但不会阻止该对象被垃圾回收器(GC)回收。弱引用通常用于需要缓存或跟踪对象,但又不希望因保留引用而导致内存泄漏的场景。弱…...
在Linux虚拟机下使用vscode,#include无法跳转问题
总结:需要通过Linux指令来添加编译器和压缩文件,解压,这样获得的编译器会具有可执行权限类似于 -rwxr-xr-x 1 user user 12345 Apr 26 14:22 myscript.sh 如果你直接从window中拖入文件到Linux文件下,你需要自己来再度开启可编译…...
MIL、SIL、HIL与Back-to-Back测试详解:从模型到硬件的完整验证链
1. 引言 在嵌入式系统和控制算法开发中,MIL、SIL、HIL和Back-to-Back测试构成了从模型设计到硬件部署的完整验证流程。它们覆盖不同开发阶段,确保系统功能正确性、实时性和可靠性。 本文将清晰解析这四种测试方法的核心概念、应用场景及差异。 2. 四种测…...
【Android Compose】焦点管理
官方文档链接: https://developer.android.google.cn/develop/ui/compose/touch-input/focus?hlzh-cn 1、更改焦点遍历顺序 1.1、替换一维遍历顺序 (1)创建焦点引用对象: /// 创建4个引用对象(二选一)…...
启动命令汇总(Redis / Kafka / Flume / Spark)
本文总结了本地开发环境(Windows系统)中启动推荐系统所需的所有组件命令,包括 Redis、Kafka、Flume 及 SparkStreaming 程序的启动流程。 1. 启动 Redis 进入 Redis 安装目录,执行: redis-server.exe测试连接&#x…...
python 画折线统计图
Python 画折线统计图(line chart)最常用的是 matplotlib。 最基本的折线图代码如下: import matplotlib.pyplot as plt# 假设这是你的数据 x [1, 2, 3, 4, 5] y [2, 3, 5, 7, 11]# 创建折线图 plt.plot(x, y, markero) # markero 是在点…...
java面向对象编程【高级篇】之继承
目录 🚀前言🤔什么是继承?🌟权限修饰符💯private 修饰符💯默认(无修饰符)💯protected 修饰符💯public 修饰符💯归纳 🦜继承的特点&…...
【数论分块】数论分块算法模板及真题
1.数论分块的含义 数论分块算法,就是枚举出使得取整函数发生变化的地方。 例如,对表达式 ⌊ n i ⌋ \lfloor \frac{n}{i} \rfloor ⌊in⌋使用数论分块算法,就可以在 O ( n ) O(\sqrt n) O(n )的时间复杂度下枚举所有满足 ⌊ n i − 1 ⌋…...
DIY 3D打印机 原理及步骤概况
一、3D打印机的基本原理 硬件组成: 运动系统:控制X/Y/Z轴的步进电机(或直线电机),决定打印头的移动精度。 热端(挤出机):加热并挤出材料(如PLA、ABS塑料)。 …...
深度探索:DeepSeek赋能WPS图表绘制
一、研究背景 在当今数字化信息爆炸的时代,数据处理与可视化分析已成为众多领域研究和决策的关键环节。随着数据量的急剧增长和数据维度的不断丰富,传统的数据可视化工具在应对复杂数据时逐渐显露出局限性。Excel作为广泛应用的电子表格软件,…...
内存四区(栈)
今天我再次学到了有趣的知识,内存四区! 内存四区分为代码区,全局区,栈区,堆区,今天我们详细来讲讲栈区! 内存四区和栈区都是用来存放数据的,而栈区存放的数据具体有两类 1.形参数…...
Nginx性能优化:从配置到缓存,全面提升Web服务器性能
一、基础配置优化:释放硬件潜能 进程与连接调优 worker_processes: 推荐设置为 auto(自动匹配CPU核心数),但在特殊场景下需手动优化:worker_processes 8; # 8核CPU手动指定 worker_cpu_affinity 000…...
系统架构设计(三):质量属性
常见分类 一般来说,质量属性可以分为以下几类: 类别常见质量属性性能相关响应时间、吞吐量、资源利用率、实时性、可扩展性可用性相关可用性、高可用性(HA)、可靠性、容错性、恢复性可维护性相关可维护性、可测试性、可扩展性、…...
C#中常见的设计模式
文章目录 引言设计模式的分类创建型模式 (Creational Patterns)1. 单例模式 (Singleton)2. 工厂方法模式 (Factory Method)3. 抽象工厂模式 (Abstract Factory)4. 建造者模式 (Builder) 结构型模式 (Structural Patterns)5. 适配器模式 (Adapter)6. 装饰器模式 (Decorator)7. 外…...
C# 枚举(Enum)声明与使用详解
在 C# 编程中,枚举(Enum)是一种非常实用的数据类型,它允许你定义一组具有名称的整型常量,使代码更具可读性和可维护性。枚举可以有效地替代使用硬编码数值,尤其是在处理状态、选项或标志时。本文将深入探讨…...
Linux-进程控制
目录 一、进程创建 1.1、fork()函数 1.2、fork的返回值 1.3、写实拷贝(Copy-on-Write,COW) 1.4、fork常规用法 1.5、fork调用失败的原因 二、进程退出 三、进程等待 1、wait和waitpid 1.1、解决僵尸进程问题 1.2、status参数 程序正…...
【优选算法 | 滑动窗口】滑动窗口算法:高效处理子数组和子串问题
算法相关知识点可以通过点击以下链接进行学习一起加油!双指针 在本篇文章中,我们将深入剖析滑动窗口算法的核心原理。从基础概念到实战应用,带你了解如何利用滑动窗口高效解决连续子数组和子串等问题。无论你是算法入门的新手,还是…...
RabbitMQ全栈实践手册:从零搭建消息中间件到SpringAMQP高阶玩法
目录 前言 认识MQ 同步调用 异步调用 技术选型 安装 SpringAMQP 交换机类型 队列交换机绑定 环境搭建 Fanout交换机 声明队列和交换机 消息发送 消息接收 总结 Direct交换机 声明队列和交换机 消息发送 消息接收 总结 Topic交换机 声明队列和交换机 消息…...
头歌实训之存储过程、函数与触发器
🌟 各位看官好,我是maomi_9526! 🌍 种一棵树最好是十年前,其次是现在! 🚀 今天来学习C语言的相关知识。 👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更…...