第一章 指针仪表识别之仪表检测

2023-11-04

指针式仪表读数算法主要用于工业变电站环境,变电站环境复杂,仪表类型众多。仪表图像通过巡检机器人的可见光相机采集,由于机器人在巡检过程中行走路线较为固定,相机难以正对仪表平面采集图像,导致获得的仪表图像会因为拍摄位置、角度、光照等因素的影响产生较大的差异,图像可能存在仪表模糊和被遮挡等情况,这对于仪表图像的直接识别增加了难度。因此,为了提高仪表识别的准确度,识别前需要对图像进行仪表区域定位,排除背景干扰信息,提高后续表盘信息识别的准确性。

一、基于Hough变换的仪表检测(附源码)

Hough变换是一种专门用于检测物体几何形状的图像处理算法,最开始用于检测图像中的直线,经过改进后可用于检测多种形状,例如圆形、椭圆和多边形等。指针式仪表轮廓为圆形或者方形,因此,可以使用Hough变换检测图像中的圆形或者方形形状,检测出的位置即为仪表所在的位置。
Hough变换圆检测的原理和二维空间直线检测原理类似,只不过直线检测检测中只有两个自由度,而圆的一般方程为
在这里插入图片描述
那么在图像空间有三个自由度,即圆心a, b和半径r,那么就需要更大的计算量。在圆检测过程中,可以先设定半径r的取值范围,相当于提供一个先验设定,然后在二维空间内寻找a和b,减少算法计算量。
标准的Hough变换圆检测方法是通过直接累加法来实现的,这种方法存在计算量大,耗时多等问题,在很多场合很难使用,因此提出了很多改进的Hough变换圆检测方法,例如利用梯度信息的圆检测方法在一定程度上提高了圆形物体的检测速度。
通过Hough变换直线检测和圆检测的原理和过程可以看出,要在图像中检测出目标的位置,首先需要提取图像边缘信息,然后再遍历所有像素点,并进行Hough变换,最后检测结果得到目标物体信息,这个过程增加了计算量,降低了目标检测的速度。同时,在变电站实际环境中,背景干扰信息众多,存在很多的圆形相似物体,并且因为机器人拍摄路径不易,采集的图像中的仪表大小不一,导致仪表的圆半径大小不一,并且当相机镜头不正对仪表的表盘时,采集的图像中的仪表发生尺度变换,圆形仪表可能在图像中变成不规则的椭圆形状,这些原因都会给Hough变换圆检测带来困难。基于Hough变换的仪表定位算法如下。

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;


int main()
{
	Mat Image = imread("../3.jpg");

	Size dsize = Size(Image.cols * 0.5, Image.rows * 0.5);
	Mat srcImage(dsize, Image.type());

	resize(Image, srcImage, srcImage.size());

	Mat midImage, dstImage;

	cvtColor(srcImage, midImage, COLOR_BGR2GRAY); //转化边缘检测后的图为灰度图
	GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);
	vector<Vec3f> circles;
	HoughCircles(midImage, circles, HOUGH_GRADIENT, 1, midImage.rows / 5, 150, 100, 0, 0);

	for (size_t i = 0; i < circles.size(); i++)
	{
		Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
		int radius = cvRound(circles[i][2]);
		//绘制圆心
		circle(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0);
		//绘制圆轮廓
		circle(srcImage, center, radius, Scalar(0, 255, 0), 3, 8, 0);
	}

	imwrite("../circles_detection.jpg", srcImage);
	imshow("Output", srcImage);
	waitKey(0);
	return 0;

}

检测将结果如下:
在这里插入图片描述

二、基于SURF模板匹配仪表检测(附源码)

图像的模板匹配算法是一种基于图像特征检测、特征描述和特征匹配的算法。特征检测是指检测图像中满足用户定义的特征,在确定稳定的特征集后,提取特征的位置、方向、颜色、纹理和尺度等信息。特征描述是指使用一定的描述规则对特征信息进行量化分析并表征其特征信息。特征匹配是指对提取的特征信息进行筛选,将不满足条件的特征信息进行剔除,感兴趣的特征保留。特征检测中常用的方法有Harris角点检测,SIFT特征检测,SURF特征点检测,ORB特征点检测和SAFT特征点检测等,以SURF特征点检测方法为例,基于模板匹配的仪表检测方法如下:

