OpenCV3历程(5)——裂缝的检测与测量

2023-10-26

一、开始先介绍几个即将用到的函数及知识点

1、LUT函数

函数简介:

void LUT(
  InputArray src,         //原始图像的地址;
  InputArray lut,         //查找表的地址,对于多通道图像的查找,它可以有一个通道,也可以与原始图像有相同的通道;
  OutputArray dst         //输出图像的地址。
)

函数介绍(单通道为例):

对于8位单通道图片,其像素灰度为0-255,假如我们想将图像某一灰度值换成其他灰度值,用查找就很好用。

  例如:我们想将一张图片灰度为0-100的像素的灰度变成0,101-200的变成100,201-255的变成255。我们就可已建立如下的一张表格;

 

当把此表格应用到图片时,图片0-100灰度的像素灰度就变成0,101-200的变成100,201-255的就变成255。映射表差不多就是这个意思。

典型用法(借助图像取反示例说明)是:

虽然手动遍历可以达到同样效果,但尽量使用 OpenCV 内置函数。调用LUT 函数可以获得最快的速度,这是因为OpenCV库可以通过英特尔线程架构启用多线程。

    //建立查找表
    Mat lookUpTable(1, 256, CV_8U);
    uchar *p = lookUpTable.data;
    for(int i=0; i<256; i++)
        p[i]=255-i;
    //通过LUT函数实现图像取反
    LUT(img1,lookUpTable,img1);

2、saturate_cast防止数据溢出

在OpenCV学习中经常看见saturate_cast的使用,为什么函数会用到saturate_cast呢,因为无论是加是减,乘除,都会超出一个像素灰度值的范围(0~255)所以,所以当运算完之后,结果为负,则转为0,结果超出255,则为255。另外在梯度锐化的函数里,也会涉及到saturate_cast。示例如下:

代码来自:https://blog.csdn.net/mjlsuccess/article/details/12401839

//使用图像混合例子中的C语言版本演示
for (int i=0; i<src1.rows; i++)
{
	const uchar* src1_ptr = src1.ptr<uchar>(i);
	const uchar* src2_ptr = src2.ptr<uchar>(i);
	uchar* dst_ptr  = dst.ptr<uchar>(i);
	for (int j=0; j<src1.cols*nChannels; j++)
	{
    //加溢出保护
	dst_ptr[j] = saturate_cast<uchar>(src1_ptr[j]*alpha + src2_ptr[j]*beta + gama);//gama = -100, alpha = beta = 0.5
    //不加溢出保护
    //	dst_ptr[j] = (src1_ptr[j]*alpha + src2_ptr[j]*beta + gama);
	}
}
imshow("output",dst);

 

加了溢出保护
没加溢出保护
没加溢出保护

 

 大致的原理应该如下:

if(data<0)
        data=0;
else if(data>255)
	data=255;

3、std::stack 基本操作

C++ Stack(堆栈) 是一个容器类的改编,为程序员提供了堆栈的全部功能,——也就是说实现了一个先进后出(FILO)的数据结构。

c++ stl栈stack的头文件为

#include <stack> 

c++ stl栈stack的成员函数介绍

//操作 比较和分配堆栈

empty() //堆栈为空则返回真

pop()   //移除栈顶元素

push()  //在栈顶增加元素

size()  //返回栈中元素数目

top()   //返回栈顶元素

4、C++中在一个类中定义另一个只有带参数构造函数的类的对象

此处参考网址:https://www.cnblogs.com/rednodel/p/5148156.html

#include<iostream>
using namespace std;

class A
{
public:    
  A( int i ){}
};

class B {
public:    
  B():a(1){}   
//或:B( int i ):a( i ){ }。对a提供参数一定要按这种形式,在冒号后,不能在花括号里面!
private:    
  A a;
};

void main()
{    
  B b;
}

 5、为什么要定义Mat_类

