相机One Shot标定

news2024/11/24 7:33:34

1 原理说明

原理部分网上其他文章[1][2]也已经说的比较明白了,这里不再赘述。

2 总体流程

参考论文作者开源的Matlab代码[3]和github上的C++代码[4]进行说明(不得不说还是Matlab代码更优雅)

论文方法总体分两部,第一部是在画面中找到所有的类棋盘格角点,第二步是角点的基础上构建出棋盘格形状。

3 模块说明

3.1 寻找角点

论文寻找角点的思想是用2x4个模板对输入图像进行逐像素匹配,得到类棋盘格角点,然后使用优化方法对角点进行亚像素优化得到最终角点;

寻找角点算法流程如下:

总体来说寻找角点的流程可分为4步:

  1. 模板匹配:包括选择尺度、模板创建、模板匹配、结果融合
  2. 非极大值抑制
  3. 角点优化:包括角点方向计算和优化、角点位置优化
  4. 分数计算和角点调整:包括分数计算、角点调整

3.1.1 模板匹配

论文中模板匹配使用了2x4个模板(见上述)对全图像进行匹配,为了适应不同尺度的棋盘格图像,论文创建了3种不同尺度的2x4个模板。

% 3 scales
radius(1) = 4;
radius(2) = 8;
radius(3) = 12;

% template properties
template_props = [
  0 pi/2 radius(1); pi/4 -pi/4 radius(1);     % 小尺度
  0 pi/2 radius(2); pi/4 -pi/4 radius(2);     % 中尺度
  0 pi/2 radius(3); pi/4 -pi/4 radius(3)];    % 大尺度

disp('Filtering ...');

% filter image
img_corners = zeros(size(img,1),size(img,2));
for template_class=1:size(template_props,1)
  
  % create correlation template
  template = createCorrelationPatch(template_props(template_class,1),template_props(template_class,2),template_props(template_class,3));
  
  % filter image according with current template
  img_corners_a1 = conv2(img,template.a1,'same');
  img_corners_a2 = conv2(img,template.a2,'same');
  img_corners_b1 = conv2(img,template.b1,'same');
  img_corners_b2 = conv2(img,template.b2,'same');
end

在得到不同模板的结果后需要进行结果融合,论文给的公式是:

对应的实现是:

  % compute mean
  img_corners_mu = (img_corners_a1+img_corners_a2+img_corners_b1+img_corners_b2)/4;
  
  % case 1: a=white, b=black
  img_corners_a = min(img_corners_a1-img_corners_mu,img_corners_a2-img_corners_mu);
  img_corners_b = min(img_corners_mu-img_corners_b1,img_corners_mu-img_corners_b2);
  img_corners_1 = min(img_corners_a,img_corners_b);
  
  % case 2: b=white, a=black
  img_corners_a = min(img_corners_mu-img_corners_a1,img_corners_mu-img_corners_a2);
  img_corners_b = min(img_corners_b1-img_corners_mu,img_corners_b2-img_corners_mu);
  img_corners_2 = min(img_corners_a,img_corners_b);
  
  % update corner map
  img_corners = max(img_corners,img_corners_1);
  img_corners = max(img_corners,img_corners_2);

3.1.2 非极大值抑制

这个就不详细介绍了,反正就是非极大值抑制...

3.1.3 角点优化

论文中对于角点优化说的不咋详细,所以主要参考作者的开源代码。这一部分主要的步骤是:

  1. Sobel算子计算图像x,y方向梯度
  2. 根据图像梯度计算图像梯度方向和权重(强度)
  3. 根据图像附近区域像素梯度方向和权重,计算角点方向
    1. 对应论文中的梯度方向直方图统计过程
function [v1,v2] = edgeOrientations(img_angle,img_weight)

% init v1 and v2
v1 = [0 0];
v2 = [0 0];

% number of bins (histogram parameter)
bin_num = 32;

% convert images to vectors
vec_angle  = img_angle(:);
vec_weight = img_weight(:);

% convert angles from normals to directions
vec_angle = vec_angle+pi/2;
vec_angle(vec_angle>pi) = vec_angle(vec_angle>pi)-pi;

% create histogram
angle_hist = zeros(1,bin_num);
for i=1:length(vec_angle)
  bin = max(min(floor(vec_angle(i)/(pi/bin_num)),bin_num-1),0)+1;
  angle_hist(bin) = angle_hist(bin)+vec_weight(i);
end

