今天在整理电脑文件时,发现了几个月前做的一个项目,是关于指针仪表盘读取的,也是当时导师布置给我的一个任务,我决定梳理下,写个博客,也方便以后若有需要时可以随时查找。

本篇博客记录了我开发这个小项目的全部过程,以及对于需求的改变、方案的更新等等。PS:用到的都是传统的机器视觉方法,不涉及深度学习方面的知识。仅供参考

内容

  • 方案1.0
    • 一.任务说明(仅关于视觉部分)
    • 二.方案内容
  • 方案2.0
    • 一.方案描述
    • 二.程序思路
    • 三.遇到的问题
    • 四.解决思路
    • 五.源码
  • 方案3.0
    • 一.问题描述
    • 二.解决方法
    • 三.源码
  • PS

方案1.0

一.任务说明(仅关于视觉部分)

在这里插入图片描述
要求:可精确稳定的识别出表头中的数据,精确到1MPa。
场景:①对方就唯一的这种表,也就是对象唯一。
②有一个检测箱,箱里有摄像头和其他硬件可远程通讯,压力表连同被测罐连在一起,放到检测箱里固定位置度数及检查其他内容。也就是读表只是它的一部分工作。
③那么每个表和摄像头之间位置是相对固定的。
(其他关于界面、硬件部分需求这里就不介绍了)

二.方案内容

在这里插入图片描述
在这里插入图片描述
一开始接到的图片就这么一张,我首先想到的是用opencv自带的模板匹配的方法,将刻度盘作为我的模板,去寻找图片中的ROI区域,很显然,在当时只有一种图片的情况下,效果简直太棒,然而却忽视了一个重要的问题。
先看下当时的效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
关于模板匹配参考的资料:
https://blog.csdn.net/wzz18191171661/article/details/91345166

方案2.0

一.方案描述

在方案1.0中,提到了当时我忽视了一个重要的问题,就是模板匹配这个方法,要求你的模板大小尺寸必须和你要匹配的图像中的目标对象尺寸差不多,就好比你的模板是300×300的,而你要匹配的图像ROI区域可能只有100×100或者900×900的大小,这样模板匹配的方法就行不通了。过了几天,导师又给了我第二批的图片。
在这里插入图片描述
(上面这批图片都是1840*4000的大图片,ROI区域很大)
思考了下,突然想到可以使用多尺度模板匹配的方法,所谓多尺度,比如说我这里选取的模板大小就是300×300的,对于图片的1840×4000的超大图片,我把它一步一步的缩小或者放大(这里是缩小),就这样每次缩小图片的一点点,缩小一次就拿我的300×300模板去匹配一次,虽然有点笨且运行速度相比于之前慢了些,但能解决问题就行,果然这种方法还是可靠的。
效果如下:
在这里插入图片描述

二.程序思路