/*
* @概述: 采用SURF算子在场景中进行仪表检测
* @类和函数: SurfFeatureDetector + SurfDescriptorExtractor + FlannBasedMatcher + findHomography + perspectiveTransform
* @实现步骤:
*		Step 1: 在图像中使用SURF算法SurfFeatureDetector检测关键点
*		Step 2: 对检测到的每一个关键点使用SurfDescriptorExtractor计算其特征向量(也称描述子)
*		Step 3: 使用FlannBasedMatcher通过特征向量对关键点进行匹配,使用阈值剔除不好的匹配
*		Step 4: 利用findHomography基于匹配的关键点找出相应的透视变换
*		Step 5: 利用perspectiveTransform函数映射点群,在场景中获取目标的位置
*/

#include <ctime>
#include <iostream>
#include "opencv2/core/core.hpp"	
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/nonfree/features2d.hpp"	    //SurfFeatureDetector实际在该头文件中
#include "opencv2/features2d/features2d.hpp"	//FlannBasedMatcher实际在该头文件中
#include "opencv2/calib3d/calib3d.hpp"	        //findHomography所需头文件
#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;


int main(int argc, char** argv)
{
	Mat imgObject = imread("../1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	Mat imgScene = imread("../192.168.1.34_01_2019032017182917.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	
	resize(imgObject, imgObject, Size(imgObject.rows*0.5, imgObject.cols*0.5));  //对图片进行修改
	resize(imgScene, imgScene, Size(imgScene.rows, imgScene.cols*0.4));         //对图片进行修改

	if (!imgObject.data || !imgScene.data)
	{
		cout << " --(!) Error reading images " << endl;
		return -1;
	}

	double begin = clock();

	// Step 1: 使用SURF算子检测特征点

	int minHessian = 400;
	SurfFeatureDetector detector(minHessian);
	vector<KeyPoint> keypointsObject, keypointsScene;
	detector.detect(imgObject, keypointsObject);
	detector.detect(imgScene, keypointsScene);
	cout << "object--number of keypoints: " << keypointsObject.size() << endl;
	cout << "scene--number of keypoints: " << keypointsScene.size() << endl;

	//  Step 2: 使用SURF算子提取特征(计算特征向量)

	SurfDescriptorExtractor extractor;
	Mat descriptorsObject, descriptorsScene;
	extractor.compute(imgObject, keypointsObject, descriptorsObject);
	extractor.compute(imgScene, keypointsScene, descriptorsScene);

	//  Step 3: 使用FLANN法进行匹配

	FlannBasedMatcher matcher;
	vector< DMatch > allMatches;

	matcher.match(descriptorsObject, descriptorsScene, allMatches);
	cout << "number of matches before filtering: " << allMatches.size() << endl;

	//-- 计算关键点间的最大最小距离

	double maxDist = 0;
	double minDist = 200;

	for (int i = 0; i < descriptorsObject.rows; i++)
	{
		double dist = allMatches[i].distance;
		if (dist < minDist)
			minDist = dist;
		if (dist > maxDist)
			maxDist = dist;

	}
	printf("	max dist : %f \n", maxDist);
	printf("	min dist : %f \n", minDist);

	//-- 过滤匹配点,保留好的匹配点(这里采用的标准:distance<3*minDist)

	vector< DMatch > goodMatches;
	for (int i = 0; i < descriptorsObject.rows; i++)
	{
		if (allMatches[i].distance < 4 * minDist)
			goodMatches.push_back(allMatches[i]);
	}
	cout << "number of matches after filtering: " << goodMatches.size() << endl;

	//-- 显示匹配结果

	Mat resultImg;
	drawMatches(imgObject, keypointsObject, imgScene, keypointsScene,
		goodMatches, resultImg, Scalar::all(-1), Scalar::all(-1), vector<char>(),
		DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS //不显示未匹配的点
		);

	//-- 输出匹配点的对应关系
	for (int i = 0; i < goodMatches.size(); i++)
		printf("	good match %d: keypointsObject [%d]  -- keypointsScene [%d]\n", i,
		goodMatches[i].queryIdx, goodMatches[i].trainIdx);


	///-- Step 4: 使用findHomography找出相应的透视变换

	vector<Point2f> object;
	vector<Point2f> scene;
	for (size_t i = 0; i < goodMatches.size(); i++)
	{
		//-- 从好的匹配中获取关键点: 匹配关系是关键点间具有的一 一对应关系,可以从匹配关系获得关键点的索引
		//-- e.g. 这里的goodMatches[i].queryIdx和goodMatches[i].trainIdx是匹配中一对关键点的索引
		object.push_back(keypointsObject[goodMatches[i].queryIdx].pt);
		scene.push_back(keypointsScene[goodMatches[i].trainIdx].pt);
	}

	Mat H = findHomography(object, scene, CV_RANSAC);

	///-- Step 5: 使用perspectiveTransform映射点群,在场景中获取目标位置
	std::vector<Point2f> objCorners(4);
	objCorners[0] = cvPoint(0, 0);
	objCorners[1] = cvPoint(imgObject.cols, 0);
	objCorners[2] = cvPoint(imgObject.cols, imgObject.rows);
	objCorners[3] = cvPoint(0, imgObject.rows);
	std::vector<Point2f> sceneCorners(4);
	perspectiveTransform(objCorners, sceneCorners, H);

	//-- 在被检测到的目标四个角之间划线

	line(resultImg, sceneCorners[0] + Point2f(imgObject.cols, 0), sceneCorners[1] + Point2f(imgObject.cols, 0), Scalar(0, 255, 0), 4);
	line(resultImg, sceneCorners[1] + Point2f(imgObject.cols, 0), sceneCorners[2] + Point2f(imgObject.cols, 0), Scalar(0, 255, 0), 4);
	line(resultImg, sceneCorners[2] + Point2f(imgObject.cols, 0), sceneCorners[3] + Point2f(imgObject.cols, 0), Scalar(0, 255, 0), 4);
	line(resultImg, sceneCorners[3] + Point2f(imgObject.cols, 0), sceneCorners[0] + Point2f(imgObject.cols, 0), Scalar(0, 255, 0), 4);

	//-- 显示检测结果
	imshow("detection result", resultImg);
	double end = clock();
	cout << "\nSURF--elapsed time: " << (end - begin) / CLOCKS_PER_SEC * 1000 << " ms\n";
	waitKey(0);
	return 0;
}

检测结果如下
在这里插入图片描述

三、基于YOLO深度学习的仪表检测(附源码)

以上两种方法,在室内光线较好的环境下,如果采集到高清的仪表图像,通过以上方法可以得到准确的检测结果。但是,如果该算法应用到室外复杂环境,当采集仪表图像受雨雾、遮挡、光照等影响时,采集到模糊图像将会严重影响到仪表的检测精度,而基于深度学习的方法抗干扰性强,可以应对各种复杂环境。本文以YOLOv3目标检测算法为例,通过模型训练得到仪表检测模型。
基于yolov3训练的仪表识别模型及配置文件下载链接:基于YOLOv3的仪表检测模型及配置文件

#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/dnn/shape_utils.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
 
// Remove the bounding boxes with low confidence using non-maxima suppression
void postprocess(cv::Mat& frame, std::vector<cv::Mat>& outs);
 
// Get the names of the output layers
std::vector<cv::String> getOutputsNames(const cv::dnn::Net& net);
 
// Draw the predicted bounding box
void drawPred(int classId, float conf, int left, int top, int right, int bottom, cv::Mat& frame);
 
// Initialize the parameters
float confThreshold = 0.5; // Confidence threshold
float nmsThreshold = 0.4;  // Non-maximum suppression threshold
int inpWidth = 416;        // Width of network's input image
int inpHeight = 416;       // Height of network's input image
 
std::vector<std::string> classes;
 
int main(int argc, char** argv)
{
    // Load names of classes,  configuration and weight files
    std::string classesFile = "../meter.names";
    cv::String modelConfiguration = "../yolov3.cfg";
    cv::String modelWeights = "../yolov3.weights";
    
    std::ifstream classNamesFile(classesFile.c_str());
    if (classNamesFile.is_open())
    {
        std::string className = "";
        while (std::getline(classNamesFile, className))
            classes.push_back(className);
    }
    else{
        std::cout<<"can not open classNamesFile"<<std::endl;
    }

    // Load the network
    cv::dnn::Net net = cv::dnn::readNetFromDarknet(modelConfiguration, modelWeights);
    std::cout<<"Read Darknet..."<<std::endl;
    net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
    net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
 
    // Process frames.
    std::cout <<"Processing..."<<std::endl;
    //cv::VideoCapture cap(0);
    cv::Mat frame;
    frame = imread("../test.jpg");
    
    //show frame
    cv::imshow("frame",frame);

    // Create a 4D blob from a frame.
    cv::Mat blob;
    cv::dnn::blobFromImage(frame, blob, 1/255.0, cv::Size(inpWidth, inpHeight), cv::Scalar(0,0,0), true, false);

    //Sets the input to the network
    net.setInput(blob);

    // Runs the forward pass to get output of the output layers
    std::vector<cv::Mat> outs;
    net.forward(outs, getOutputsNames(net));

    // Remove the bounding boxes with low confidence
    postprocess(frame, outs);

    // Put efficiency information. The function getPerfProfile returns the
    // overall time for inference(t) and the timings for each of the layers(in layersTimes)
    std::vector<double> layersTimes;
    double freq = cv::getTickFrequency() / 1000;
    double t = net.getPerfProfile(layersTimes) / freq;
    std::string label = cv::format("Inference time for a frame : %.2f ms", t);
    cv::putText(frame, label, cv::Point(0, 15), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255));

    // Write the frame with the detection boxes
    cv::Mat detectedFrame;
    frame.convertTo(detectedFrame, CV_8U);
     //show detectedFrame
    cv::imshow("detectedFrame",detectedFrame);
    waitKey(0);
    return 0;
}
 
