相机One Shot标定

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 templatetemplate = createCorrelationPatch(template_props(template_class,1),template_props(template_class,2),template_props(template_class,3));% filter image according with current templateimg_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 meanimg_corners_mu = (img_corners_a1+img_corners_a2+img_corners_b1+img_corners_b2)/4;% case 1: a=white, b=blackimg_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=blackimg_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 mapimg_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)<=1return;
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.3return;
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 vectoro = [img_du(v,u) img_dv(v,u)];if norm(o)<0.1continue;endo = o/norm(o);% robust refinement of orientation 1if 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 2if 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)];endendend% 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 vectoro = [img_du(v,u) img_dv(v,u)];if norm(o)<0.1continue;endo = o/norm(o);% robust subpixel corner estimationif u~=cu || v~=cv % do not consider center pixel% compute rel. position of pixel and distance to vectorsw  = [u v]-[cu cv];d1 = norm(w-w*v1'*v1);d2 = norm(w-w*v2'*v2);% if pixel corresponds with either of the vectors / directionsif d1<3 && abs(o*v1')<0.25 || d2<3 && abs(o*v2')<0.25du = img_du(v,u);dv = img_dv(v,u);H = [du dv]'*[du dv];G = G + H;b = b + H*[u v]';endendendend% set new corner location if G has full rankif rank(G)==2corner_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 largeif norm(corner_pos_new-corner_pos_old)>=4corners.v1(i,:) = [0 0];corners.v2(i,:) = [0 0];end% otherwise: set corner to invalidelsecorners.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.5img_filter(y,x) = +1;endend
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)<9chessboard = [];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.3chessboard = [];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 chessboardwhile 1% compute current energyenergy = chessboardEnergy(chessboard,corners);% compute proposals and energiesfor j=1:4proposal{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 reducedif p_energy(min_idx)<energychessboard = proposal{min_idx};% otherwise exit loopelsebreak;endend

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 chessboardsoverlap = 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;endendend% add chessboard (and replace overlapping if neccessary)if ~any(overlap(:,1))chessboards{end+1} = chessboard;elseidx = find(overlap(:,1)==1);if ~any(overlap(idx,2)<=chessboardEnergy(chessboard,corners))chessboards(idx) = [];chessboards{end+1} = chessboard;endendend

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.xdnf.cn/news/141085.html

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

相关文章

Vue 使用vue-pdf 显示pdf文件 切换页面 缩放 全屏 自动播放等

<template><div id"container"><!-- 上一页、下一页--><div class"right-btn"><div click"toFullOrExit" class"turn-btn"><span>{{ isFull 1 ? "取消全屏" : "全屏" }}&l…

机器学习第十四课--神经网络

总结起来&#xff0c;对于深度学习的发展跟以下几点是离不开的: 大量的数据(大数据)计算资源(如GPU)训练方法(如预训练) 很多时候&#xff0c;我们也可以认为真正让深度学习爆发起来的是数据和算力&#xff0c;这并不是没道理的。 由于神经网络是深度学习的基础&#xff0c;学…

分类预测 | Matlab实现NGO-CNN-SVM北方苍鹰算法优化卷积支持向量机分类预测

分类预测 | Matlab实现NGO-CNN-SVM北方苍鹰算法优化卷积支持向量机分类预测 目录 分类预测 | Matlab实现NGO-CNN-SVM北方苍鹰算法优化卷积支持向量机分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现NGO-CNN-SVM北方苍鹰算法优化卷积支持向量机分类预…

32 随机链表的复制

随机链表的复制 题解1 哈希表题解2 回溯哈希哈希思路精简 题解3 优化迭代 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点…

操作系统权限提升(二十八)之数据库提权-SQL Server 数据库安装

SQL Server 数据库安装 SQL Server介绍 SQL Server 是Microsoft 公司推出的关系型数据库管理系统。具有使用方便可伸缩性好与相关软件集成程度高等优点,可跨越从运行Microsoft Windows 98 的膝上型电脑到运行Microsoft Windows 2012 的大型多处理器的服务器等多种平台使用。…

Linux下git安装及使用

Linux下Git使用 1. git的安装 sudo apt install git安装完&#xff0c;使用git --version查看git版本 2. 配置git git config --global user.name "Your Name“ ##配置用户 git config --global user.email emailexample.com ##配置邮箱git config --global --list …

PHP后台实现微信小程序登录

微信小程序官方给了十分详细的登陆时序图&#xff0c;当然为了安全着想&#xff0c;应该加上签名加密。 微信小程序端 1).调用wx.login获取 code 。 2).调用wx.getUserInfo获取签名所需的 rawData , signatrue , encryptData 。 3).发起请求将获取的数据发送的后台。 login: …

面向面试知识-Redis

面向面试知识-Redis 什么是Redis 运行于内存的基于key-value的非关系型数据库。 一款开源的内存数据结构存储&#xff0c;用作数据库、缓存、消息代理等。&#xff08;可以基于Redis实现分布式锁、以及消息队列&#xff09; 发布订阅&#xff1f;&#xff1f; 对数据类型的操…

Jmeter接口测试

前言&#xff1a; 本文主要针对http接口进行测试&#xff0c;使用Jmeter工具实现。 Jmter工具设计之初是用于做性能测试的&#xff0c;它在实现对各种接口的调用方面已经做的比较成熟&#xff0c;因此&#xff0c;本次直接使用Jmeter工具来完成对Http接口的测试。 1.介绍什么是…

利用爬虫技术自动化采集汽车之家的车型参数数据

导语 汽车之家是一个专业的汽车网站&#xff0c;提供了丰富的汽车信息&#xff0c;包括车型参数、图片、视频、评测、报价等。如果我们想要获取这些信息&#xff0c;我们可以通过浏览器手动访问网站&#xff0c;或者利用爬虫技术自动化采集数据。本文将介绍如何使用Python编写…

使用Python做一个微信机器人

介绍 简介 该程序将微信的内部功能提取出来&#xff0c;然后在程序里加载Python&#xff0c;接着将这些功能导出成库函数&#xff0c;就可以在Python里使用这些函数 程序启动的时候会执行py_code目录下的main.py&#xff0c;类似于你在命令行使用python main.py。 现在会以…

011_第一代软件开发(三)

第一代软件开发(三) 文章目录 第一代软件开发(三)项目介绍带下知识点系统日志滤波器陷波滤波器带通滤波器 打印初始化调用打印机打印文件保存到PDF 总结一下 关键字&#xff1a; Qt、 Qml、 日志、 打印、 滤波器 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这…

rom修改----安卓系列机型如何内置app 如何选择so文件内置

系统内置app的需求 在与各工作室对接中操作单中&#xff0c;很多需要内置客户特定的有些app到系统里&#xff0c;这样方便客户刷入固件后直接调用。例如内置apk 去开机引导 去usb调试 默认开启usb安全设置等等。那么很多app内置有不同的反应。有的可以直接内置。有的需要加so…

【三、centOS安装后的基本配置】

Centos的ip地址设定&#xff0c;cmd查看 Windows: ipconfig 再到windows电脑的网络共享中心查看 设置虚拟机的IPv4&#xff0c;锁定本地电脑的ip地址和网关 再重启虚拟机机器&#xff0c;vi /etc/sysconfig/network-scripts/ifcfg-ens33 TYPE"Ethernet" PROXY_MET…

JavaScript学习笔记05

JavaScript笔记05 操作 BOM 对象&#xff08;重点&#xff09; 什么是 BOM BOM&#xff08;Browser Object Model&#xff09;是指浏览器对象模型&#xff0c;是用于描述这种对象与对象之间层次关系的模型。浏览器对象模型&#xff08;BOM&#xff09;提供了独立于内容的、可…

设计模式再探——原型模式

目录 一、背景介绍二、思路&方案三、过程1.原型模式简介2.原型模式的类图3.原型模式代码4.原型模式深度剖析5.原型模式与spring 四、总结五、升华 一、背景介绍 最近在做业务实现的时候&#xff0c;为了通过提升机器来降低开发人员的难度和要求&#xff0c;于是在架构设计…

用Redis做数据排名

1.背景 用Redis做数据缓存用的比较多&#xff0c;大家都能熟练使用String和Hash结构去存储数据&#xff0c;今天讲下如何使用ZSet来做数据排名。 假设场景是需要按天存储全国城市的得分数据&#xff0c;可以查询前十名的城市排名。 这个case可以使用传统关系型数据库做…

【lesson7】git的介绍及使用

文章目录 什么是gitgit的历史git使用在gitee上创建仓库git clone HTTPS地址git add .git add 文件名git commit “日志”git pushgit loggit rm 文件名git statusgit pull 什么是git git是版本控制器&#xff0c;那么什么是版本控制器呢&#xff1f; 下面讲个故事为大家讲解一…

AI AIgents时代 - (三.) AutoGPT和AgentGPT

前两篇讲解了Agent的原理和组件&#xff0c;这节我将给大家介绍两个agent项目&#xff0c;给出它们的工作原理和区别&#xff0c;并教大家亲手尝试使用 Agents&#x1f389; &#x1f7e2; AutoGPT&#x1f916;️ 我们的老朋友&#xff0c;之前文章也专门写过。AutoGPT 是一…

iphone的safari浏览器实现全屏的pwa模式,并修改顶部状态栏背景颜色

要想修改顶部背景颜色&#xff0c;需要用到这个属性&#xff1a;content就是你要设置的颜色 <!-- 状态栏的背景色 --><meta name"theme-color" content"#f8f8f8" /> 然后再加上下面的设置&#xff1a; <!-- 网站开启对 web app 程序的支持…