1.需要一个仪表盘的模板,要正,精确,清楚,标定好这个模板的刻度的像素坐标,圆心的像素坐标等等,用这个模板去匹配相机拍摄到的对象,这里运行opencv自带的特征匹配。(采用多尺度模板匹配的方法)
2.提取到ROI区域后,对于图像是否正,还需要进行旋转矫正,观察发现刻度盘中氧气下面的蓝色线的特征,以此为基准来获取当前刻度盘的旋转角度。(这里默认刻度盘是180°内的倾斜,总不至于刻度盘是颠倒的吧)
(图像矫正时还考虑到了用离散傅里叶矫正,因为曾经在看书的时候书上说离散傅里叶对于图像处理的一个重要应该就是可以判断当前图片的倾斜角度,后发现不行,参考博客:
https://blog.csdn.net/wsp_1138886114/article/details/83374333
3.采用无监督学习的Kmeans算法,鉴于图像的复杂度,提取出每个刻度不太容易,观察发现因为刻度和指针的颜色肯定和周围不同,至于到底是什么颜色我不需要管,交给Kmeans就行了,只要设定最后的聚类种类为2,返回聚类后的结果获得两个阈值点,然后以这个为阈值,把图像进行二值化分割,图像进行二值化分割后,这里有没有刻度反而对我不重要了,因为在模板中我已经将所有的刻度都标定好了,这里只需要读取当前指针的位置就行了。(采用Kmeans二值化后,指针是白色的,采用图像的颜色反转,将指针变成黑色,从而进行后续操作),这里使用形态学处理会让效果更好,https://segmentfault.com/a/1190000015650320
4.表盘读取的方法:以表盘中心为起点,画一条线段,进行旋转,这条直线的粗细程度要看当前指针的粗细程度,让这条直线进行旋转,当它与指针重合最多的时候,就是该位置,读取当前的角度值,再去我之前设置好了的刻度表里面去读数就好了

三.遇到的问题

①当时使用多尺度模板匹配的方法,虽然可以很精确地截取到图片中的ROI区域,但带来了另一个问题,就是提取到的ROI区域这个刻度圆盘,它发生了旋转,更为要命的是有的刻度圆盘已经发生了畸形。
②在图像处理中,对于正常的旋转矫正,只需要知道当前的倾斜角度就可以旋转了;而对于畸形的这种,则需要透视矫正,比较麻烦。
③先解决倾斜角度的旋转,首先如何获取这个角度的值是一个问题,正常的方法是使用霍夫直线检测来提取直线的倾斜角度,根据我的观察发现,无论是什么情况,刻度圆盘中氧气表三个字下面的蓝色线段,很明显且清楚,于是从这里下手。

四.解决思路

在这里插入图片描述
上面这幅图是仪表盘比较清除的图像,
紧接着,如何识别出这个蓝色的线段呢?若采用霍夫直线检测,则会检测出很多的直线出来,到时候这个筛选标准又是什么?又是一个问题。某日在逛知乎的时候,突然看到了一篇文章
https://zhuanlan.zhihu.com/p/67930839(RGB、HSV和HSL颜色空间)
其中有一段话:RGB颜色空间更加面向于工业,而HSV更加面向于用户,大多数做图像识别这一块的都会运用HSV颜色空间,因为HSV颜色空间表达起来更加直观。这时候想到,这个蓝色在整个ROI区域中都是独一无二的,何不把它提取出来呢?关于获取图片中指定的颜色部分,参考了这篇博客
https://blog.csdn.net/qq_40456669/article/details/93375709
在这里插入图片描述
可以看到蓝色的HSV值,编程后的效果如下:效果直呼感人!
在这里插入图片描述
进入下一个问题,怎么知道这个线段的倾斜角度呢?这里我采用了指针刻度读取的办法,在该图的中心画一个线段,旋转360°,先把这个图取反,然后读取每旋转一度画个指针与该度数方向重合的点的数量,读取重合点的数量最多的时候的度数值,经过运算就可以知道这条线段的倾斜角度,也就是整个ROI区域的旋转角度,解决!
在这里插入图片描述
而对于畸形,透视矫正,当时并没有考虑,这里先等下说,先看下程序效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五.源码

程序细节:
选取特征匹配的模板:second_template
300*300
代码:
1_formulas 角度转数值的计算公式
2_roi 提取ROI区域,返回框选好了的ROI区域img_2
3_rotate 将图像矫正 返回矫正好了的图像 img_3
4_kmeans 采用kmeans二值化处理

formula_1.py

import mathcenter = [151 , 147]  # 模板template1指针刻度盘的圆心位置# 刻度盘上每个数值的坐标
a = {0:(68,91),1:(76,78),2:(80,75),3:(83,71),4:(87,68),5:(91,65),6:(96,61),7:(102,57),8:(107,53),9:(113,52),10:(121,50),11:(126,47),12:(132,46),13:(139,45),14:(145,44),15:(152,45),16:(159,45),17:(166,46),18:(172,47),19:(179,49),20:(186,51),21:(192,54),22:(198,57),23:(204,61),24:(210,65),25:(215,69),26:(220,74),27:(224,79),28:(229,84),29:(233,90),30:(238,97)}count = 0
result = {}# 计算指针刻度盘中每个刻度的角度
for k ,v in a.items():r = math.acos((v[0]-center[0])/((v[0]-center[0])**2 + (v[1]-center[1])**2)**0.5) # 得到弧度值r = r*180/math.pi  # 将弧度值转化为角度值a[k] = rif k != 31:r=360-r# print(k, r)result[k]=rcount+=1print(result)result_list = result.items()
lst = sorted(result_list,key=lambda x:x[1])# 读取指针所指的刻度,稍微大一点的整数刻度,比如20,30,40等等
def get_next(c):l = len(lst) # 10n = 0for i in range(len(lst)):if lst[i][0] == c:n = i+1if n == l:n = 0breakreturn lst[n]# 参数rad:表示当前指针所指的角度。角度是以右边x轴为0刻度,顺时针旋转读取
def get_rad_val(rad):old=Nonefor k, v in lst:# print(k,v)if rad > v :old = kprint(old)r = result[old]d = rad-rnx = get_next(old)print(1*abs(d/(nx[1] - r)))print(nx)t = old+1*abs(d/(nx[1] - r))print(t)return t

roi_2.py

"""第一第二步:该程序的目的是用模板匹配到图片中的ROI区域"""
import numpy as np
import argparse
import glob
import imutils
import cv2def select_roi_area(img):ap = argparse.ArgumentParser()ap.add_argument("-v", "--visualize", help="Flag indicating whether or not to visualize each iteration")args = vars(ap.parse_args())# 读取模板图片template = cv2.imread("second_template.jpg")# 转换为灰度图片template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)# 执行边缘检测template = cv2.Canny(template, 50, 200)(tH, tW) = template.shape[:2]# 显示模板cv2.imshow("Template", template)# 遍历所有的图片寻找模板# 读取测试图片并将其转化为灰度图片gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)found = None# 循环遍历不同的尺度for scale in np.linspace(0.2, 1.0, 20)[::-1]:# 根据尺度大小对输入图片进行裁剪resized = imutils.resize(gray, width = int(gray.shape[1] * scale))r = gray.shape[1] / float(resized.shape[1])# 如果裁剪之后的图片小于模板的大小直接退出if resized.shape[0] < tH or resized.shape[1] < tW:break# 首先进行边缘检测,然后执行模板检测,接着获取最小外接矩形edged = cv2.Canny(resized, 50, 200)result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF)(_, maxVal, _, maxLoc) = cv2.minMaxLoc(result)# 结果可视化if args.get("visualize", False):# 绘制矩形框并显示结果clone = np.dstack([edged, edged, edged])cv2.rectangle(clone, (maxLoc[0], maxLoc[1]), (maxLoc[0] + tW, maxLoc[1] + tH), (0, 0, 255), 2)cv2.imshow("Visualize", clone)cv2.waitKey(0)# 如果发现一个新的关联值则进行更新if found is None or maxVal > found[0]:found = (maxVal, maxLoc, r)# 计算测试图片中模板所在的具体位置,即左上角和右下角的坐标值,并乘上对应的裁剪因子(_, maxLoc, r) = found(startX, startY) = (int(maxLoc[0] * r), int(maxLoc[1] * r))(endX, endY) = (int((maxLoc[0] + tW) * r), int((maxLoc[1] + tH) * r))# 绘制并显示结果cv2.rectangle(img, (startX, startY), (endX, endY), (255, 0, 0), 2)cv2.imshow("Image", cv2.resize(img,(int(img.shape[1]*0.2),int(img.shape[0]*0.2))))new_ = img[startY:endY + 1, startX:endX + 1, ]img_2 = cv2.resize(new_,(int(new_.shape[1]*0.5),int(new_.shape[0]*0.5)))cv2.imshow("roi",img_2)cv2.waitKey(0)cv2.destroyAllWindows()return img_2

rotate_3.py

# 第三步:图像的矫正
import cv2
import numpy as np
from math import cos, pi, sindef get_rotate_rad(img):'''获取角度'''shape = img.shapec_y, c_x= int(shape[0] / 2), int(shape[1] / 2)x1=c_x+c_x*0.8src = img.copy()freq_list = []for i in range(361):x = (x1 - c_x) * cos(i * pi / 180) + c_xy = (x1 - c_x) * sin(i * pi / 180) + c_ytemp = src.copy()cv2.line(temp, (c_x, c_y), (int(x), int(y)+14), (0, 0, 255), thickness=2)t1 = img.copy()t1[temp[:, :] == 255] = 255c = img[temp[:, :] == 255]points = c[c == 255]freq_list.append((len(points), i))cv2.imshow('d', temp)cv2.imshow('d1', t1)cv2.waitKey(1)print(freq_list)print('当前角度:',max(freq_list, key=lambda x: x[0]),'度')cv2.destroyAllWindows()return max(freq_list)def have_rotate_image(src):cv2.namedWindow("input", cv2.WINDOW_AUTOSIZE)cv2.imshow("input", src)"""提取图中的蓝色部分"""hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)low_hsv = np.array([100,43,46])high_hsv = np.array([124,255,255])mask = cv2.inRange(hsv,lowerb=low_hsv,upperb=high_hsv)cv2.imshow("test",mask)no_mask = 255 - mask  # 颜色取反,将指针变为黑色n_mask = cv2.resize(no_mask,(int(no_mask.shape[1]*0.5),int(no_mask.shape[0]*0.5)))a = get_rotate_rad(n_mask)print(a[1])angle = a[1] - 180# angle为正,逆时针旋转;为负,顺时针旋转print("当前ROI旋转的角度:{}".format(angle))matRotate = cv2.getRotationMatrix2D((src.shape[1]*0.5,src.shape[0]*0.5),angle,1)dst = cv2.warpAffine(src,matRotate,(src.shape[1],src.shape[0]))img_3 = cv2.resize(dst,(int(dst.shape[1]*0.5),int(dst.shape[0]*0.5)))cv2.imshow("dst",img_3)cv2.waitKey(0)cv2.destroyAllWindows()return img_3

