2 图片的分割处理和亚像素精度处理(c++和python)

        本文的图片处理分为图片分割、图像的亚像素坐标处理。亚像素处理的原理可以看论文一种基于多项式插值改进的亚像素细分算法,该论文的详解及c++的代码实现可以看博文基于多项式插值的亚像素边缘定位算法_基于多项式插值的亚像素算法-CSDN博客。下面的内容很多来自以上博文的内容,我只是对部分代码做了稍微的修改。

        注意,前三部分是亚像素的理论和c++的代码实现,第四部分是python的代码实现。

一. 背景

        在测量或者定位的应用中会涉及到边缘检测, 但是像 OpenCV 这样的开源库中边缘检测算法的精度在像素级别, 比如 Canny, Sobel blablabla. 要想提高精度就需要用到 亚像素 的技术, 在不改变硬件成本的前提下提高检测精度。

二、代码实现(龟速版)

1.梯度幅值

梯度检测包含幅值和方向,用8个方向模板在检测图像上进行卷积运算(模板滑过的地方的像素值和模板中对应的值相乘, 最后全部加总), 得到 8 张梯度图像, 方向模板如下. 模板的方向就是和 X 轴的夹角。

以下代码生成 8 个方向模板

#include<opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include<list>
#include<vector>
#include <typeinfo>using namespace cv;
using namespace std;#define KERNEL_SUM 8Mat kernels[KERNEL_SUM];int k = 0;
kernels[k++] = (Mat_<float>(3, 3) <<  1,  2,  1,  0,  0,  0, -1, -2, -1);	// 270°
kernels[k++] = (Mat_<float>(3, 3) <<  2,  1,  0,  1,  0, -1,  0, -1, -2);	// 315°
kernels[k++] = (Mat_<float>(3, 3) <<  1,  0, -1,  2,  0, -2,  1,  0, -1);	// 0°
kernels[k++] = (Mat_<float>(3, 3) <<  0, -1, -2,  1,  0, -1,  2,  1,  0);	// 45°flip(kernels[0], kernels[k++], 0);											// 90°kernels[k++] = (Mat_<float>(3, 3) << -2, -1,  0, -1,  0,  1,  0,  1,  2);	// 135°flip(kernels[2], kernels[k++], 1);											// 180°kernels[k++] = (Mat_<float>(3, 3) <<  0,  1,  2, -1,  0,  1, -2, -1,  0);	// 225°

        接下来利用模板卷积生成梯度图像, 假设要检测的图像长下面这个样, 边缘是模糊的

        利用 filter2D 函数计算梯度

// 梯度图像
Mat gradients[KERNEL_SUM];
// 检测图像, 路径自己更改, 注意要是单通道图像
Mat imgsrc = imread("E:\\vs\\daima\\opencvs\\OpencvPractice\\1.jpg");//IMREAD_ANYCOLORfor (int k = 0; k < KERNEL_SUM; k++)
{filter2D(imgsrc, gradients[k], CV_16S, kernels[k]);// CV_64F    //Mat imgshowt;normalize(gradients[k], imgshowt, 0, 255, NORM_MINMAX);cv::Mat rlt;imgshowt.convertTo(rlt, CV_8UC1);//将imgshowt转换为无符号单通道的整型并赋值给rlt  CV_8UC1cvtColor(rlt, gradients[k], cv::COLOR_BGR2GRAY);//将rlt转换为灰度图并赋值给gradients[k]imshow("img", rlt);waitKey(0);
}

        注意,这里和前面博文的代码稍有不同,因为原图像是3通道的图像(我在前面博文截取了个圆的图片用来处理),在以上代码中用filter2D函数后将处理的图片修改为了单通道图片,并且显示了8个卷积核处理的不同图片,结果如下(截取了前博文的图片,但效果相同):

        从图中可以看出各模板可以检测出指定方向的边缘, 其中白色表示该方向最大梯度值, 黑色表示反向最大梯度值。

梯度幅值最大值处的点就是边缘的整数坐标。