在读取矩阵元素是,以获取矩阵某行的地址时,需要指定数据类型。这样首先需要不停地写“<uchar>”,让人感觉很繁琐,在繁琐和烦躁中容易犯错,如下面代码中的错误,用at()获取矩阵元素时错误的使用了double类型。这种错误不是语法错误,因此在编译时编译器不会提醒。在程序运行时,at()函数获取到的不是期望的(i,j)位置处的元素,数据已经越界,但是运行时也未必会报错。这样的错误使得你的程序忽而看上去正常,忽而弹出“段错误”,特别是在代码规模很大时,难以查错。

如果使用Mat_类,那么就可以在变量声明时确定元素的类型,访问元素时不再需要制定元素类型,即使得代码简洁,又减少了出错的可能性。上面代码可以用Mat_实现,实现代码如下面例程里的第二个双重for循环。

#include <iostream>
#include "opencv2/opencv.hpp"
#include<stdio.h>

using namespace std;
using namespace cv;

int main(int argc,char* argv[])
{
   Mat M(600,800,CV_8UC1);
   for(int i=0;i<M.rows;++i){
   //获取指针时需要指定类型
       uchar *p=M.ptr<uchar>(i);
    for(int j=0;j<M.cols;++j){
         double d1=(double)((i+j)%255);
   //用at读像素时,需要指定类型
         M.at<uchar>(i,j)=d1;
         double d2=M.at<uchar>(i,j);
       }
   }


   //在变量声明时,指定矩阵元素类型
   Mat_<uchar> M1=(Mat_<uchar>&)M;
   for(int i=0;i<M1.rows;++i)
   {
   //不需要指定元素类型,语言简洁
   uchar *p=M1.ptr(i);


       for(int j=0;j<M1.cols;++j){
       double d1=(double)((i+j)%255);
   //直接使用matlab风格的矩阵元素读写,简洁
        M1(i,j)=d1;
        double d2=M1(i,j);
     }
   }
   return 0;
}

二、实例裂缝检测源码

这里的代码来自(表示感谢):https://blog.csdn.net/FunnyWhiteCat/article/details/81387561

首先看原图:

 处理流程思路:

  1. 图像灰度化
  2. 增加对比度
  3. Canny边缘检测
  4. 用形态学连接临近裂缝
  5. 找出所有连通域,删除非裂缝噪点区域
  6. 对每个连通域提取骨架,测量长度和宽度

源码:

#include <opencv2\opencv.hpp>
#include <iostream>
#include <stack>

using namespace cv;
using namespace std;

//c++中在一个类中定义另一个只有带参数构造函数的类的对象
class CrackInfo
{
   public:
	   CrackInfo(Point& position, long length, float width) {};
};

/* 增加对比度 */
void addContrast(Mat & srcImg);
/* 交换两个Mat */
void swapMat(Mat & srcImg, Mat & dstImg);
/* 二值化图像。0->0,非0->255 */
void binaryzation(Mat & srcImg);
/* 检测连通域,并删除不符合条件的连通域 */
void findConnectedDomain(Mat & srcImg, vector<vector<Point>>& connectedDomains, int area, int WHRatio);
/* 提取连通域的骨架 */
void thinImage(Mat & srcImg);
/* 获取图像中白点的数量 */
void getWhitePoints(Mat &srcImg, vector<Point>& domain);
/* 计算宽高信息的放置位置 */
Point calInfoPosition(int imgRows, int imgCols, int padding, const std::vector<cv::Point>& domain);