kmeans_4.py

import numpy as np
import cv2
from sklearn.cluster import KMeans
from sklearn.utils import shuffle
from math import cos, pi, sindef v2_by_k_means(img):'''使用k-means二值化'''original_img = np.array(img, dtype=np.float64) # original_img与img格式一样,但为白色src = original_img.copy()delta_y = int(original_img.shape[0] * (0.4))delta_x = int(original_img.shape[1] * (0.4))original_img = original_img[delta_y:-delta_y, delta_x:-delta_x]h, w, d = src.shapeprint(w, h, d)dts = min([w, h])print(dts)r2 = (dts / 2) ** 2c_x, c_y = w / 2, h / 2a: np.ndarray = original_img[:, :, 0:3].astype(np.uint8)# 获取尺寸(宽度、长度、深度)height, width = original_img.shape[0], original_img.shape[1]depth = 3print(depth)image_flattened = np.reshape(original_img, (width * height, depth))'''K-Means算法'''image_array_sample = shuffle(image_flattened, random_state=0)# 随机打乱image_flattened中的元素estimator = KMeans(n_clusters=2, random_state=0) # 生成两个质心estimator.fit(image_array_sample)    '''为原始图片的每个像素进行类的分配。'''src_shape = src.shapenew_img_flattened = np.reshape(src, (src_shape[0] * src_shape[1], depth))cluster_assignments = estimator.predict(new_img_flattened)'''我们建立通过压缩调色板和类分配结果创建压缩后的图片'''compressed_palette = estimator.cluster_centers_print(compressed_palette) # 收敛到的质心位置a = np.apply_along_axis(func1d=lambda x: np.uint8(compressed_palette[x]), arr=cluster_assignments, axis=0)img = a.reshape(src_shape[0], src_shape[1], depth)print(compressed_palette[0, 0])threshold = (compressed_palette[0, 0] + compressed_palette[1, 0]) / 2img[img[:, :, 0] > threshold] = 255img[img[:, :, 0] < threshold] = 0cv2.imshow('sd0', img)# 下一步因为指针仪表盘是圆形,所以去除掉圆以外的干扰因素for x in range(w):for y in range(h):distance = ((x - c_x) ** 2 + (y - c_y) ** 2)if distance > r2:passimg[y, x] = (255, 255, 255)cv2.imshow('sd', img)img = 255 - imgcv2.imshow('opposite',img)cv2.waitKey(0)cv2.destroyAllWindows()return imgdef dilate(img):'''将Kmeans二值化后的图像进行膨胀处理'''kernel = np.ones((5, 5), np.uint8)dilation = cv2.dilate(img, kernel, iterations=1)return dilationdef get_pointer_rad(img):'''获取角度'''shape = img.shapec_y, c_x, depth = int(shape[0] / 2), int(shape[1] / 2), shape[2]x1=c_x+c_x*0.4src = img.copy()freq_list = []for i in range(361):x = (x1 - c_x) * cos(i * pi / 180) + c_xy = (x1 - c_x) * sin(i * pi / 180) + c_ytemp = src.copy()cv2.line(temp, (c_x, c_y), (int(x), int(y)), (0, 0, 255), thickness=6)t1 = img.copy()t1[temp[:, :, 2] == 255] = 255c = img[temp[:, :, 2] == 255]points = c[c == 0]freq_list.append((len(points), i))cv2.imshow('d', temp)cv2.imshow('d1', t1)cv2.waitKey(1)print('当前角度:',max(freq_list, key=lambda x: x[0]),'度')cv2.destroyAllWindows()return max(freq_list, key=lambda x: x[0])

