提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言 一、开发目的 二、项目框架 三、qt界面制作 四、截取界面 五、模板匹配 六、主函数 总结
前言
导师让干的活,要传给别人,记录一下自己的付出和成果
一、开发目的
由于某些企业的仪表盘界面,还需进行人工读取和记录,所以要使用程序来解放人民的双手。且由于电脑系统还是上古时代的产品,所以代码占用内存要非常小。
二、项目框架
1.仪表制作: 此小项目需要用qt制作界面,模拟某企业的仪表盘进行识别。
2.识别输入:采用微软提供的一组C++模板库来对qt界面进行截图,并作为识别的输入。
3.识别:采用opencv模板匹配进行识别,模板匹配简单易用,但对于旋转、缩放、光照变化等情况的鲁棒性较差。对于这些复杂情况,可能需要结合其他更高级的图像处理技术,如轮廓检测或深度学习等方法。
三、qt界面制作
ui->setupUi(this);
//this->resize(1440,900);
ui->lcdNumber_1->setDigitCount(4);
ui->lcdNumber_1->setStyleSheet("background:black;color:#4dff00;");
ui->lcdNumber_2->setDigitCount(4);
ui->lcdNumber_2->setStyleSheet("background:black;color:#4dff00;");
ui->lcdNumber_3->setDigitCount(4);
ui->lcdNumber_3->setStyleSheet("background:black;color:#4dff00;");
ui->lcdNumber_4->setDigitCount(4);
ui->lcdNumber_4->setStyleSheet("background:black;color:#4dff00;");
ui->lcdNumber_5->setDigitCount(4);
ui->lcdNumber_5->setStyleSheet("background:black;color:#ff0022;");
ui->lcdNumber_6->setDigitCount(4);
ui->lcdNumber_6->setStyleSheet("background:black;color:#ff0022;");
ui->lcdNumber_7->setDigitCount(4);
ui->lcdNumber_7->setStyleSheet("background:black;color:#ff0022;");
ui->lcdNumber_8->setDigitCount(4);
ui->lcdNumber_8->setStyleSheet("background:black;color:#ff0022;");
ui->lcdNumber_9->setDigitCount(4);
ui->lcdNumber_9->setStyleSheet("background:black;color:#4dff00;");
ui->lcdNumber_10->setDigitCount(4);
ui->lcdNumber_10->setStyleSheet("background:black;color:#4dff00;");
ui->lcdNumber_11->setDigitCount(4);
ui->lcdNumber_11->setStyleSheet("background:black;color:#4dff00;");
ui->lcdNumber_12->setDigitCount(4);
ui->lcdNumber_12->setStyleSheet("background:black;color:#4dff00;");
float num1,num2,num3,num4,num5,num6,num7,num8,num9,num10,num11,num12;
num1 = (qrand()%(40-10)+10)*0.4;
num2 = (qrand()%(40-10)+10)*0.4;
num3 = (qrand()%(40-10)+10)*0.4;
num4 = (qrand()%(40-10)+10)*0.4;
num5 = (qrand()%(40-10)+10)*0.4;
num6 = (qrand()%(40-10)+10)*0.4;
num7 = (qrand()%(40-10)+10)*0.4;
num8 = (qrand()%(40-10)+10)*0.4;
num9 = (qrand()%(40-10)+10)*0.4;
num10 = (qrand()%(40-10)+10)*0.4;
num11 = (qrand()%(40-10)+10)*0.4;
num12 = (qrand()%(40-10)+10)*0.4;
num1 = (qrand()%(40-10)+10)*0.4;
num2 = (qrand()%(40-10)+10)*0.4;
num3 = (qrand()%(40-10)+10)*0.4;
num4 = (qrand()%(40-10)+10)*0.4;
num5 = (qrand()%(40-10)+10)*0.4;
num6 = (qrand()%(40-10)+10)*0.4;
num7 = (qrand()%(40-10)+10)*0.4;
num8 = (qrand()%(40-10)+10)*0.4;
num9 = (qrand()%(40-10)+10)*0.4;
num10 = (qrand()%(40-10)+10)*0.4;
num11 = (qrand()%(40-10)+10)*0.4;
num12 = (qrand()%(40-10)+10)*0.4;
ui->lcdNumber_1->display(num1);
ui->lcdNumber_2->display(num2);
ui->lcdNumber_3->display(num3);
ui->lcdNumber_4->display(num4);
ui->lcdNumber_5->display(num5);
ui->lcdNumber_6->display(num6);
ui->lcdNumber_7->display(num7);
ui->lcdNumber_8->display(num8);
ui->lcdNumber_9->display(num9);
ui->lcdNumber_10->display(num10);
ui->lcdNumber_11->display(num11);
ui->lcdNumber_12->display(num12);
界面制作比较简单,只需拉几个仪表图再用函数显示随机数,并用定时器设置固定时间变换一次就ok。
四、截取界面
bool SavePic(wstring name, HWND hWnd) {
HDC hDc = NULL;
hWnd = (hWnd == NULL) ? GetDesktopWindow() : hWnd;
hDc = GetDC(hWnd); //获取DC
if (hDc == NULL) return false;
int bitOfPix = GetDeviceCaps(hDc, BITSPIXEL); //获取DC像素的大小
int width = 1440; //获取DC宽度
int hight = 900; //获取DC高度
UINT dpi = GetDpiForWindow(hWnd); //获取dpi
float fold; //根据dpi计算放大倍数
switch (dpi) {
case 96:
fold = 1;
break;
case 120:
fold = 1.25;
break;
case 144:
fold = 1.5;
break;
case 192:
fold = 2;
break;
case 216:
fold = 2.25;
break;
default:
fold = 1;
break;
}
width *= fold; //复原宽度
hight *= fold; //复原高度
CImage image;
image.Create(width, hight, bitOfPix); //为图像类创建与窗口DC相同大小的DC
BitBlt(image.GetDC(), 0, 0, width, hight, hDc, 0, 0, SRCCOPY); //将窗口DC图像复制到image
//name = to_wstring(i) + name;
image.Save(name.data(), Gdiplus::ImageFormatPNG); //保存为png格式图片文件
image.ReleaseDC(); //释放DC
ReleaseDC(hWnd, hDc); //释放DC资源
}
五、模板匹配
vector getcontour(Mat imgDil, Mat imgThre)//判断轮廓
{
vector contour;
vector hierarchy;
findContours(imgDil, contour, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_TC89_KCOS);
vector conPoly(contour.size());
vector boundRect(contour.size());
vector imgCrop;
for (int i = 0; i < contour.size(); i++)
{
int area = contourArea(contour[i]);//轮廓面积用于排除黑点
cout = 0; i--) {
if (seq[i] < 10) {
result += seq[i] * j;
j = j * 10;
}
else {
point = i;
}
}
if (point != 0)result = result * pow(0.1, seq.size() - point - 1);
return result;
}
bool compareVectors(const std::vector& vec1, const std::vector& vec2) {
// 如果两个向量大小不同,则它们不相等
if (vec1.size() != vec2.size()) {
return false;
}
// 逐个比较向量中的元素
for (size_t i = 0; i < vec1.size(); ++i) {
if (vec1[i] != vec2[i]) {
return false;
}
}
// 如果所有元素都相等,则两个向量相等
return true;
}
六、主函数
void main() {
int i = 1;
vector vecResult;
while (i++) {
clock_t start, stop;
HWND hq = FindWindow(NULL, TEXT("MainWindow"));
SavePic(L"1.png", hq);
Sleep(2640);
//cv::Mat image2 = cv::imread("4.png");
/*cv::imshow("meinv", image2);
cv::waitKey(0);*/
//string path = to_string(i) + ".png";
string path = "1.png";
Mat img = imread(path);//读取图片
Mat imgGray, imgBlur, imgCanny, imgDila, imgErode, imgThre;
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
//preprocessing
cvtColor(img, imgGray, COLOR_BGR2GRAY, 0);
threshold(imgGray, imgThre, 0, 255, THRESH_BINARY);
GaussianBlur(imgThre, imgBlur, Size(65, 65), 1, 1);
Canny(imgBlur, imgCanny, 40, 120);
dilate(imgCanny, imgDila, kernel);
//灰度->高斯滤波->Canny边缘算法->膨胀
vector imgFinal = getcontour(imgDila, imgThre);
/*imshow("Image", img);
imshow("Image Gray", imgGray);
imshow("Image Blur", imgBlur);
imshow("Image Canny", imgCanny);
imshow("Image dila", imgDila);
waitKey(0);*/
/*clock_t start, stop;
start = clock();*/
float result = 0;
start = clock();
vector vecResult2(vecResult.begin(), vecResult.end());
vecResult.clear();
for (int i = 0; i < imgFinal.size(); i++) {
result = imgDetect(imgFinal[i]);
cout |