// Get the names of the output layers
std::vector<cv::String> getOutputsNames(const cv::dnn::Net& net)
{
    static std::vector<cv::String> names;
    if (names.empty())
    {
        //Get the indices of the output layers, i.e. the layers with unconnected outputs
        std::vector<int> outLayers = net.getUnconnectedOutLayers();
 
        //get the names of all the layers in the network
        std::vector<cv::String> layersNames = net.getLayerNames();
 
        // Get the names of the output layers in names
        names.resize(outLayers.size());
        for (size_t i = 0; i < outLayers.size(); ++i)
            names[i] = layersNames[outLayers[i] - 1];
    }
    return names;
}
 
// Remove the bounding boxes with low confidence using non-maxima suppression
void postprocess(cv::Mat& frame, std::vector<cv::Mat>& outs)
{
    std::vector<int> classIds;
    std::vector<float> confidences;
    std::vector<cv::Rect> boxes;
 
    for (size_t i = 0; i < outs.size(); ++i)
    {
        // Scan through all the bounding boxes output from the network and keep only the
        // ones with high confidence scores. Assign the box's class label as the class
        // with the highest score for the box.
        float* data = (float*)outs[i].data;
        for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols)
        {
            cv::Mat scores = outs[i].row(j).colRange(5, outs[i].cols);
            cv::Point classIdPoint;
            double confidence;
            // Get the value and location of the maximum score
            cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
 
            if (confidence > confThreshold)
            {
                int centerX = (int)(data[0] * frame.cols);
                int centerY = (int)(data[1] * frame.rows);
                int width = (int)(data[2] * frame.cols);
                int height = (int)(data[3] * frame.rows);
                int left = centerX - width / 2;
                int top = centerY - height / 2;
 
                classIds.push_back(classIdPoint.x);
                confidences.push_back((float)confidence);
                boxes.push_back(cv::Rect(left, top, width, height));
            }
        }
    }
 
    // Perform non maximum suppression to eliminate redundant overlapping boxes with
    // lower confidences
    std::vector<int> indices;
    cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
    for (size_t i = 0; i < indices.size(); ++i)
    {
        int idx = indices[i];
        cv::Rect box = boxes[idx];
        drawPred(classIds[idx], confidences[idx], box.x, box.y,
                 box.x + box.width, box.y + box.height, frame);
    }
}
 