main_code.py

import cv2
from formula_1 import get_rad_val
from roi_2 import select_roi_area
from rotate_3 import have_rotate_image
from kmeans_4 import v2_by_k_means,dilate,get_pointer_radif __name__ == '__main__':srcImage = cv2.imread("train/3.jpg")# 第一步:选出ROI区域roiIimage = select_roi_area(srcImage)# 第二步:对ROI区间进行矫正rotateImage = have_rotate_image(roiIimage)# 第三步:进行kemeans二值化kmeansImage = v2_by_k_means(rotateImage)# 第四步:将Kmeans二值化后的图像进行膨胀处理dilateImage = dilate(kmeansImage)# 第五步:获取当前的指针角度angle = get_pointer_rad(dilateImage)# 第六步:角度转换成数值value = get_rad_val(angle[1])print("当前刻度盘的数值是:{}".format(value))

PS:后来与老师的沟通中,才了解到实际的工作环境中,摄像头能够保证与刻度盘的平面互相平行,这样一来就不存在刻度盘的畸形这种情况了,就是说不需要进行透视矫正了。

方案3.0

一.问题描述

虽然否决了图像畸形不需要透视矫正,但又有了个问题,因为给的那十张图片场景都很单一,如果放在更为复杂的环境当中,或者与很多的刻度盘放在一起,那还能准确的找到ROI区域吗?一开始我认为,多尺度模板匹配可以很好的解决这些问题,也没太在意。不过后来想想还是去测试一下吧,于是我简单的P了几张图片,如下:
在这里插入图片描述
然后当我使用多尺度模板匹配的方法去寻找ROI区域时,发现根本找不到ROI区域。

二.解决方法

①查了相关资料,总结:若多尺度模板匹配的方法效果不好的话,可以考虑关键点匹配法,比较经典的关键点检测算法包括SIFT和SURF等,主要的思路是首先通过关键点检测算法获取模板和测试图片中的关键点;然后使用关键点匹配算法处理即可,这些关键点可以很好的处理尺度变化、视角变换、旋转变化、光照变化等,具有很好的不变性。
查询资料:https://blog.csdn.net/zhuisui_woxin/article/details/84400439
(基于FLANN的匹配器(FLANN based Matcher)描述特征点)精确完成了特征匹配的任务!
意外发现:之前在方案2.0中说到了,获取ROI区域的旋转角度时,费了工夫,然而当我使用基于FLANN的匹配器的时候,发现框选的部分,自动将那个旋转角度的多边形给框选了出来:
在这里插入图片描述
②但接着又遇到一个新问题,python的PIL库自带的方法只能进行矩形的切割,但这里是多边形各个顶点的坐标,如何对现有的图片按照这个多边形进行切割呢?首先可以确定的是,我肯定已经获取到了这个四边形的四个顶点坐标,否则不会框选出来,依照这个思路,参考这篇文章:http://www.6tie.net/p/1177178.html (使用Opencv python从Image中裁剪凹面多边形)
在这里插入图片描述
完美切割出来,
进入下一个步骤,将这个裁剪出来的ROI区域进行透视变换,参考资料:
https://blog.csdn.net/t6_17/article/details/78729097。博客中是自己写的四个点坐标,这里因为上一步已经获取到了四个顶点的坐标,所以这里直接进行透视变换,因为我选的模板是300*300的正方形,所以我把这个ROI区域也透视变换为正方形的图片,方便后面的进一步运算,透视变换的结果如下:
在这里插入图片描述至此,下面的操作就和之前的方案一样了:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三.源码

程序细节:
选取特征匹配的模板:second_template
300*300
代码:
第一步:指针数值的算法理论 formula_1
第二步:基于FLANN匹配roi区域 find_roi_FLANN_2
第三步:在原图上剪切出需要的多边形roi区域
cut_roi_3
第四步:进行透视变换将多边形转化为正方形(为了与模板一样方便后面运算)perspective_roi_4
第五步:kmeans_5

formula_1.py