2. 梯度方向

        梯度方向指向梯度幅值最大的方向, 现在已经有 8 张幅值图像, 只要比较其中最大的幅值即可得到其方向, 例如第 0 张梯度图像在 (i, j) 处的幅值比其他图像都大, 则 (i, j) 点的梯度方向是 270°. 下面我们用代码求出最大幅度值和方向。

//2. 梯度方向// (1. 角度列表
const short angle_list[] = { 270, 315, 0, 45, 90, 135, 180, 225 };
// (2. 总幅值矩阵
Mat amplitude(imgsrc.rows, imgsrc.cols, CV_8UC1, Scalar::all(0));// (3. 角度矩阵, 后面初始化成 -64 只是为了归一化之后能显示角度 0
Mat angle(imgsrc.rows, imgsrc.cols, CV_16SC1, Scalar::all(-64));//CV_16SC1   -64for (int r = 0; r < imgsrc.rows; r++)
{short* pAng = angle.ptr<short>(r);for (int c = 0; c < imgsrc.cols; c++){// 找出最大值for (int i = 0; i < KERNEL_SUM; i++){if (amplitude.ptr<unsigned char>(r)[c] < gradients[i].ptr<unsigned char>(r)[c]){amplitude.ptr<unsigned char>(r)[c] = gradients[i].ptr<unsigned char>(r)[c];pAng[c] = angle_list[i];}}}
}Mat imgshow;imshow("amplitude", amplitude);
imwrite("D:\Datas\\1.jpg",amplitude);
waitKey(0);normalize(angle, imgshow, 0, 255, NORM_MINMAX);
imgshow.convertTo(imgshow, CV_8UC1);
imshow("amplitude", imgshow);
waitKey(0);

        完成之后显示幅值和角度图像如下:

 

3. 单像素边缘

        以上的方式处理的图像边缘是比较粗的,那么我们如何将边缘的粗细提取成单像素呢,就是找最亮的像素点作为边缘。这个也比较简单, 只要在 3 × 3 的邻域中根据梯度的方向比较中心点 “左右” 的两个点幅值就可以知道了. 左右我打了引号, 有可能是在对角方向和上下方向. 如果不能理解的话, 把幅值图放大如下, 仿佛看到了马赛克

        我们发现在梯度方向幅值从小到大, 再变小, 我们只需要判断中间是否大于两边(“左右”)的幅值,如果同时大于两边,则是边缘点, 如果不是同时大于两边, 则不是边缘点, 下面用代码实现此判断。

 // 3.单像素边缘,整数坐标边缘图像//cout << "===============> start 单像素边缘 <================" << endl;Mat edge(imgsrc.rows, imgsrc.cols, CV_8UC1, Scalar::all(0));for (int r = 1; r < imgsrc.rows - 1; r++){// 3 * 3 邻域, 所以用 3 个指针, 一个指针指一行const unsigned char* pAmp1 = amplitude.ptr<unsigned char>(r - 1);const unsigned char* pAmp2 = amplitude.ptr<unsigned char>(r);const unsigned char* pAmp3 = amplitude.ptr<unsigned char>(r + 1);const short* pAng = angle.ptr<short>(r);unsigned char* pEdge = edge.ptr<unsigned char>(r);for (int c = 1; c < imgsrc.cols - 1; c++){switch (pAng[c]){case 270:if (pAmp2[c] > pAmp1[c] && pAmp2[c] >= pAmp3[c]){pEdge[c] = 255;}break;case 90:if (pAmp2[c] >= pAmp1[c] && pAmp2[c] > pAmp3[c]){pEdge[c] = 255;}break;case 315:if (pAmp2[c] > pAmp1[c - 1] && pAmp2[c] >= pAmp3[c + 1]){pEdge[c] = 255;}break;case 135:if (pAmp2[c] >= pAmp1[c - 1] && pAmp2[c] > pAmp3[c + 1]){pEdge[c] = 255;}break;case 0:if (pAmp2[c] > pAmp2[c - 1] && pAmp2[c] >= pAmp2[c + 1]){pEdge[c] = 255;}break;case 180:if (pAmp2[c] >= pAmp2[c - 1] && pAmp2[c] > pAmp2[c + 1]){pEdge[c] = 255;}break;case 45:if (pAmp2[c] >= pAmp1[c + 1] && pAmp2[c] > pAmp3[c - 1]){pEdge[c] = 255;}break;case 225:if (pAmp2[c] > pAmp1[c + 1] && pAmp2[c] >= pAmp3[c - 1]){pEdge[c] = 255;}break;default:break;}}}imshow("edg", edge);//总共有462个点为255(白色)waitKey(0);//cout << "===============> end 单像素边缘 <================" << endl;

        该代码得到的图片显示结果如下:

        现在的边缘是不是只有一个像素宽了, 到这里可以算是完成了 50% 工作了, 还有两个问题需要解决, 一是如何求出亚像素坐标, 二是怎样表示亚像素坐标

4. 亚像素坐标

        根据以下公式可计算亚像素坐标, 其实这个公式是二次多项式拟合(剪切前面博文的内容)

        下面代码中, sin 前面的负号非常关键, 因为图像的 y 方向和直角坐标系的 y 方向相反

// 4. 亚像素坐标
cout << "===============> start 亚像素坐标 <================" << endl;// 根号2
const double root2 = sqrt(2.0);
// 三角函数表
double tri_list[2][KERNEL_SUM] = { 0 };for (int i = 0; i < KERNEL_SUM; i++)
{tri_list[0][i] = cos(angle_list[i] * CV_PI / 180.0);// sin前面的负号非常关键, 因为图像的y方向和直角坐标系的y方向相反tri_list[1][i] = -sin(angle_list[i] * CV_PI / 180.0);}// vector 方式记录小数坐标
vector<Point3f> vPts;
// Mat 方式记录小数坐标, 注意这里是双通道
Mat coordinate(imgsrc.rows, imgsrc.cols, CV_32FC2, Scalar::all(0));for (int r = 1; r < imgsrc.rows - 1; r++)
{// 3 * 3 邻域, 所以用3个指针, 一个指针指一行const short* pAmp1 = amplitude.ptr<short>(r - 1);const short* pAmp2 = amplitude.ptr<short>(r);const short* pAmp3 = amplitude.ptr<short>(r + 1);const short* pAng = angle.ptr<short>(r);const short* pEdge = edge.ptr<short>(r);float* pCoordinate = coordinate.ptr<float>(r);for (int c = 1; c < imgsrc.cols - 1; c++){if (pEdge[c]){int nAngTmp = 0;double dTmp = 0;switch (pAng[c]){case 270:nAngTmp = 0;dTmp = ((double)pAmp1[c] - pAmp3[c]) / (pAmp1[c] + pAmp3[c] - 2 * pAmp2[c] + 0.000001) * 0.5;break;case 90:nAngTmp = 4;dTmp = -((double)pAmp1[c] - pAmp3[c]) / (pAmp1[c] + pAmp3[c] - 2 * pAmp2[c] + 0.000001) * 0.5;break;case 315:nAngTmp = 1;dTmp = ((double)pAmp1[c - 1] - pAmp3[c + 1]) / (pAmp1[c - 1] + pAmp3[c + 1] - 2 * pAmp2[c] + 0.000001) * root2 * 0.5;break;case 135:nAngTmp = 5;dTmp = -((double)pAmp1[c - 1] - pAmp3[c + 1]) / (pAmp1[c - 1] + pAmp3[c + 1] - 2 * pAmp2[c] + 0.000001) * root2 * 0.5;break;case 0:nAngTmp = 2;dTmp = ((double)pAmp2[c - 1] - pAmp2[c + 1]) / (pAmp2[c - 1] + pAmp2[c + 1] - 2 * pAmp2[c] + 0.000001) * 0.5;break;case 180:nAngTmp = 6;dTmp = -((double)pAmp2[c - 1] - pAmp2[c + 1]) / (pAmp2[c - 1] + pAmp2[c + 1] - 2 * pAmp2[c] + 0.000001) * 0.5;break;case 45:nAngTmp = 3;dTmp = ((double)pAmp3[c - 1] - pAmp1[c + 1]) / (pAmp1[c + 1] + pAmp3[c - 1] - 2 * pAmp2[c] + 0.000001) * root2 * 0.5;break;case 225:nAngTmp = 7;dTmp = -((double)pAmp3[c - 1] - pAmp1[c + 1]) / (pAmp1[c + 1] + pAmp3[c - 1] - 2 * pAmp2[c] + 0.000001) * root2 * 0.5;break;default:break;}const double x = c + dTmp * tri_list[0][nAngTmp];const double y = r + dTmp * tri_list[1][nAngTmp];const short z = angle_list[nAngTmp];//cout << dTmp<< "    "<< tri_list[0][nAngTmp]<<"   "<< dTmp * tri_list[0][nAngTmp] << endl;// vector方式vPts.push_back(Point3f((float)x, (float)y, (short)z));// Mat 方式pCoordinate[c << 1] = (float)x;pCoordinate[(c << 1) + 1] = (float)y;}}
}//cout << "" << vPts.size() << endl;//总共有462个点为255(白色)
//for (size_t i = 0; i < vPts.size(); i++)
//{
//    cout << vPts[i].z << ":    " << vPts[i].x << ",    " << vPts[i].y <<endl;
//}cout << "===============> end 亚像素坐标 <================" << endl;
return 0;

        注意,以上代码大家要了解为什么不同角度下加减不同,了解这个很重要。

三、龟速测试

至此, 龟速版本的代码已经完成了, 找一张其他图像试试? 找 lena 来试试。

        看到边缘图像有的同学可能要伤心了, 女神怎么变成这样了, 那么多边缘被检测出来了, 我们不需要那么多边缘啊. 同学别急, 检测出来那么多边缘是因为我们没有对梯度幅度进行筛选, 你想一下, 我们在计算单像素边缘的时候只要满足中间大于两边就算边缘, 女神图像中有一些中间只比两边大了一点点, 所以这种边缘可以去除,  我们想要的是比较强烈的边缘,解决办法就是设定一个阈值, 当梯度值大于阈值是才算真正的边缘。

将单像素边缘检测修改如下:

// 3.单像素边缘,整数坐标边缘图像
//cout << "===============> start 单像素边缘 <================" << endl;// 阈值
double thres = 128;	// 此处为增加Mat edge(imgsrc.rows, imgsrc.cols, CV_8UC1, Scalar::all(0));for (int r = 1; r < imgsrc.rows - 1; r++)
{// 3 * 3 邻域, 所以用 3 个指针, 一个指针指一行const unsigned char* pAmp1 = amplitude.ptr<unsigned char>(r - 1);const unsigned char* pAmp2 = amplitude.ptr<unsigned char>(r);const unsigned char* pAmp3 = amplitude.ptr<unsigned char>(r + 1);const short* pAng = angle.ptr<short>(r);unsigned char* pEdge = edge.ptr<unsigned char>(r);for (int c = 1; c < imgsrc.cols - 1; c++){// 以下判断为增加部分if (pAmp2[c] < thres){continue;}//switch (pAng[c]){case 270:if (pAmp2[c] > pAmp1[c] && pAmp2[c] >= pAmp3[c]){pEdge[c] = 255;}break;case 90:if (pAmp2[c] >= pAmp1[c] && pAmp2[c] > pAmp3[c]){pEdge[c] = 255;}break;case 315:if (pAmp2[c] > pAmp1[c - 1] && pAmp2[c] >= pAmp3[c + 1]){pEdge[c] = 255;}break;case 135:if (pAmp2[c] >= pAmp1[c - 1] && pAmp2[c] > pAmp3[c + 1]){pEdge[c] = 255;}break;case 0:if (pAmp2[c] > pAmp2[c - 1] && pAmp2[c] >= pAmp2[c + 1]){pEdge[c] = 255;}break;case 180:if (pAmp2[c] >= pAmp2[c - 1] && pAmp2[c] > pAmp2[c + 1]){pEdge[c] = 255;}break;case 45:if (pAmp2[c] >= pAmp1[c + 1] && pAmp2[c] > pAmp3[c - 1]){pEdge[c] = 255;}break;case 225:if (pAmp2[c] > pAmp1[c + 1] && pAmp2[c] >= pAmp3[c - 1]){pEdge[c] = 255;}break;default:break;}}
}
imshow("edg", edge);//总共有462个点为255(白色)
imwrite("D:\Datas\\2.jpg", edge);
waitKey(0);//cout << "===============> end 单像素边缘 <================" << endl;

四、python的代码实现

由于上面已经讲清楚原理和步骤,python代码和c++相似。代码如下:

import math
import numpy as np
import cv2
import matplotlib.pyplot as plt#8个卷积核,分别对应0,45,90,135,180,225,270,315
#度数
angle_index = np.array((0,45,90,135,180,225,270,315)) #(1,8)
#卷积核
keras = np.zeros((8,3,3)) #存放8个3X3的卷积核
keras[0] = np.array(([1,  0, -1],[2,  0, -2],[1,  0, -1]), dtype="float32")# 0
keras[1] = np.array(([0, -1, -2],[1,  0, -1],[2,  1,  0]), dtype="float32")# 45
keras[2] = np.array(([-1,  -2, -1],[0,  0, 0],[1,  2, 1]), dtype="float32")# 90
keras[3] = np.array(([-2,  -1, 0],[-1,  0, 1],[0,  1, 2]), dtype="float32")# 135
keras[4] = np.array(([-1,  0, 1],[-2,  0, 2],[-1,  0, 1]), dtype="float32")# 180
keras[5] = np.array(([0,  1, 2],[-1,  0, 1],[-2,  -1, 0]), dtype="float32")# 225
keras[6] = np.array(([1,  2, 1],[0,  0, 0],[-1,  -2, -1]), dtype="float32")# 270
keras[7] = np.array(([2,  1, 0],[1,  0, -1],[0,  -1, -2]), dtype="float32")# 315if __name__ == "__main__":# 1.输入图片路径,读取图片img1 = cv2.imread(r"imgs/1.jpg") #imgs/1.jpg# 2.灰度化处理图像grayImage = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)# 3.创建存放8个边缘处理的图片的容器dst = np.zeros((8,grayImage.shape[0],grayImage.shape[1]))# 循环8个卷积核,对不同的卷积核进行filter2D处理for i in range(8):dst[i] = cv2.filter2D(grayImage, -1, keras[i])# 4.梯度方向#对比上面8个图片,找出zui# (1 创建一个将8个半圆合并成一个圆的图片amplitude = np.zeros((grayImage.shape[0],grayImage.shape[1]))angle = np.zeros((grayImage.shape[0],grayImage.shape[1])) #每个坐标对应的角度for i in range(grayImage.shape[0]):for j in range(grayImage.shape[0]):st = 0for k in range(8):if amplitude[i][j] < dst[k][i][j]:amplitude[i][j] = dst[k][i][j]st = angle_index[k]angle[i][j] = stcv2.imshow("ss",amplitude)cv2.waitKey(0)cv2.imshow("ss", angle)cv2.waitKey(0)# 5.单像素边缘#在amplitude中找到单个像素点#(1 创建一个单个像素点的图片处理器edge = np.zeros((grayImage.shape[0], grayImage.shape[1]))for r in range(1,grayImage.shape[0]-1):pAmp1 = amplitude[r-1]pAmp2 = amplitude[r]pAmp3 = amplitude[r + 1]for c in range(1, grayImage.shape[1] - 1):if angle[r][c] == 270:if (pAmp2[c] > pAmp1[c] and pAmp2[c] >= pAmp3[c]):edge[r][c] = 255if angle[r][c] == 90:if (pAmp2[c] >= pAmp1[c] and pAmp2[c] > pAmp3[c]):edge[r][c] = 255if angle[r][c] == 315:if (pAmp2[c] > pAmp1[c - 1] and pAmp2[c] >= pAmp3[c + 1]):edge[r][c] = 255if angle[r][c] == 135:if (pAmp2[c] >= pAmp1[c - 1] and pAmp2[c] > pAmp3[c + 1]):edge[r][c] = 255if angle[r][c] == 0:if (pAmp2[c] > pAmp2[c - 1] and pAmp2[c] >= pAmp2[c + 1]):edge[r][c] = 255if angle[r][c] == 180:if (pAmp2[c] >= pAmp2[c - 1] and pAmp2[c] > pAmp2[c + 1]):edge[r][c] = 255if angle[r][c] == 45:if (pAmp2[c] >= pAmp1[c + 1] and pAmp2[c] > pAmp3[c - 1]):edge[r][c] = 255if angle[r][c] == 225:if (pAmp2[c] > pAmp1[c + 1] and pAmp2[c] >= pAmp3[c - 1]):edge[r][c] = 255cv2.imshow("tt",edge)cv2.waitKey(0)# 6.亚像素坐标root2 = math.sqrt(2.0) #根号2tri_list = np.zeros((2,8))#三角函数表for i in range(8):tri_list[0][i] = math.cos(angle_index[i] * math.pi / 180.0)tri_list[1][i] = -math.sin(angle_index[i] * math.pi / 180.0)#sin前面的负号非常关键, 因为图像的y方向和直角坐标系的y方向相反vPts = [] #记录小数坐标(x,y)for r in range(1,grayImage.shape[0]-1):# 3 * 3 邻域, 所以用3个指针, 一个指针指一行pAmp1 = amplitude[r - 1]pAmp2 = amplitude[r]pAmp3 = amplitude[r + 1]for c in range(1, grayImage.shape[1] - 1):dTmp = 0nAngTmp = 0if angle[r][c] == 270:nAngTmp = 6dTmp = (pAmp1[c] - pAmp3[c]) / (pAmp1[c] + pAmp3[c] - 2 * pAmp2[c] + 0.00001) * 0.5elif angle[r][c] == 90:nAngTmp = 2dTmp = -(pAmp1[c] - pAmp3[c]) / (pAmp1[c] + pAmp3[c] - 2 * pAmp2[c] + 0.00001) * 0.5elif angle[r][c] == 315:nAngTmp = 7dTmp = (pAmp1[c - 1] - pAmp3[c + 1]) / (pAmp1[c - 1] + pAmp3[c + 1] - 2 * pAmp2[c] + 0.00001) * root2 * 0.5elif angle[r][c] == 135:nAngTmp = 3dTmp = -(pAmp1[c - 1] - pAmp3[c + 1]) / (pAmp1[c - 1] + pAmp3[c + 1] - 2 * pAmp2[c] + 0.00001) * root2 * 0.5elif angle[r][c] == 0:nAngTmp = 0dTmp = (pAmp2[c - 1] - pAmp2[c + 1]) / (pAmp2[c - 1] + pAmp2[c + 1] - 2 * pAmp2[c] + 0.00001) * 0.5elif angle[r][c] == 180:nAngTmp = 4dTmp = -(pAmp2[c - 1] - pAmp2[c + 1]) / (pAmp2[c - 1] + pAmp2[c + 1] - 2 * pAmp2[c] + 0.00001) * 0.5elif angle[r][c] == 45:nAngTmp = 1dTmp = (pAmp3[c - 1] - pAmp1[c + 1]) / (pAmp1[c + 1] + pAmp3[c - 1] - 2 * pAmp2[c] + 0.00001) * root2 * 0.5elif angle[r][c] == 225:nAngTmp = 5dTmp = -(pAmp3[c - 1] - pAmp1[c + 1]) / (pAmp1[c + 1] + pAmp3[c - 1] - 2 * pAmp2[c] + 0.00001) * root2 * 0.5x = c + dTmp * tri_list[0][nAngTmp]y = r + dTmp * tri_list[1][nAngTmp]vPts.append([x,y])

        运行结果和c++的相似,大家可以自行选择编程语言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/29631.shtml

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

相关文章

【论文阅读】-- 时间空间化:用于深度分类器训练的可扩展且可靠的时间旅行可视化

Temporality Spatialization: A Scalable and Faithful Time-Travelling Visualization for Deep Classifier Training 摘要1 引言2 动机3 问题定义4 方法论4.1 时空复合体4.2 复数约简 5 实验6 相关工作7 结论参考文献 摘要 时间旅行可视化回答了深度分类器的预测是如何在训练…

MATLAB画图时添加标注显示有效数字的位数,可以编辑此函数

本来系统有个函数&#xff0c;在图像窗口选择标注工具&#xff0c;再在图像窗口右击鼠标&#xff0c;选择"编辑文本更新函数..."&#xff0c;即打开系统的设置函数&#xff0c;可以修改最后一行&#xff1a; formattedValue [valueFormat num2str(value,4) removeV…

QT-day3

1、思维导图 2、升级优化自己应用程序的登录界面。 要求&#xff1a; 1. qss实现 2. 需要有图层的叠加 &#xff08;QFrame&#xff09; 3. 设置纯净窗口后&#xff0c;有关闭等窗口功能。 4. 如果账号密码正确&#xff0c;则实现登录界面关闭&#xff0c;另一个应用界面显示。…

C#标志位的使用

C#作为一种功能强大的编程语言&#xff0c;是在.NET框架中广泛使用的语言之一。在实际应用中&#xff0c;C#的标志位在各种系统设计和编程实践中会涉及到。这篇文章将讨论如何使用C#的标志位来跟踪报警声音的播放状态。 报警系统是一种广泛应用的系统&#xff0c;它可以在关键时…

本地部署Ollama+qwen本地大语言模型Web交互界面

什么是 Ollama WebUI&#xff1f; Ollama WebUI 已经更名为 Open WebUI. Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 WebUI&#xff0c;旨在完全离线操作。它支持各种 LLM 运行程序&#xff0c;包括 Ollama 和 OpenAI 兼容的 API。 Ollama WebUI 是一个革命性的 L…

深度学习(九)——神经网络:最大池化的作用

一、 torch.nn中Pool layers的介绍 官网链接&#xff1a; https://pytorch.org/docs/stable/nn.html#pooling-layers 1. nn.MaxPool2d介绍 nn.MaxPool2d是在进行图像处理时&#xff0c;Pool layers最常用的函数 官方文档&#xff1a;MaxPool2d — PyTorch 2.0 documentation &…

微信小程序毕业设计-小区疫情防控系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

ChatGPT的问题与回复的内容导出(Chorme)

我给出两种方式&#xff0c;第一种方式无使用要求&#xff0c;第二种方式必须安装Chorme 个人更推荐第二种方式 第一种方式&#xff1a;使用chatgpt自带的数据导出 缺点&#xff1a;会将当前未归档的所有聊天记录导出&#xff0c;发送到你的电子邮箱中 第二种方式&#xff1a…

STM32 proteus + STM32Cubemx仿真教程(第五课ADC光敏电阻采样教程)

文章目录 前言一、ADC概念二、光敏电阻的概念1. 光敏电阻的工作原理2. 光敏电阻的特性3. 光敏电阻的应用4. 光敏电阻的电路设计5. 实际使用中的注意事项总结 三、STM32Cubemx创建工程四、proteus仿真电路图五、代码编写1. HAL_ADC_Start 函数原型参数返回值功能描述示例 2. HAL…

Java每日作业day6.18

ok了家人们今天我们继续学习方法的更多使用&#xff0c;闲话少叙&#xff0c;我们来看今天学了什么 1.重载 在同一个类中&#xff0c;可不可以存在同名的方法&#xff1f;重载:在同一个类中&#xff0c;定义了多个同名的方法&#xff0c;但每个方法具有不同的参数类型或参数个…

网络编程4----网络原理(面试及期末必备)

1 应用层 应用层是与程序员关系最密切的一层&#xff0c;在应用层这里了&#xff0c;很多时候&#xff0c;都是使用程序员自定义的协议&#xff0c;当然&#xff0c;也有很多现成的协议供我们使用。 “自定义协议”&#xff1a; 自定义一个协议&#xff0c;也就是自己做一个…

接口联调测试

在我们工作过程中&#xff0c;有时需要一些接口进行联调。接口联调测试&#xff0c;就是按照业务要求&#xff0c;把接口进行组合测试。接口组合起来才能实现完整的业务&#xff0c;体现更大的价值。 接口联调测试业务分析&#xff1a; 原因&#xff1a; 项目中的接口是多个…

全国产城市轨道交通运营公安AI高清视频监控系统

方案简介 城市轨道交通运营公安高清视频监控系统解决方案针对运营部门和公安部门的安保需求&#xff0c;选用华维视讯的各类前端和视频编解码、控制产品&#xff0c;通过统一平台提供视频监控服务和智能应用&#xff0c;满足轨道交通运营业主客运组织和抢险指挥的需求&#xff…

C++ | Leetcode C++题解之第151题反转字符串中的单词

题目&#xff1a; 题解&#xff1a; class Solution { public:string reverseWords(string s) {int left 0, right s.size() - 1;// 去掉字符串开头的空白字符while (left < right && s[left] ) left;// 去掉字符串末尾的空白字符while (left < right &…

03-ES6新语法

1. ES6 函数 1.1 函数参数的扩展 1.1.1 默认参数 function fun(name,age17){console.log(name","age); } fn("张美丽",18); // "张美丽",18 fn("张美丽",""); // "张美丽" fn("张美丽"); // &…

推荐常用的三款源代码防泄密软件

三款源代码防泄密软件——安秉源代码加密、Virbox Protector 和 MapoLicensor——确实各自在源代码保护的不同方面有其专长。这些软件可以满足企业对于源代码保护的三大需求&#xff1a;防止泄露、防止反编译和防止破解。 安秉源代码加密&#xff1a; 专注于源代码文件的加密&…

南阳理工学院(期末)算法分析练习题

一、算法阅读分析题&#xff1a; 1.分析如下算法&#xff0c;回答问题&#xff08;10分&#xff09;。 该算法的作用是什么(2分)&#xff1f;分析该算法的时间复杂度(5分)?设计算法的一个输入&#xff0c;并给出对应的算法输出结果(3分) &#xff08;1&#xff09;该算法的作…

WMS系统调拨盘点功能:优化仓储管理效率

一、调拨功能概述 WMS系统的调拨功能是指仓库内部或者不同仓库之间对商品进行转移的过程。调拨的目的在于平衡库存、优化存储空间和提高物流效率。调拨功能主要包括以下几个方面&#xff1a; 1. 调拨申请&#xff1a;根据业务需求&#xff0c;仓库管理员可以发起调拨申请&…

游泳耳机哪个牌子好性价比高?精选高性价比的四大游泳耳机!

在现代社会中&#xff0c;随着健身和水中运动的普及&#xff0c;游泳耳机作为一种关键的健身配件&#xff0c;正日益受到广泛关注和需求。无论是在游泳池畅游还是深潜海底&#xff0c;好的游泳耳机不仅能提供高品质的音乐享受&#xff0c;更能保护耳朵免受水压和湿润环境的侵害…

用VBA快速将Word文档表格转化为纯文本

一、原表格以及转移出来的文本 转为纯文本时&#xff0c;每一行内容保留表头&#xff0c;文本在表格下方 二、代码 Sub 表格转为纯文本()Dim t As Singlet TimerDim i As Integer, j As IntegerDim ta As TableDim arr() As StringSet ta ActiveDocument.Range.Tables(1)Re…