% find modes of smoothed histogram
[modes,angle_hist_smoothed] = findModesMeanShift(angle_hist,1);

% if only one or no mode => return invalid corner
if size(modes,1)<=1
  return;
end

% compute orientation at modes
modes(:,3) = (modes(:,1)-1)*pi/bin_num;

% extract 2 strongest modes and sort by angle
modes = modes(1:2,:);
[foo idx] = sort(modes(:,3),1,'ascend');
modes = modes(idx,:);

% compute angle between modes
delta_angle = min(modes(2,3)-modes(1,3),modes(1,3)+pi-modes(2,3));

% if angle too small => return invalid corner
if delta_angle<=0.3
  return;
end

% set statistics: orientations
v1 = [cos(modes(1,3)) sin(modes(1,3))];
v2 = [cos(modes(2,3)) sin(modes(2,3))];
  1. 角点方向优化
    1. 步骤3中计算角点方向比较粗糙,这里对方向进行优化处理
    2. 优化方法对应论文公式(4),主要是计算角点附件有效点的梯度累加矩阵的最小特征值对应的特征向量(有点拗口:D)
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % corner orientation refinement %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  A1 = zeros(2,2);
  A2 = zeros(2,2);
  
  for u=max(cu-r,1):min(cu+r,width)
    for v=max(cv-r,1):min(cv+r,height)
      
      % pixel orientation vector
      o = [img_du(v,u) img_dv(v,u)];
      if norm(o)<0.1
        continue;
      end
      o = o/norm(o);
      
      % robust refinement of orientation 1
      if abs(o*v1')<0.25 % inlier?
        A1(1,:) = A1(1,:) + img_du(v,u) * [img_du(v,u) img_dv(v,u)];
        A1(2,:) = A1(2,:) + img_dv(v,u) * [img_du(v,u) img_dv(v,u)];
      end
      
      % robust refinement of orientation 2
      if abs(o*v2')<0.25 % inlier?
        A2(1,:) = A2(1,:) + img_du(v,u) * [img_du(v,u) img_dv(v,u)];
        A2(2,:) = A2(2,:) + img_dv(v,u) * [img_du(v,u) img_dv(v,u)];
      end
      
    end
  end
  
  % set new corner orientation
  [v1,foo1] = eig(A1); v1 = v1(:,1)'; corners.v1(i,:) = v1;
  [v2,foo2] = eig(A2); v2 = v2(:,1)'; corners.v2(i,:) = v2;
  1. 角点位置优化
    1. 优化方法对应论文公式(2),求解方法对应论文公式(3)
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %  corner location refinement  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  G = zeros(2,2);
  b = zeros(2,1);
  for u=max(cu-r,1):min(cu+r,width)
    for v=max(cv-r,1):min(cv+r,height)
      
      % pixel orientation vector
      o = [img_du(v,u) img_dv(v,u)];
      if norm(o)<0.1
        continue;
      end
      o = o/norm(o);
      
      % robust subpixel corner estimation
      if u~=cu || v~=cv % do not consider center pixel
        
        % compute rel. position of pixel and distance to vectors
        w  = [u v]-[cu cv];
        d1 = norm(w-w*v1'*v1);
        d2 = norm(w-w*v2'*v2);
        
        % if pixel corresponds with either of the vectors / directions
        if d1<3 && abs(o*v1')<0.25 || d2<3 && abs(o*v2')<0.25
          du = img_du(v,u);
          dv = img_dv(v,u);
          H = [du dv]'*[du dv];
          
          G = G + H;
          b = b + H*[u v]';
        end
      end
    end
  end

  % set new corner location if G has full rank
  if rank(G)==2
    corner_pos_old = corners.p(i,:);
    corner_pos_new = (G\b)';
    corners.p(i,:) = corner_pos_new;
    
    % set corner to invalid, if position update is very large
    if norm(corner_pos_new-corner_pos_old)>=4
      corners.v1(i,:) = [0 0];
      corners.v2(i,:) = [0 0];
    end
    
  % otherwise: set corner to invalid
  else
    corners.v1(i,:) = [0 0];
    corners.v2(i,:) = [0 0];
  end

3.1.4 分数计算和角点调整

  • 分数计算

分数计算是用来计算每个角点的得分,然后与用户设置的阈值进行比较,如果超过阈值则为合格角点。这里论文说的和代码里面的有点对不上感觉,论文说方法的是求角点附近图像的二阶导,然后和一个模板做normalized cross-correlation;但是代码里面实现的方式是:

  1. 计算论文中Figure 2.e中的模板T
% center
c = ones(1,2)*(size(img_weight,1)+1)/2;

% compute gradient filter kernel (bandwith = 3 px)
img_filter = -1*ones(size(img_weight,1),size(img_weight,2));
for x=1:size(img_weight,2)
  for y=1:size(img_weight,1)
    p1 = [x y]-c;
    p2 = p1*v1'*v1;
    p3 = p1*v2'*v2;
    if norm(p1-p2)<=1.5 || norm(p1-p3)<=1.5
      img_filter(y,x) = +1;
    end
  end
end
  1. 将模板T与之前得到的图像梯度权重分别做归一化,然后做相关,得到相关系数score_gradient
% convert into vectors
vec_weight = img_weight(:);
vec_filter = img_filter(:);

% normalize
vec_weight = (vec_weight-mean(vec_weight))/std(vec_weight);
vec_filter = (vec_filter-mean(vec_filter))/std(vec_filter);

% compute gradient score
score_gradient = max(sum(vec_weight.*vec_filter)/(length(vec_weight)-1),0);
  1. 按角点的2个主方向生成4个模板
  2. 计算模板匹配值score_intensity(过程与3.1.1的模板匹配一样)
% create intensity filter kernel
template = createCorrelationPatch(atan2(v1(2),v1(1)),atan2(v2(2),v2(1)),c(1)-1);

% checkerboard responses
a1 = sum(template.a1(:).*img(:));
a2 = sum(template.a2(:).*img(:));
b1 = sum(template.b1(:).*img(:));
b2 = sum(template.b2(:).*img(:));

% mean
mu = (a1+a2+b1+b2)/4;

% case 1: a=white, b=black
score_a = min(a1-mu,a2-mu);
score_b = min(mu-b1,mu-b2);
score_1 = min(score_a,score_b);

% case 2: b=white, a=black
score_a = min(mu-a1,mu-a2);
score_b = min(b1-mu,b2-mu);
score_2 = min(score_a,score_b);

% intensity score: max. of the 2 cases
score_intensity = max(max(score_1,score_2),0);
  1. 计算score = score_intensity * score_gradient
  2. 改变模板尺度(与 3.1.1一样),重复步骤1~5,计算所有尺度中的分数最大值

不知道论文和代码中的方法是否等价,留以后考证。

  • 角度调整

这部分主要是对计算角点的主方向做一个调整,以减少后面多图像匹配(我们用不到)过程中的歧义性

% make v1(:,1)+v1(:,2) positive (=> comparable to c++ code)
idx = corners.v1(:,1)+corners.v1(:,2)<0;
corners.v1(idx,:) = -corners.v1(idx,:);

% make all coordinate systems right-handed (reduces matching ambiguities from 8 to 4)
corners_n1 = [corners.v1(:,2) -corners.v1(:,1)];
flip       = -sign(corners_n1(:,1).*corners.v2(:,1)+corners_n1(:,2).*corners.v2(:,2));
corners.v2 = corners.v2.*(flip*ones(1,2));

3.2 构建棋盘格

论文提出的棋盘格构建是基于生长的方法,所以首先要选定几个点作为初始棋盘格,然后在初始棋盘格的基础上向外生长,在生长的过程中需要对多种可能的生长方式进行判断,判断新生长出来的棋盘格是不是最优,最终得到最优的棋盘格结构。

通过上述步骤,可以得到多个棋盘格结构,如果这些棋盘格结构中有重叠的话,则需要做一个去重处理。

对于判断生长和去重过程中的哪个棋盘格结构更优,论文给出了一种棋盘格能量计算方法,参考论文公式(6)。

所以整体棋盘格构建流程如下:

3.2.1 选择初始点

没什么讲究,所有点都拿来试一试...

3.2.2 构建初始棋盘格

构建初始棋盘格是将选择的初始点扩展成3x3共9个点,组成一个小小的初始棋盘格。方法是从初始点开始,往2个主方向和2个主方向的反方向(一共4个方向)各找一个距离最近的点,这样就有了5个点,然后再从上下两个点以同样的方法往左右扩展,最终形成3x3棋盘格。

% return if not enough corners
if size(corners.p,1)<9
  chessboard = [];
  return;
end

% init chessboard hypothesis
chessboard = zeros(3,3);

% extract feature index and orientation (central element)
v1 = corners.v1(idx,:);
v2 = corners.v2(idx,:);
chessboard(2,2) = idx;

% find left/right/top/bottom neighbors
[chessboard(2,3),dist1(1)] = directionalNeighbor(idx,+v1,chessboard,corners);
[chessboard(2,1),dist1(2)] = directionalNeighbor(idx,-v1,chessboard,corners);
[chessboard(3,2),dist2(1)] = directionalNeighbor(idx,+v2,chessboard,corners);
[chessboard(1,2),dist2(2)] = directionalNeighbor(idx,-v2,chessboard,corners);

% find top-left/top-right/bottom-left/bottom-right neighbors
[chessboard(1,1),dist2(3)] = directionalNeighbor(chessboard(2,1),-v2,chessboard,corners);
[chessboard(3,1),dist2(4)] = directionalNeighbor(chessboard(2,1),+v2,chessboard,corners);
[chessboard(1,3),dist2(5)] = directionalNeighbor(chessboard(2,3),-v2,chessboard,corners);
[chessboard(3,3),dist2(6)] = directionalNeighbor(chessboard(2,3),+v2,chessboard,corners);

% initialization must be homogenously distributed
if any(isinf(dist1)) || any(isinf(dist2)) || ...
   std(dist1)/mean(dist1)>0.3 || std(dist2)/mean(dist2)>0.3
  chessboard = [];
  return;
end

可以看到,在通过directionalNeighbor扩展了之后,还对扩展出去的距离做了一个判断,避免产生太过离谱的初始棋盘格。

directionalNeighbor的具体实现如下,其中dist_point+5*dist_edge作为距离这一个有点迷,可能是想兼顾考虑径向和切向距离,但是不知道数学原理是什么(虽然效果确实不错)

function [neighbor_idx,min_dist] = directionalNeighbor(idx,v,chessboard,corners)

% list of neighboring elements, which are currently not in use
unused       = 1:size(corners.p,1);
used         = chessboard(chessboard~=0);
unused(used) = [];

% direction and distance to unused corners
dir  = corners.p(unused,:) - ones(length(unused),1)*corners.p(idx,:);
dist = (dir(:,1)*v(1)+dir(:,2)*v(2));

% distances
dist_edge = dir-dist*v;
dist_edge = sqrt(dist_edge(:,1).^2+dist_edge(:,2).^2);
dist_point = dist;
dist_point(dist_point<0) = inf;

% find best neighbor
[min_dist,min_idx] = min(dist_point+5*dist_edge);
neighbor_idx = unused(min_idx);

3.2.3 棋盘格生长

这个流程没啥好说的,确定了初始棋盘格之后,就不断往4个方向生长,然后选一个能量最低的作为最优解,作为新的初始棋盘格。

  % try growing chessboard
  while 1
    
    % compute current energy
    energy = chessboardEnergy(chessboard,corners);
    
    % compute proposals and energies
    for j=1:4
      proposal{j} = growChessboard(chessboard,corners,j);
      p_energy(j) = chessboardEnergy(proposal{j},corners);
    end
    
    % find best proposal
    [min_val,min_idx] = min(p_energy);
    
    % accept best proposal, if energy is reduced
    if p_energy(min_idx)<energy
      chessboard = proposal{min_idx};
      
    % otherwise exit loop
    else
      break;
    end
  end

3.2.4 棋盘格去重

当棋盘格中包含的任意一个角点在已存在的棋盘格中也存在了,则认为存在棋盘格重复。去重采用的方法是看看当前棋盘格的和已存在的棋盘格哪个更优(哪个能量更低),如果当前棋盘格能量更低,则替换掉原来的棋盘格。

  % if chessboard has low energy (corresponding to high quality)
  if chessboardEnergy(chessboard,corners)<-10

    % check if new chessboard proposal overlaps with existing chessboards
    overlap = zeros(length(chessboards),2);
    for j=1:length(chessboards)
      for k=1:length(chessboards{j}(:))
        if any(chessboards{j}(k)==chessboard(:))
          overlap(j,1) = 1;
          overlap(j,2) = chessboardEnergy(chessboards{j},corners);
          break;
        end
      end
    end

    % add chessboard (and replace overlapping if neccessary)
    if ~any(overlap(:,1))
      chessboards{end+1} = chessboard;
    else
      idx = find(overlap(:,1)==1);
      if ~any(overlap(idx,2)<=chessboardEnergy(chessboard,corners))
        chessboards(idx) = [];
        chessboards{end+1} = chessboard;
      end
    end
  end

4 参考资料

[1] Geiger, A., Moosmann, F., Car, Ö. and Schuster, B., 2012, May. Automatic camera and range sensor calibration using a single shot. In 2012 IEEE international conference on robotics and automation (pp. 3936-3943). IEEE.
[2] 基于生长的棋盘格角点检测方法--(1)原理介绍_findchessboardcornerssb原理介绍_计算机视觉life的博客-CSDN博客
[3] Andreas Geiger (cvlibs.net)
[4] onlyliucat/Multi-chessboard-Corner-extraction-detection-: chess board corner extraction and chess board recovery "Automatic Camera and Range Sensor Calibration using a single Shot" (github.com)

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

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

相关文章

李宏毅hw-9:Explainable ML

——欲速则不达&#xff0c;我已经很幸运了&#xff0c;只要珍惜这份幸运就好了&#xff0c;不必患得患失&#xff0c;慢慢来。 ----查漏补缺&#xff1a; 1.关于这个os.listdir的使用 2.从‘num_文件名.jpg’中提取出数值&#xff1a; 3.slic图像分割标记函数的作用&#xf…

【音视频流媒体】4、摄像头:分辨率、光圈|快门|感光度、焦距

文章目录 一、摄像头分辨率二、光圈、快门、感光度2.1 光圈2.1.1 外观2.1.2 光圈在相机中如何表示的2.1.3 对拍照的影响2.1.4 如何选择合适的光圈2.1.5 光圈在相机中如何设置 2.2 快门2.2.1 外观2.2.2 快门在相机中的表示2.2.3 快门对于拍照有什么影响2.2.4 选择合适的快门2.2.…

【C#】.Net基础语法一

目录 一、程序集信息 【1.1】Properties中AssemblyInfo文件 二、.Net程序的两次编译过程 三、.Net中命名空间和类 【3.1】引入命名空间 【3.2】修改默认的命名空间 【3.3】命名空间的总结 四、.Net中数据类型 【4.1】数值型 【4.2】非数值型 五、.Net中变量 【5.1】…

Selenium WebUI 自动化测试框架

框架结构 框架结构 框架基于 PO 模型进行设计&#xff0c;将页面元素与操作进行拆分&#xff0c;减少页面改动时的维护成本&#xff1b;同时使用 xsd 自定义 xml 标签&#xff0c;通过解析 xml 来驱动 selenium 进行执行&#xff0c;减少了一定的语言学习成本。 主要功能 基于…

[架构之路-221]:鸿蒙系统和安卓系统的比较:微内核VS宏内核, 分布式VS单体式

目录 一、鸿蒙系统和安卓系统的系统架构 1.1 鸿蒙系统的分层架构 1.2 安卓系统的分层架构 1.3 鸿蒙系统和安卓系统是操作系统吗&#xff1f; 二、鸿蒙系统和安卓系统的系统架构比较 2.1 它们与Linux操作系统的关系 2.2 架构比较 三、操作系统基础 3.1 微内核架构 3.2…

leetcode刷题 二维数组 八方向

题目描述 输入&#xff1a;board [[0,1,0],[0,0,1],[1,1,1],[0,0,0]] 输出&#xff1a;[[0,0,0],[1,0,1],[0,1,1],[0,1,0]] 题目分析:就是以二维数组某个元素为中心&#xff0c;寻找周围八个方向的元素&#xff0c;按照题目要求修改二维数组元素返回&#xff1b; 拷贝一份二…

FPGA板卡启动以及LED灯带调试

环境配置 软件&#xff1a; MobaXterm&#xff08;free版本即可&#xff09;下载教程参考&#xff1a; MobaXterm&#xff08;终端工具&#xff09;下载&安装&使用教程_蜗牛也不慢......的博客-CSDN博客 Win32 Disklmager 下载教程参考&#xff1a; 不分类工具&am…

Nature Communications | 张阳课题组:端到端深度学习实现高精度RNA结构预测

RNA分子是基因转录的主要执行者&#xff0c;也是细胞运作的隐形功臣。它们在基因表达调控、支架构建以及催化活性等多个生命过程中都扮演着关键角色。虽然RNA如此重要&#xff0c;但由于实验数据的缺乏&#xff0c;准确预测RNA 的三维空间结构仍然是目前计算生物学面临的重大挑…

HDMI之HDCP 2.3

Authentication and Key Exchange Without Stored Km With Stored Km HDCP2Version DDC时序 协议截图 Bit2为1,可知DUT设备支持HDCP 2.2及以上版本 RxStatus DDC时序 协议截图 <

C++ 类、方法的同一声明不同实现的方式

问题提出 头文件&#xff1a;声明CurrentTime类和PrintTime方法。 #ifndef CURRENT_TIME_H #define CURRENT_TIME_H class CurrentTime { public:void PrintTime(); }; #endifmain函数&#xff1a;创建CurrentTime对象&#xff0c;调用PrintTime。 #include "current_t…

UNet网络模型:数据集制作

UNet网络模型&#xff1a;数据集制作 一般语义分割的原始图片和标记图片在以下目录下&#xff1a; SegmentationClass&#xff1a;标记图片。 JPEGImages&#xff1a;原始图片。 数据集往往都是很多的图片等信息&#xff0c;对于数据集类来说&#xff0c;一个类里有所有数据…

腾讯mini项目-【指标监控服务重构-会议记录】2023-07-06

7/6 会议记录 Profile4个步骤 解压kafka消息初始化性能事件&#xff0c;分析事件将数据写入kafkaRun 开始执行各stage handler 上报耗时到otel-collector。。。 // ConsumerDispatchHandler consumer // // param msg *sarama.ConsumerMessage // param consumer *databus.K…

FPGA project : rom_vga_jump

只有vga_pix 模块代码与rom_vga不同&#xff0c;所以只上传了这个模块的代码与仿真代码。 // #define BLACK 0x0000 // 黑色 // #define NAVY 0x000F // 深蓝色 // #define DGREEN 0x03E0 // 深绿色 // #define DCYAN …

Linux系统下安装Mysql

1、执行命令&#xff1a;rpm -qa | grep -i mysql&#xff0c;先查看系统之前是否有安装相关的rpm包&#xff0c;如果有&#xff0c;会显示类似下面的信息&#xff1b; 2、通过命令yum -y remove mysql-*  一次性删除系统上所有相关的rpm包&#xff0c;或者通过命令yum -y …

zemax显微镜设计

光学显微镜&#xff08;Optical Microscope&#xff0c;简写OM&#xff09;是利用光学原理&#xff0c;把人眼所不能分辨的微小物体放大成像&#xff0c;以供人们提取微细结构信息的光学仪器&#xff0c;第一架复式光学显微镜是于1665年由英国物理学家虎克制作。 首先做物镜 入…

(第三百篇BLOG记录)写于象牙终章与从零开始-20230924

启 由于若干原因&#xff08;包括但不限于紧锣密鼓的完成博士毕业的一系列实验和论文撰写、学习各种百花齐放的有意思的领域、完成人生身份的重大转变&#xff09;&#xff0c;导致卡在299篇博客已经很久了&#xff0c;不过算了一下还是在一个较长时间维度上可以基本保持每周一…

数据库——理论基础

目录 1.1 什么是数据库 1.2 数据库管理系统&#xff08;DBMS&#xff09; 1.3 数据库和文件系统的区别 1.4 数据库的发展史 1.5常见的数据库 1.5.1关系型数据库 1.5.2 非关系型数据库 1.6 DBMS支持的数据模型 1.1 什么是数据库 数据&#xff1a;描述事物的符号记录 数…

云计算中的关键技术——虚拟化

在数据中心里面&#xff0c;也有一种类似的开源技术 qemu-kvm&#xff0c;能让你在一台巨大的物理机里面&#xff0c;掏出一台台小的机器。这套软件就能解决上面的问题&#xff1a;一点就能创建&#xff0c;一点就能销毁。你想要多大就有多大&#xff0c;每次创建的系统还都是新…

Windows系统如何临时关闭“Windows安全中心实时保护”

前言 启动windows depender实时保护可能会使系统不太流畅&#xff0c;也可能会导致我们的程序无法正常运行&#xff0c;因为它会拦截或搜索我们的正常工作。 暂时关闭windows depender的实时保护对许多用户来说非常重要。 一、Win10系统关闭方法 打开Windows安全中心&#…

Spring面试题20:Spring怎样开启注解装配?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Spring怎样开启注解装配? 要在Spring中开启注解装配,需要进行以下几个步骤: 添加必要的依赖:在项目的构建工具(如Maven或Gradle)配置文件中…