import mathcenter = [151 , 147]  # 模板template1指针刻度盘的圆心位置# 刻度盘上每个数值的坐标
a = {0:(68,91),1:(76,78),2:(80,75),3:(83,71),4:(87,68),5:(91,65),6:(96,61),7:(102,57),8:(107,53),9:(113,52),10:(121,50),11:(126,47),12:(132,46),13:(139,45),14:(145,44),15:(152,45),16:(159,45),17:(166,46),18:(172,47),19:(179,49),20:(186,51),21:(192,54),22:(198,57),23:(204,61),24:(210,65),25:(215,69),26:(220,74),27:(224,79),28:(229,84),29:(233,90),30:(238,97)}count = 0
result = {}# 计算指针刻度盘中每个刻度的角度
for k ,v in a.items():r = math.acos((v[0]-center[0])/((v[0]-center[0])**2 + (v[1]-center[1])**2)**0.5) # 得到弧度值r = r*180/math.pi  # 将弧度值转化为角度值a[k] = rif k != 31:r=360-r# print(k, r)result[k]=rcount+=1# print(result)
# {0: 214.00749241973224, 1: 222.61405596961117, 2: 225.40066325579215, 3: 228.17983011986422,
# 4: 230.9881483757755, 5: 233.8067926944353, 6: 237.39966642630975, 7: 241.43416320625343,
# 8: 244.91640599380906, 9: 248.19859051364818, 10: 252.81429385577522, 11: 255.9637565320735,
# 12: 259.3460974000615, 13: 263.2901631922431, 14: 266.6661493384634, 15: 270.56170533256653,
# 16: 274.4846060095446, 17: 278.44752724790845, 18: 281.85977912094796, 19: 285.94539590092285,
# 20: 290.03101268089773, 21: 293.79077386577717, 22: 297.5745639596944, 23: 301.64465903709254,
# 24: 305.735476014867, 25: 309.36931724236473, 26: 313.38646106711883, 27: 317.0309142368531,
# 28: 321.0724564072077, 29: 325.1959882472868, 30: 330.113473059576}result_list = result.items()
lst = sorted(result_list,key=lambda x:x[1])# 读取指针所指的刻度,稍微大一点的整数刻度,比如20,30,40等等
def get_next(c):l = len(lst) # 10n = 0for i in range(len(lst)):if lst[i][0] == c:n = i+1if n == l:n = 0breakreturn lst[n]# 参数rad:表示当前指针所指的角度。角度是以右边x轴为0刻度,顺时针旋转读取def get_rad_val(rad):old=Nonefor k, v in lst:# print(k,v)if rad > v :old = k# print(old)r = result[old]d = rad-rnx = get_next(old)# print(1*abs(d/(nx[1] - r)))# print(nx)t = old+1*abs(d/(nx[1] - r))# print(t)return t

find_roi_FLANN_2.py

"""第一第二步:该程序的目的是用模板匹配到图片中的ROI区域"""
# 基于FLANN的匹配器(FLANN based Matcher)定位图片
import numpy as np
import cv2def find_roi(template,target):MIN_MATCH_COUNT = 10  # 设置最低特征点匹配数量为10#创建sift检测器sift = cv2.xfeatures2d.SIFT_create()#使用SIFT查找关键点和描述符(keypoints和descriptors)kp1, des1 = sift.detectAndCompute(template, None) #计算出图像的关键点和sift特征向量kp2, des2 = sift.detectAndCompute(target, None)# 创建设置FLANN匹配FLANN_INDEX_KDTREE = 0 # FLANN 参数index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)search_params = dict(checks=50)flann = cv2.FlannBasedMatcher(index_params, search_params) # 使用FlannBasedMatcher 寻找最近邻近似匹配matches = flann.knnMatch(des1, des2, k=2) # 使用knnMatch匹配处理,并返回匹配matches# 通过coff系数来决定匹配的有效关键点数量good = [] # 0.1 0.7  0.8  参数可以自己修改进行测试# 舍弃大于0.7的匹配# 还是通过描述符的距离进行选择需要的点for m, n in matches:if m.distance < 0.7 * n.distance:good.append(m)if len(good) > MIN_MATCH_COUNT:# 获取关键点的坐标src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)# 计算变换矩阵和MASKM, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)#找到两个平面之间的转换矩阵matchesMask = mask.ravel().tolist()h, w = template.shape# 使用得到的变换矩阵对原图像的四个角进行变换,获得在目标图像上对应的坐标pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)dst = cv2.perspectiveTransform(pts, M)cv2.polylines(target, [np.int32(dst)], True, 0, 2, cv2.LINE_AA)# cv2.drawContours(target, [np.int32(dst)], -1, (0, 255, 0), 3)else:print("Not enough matches are found - %d/%d" % (len(good), MIN_MATCH_COUNT))matchesMask = Nonedraw_params = dict(matchColor=(0, 255, 0),singlePointColor=None,matchesMask=matchesMask,flags=2)result = cv2.drawMatches(template, kp1, target, kp2, good, None, **draw_params) #进行画图操作result = cv2.resize(result,(int(result.shape[1]*0.3),int(result.shape[0]*0.3)))cv2.imshow("find_roi_2", result)cv2.waitKey(0)return result,dst

cut_roi_3.py

# 多边形的切割
import numpy as np
import cv2def polylines_cut(img,pts):## (1) 裁剪边界矩形rect = cv2.boundingRect(pts)x,y,w,h = rectcroped = img[y:y+h, x:x+w].copy()## (2) 生成掩膜pts = pts - pts.min(axis=0)mask = np.zeros(croped.shape[:2], np.uint8)cv2.drawContours(mask, [pts], -1, (255, 255, 255), -1, cv2.LINE_AA)## (3) 反运算dst = cv2.bitwise_and(croped, croped, mask=mask)## (4) 添加白色背景bg = np.ones_like(croped, np.uint8)*255cv2.bitwise_not(bg,bg, mask=mask)dst2 = bg + dstcv2.imshow("cut_roi_3", cv2.resize(dst2,(int(dst2.shape[1]*0.3),int(dst2.shape[0]*0.3))))cv2.waitKey(0)return dst2,pts

perspective_roi_4.py