int main(int argc, char** argv) {
	Mat srcImg = imread("./image/20180803215201452.jpg");
	Mat dstImg, dstImg2;
	//灰度化
	cvtColor(srcImg, dstImg, CV_BGR2GRAY, 1);
	//增加对比度
	addContrast(dstImg);
	//图像交换
	swapMat(srcImg, dstImg);
	//边缘检测
	Canny(srcImg, dstImg, 50, 150);
	//形态学变换
	Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
	dilate(dstImg, dstImg, kernel);//膨胀
	morphologyEx(dstImg, dstImg, CV_MOP_CLOSE, kernel, Point(-1, -1), 3);
	morphologyEx(dstImg, dstImg, CV_MOP_CLOSE, kernel);
	//寻找连通域
	vector<vector<Point>> connectedDomains;
	findConnectedDomain(dstImg, connectedDomains, 20, 3);
	kernel = getStructuringElement(MORPH_ELLIPSE, Size(7, 7));
	morphologyEx(dstImg, dstImg, CV_MOP_CLOSE, kernel, Point(-1, -1), 5);

	connectedDomains.clear();
	findConnectedDomain(dstImg, connectedDomains, 20, 3);
	kernel = getStructuringElement(MORPH_CROSS, Size(3, 3));
	morphologyEx(dstImg, dstImg, CV_MOP_OPEN, kernel);

	kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
	erode(dstImg, dstImg, kernel);

	connectedDomains.clear();
	findConnectedDomain(dstImg, connectedDomains, 20, 3);

	cout << "开始测量" << endl;
	cout << "连通域数量:" << connectedDomains.size() << endl;
	Mat lookUpTable(1, 256, CV_8U, Scalar(0));
	vector<CrackInfo> crackInfos;
	for (auto domain_it = connectedDomains.begin(); domain_it != connectedDomains.end(); ++domain_it) {
		LUT(dstImg, lookUpTable, dstImg);
		for (auto point_it = domain_it->cbegin(); point_it != domain_it->cend(); ++point_it) {
			dstImg.ptr<uchar>(point_it->y)[point_it->x] = 255;
		}
		double area = (double)domain_it->size();
		thinImage(dstImg);
		getWhitePoints(dstImg, *domain_it);
		long length = (long)domain_it->size();
		Point position = calInfoPosition(dstImg.rows, dstImg.cols, 50, *domain_it);
		crackInfos.push_back(CrackInfo(position, length, (float)(area / length)));
	}

	cout << "开始绘制信息" << endl;
	cout << "信息数量:" << crackInfos.size() << endl;

	LUT(dstImg, lookUpTable, dstImg);
	for (auto domain_it = connectedDomains.cbegin(); domain_it != connectedDomains.cend(); ++domain_it) {
		for (auto point_it = domain_it->cbegin(); point_it != domain_it->cend(); ++point_it) {
			dstImg.ptr<uchar>(point_it->y)[point_it->x] = 255;
		}
	}

	//ostringstream info;
	//for (auto it = crackInfos.cbegin(); it != crackInfos.cend(); ++it) {
	//	info.str("");
	//	info << *it;
	//	putText(dstImg, info.str(), it->Position, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
	//}

	imwrite("result1.png", dstImg);
	cout << "保存图像完成" << endl;
	return 0;
}