// Draw the predicted bounding box
void drawPred(int classId, float conf, int left, int top, int right, int bottom, cv::Mat& frame)
{
    //Draw a rectangle displaying the bounding box
    cv::rectangle(frame, cv::Point(left, top), cv::Point(right, bottom), cv::Scalar(0, 0, 255));
 
    //Get the label for the class name and its confidence
    std::string label = cv::format("%.2f", conf);
    if (!classes.empty())
    {
        CV_Assert(classId < (int)classes.size());
        label = classes[classId] + ":" + label;
    }
    else
    {
        std::cout<<"classes is empty..."<<std::endl;
    }
 
    //Display the label at the top of the bounding box
    int baseLine;
    cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
    top = std::max(top, labelSize.height);
    cv::putText(frame, label, cv::Point(left, top), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255,255,255));
}

基于yolov3的指针仪表检测结果如下
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第一章 指针仪表识别之仪表检测 的相关文章

  • 如何使图像呈现出陈旧、布满灰尘、颜色褪色的外观?

    我有旧画的图像 这些画很旧 布满灰尘 颜色褪色 如图所示here https i stack imgur com xuoEF jpg 如何赋予任何图像这种 旧 外观 我找不到任何过滤器或 openCV 函数来实现这种类型的外观 EDIT 我
  • opencv 视频上的颜色阈值

    I am thresholding for a color range in an opencv video The goal is to seperate the B mode black and white information on
  • 收据褪色部分可以恢复吗?

    我有一些包含一些扫描收据的文件 我需要使用 OCR 从中提取文本 由于收据上打印的文字在一段时间后会褪色 导致收据上的某些文字不清晰 影响OCR结果 褪色单词的一些示例 有什么方法可以恢复褪色的部分 以便提高 OCR 结果吗 我在OpenC
  • 如何解决 Python 'Pyzbar' 库的导入错误?

    我刚刚开始熟悉 Pyzbar 库 但是当使用decode方法我得到一个错误 这是代码 import cv2 import numpy as np import pyzbar code image cv2 imread C Users Ace
  • 使用 openCV 和 python 检测物体

    我正在尝试使用 OpenCV 和 Python 检测下图中的白点 我尝试使用函数 cv2 HoughCircles 但没有成功 我需要使用不同的方法吗 这是我的代码 import cv2 cv import numpy as np impo
  • 如何使用 OpenCV 检测图像帧中的对象?

    我正在使用 Raspberry Pi 开发一个漫游器 它将清扫房间并捡起掉落在地上的物体 为了检测物体 我使用了在流动站操作开始时拍摄的参考图像 以及每 10 秒单击一次的图像 新图像 为了确定图像帧是否发生变化 我在参考图像和新图像之间进
  • brew 链接 jpeg 问题

    我正在尝试安装opencv在 Mac OSX Lion 上 brew install opencv 我收到以下错误 以及其他一些类似的错误 Error The linking step did not complete successful
  • opencv createsamples没有错误,但是没有找到样本

    我在用着this http coding robin de 2013 07 22 train your own opencv haar classifier html教程 我正在根据我的正面图像创建大量样本 我正在使用 Windows 这是
  • OpenCV的拼接模块可以拼接平行运动相机拍摄的图像吗?

    我想知道是否缝合 http docs opencv org modules stitching doc stitching html http docs opencv org modules stitching doc stitching
  • 使用opencv计算深度视差图

    我无法使用 opencv 从视差图计算深度 我知道两个立体图像中的距离是用以下公式计算的z baseline focal disparity p 但我不知道如何使用地图计算视差 我使用的代码如下 为我提供了两个图像的视差图 import n
  • 使用Python的工业视觉相机[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • OpenCV 错误:使用 COLOR_BGR2GRAY 函数时断言失败

    我在使用 opencv 时遇到了一个奇怪的问题 我在 jupyter 笔记本中工作时没有任何问题 但在尝试运行此 Sublime 时却出现问题 错误是 OpenCV错误 cvtColor中断言失败 深度 CV 8U 深度 CV 16U 深度
  • 使用 ffmpeg 或 OpenCV 处理原始图像

    看完之后维基百科页面 http en wikipedia org wiki Raw image format原始图像格式 是任何图像的数字负片 为了查看或打印 相机图像传感器的输出具有 进行处理 即转换为照片渲染 场景 然后以标准光栅图形格
  • OpenCV C++ 如何知道每行的轮廓数进行排序?

    我有一个二值图像 https i stack imgur com NRLVv jpg在这张图片中 我可以使用重载的函数轻松地对从上到下 从左到右找到的轮廓进行排序std sort 我首先通过以下方式从上到下排序 sort contours
  • 仅获取图像中的外部轮廓

    我有这段代码 可以在图像中绘制轮廓 但我只需要外部轮廓 import cv2 import numpy as np camino C Users Usuario Documents Deteccion de Objetos 123 jpg
  • 如何使用 Python 裁剪图像中的矩形

    谁能给我关于如何裁剪两个矩形框并保存它的建议 我已经尝试过这段代码 但效果不佳 import cv2 import numpy as np Run the code with the image name keep pressing spa
  • 从包含带边框的表格的图像中提取表格结构

    我正在尝试提取下表中的单元格位置 应用自适应阈值处理后 我能够获得细胞位置周围的轮廓 并且 HoughLines 获得垂直和水平结构元素 这是我的代码 img cv2 imread os path join img path file im
  • OpenCV 跟踪器:模型未在函数 init 中初始化

    在视频的第一帧 我运行一个对象检测器 它返回对象的边界框 如下所示
  • 二值图像中骨架上两点之间的最短路径

    我有一个二进制图像 其中包含图像的一个像素宽度骨架 您可能基本上知道 在这个二值图像中 我在骨架上有 1 在其他地方有 0 如何找到骨架上两个非零元素之间的最短距离 路径也应该在骨架本身上 我想使用 A star 算法的 C 实现 我找到了
  • 在 Visual Studio 2012 中安装 OpenCV

    我正在尝试安装 OpenCV 来与 Visual Studio 一起使用 我使用的是2012Pro版本 但我认为它应该与vs10相同 我正在关注这个教程 http docs opencv org doc tutorials introduc

随机推荐

  • centos安装 TA-Lib

    奇葩问题 问题一 gcc 编译器未安装 问题二 command gcc failed with exit status 1 问题三 Traceback most recent call last File run1 py line 3 in
  • 【代码随想录】数组——二分查找相关题目

    int middle left right left 2 防止溢出 等同于 left right 2 35 搜索插入位置 如果目标值不存在于数组中 返回它将会被按顺序插入的位置 这个要求自己没法实现 自己实现的会溢出 当考虑left不行时
  • 如何深度理解整体架构设计?

    一 什么是架构和架构本质 在软件行业 对于什么是架构 都有很多的争论 每个人都有自己的理解 此君说的架构和彼君理解的架构未必是一回事 因此我们在讨论架构之前 我们先讨论架构的概念定义 概念是人认识这个世界的基础 并用来沟通的手段 如果对架构
  • STM32CubeMX简单配置流程

    文章目录 前言 1 创建工程 2 创建STM32F103C8Tx系列工程 3 首先配置系统下载口 STLINK 4 配置外部时钟 5 配置相应功能 6 系统时钟配置 7 工程设置1 8 工程设置2 前言 借此平台记录一些以前保存的资料 防止
  • flask+云服务器 公网IP无法访问的问题

    最近做一些工作涉及到了flask的使用 写了一个简单的程序后 自己的云服务器公网IP一直无法访问 解决这个问题费了我好长时间 我自己用的是阿里云服务器 系统是centos 我在网上找到了几种说法 有人说是端口的问题 网上最多的说法是自己访问
  • C/C++安全编程规范

    一 安全编程概述 1 安全编程的目的 安全编程是一种软件开发方法 目的是通过采取具体措施来减少程序中存在的安全漏洞和黑客攻击的可能性 确保软件在运行过程中不会遭受攻击或泄露敏感信息 2 在进行安全编程时 需要遵循的安全最佳实践和规范 2 1
  • Rocketmq-- RocketMQ4.X基础介绍

    一 阿里开源消息队列 RocketMQ4 x介绍和新概念讲解 Apache RocketMQ作为阿里开源的一款高性能 高吞吐量的分布式消息中间件 1 1 特点 支持Broker和Consumer端消息过滤 支持发布订阅模型 和点对点 支持拉
  • Excel Row函数和Rows函数的使用方法,含Row(A:A)与Row(1:1)实例

    在 Excel 中 Row函数用于返回单元格的行号 Rows函数用于返回数组或引用单元格的行数 如果Row函数省略参数 默认返回公式所在单元格的行号 Rows函数不能省略参数 Rows函数常与Indirect函数 Index函数 If函数
  • 20230314-近视的小张

    1 题目名称 近视的小张 时间限制 1000ms内存限制 256M 题目描述 小张和他的 M 个朋友来到了一个十分神奇的地方 在这里有 N 个 柱子 对于每个 1 lt i lt N 第 i 个柱子都有两个属性 H i P i H i 表示
  • tasklet与workqueue的区别及底层实现区别

    softirq和tasklet都属于软中断 tasklet是softirq的特殊实现 workqueue是普通的工作队列 1 softirq 软中断支持SMP 同一个softirq可以在不同的CPU上同时运行 softirq必须是可重入的
  • Zabbix 如何动态执行监控采集脚本

    在使用Zabbix自定义脚本采集监控数据的时候 通常会遇到以下一些问题 服务器扩容之后 监控脚本如何部署到新的服务器上 监控脚本需要修改时 如何自动修改所有相同的监控脚本 如何备份监控采集脚本避免因服务器异常后丢失 新部署自定义监控 如何避
  • 能通过一张照片(2D)得到3D的模型吗?

    如下内容已经整理成 PDF 很好奇其实如果将人眼所看到的画面保存下来 拍照 人类是可以感知照片内的各个物体 是不是可以理解成这是一种2D到3D认知的转换 作者 知乎用户 链接 https www zhihu com question 529
  • win7蓝屏报错:STOP:0x0000007E

    报错环境 win 7 报错信息 STOP 0x0000007E 解决办法 0X0000007E代码的意思是电脑中病毒了或是电脑内存条出现了问题 电脑中病毒问题怎么处理 2 1如果是电脑中病毒 开机按电脑上的F8键 在电脑开机菜单栏找到 安全
  • 经典网络LeNet-5介绍及代码测试(Caffe, MNIST, C++)

    LeNet 5 包含7个层 layer 如下图所示 输入层没有计算在内 输入图像大小为32 32 1 是针对灰度图进行训练和预测的 论文名字为 Gradient Based Learning Applied to Document Reco
  • 为什么街头篮球总提示服务器维护,我玩街头篮球,但这几天它总是说连接不上服务器怎么回事?...

    我玩街头篮球 但这几天它总是说连接不上服务器怎么回事 來源 互聯網 2010 04 26 07 19 32 評論 分類 遊戲 gt gt 網絡遊戲 gt gt 街頭籃球 問題描述 我下载了补丁 參考答案 无法连接服务器 情况屡见不鲜 不巧
  • 如何应急响应

    应急响应事件分类 大致可以分为三类 1 勒索病毒 勒索病毒危害不言而喻 一旦中了勒索病毒 几乎很难破解 只能通过重装系统 数据备份恢复或者缴纳相应被勒索的比特币支付进行病毒解除 仍有一种比较渺茫的方式进行病毒解除 那就是溯源到攻击者 通过法
  • Expanding Low-Density Latent Regions for Open-Set Object Detection

    Expanding Low Density Latent Regions for Open Set Object Detection CVPR2022 Code https github com csuhan opendet2 这篇文章认为
  • 【Spring八】Spring与Hibernate整合

    Hibernate所需元素 三要素 实体类 hbm xml hibernate cfg xml Spring所需元素 applicationContext xml hibernate在操作数据库时 使用sessionFactory open
  • 华为OD机试 - 绘图机器(Java)

    题目描述 绘图机器的绘图笔初始位置在原点 0 0 机器启动后按照以下规则来进行绘制直线 1 尝试沿着横线坐标正向绘制直线直到给定的终点E 2 期间可以通过指令在纵坐标轴方向进行偏移 offsetY为正数表示正向偏移 为负数表示负向偏移 给定
  • 第一章 指针仪表识别之仪表检测

    文章目录 一 基于Hough变换的仪表检测 附源码 二 基于SURF模板匹配仪表检测 附源码 三 基于YOLO深度学习的仪表检测 附源码 指针式仪表读数算法主要用于工业变电站环境 变电站环境复杂 仪表类型众多 仪表图像通过巡检机器人的可见光