import numpy as np
import cv2def perspective_roi(cut_img,src_img,points):if cut_img.shape[0]>cut_img.shape[1]:L = cut_img.shape[0]else:L = cut_img.shape[1]print("L的取值:",L)# 下面进行透视变换src = np.float32([[np.int(points[0][0][0]),np.int(points[0][0][1])],[np.int(points[1][0][0]),np.int(points[1][0][1])],[np.int(points[2][0][0]),np.int(points[2][0][1])],[np.int(points[3][0][0]),np.int(points[3][0][1])]])dst = np.float32([[0, 0], [0, L], [L, L], [L, 0]])m = cv2.getPerspectiveTransform(src, dst)result = cv2.warpPerspective(src_img, m, (L, L))result = cv2.resize(result, (int(result.shape[1] * 0.5), int(result.shape[0] * 0.5)))cv2.imshow("perspective_roi_4", result)goal_result = cv2.resize(result,(300,300))cv2.waitKey(0)return goal_result

xiugai_kmeans_5.py

import numpy as np
import cv2
from sklearn.cluster import KMeans
from sklearn.utils import shuffle
from math import cos, pi, sindef v2_by_k_means(img):'''使用k-means二值化'''original_img = np.array(img, dtype=np.float64) # original_img与img格式一样,但为白色src = original_img.copy() # 300*300delta_y = int(original_img.shape[0] * (0.4)) #120delta_x = int(original_img.shape[1] * (0.4)) #120original_img = original_img[delta_y:-delta_y, delta_x:-delta_x] #60*60# print("delta_y:{},delta_x:{},original_img:{}".format(delta_y,delta_x,original_img.shape)h, w, d = src.shape# print("h,w,d:",h,w,d)dts = min([w, h])r2 = (dts / 2) ** 2c_x, c_y = w / 2, h / 2a: np.ndarray = original_img[:, :, 0:3].astype(np.uint8)# 获取尺寸(宽度、长度、深度)height, width = original_img.shape[0], original_img.shape[1]depth = 3image_flattened = np.reshape(original_img, (width * height, depth))'''K-Means算法'''image_array_sample = shuffle(image_flattened, random_state=0)# 随机打乱image_flattened中的元素estimator = KMeans(n_clusters=2, random_state=0) # 生成两个质心estimator.fit(image_array_sample)'''为原始图片的每个像素进行类的分配。'''src_shape = src.shapenew_img_flattened = np.reshape(src, (src_shape[0] * src_shape[1], depth))cluster_assignments = estimator.predict(new_img_flattened)'''我们建立通过压缩调色板和类分配结果创建压缩后的图片'''compressed_palette = estimator.cluster_centers_print("收敛到的质心位置:",compressed_palette) # 收敛到的质心位置a = np.apply_along_axis(func1d=lambda x: np.uint8(compressed_palette[x]), arr=cluster_assignments, axis=0)img = a.reshape(src_shape[0], src_shape[1], depth)threshold = (compressed_palette[0, 0] + compressed_palette[1, 0]) / 2img[img[:, :, 0] > threshold] = 255img[img[:, :, 0] < threshold] = 0cv2.imshow('sd0', img) # 300*300# 下一步因为指针仪表盘是圆形,所以去除掉圆以外的干扰因素for x in range(w):for y in range(h):distance = ((x - c_x) ** 2 + (y - c_y) ** 2)if distance > r2:passimg[y, x] = (255, 255, 255)cv2.imshow('sd', img)img = 255 - imgcv2.imshow('opposite',img)cv2.waitKey(0)cv2.destroyAllWindows()return imgdef dilate(img):'''将Kmeans二值化后的图像进行膨胀处理'''kernel = np.ones((3, 3), np.uint8)dilation = cv2.dilate(img, kernel, iterations=1)return dilation'''下面才是刻度盘读取的核心'''
def get_pointer_rad(img):'''获取角度'''shape = img.shapec_y, c_x, depth = int(shape[0] / 2), int(shape[1] / 2), shape[2]# c_y,c_x表示画的指针线段的起点(圆心)x1=c_x+c_x*0.3src = img.copy()freq_list = []for i in range(361):# 下面的x,y是指针线段的终点坐标x = (x1 - c_x) * cos(i * pi / 180) + c_xy = (x1 - c_x) * sin(i * pi / 180) + c_ytemp = src.copy()cv2.line(temp, (c_x-2, c_y-2), (int(x), int(y)), (0, 0, 255), thickness=14)t1 = img.copy()t1[temp[:, :, 2] == 255] = 255c = img[temp[:, :, 2] == 255]points = c[c == 0] # 0表示黑色,即旋转指针中重合黑色的点最多的角度freq_list.append((len(points), i))cv2.imshow('d', temp)cv2.imshow('d1', t1)cv2.waitKey(0)print('当前角度:',max(freq_list, key=lambda x: x[0]),'度')print(max(freq_list, key=lambda x: x[0]))return max(freq_list, key=lambda x: x[0])

main_code.py

import cv2
import numpy as np
from formula_1 import get_rad_val
from find_roi_FLANN_2 import find_roi
from cut_roi_3 import polylines_cut
from perspective_roi_4 import perspective_roi
from xiugai_kmeans_5 import v2_by_k_means,dilate,get_pointer_radif __name__ == '__main__':template = cv2.imread("second_template.jpg",0)target = cv2.imread('train/5.jpg')target_gray = cv2.cvtColor(target,cv2.COLOR_BGR2GRAY)  # 目标图像cv2.imshow("src",template)#第一步:基于FLANN匹配roi区域find_roi_image,points = find_roi(template,target_gray)#第二步:在原图上剪切出需要的多边形roi区域pts = np.array([[np.int(points[0][0][0]),np.int(points[0][0][1])],[np.int(points[1][0][0]),np.int(points[1][0][1])],[np.int(points[2][0][0]),np.int(points[2][0][1])],[np.int(points[3][0][0]),np.int(points[3][0][1])]])cut_roi_image,keypoints = polylines_cut(target,pts)#第三步:进行透视变换将多边形转化为正方形(为了与模板一样方便后面运算)perspective_roi_4jiaozheng_image = perspective_roi(cut_roi_image,target,points)#第四步:kmeans_5kmeansImage = v2_by_k_means(jiaozheng_image)# 第四步:将Kmeans二值化后的图像进行膨胀处理# dilateImage = dilate(kmeansImage)# 第五步:获取当前的指针角度angle = get_pointer_rad(kmeansImage)# 第六步:角度转换成数值value = get_rad_val(angle[1])print("第5张图片的刻度盘的数值是:{}".format(value))#cv2.waitKey(0)