/*利用查找表(Look-up table)增加图像对比度*/
void addContrast(Mat & srcImg) {
	Mat lookUpTable(1, 256, CV_8U);
	double temp = pow(1.1, 5);
	uchar* p = lookUpTable.data;
	for (int i = 0; i < 256; ++i)
		p[i] = saturate_cast<uchar>(i * temp);
	LUT(srcImg, lookUpTable, srcImg);
}
/*图像交换*/
void swapMat(Mat & srcImg, Mat & dstImg) {
	Mat tempImg = srcImg;
	srcImg = dstImg;
	dstImg = tempImg;
}
/* 检测连通域,并删除不符合条件的连通域 */
void findConnectedDomain(Mat & srcImg, vector<vector<Point>>& connectedDomains, int area, int WHRatio) {
	Mat_<uchar> tempImg = (Mat_<uchar> &)srcImg;

	for (int i = 0; i < tempImg.rows; ++i) {
		uchar* row = tempImg.ptr(i);    调取存储图像内存的第i行的指针
		for (int j = 0; j < tempImg.cols; ++j) {
			if (row[j] == 255) {
				stack<Point> connectedPoints;
				vector<Point> domain;
				connectedPoints.push(Point(j, i));
				while (!connectedPoints.empty()) {
					Point currentPoint = connectedPoints.top();
					domain.push_back(currentPoint);

					int colNum = currentPoint.x;
					int rowNum = currentPoint.y;

					tempImg.ptr(rowNum)[colNum] = 0;
					connectedPoints.pop();

					if (rowNum - 1 >= 0 && colNum - 1 >= 0 && tempImg.ptr(rowNum - 1)[colNum - 1] == 255) {
						tempImg.ptr(rowNum - 1)[colNum - 1] = 0;
						connectedPoints.push(Point(colNum - 1, rowNum - 1));
					}
					if (rowNum - 1 >= 0 && tempImg.ptr(rowNum - 1)[colNum] == 255) {
						tempImg.ptr(rowNum - 1)[colNum] = 0;
						connectedPoints.push(Point(colNum, rowNum - 1));
					}
					if (rowNum - 1 >= 0 && colNum + 1 < tempImg.cols && tempImg.ptr(rowNum - 1)[colNum + 1] == 255) {
						tempImg.ptr(rowNum - 1)[colNum + 1] = 0;
						connectedPoints.push(Point(colNum + 1, rowNum - 1));
					}
					if (colNum - 1 >= 0 && tempImg.ptr(rowNum)[colNum - 1] == 255) {
						tempImg.ptr(rowNum)[colNum - 1] = 0;
						connectedPoints.push(Point(colNum - 1, rowNum));
					}
					if (colNum + 1 < tempImg.cols && tempImg.ptr(rowNum)[colNum + 1] == 255) {
						tempImg.ptr(rowNum)[colNum + 1] = 0;
						connectedPoints.push(Point(colNum + 1, rowNum));
					}
					if (rowNum + 1 < tempImg.rows && colNum - 1 > 0 && tempImg.ptr(rowNum + 1)[colNum - 1] == 255) {
						tempImg.ptr(rowNum + 1)[colNum - 1] = 0;
						connectedPoints.push(Point(colNum - 1, rowNum + 1));
					}
					if (rowNum + 1 < tempImg.rows && tempImg.ptr(rowNum + 1)[colNum] == 255) {
						tempImg.ptr(rowNum + 1)[colNum] = 0;
						connectedPoints.push(Point(colNum, rowNum + 1));
					}
					if (rowNum + 1 < tempImg.rows && colNum + 1 < tempImg.cols && tempImg.ptr(rowNum + 1)[colNum + 1] == 255) {
						tempImg.ptr(rowNum + 1)[colNum + 1] = 0;
						connectedPoints.push(Point(colNum + 1, rowNum + 1));
					}
				}
				if (domain.size() > area) {
					RotatedRect rect = minAreaRect(domain);
					float width = rect.size.width;
					float height = rect.size.height;
					if (width < height) {
						float temp = width;
						width = height;
						height = temp;
					}
					if (width > height * WHRatio && width > 50) {
						for (auto cit = domain.begin(); cit != domain.end(); ++cit) {
							tempImg.ptr(cit->y)[cit->x] = 250;
						}
						connectedDomains.push_back(domain);
					}
				}
			}
		}
	}

	binaryzation(srcImg);
}
/* 二值化图像。0->0,非0->255 */
void binaryzation(Mat & srcImg) {
	Mat lookUpTable(1, 256, CV_8U, Scalar(255));
	lookUpTable.data[0] = 0;
	LUT(srcImg, lookUpTable, srcImg);
}
/* 提取连通域的骨架 */
void thinImage(Mat & srcImg) {
	vector<Point> deleteList;
	int neighbourhood[9];
	int nl = srcImg.rows;
	int nc = srcImg.cols;
	bool inOddIterations = true;
	while (true) {
		for (int j = 1; j < (nl - 1); j++) {
			uchar* data_last = srcImg.ptr<uchar>(j - 1);
			uchar* data = srcImg.ptr<uchar>(j);
			uchar* data_next = srcImg.ptr<uchar>(j + 1);
			for (int i = 1; i < (nc - 1); i++) {
				if (data[i] == 255) {
					int whitePointCount = 0;
					neighbourhood[0] = 1;
					if (data_last[i] == 255) neighbourhood[1] = 1;
					else  neighbourhood[1] = 0;
					if (data_last[i + 1] == 255) neighbourhood[2] = 1;
					else  neighbourhood[2] = 0;
					if (data[i + 1] == 255) neighbourhood[3] = 1;
					else  neighbourhood[3] = 0;
					if (data_next[i + 1] == 255) neighbourhood[4] = 1;
					else  neighbourhood[4] = 0;
					if (data_next[i] == 255) neighbourhood[5] = 1;
					else  neighbourhood[5] = 0;
					if (data_next[i - 1] == 255) neighbourhood[6] = 1;
					else  neighbourhood[6] = 0;
					if (data[i - 1] == 255) neighbourhood[7] = 1;
					else  neighbourhood[7] = 0;
					if (data_last[i - 1] == 255) neighbourhood[8] = 1;
					else  neighbourhood[8] = 0;
					for (int k = 1; k < 9; k++) {
						whitePointCount = whitePointCount + neighbourhood[k];
					}
					if ((whitePointCount >= 2) && (whitePointCount <= 6)) {
						int ap = 0;
						if ((neighbourhood[1] == 0) && (neighbourhood[2] == 1)) ap++;
						if ((neighbourhood[2] == 0) && (neighbourhood[3] == 1)) ap++;
						if ((neighbourhood[3] == 0) && (neighbourhood[4] == 1)) ap++;
						if ((neighbourhood[4] == 0) && (neighbourhood[5] == 1)) ap++;
						if ((neighbourhood[5] == 0) && (neighbourhood[6] == 1)) ap++;
						if ((neighbourhood[6] == 0) && (neighbourhood[7] == 1)) ap++;
						if ((neighbourhood[7] == 0) && (neighbourhood[8] == 1)) ap++;
						if ((neighbourhood[8] == 0) && (neighbourhood[1] == 1)) ap++;
						if (ap == 1) {
							if (inOddIterations && (neighbourhood[3] * neighbourhood[5] * neighbourhood[7] == 0)
								&& (neighbourhood[1] * neighbourhood[3] * neighbourhood[5] == 0)) {
								deleteList.push_back(Point(i, j));
							}
							else if (!inOddIterations && (neighbourhood[1] * neighbourhood[5] * neighbourhood[7] == 0)
								&& (neighbourhood[1] * neighbourhood[3] * neighbourhood[7] == 0)) {
								deleteList.push_back(Point(i, j));
							}
						}
					}
				}
			}
		}
		if (deleteList.size() == 0)
			break;
		for (size_t i = 0; i < deleteList.size(); i++) {
			Point tem;
			tem = deleteList[i];
			uchar* data = srcImg.ptr<uchar>(tem.y);
			data[tem.x] = 0;
		}
		deleteList.clear();

		inOddIterations = !inOddIterations;
	}
}
/* 获取图像中白点的数量 */
void getWhitePoints(Mat &srcImg, vector<Point>& domain) {
	domain.clear();
	Mat_<uchar> tempImg = (Mat_<uchar> &)srcImg;
	for (int i = 0; i < tempImg.rows; i++) {
		uchar * row = tempImg.ptr<uchar>(i);
		for (int j = 0; j < tempImg.cols; ++j) {
			if (row[j] != 0)
				domain.push_back(Point(j, i));
		}
	}
}
/* 计算宽高信息的放置位置 */
Point calInfoPosition(int imgRows, int imgCols, int padding, const std::vector<cv::Point>& domain) {
	long xSum = 0;
	long ySum = 0;
	for (auto it = domain.cbegin(); it != domain.cend(); ++it) {
		xSum += it->x;
		ySum += it->y;
	}
	int x = 0;
	int y = 0;
	x = (int)(xSum / domain.size());
	y = (int)(ySum / domain.size());
	if (x < padding)
		x = padding;
	if (x > imgCols - padding)
		x = imgCols - padding;
	if (y < padding)
		y = padding;
	if (y > imgRows - padding)
		y = imgRows - padding;

	return cv::Point(x, y);
}