PS

①在模板的制作中,需要对每个刻度进行像素点位置的测量,可以自己编个程序获取像素点位置,我偷了个懒,用的Photoshop软件,如若电脑没有下载,可以使用PS在线软件
https://www.uupoop.com/
https://blog.csdn.net/xiaocao9903/article/details/53008613

最终10个样本的测试结果:
在这里插入图片描述关于精度的问题,要调整画的那个指针的长度,线段的起点,即圆心的位置,指针的粗细等等,都会影响到读数的精度
在这里插入图片描述

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 绘画教程:常见的4种脸部绘画技巧

    如何绘画人物脸部?内向人物怎么画?外向人物怎么画?人物性格怎么画?学习绘画难吗?怎样才能学好绘画?教程非常简单,赶紧来看看叭:为了消除无论您绘制哪个字符都将绘制同一张脸的担心,我将介绍“绘制不同字符的方法”。这次,这是五次系列赛中的第四次,让我们集中讨论绘…...

    2024/5/5 16:33:19
  2. BGP反射器

    BGP反射器:解决IBGP全互联的问题 IBGP全互联的问题:一个AS内所有的BGP Speaker相互形成IBGP全互联,导致IBGP的会话数目是n(n-1)/2通过IBGP获得的最优可达路由不会发布给其他IBGP邻居(水平分割)如何解决全互联问题:1、路由反射:允许将从IBGP对等体接收的更新信息传给某…...

    2024/5/4 7:26:10
  3. leetcode刷题-16_3Sum Closest

    东阳的学习记录,坚持就是胜利!暴力法 暴力法依旧超时,其实这题和15题几乎一模一样,就不写了 从两端逼近 同样是两边向中间逼近的方法,和15题没有太大的区别 class Solution:def threeSumClosest(self, nums: list, target: int) -> int:nums.sort()# print(nums)closes…...

    2024/4/29 5:50:39
  4. VS2015 + Qt5.9.2开发中无法打开源文件“ui_*.h” 和 error MSB6006: “cmd.exe”已退出,代码为 3之解决办法。

    转载请注明出处:http://www.cnblogs.com/liangliu/p/8118149.htmlVS2015中新建的QtGuiApplication项目,总是显示#include "ui_XXXXX.h"出错,找不到源文件"ui_XXXXX.h",在文件XXXXX.ui上右键再点击编译,编译未通过,提示------》》》无法打开源文件“u…...

    2024/4/29 5:50:23
  5. 2020-08-09

    在线求解答 温控表跟fx-5u 485通讯 前几天程序也写好了都整好了 通讯也没问题 但是今天一上上电 全部没反应 温度也不采集了 程序内数值也不变化了 设置温度这些也没反应 改了半天程序也是不起作用 排除掉程序问题 我开始拆线 一共四个温控表 拆掉三块 剩一块的时候通讯正常…...

    2024/5/3 14:46:28
  6. 关于路由器

    我们区分一个问题是不是玄学,就看它是否可以被解释,可以被精准复现。 事实上,目前路由器所有的问题,都是可以被解释可以被复现的。所以路由器这玩意没有玄学。 问题无非两类,软件问题,硬件问题。 讲几个有意思的事情 1.19元的日本洋垃圾路由器,长距离ping丢包率比某199元…...

    2024/5/4 1:51:48
  7. Android问题笔记

    1 Post请求失败异常 W/System.err: java.net.SocketException: socket failed: EACCES (Permission denied)原因 权限不够 在文件清单中添加uses-permission方案<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://…...

    2024/4/29 5:50:03
  8. 2020年高手都爱用的10种插画风格,全都在这了!

    绘画初学者如何学习插画?插画风格有哪些?商业插画要如何入行?学习绘画难吗?怎样才能学好绘画?想必这些都是绘画初学者们经常在想的问题吧,就是不知道如何才能绘画好自己想要绘画的东西,比如说想要入行插画行业,但是却不知道应该如何入行才好,教程非常简单,赶紧来看看…...

    2024/4/29 5:49:59
  9. CogFindEllipseTool 几何形状查询和弥合工具

    CogFindEllipseTool的功能原理CogFindEllipseTool工具用来查找椭圆,它与CogFindCircleTool、CogFindCornerTool一样,需要预先知道椭圆的大概位置,然后再椭圆的大概位置放在椭圆弧,可以设置椭圆弧的起始角和终止角、中心点坐标、长短轴半径、卡尺数量等参数。卡尺区域在椭圆…...

    2024/4/29 5:49:53
  10. 大型架构及配置技术大数据(二)之完全分布式,节点管理,NFS网关

    一、完全分布式主机名 IP地址 软件 角色nn60 192.168.4.60/24 HDFS,YARN NameNode SecondaryNameNode ResourceManagernode61 192.168.4.61/24 HDFS,YARN DataNode NodeManagernode62 192.168.4.62/24 HDFS,YARN Data…...

    2024/5/5 11:36:12
  11. 在 Eclipse 和 sublime 中配置与使用 javascript 语法风格检测工具

    JSHint(http://www.jshint.com/)是一个JavaScript语法和风格检查工具,你可以用它来提醒代码风格相关的问题。它可以很好地被集成到许多常用的编辑器中,是统一团队编码风格的一个很好的工具。 JSHint Home: http://www.jshint.com/ JSHint Options: http://www.jshint.com/o…...

    2024/5/5 17:44:28
  12. Flume-监控端口数据案例,实时监控单个追加文件案例

    文章目录监控端口数据官方案例实时监控单个追加文件 监控端口数据官方案例 1)案例需求: 使用Flume监听一个端口,收集该端口数据,并打印到控制台。 2)需求分析:3)实现步骤: (1)安装netcat工具 [qinjl@hadoop102 software]$ sudo yum install -y nc(3)创建Flume Agen…...

    2024/4/29 5:50:10
  13. shiro自定义Realm

    三、SpringBoot整合Shiro完成权限管理案例—自定义Realm使用JdbcRealm可以完成用户权限管理,但是我们必须提供JdbcRealm规定的数据表结构;如果在我们的项目开发中 ,这个JdbcRealm规定的数据表结构不能满足开发需求,该如何处理呢?自定义数据库表结构自定义Realm实现认证和授…...

    2024/5/5 16:53:28
  14. Java学习记录 多线程篇

    线程 线程 是进程中的执行过程,一个进程包含有多个线程 进程 是一个运行的应用程序,每个进程都有自己独立的内存空间。在Windows系统中,一个运行的exe(应用程序)就是一个进程 实现线程 实现线程线程主要有 java.lang.Thread类 与 Runnable接口 Thread类Class Thread java.…...

    2024/5/5 17:19:54
  15. 两数组交集

    1、给定两个数组,编写一个函数来计算它们的交集。 示例 1: 输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2,2]示例 2: 输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[4,9]方法1:哈希表 public int[] intersect(int[] nums1,int[] nums2) {if(nums1.length>nums2…...

    2024/4/29 5:50:01
  16. idea2020.2显示out和target目录

    1.查看model里有没有out和target目录2.查看3.在idea页面进行设置4.结果显示...

    2024/4/29 5:49:52
  17. nested exception is org.apache.ibatis.binding.BindingException: Parameter ‘status‘ not found. Availa

    点击看更多解决办法 我的问题 导包时倒错了点击看更多解决办法...

    2024/4/29 5:49:48
  18. thymeleaf 遍历

    thymeleaf 遍历...

    2024/4/29 5:49:28
  19. [Ubuntu]Ubuntu16.04安装MySQL8.0

    1.去http://dev.mysql.com/downloads/repo/apt/.下载一个mysql-apt-config_0..***_all.deb,使用 sudo dpkg -i mysql-apt-config_0..***_all.deb 安装执行,选择MySQL8.0,OK。 然后apt update一下使用sudo apt install mysql-server命令,就会安装MySQL8.0按此方法会在安装过…...

    2024/4/29 5:49:30
  20. UI设计配色专辑,设计师应用技巧

    颜色不仅在设计世界里,在我们生活的世界中都扮演着很重要的角色,一套好的调色板对设计的影响是非常大的,搜UI (SOOUI) 带来更加简单高效的技巧去定义一个色板专辑。产品中大概可以得出一个公式:品牌色 + 提醒类型颜色(成功,错误,警告)+ 中性黑白灰颜色(各种字体,背景…...

    2024/4/29 5:49:27

最新文章

  1. 2. 深度学习笔记--损失函数

    在机器学习中&#xff0c;损失函数是代价函数的一部分&#xff0c;而代价函数则是目标函数的一种类型。 Loss function&#xff0c;即损失函数&#xff1a;用于定义单个训练样本与真实值之间的误差&#xff1b; Cost function&#xff0c;即代价函数&#xff1a;用于定义单个批…...

    2024/5/5 17:50:55
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 如何训练自己的ChatGPT?需要多少训练数据?

    近年&#xff0c;聊天机器人已经是很常见的AI技术。小度、siri、以及越来越广泛的机器人客服&#xff0c;都是聊天机器人的重要适用领域。然而今年&#xff0c;ChatGPT的面世让这一切都进行到一个全新的高度&#xff0c;也掀起了大语言模型&#xff08;LLM&#xff09;的热潮。…...

    2024/5/3 23:35:36
  4. 面试经典算法系列之双指针1 -- 合并两个有序数组

    面试经典算法题1 – 合并两个有序数组 LeetCode.88 公众号&#xff1a;阿Q技术站 问题描述 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#…...

    2024/5/5 8:39:32
  5. 实现窗口拖拽移动

    import Vue from "vue"; /* * 定义公共js里&#xff0c;在入口文件main.js中import&#xff1b; * 给elementUI的dialog上加上 v-dialogDrag 指令就可以实现弹窗的全屏和拉伸了。 */ // v-dialogDrag: 弹窗拖拽水平方向伸缩 Vue.directive(dialogDrag, { bind(e…...

    2024/5/4 10:53:59
  6. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/5/4 12:05:22
  7. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/5/5 12:22:20
  8. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/5/4 14:46:16
  9. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/4 23:54:44
  10. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/5/5 15:25:47
  11. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/5/4 23:54:49
  12. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/4 23:54:44
  13. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/5/4 14:46:12
  14. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/4 14:46:11
  15. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/5/4 14:46:11
  16. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/5/5 2:25:33
  17. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/4 21:24:42
  18. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/5/5 13:14:22
  19. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/5/4 13:16:06
  20. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/5 17:03:52
  21. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/4 14:46:05
  22. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/5/5 3:37:58
  23. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/5/4 23:54:30
  24. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/5 17:03:21
  25. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/5/5 15:25:31
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57