处理结果:

重叠结果

待优化......

 

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

OpenCV3历程(5)——裂缝的检测与测量 的相关文章

  • C++_数据存储_药名整理(代码+注释)

    题目描述 输入输出格式 样例 输入样例 4 AspiRin cisapride 2 PENICILLIN Cefradine 6 输出样例 Aspirin Cisapride 2 penicillin Cefradine 6 代码 注释 a
  • 西门子PLC S7-200系列有哪些基本硬件及优点?

    西门子SIMATIC系列PLC 诞生于1958年 经历了C3 S3 S5 S7系列 已成为应用非常广泛的可编程控制器 西门子S7 200系列PLC的基本硬件组成 SIMATIC S7 200的应用领域从更换继电器和接触器一直扩展到在单机 网
  • 【MySQL】复合查询

    需要云服务器等云产品来学习Linux的同学可以移步 gt 腾讯云 lt gt 阿里云 lt gt 华为云 lt 官网 轻量型云服务器低至112元 年 新用户首次下单享超低折扣 目录 一 基本查询 1 查询工资高于500或岗位为MANAGER
  • 智明星通 CEO 唐彬森:创业过程中的几笔学费

    编者按 本文来自创新工场 微信号 chuangxin2009 创业公开课 本期课程是由从海外市场起家的唐彬森老师分享 创业过程中的几笔学费 在移动互联网时代背景下 产品为王 只有真正了解用户 才能发现背后的规律 而互联网的基本规律是幂定律
  • NoSQL数据库的介绍、NoSQL的产品、NoSQL数据库的分类等;

    目录 1 1 什么是NoSQL 1 2 为什么使用NoSQL 1 3 RDBMS 传统关系型数据库 vs NoSQL 特点对比 1 4 NoSQL 简史 1 5 NoSQL 产品 1 6 NoSQL 数据库分类 1 7 目前谁在使用NoSQ
  • 静态链表的基本操作实现

    一 实验目的 巩固线性表的数据结构的存储方法和相关操作 学会针对具体应用 使用线性表的相关知识来解决具体问题 二 实验内容 建立一个由n个学生成绩的顺序表 n 的大小 由自己确 定 每一个学生的成绩信息由自己确定 实现数据的对表进行插入 删
  • python中对配置环境的理解

    在咱们学习python前 老师和书本就已经教我们应该如何配置python环境 1 安装python 安装好后 找到python exe 打开其属性 复制他的路径 2 打开控制面板中的所有控制面板项后 选择系统 点击左边的高级系统设置 在高级
  • 进程管理&&内存管理

    操作系统详述 目录 操作系统详述 一 进程管理 这是重点 1 什么是进程管理 2 如何做好进程调度 1 需要把进程这个抽象的概念用数据表示处理 抽象成一个对象 这就是面向对象思想 2 需要对进程做分区 3 现在手上有等待分配CPU的所有进程
  • Linux下使用OpenCv驱动RGB多款彩色摄像头

    最简单的驱动 cout lt lt Built with OpenCV lt lt CV VERSION lt lt endl VideoCapture capture 0 打开摄像头 if capture isOpened 判断是否打开成
  • 多模态大模型系列论文(ALBEF、BLIP、BLIP-2)

    1 ALBEF ALign the image and text BEfore Fusing 1 1 论文与代码链接 https arxiv org abs 2107 07651 GitHub salesforce ALBEF Code f
  • Linux系统项目测试环境部署步骤及操作流程

    jdk安装 在linux上安装JDK 版本位要与linux版本一致 可以通过winscp工具进行安装 把jdk包下载到windows系统上 通过winscp把jdk包直接拖到linux系统的目录中去 具体linux命令步骤 1 tar zx
  • replaceAll遇到特殊字符无法替换问题的坑

    问题 当出现 或者 或者 符等 会导致 无法替换 在一定程度上 这个也算是 一个坑吧 问题原因 replaceAll支持正则 出现正则的符号 就会被当作是正则 从而无法正常替换 解决办法 网上有一个解决方案 是采用 Matcher quot
  • JetBrains IDEA 的安装与设置

    为什么80 的码农都做不了架构师 gt gt gt JetBrains Toolbox 下载 安装 配置 JetBrains IDEA 下载 安装 配置 JetBrains Toolbox 下载 安装 官方下载地址 https downlo
  • MyBatisPlus条件查询的三种格式于null判定

    DQL编程控制 条件查询 MyBatisPlus将书写复杂的SQL查询条件进行了封装 使用编程的形式完成查询条件的组合 方式一 使用QueryWrapper查询数据 lt是小于的意思 price是数据表的字段名称 price容易写错 不推荐
  • VQGAN2_latent diffusion model

    task1 txt2image 先根据config一层层调用 先是ldm models diffusion ddpm LatentDiffusion 里面super init conditioning key conditioning ke
  • SPI协议详解(Standard SPI、Dual SPI和Queued SPI)

    1 标准SPI 1 1 SPI接口的引脚 1 SCLK 时钟线 2 MOSI master output slave input 主设备输出 从设备输入 单向传输 3 MISO master input slave output 主设备输入
  • 查找算法--二分查找 c++实现

    二分查找也称折半查找 Binary Search 它是一种效率较高的查找方法 但是 折半查找要求线性表必须采用顺序存储结构 而且表中元素按关键字有序排列 vs2017 include
  • Docker学习--Docker仓库之Docker Hub的简单了解

    Docker之所以能这么快的火起来 和Docker Hub的作用是分不开的 Docker构建了像GitHub一样的仓库 用来存放大家构建好的Docker镜像 其中已经包括了15000的镜像 大部分需求 都可以通过在Docker Hub中直接
  • npm不是以管理身份运行遇到的问题

    环境 win10 npm3 10 5 问题 在npm install lodash时 出现下列错误 npm debug log 文件内容 0 info it worked if it ends with ok1 verbose cli C

随机推荐

  • 性能测试相关术语

    性能测试相关术语 一 负载 模拟业务操作对服务器造成压力的过程 比如模拟100个用户发帖 二 性能测试 Performance Testing 模拟用户负载来测试系统在负载情况下 系统的响应时间 吞吐量等指标是否满足性能要求 三 负载测试
  • Makefile = 、:=、?=的区别

    相当于 c 语言中的 预编译的过程 在真正解释Makefile前会先将对应的 号左边的量替换成右边的量 而 则是跟 宏观的 号相似 是简单赋值的运算符号 下面举个例子就可以清楚的知道它们之间有何不同 cross arm linux cc c
  • 开关电源怎么测试文波_为什么开关电源需要测试动态响应

    1 导读概念动态响应一般是指控制系统在典型输入信号的作用下 其输出量从初始状态到最终状态的响应 对某一环节 系统 加入单位阶跃输入x t 时 其响应y t 开始逐渐上升 直到稳定在某一定值上为止 响应y t 在达到一定值之前的变化状态称为过
  • 直播分发选低延迟 RTC 还是 CDN?

    简单来看 一个完整的直播应用实现原理是 主播端采集音视频 推到服务器 再由服务器分发给观众观看 主播端负责推流 需要配置选用 RTC 链路分发直播画面或者用 CDN 链路分发 如果涉及连麦还需要考虑如何做 MCU 合流 观众订阅合流的好处是
  • python 读取配置文件config_python学习-读写配置文件-ConfigParse用法

    一 读取配置文件 config ini read filname 读取文件内容 section 获取所有section 返回list options section 获取该section所有options 返回list items sect
  • IDEA + SSH OA 第一天(Hibernate : Mapping (RESOURCE) not found)

    切入主题 看看今天的错误是如何发生的 首先这是我的项目路径 java 是 Sources Root resources 是 Resources Root 放了所需要的配置文件 其中 Hibernate 的配置 显示的是绿色 说明没有问题 在
  • Java基础知识-Map

    1 Map体系 2 各实现类说明及区别 3 哈希映射技术 哈希映射技术是一种就元素映射到数组的非常简单的技术 由于哈希映射采用的是数组结果 那么必然存在一中用于确定任意键访问数组的索引机制 该机制能够提供一个小于数组大小的整数 我们将该机制
  • Windows和Ubuntu下Firefox账号不能同步的解决办法

    最近开始用Ubuntu系统发现一个问题 我在Ubuntu系统自带的或者软件中心下的Firefox版本下创建一个账号 再在Windows的Firefox下登录发现此账号不存在 原因是Firefox有个全球服务和本地服务 Ubuntu下的Fir
  • vscode c++安装与单文件多文件编译配置(win10)

    vscode c 安装与单文件多文件编译配置 win10 总体思路 1下载Vscode mingw cmake 用于多文件编译 2配置 1 gt mingw vscode cmake环境变量 2 gt vscode 插件Chinese co
  • Redis多线程与ACL

    Redis是单线程吗 Redis 的单线程主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的 这也是 Redis 对外提供键值存储服务的主要流程 但 Redis 的其他功能 比如持久化 异步删除 集群数据同步等 其实是由额
  • JS中正则表达式常用语法总结

    目录 一 正则表达式的创建 二 的区别 三 和 四 d s w 五 六 test match 七 支持正则表达式的 String 对象的方法 一 正则表达式的创建 JS正则的创建有两种方式 new RegExp 和 直接字面量 使用RegE
  • Java Remote Debug(IDEA实现远程调试)

    前言 介绍 Java Remote Debug指的是 Java远程调试 特别是当你在本地开发的时候 你需要调试服务器上的程序时 远程调试就显得非常有用 本人就遇到这样一个问题 本地环境运行一切正常 但是部署到服务器就报错 而且问题一直找不到
  • ctfshow中web入门题关键解题思路

    一 信息搜集 1 web1 查看页面源代码 2 web2 burdsuite抓包 3 web3 burdsuite抓包 4 web4 查看robots txt文件 5 web5 查看index phps文件 6 web6 一般网站开发的源代
  • 开源IaaS云平台的分析与比较

    http blog csdn net jiayuboxin article details 11934223 http blog csdn net jiayuboxin article details 10977429 Project Sa
  • Dirichlet分布的推导与理解

    1 概述 Dirichlet 分布与贝塔分布 伽马分布有着紧密的联系 在贝叶斯统计中经常被用作其它概率分布如多项分布的先验分布 且在LDA分析中得到了广泛应用 本文结合直观理解以及详细的数学推导得到狄利克雷分布具体形式 并结合可视化以加深理
  • 解决Android Studio连接不上逍遥模拟器的问题

    1 打开逍遥模拟器 2 打开Android Studio 所要运行的项目 3 cmd 打开命令提示符 然后输入 adb connect 127 0 0 1 21503 然后回车 OK搞定 屡试不爽 看下图 其他模拟器参考这里点击打开链接
  • 在什么场景下要使用类方法

    静态方法和类方法的比较 静态方法 我们先来创建一个类 假设他是检测报告的相关信息 class Report inspection negative def init self name id number self name name se
  • 【Block-Level Verification】 SystemVerilog 数据类型_数组操作_队列_结构体_枚举类型_字符串_过程块和方法_变量生命周期_例化和链接...

    System Verilog芯片验证 System Verilog语言 1 数据类型 Verilog本身是来做硬件描述 是对硬件本身的行为进行建模 SystemVerilog是Verilog的生命延续 sv是对SystemVerilog进行
  • powershell定义命令(四)

    using System using System Collections Generic using System Collections ObjectModel using System ComponentModel using Sys
  • OpenCV3历程(5)——裂缝的检测与测量

    一 开始先介绍几个即将用到的函数及知识点 1 LUT函数 函数简介 void LUT InputArray src 原始图像的地址 InputArray lut 查找表的地址 对于多通道图像的查找 它可以有一个通道 也可以与原始图像有相同的