跨平台应用开发进阶(三): uni-app 实现资源在线升级/热更新

article/2025/8/29 19:58:34

文章目录

    • 一、前言
      • 1.1 Android升级检测机制
    • 二、wgt 资源升级包升级
      • 2.1 修改版本号
      • 2.2 发行
      • 2.3 安装资源升级包
        • 2.3.1 代码示例
        • 2.3.2 小结
    • 三、整包升级
      • 3.1 客户端实现
      • 3.2 数据表实现
      • 3.3 服务端实现
      • 3.4 发版配置
      • 3.5 注意事项
    • 四、Uni-app 版本升级中心
      • 4.1 升级中心 uni-upgrade-center - Admin
      • 4.2 前台检测更新 uni-upgrade-center-app
      • 4.3 工作原理
      • 4.4 疑问
    • 五、拓展阅读


一、前言

使用 uni-app 开发跨终端应用,可将代码编译到iOSAndroid、微信小程序等多个平台,升级时也需考虑多平台同步升级。其中,uni-app发布为小程序的升级模式较简单,只需将开发完的代码提交到小程序后台,待审核通过后用户将自动升级。

1.1 Android升级检测机制

android系统使用包名(package name)来判定应用程序的同一性,但是由于包名可以由开发者自由设置,为了保护应用程序不被其他开发者开发的同包名应用覆盖,用于发布的Android应用程序需要加上开发者签名。签名是保证app不被第三方恶意替换。

在应用程序被升级的时候,Android系统将会验证被升级的应用程序包与升级后的应用程序包是否使用了同样的开发者签名,如果一致,该应用程序可以被升级;如果不一致,那么将被视为非同一开发者开发的应用程序,用户需要先卸载已经安装的应用,然后再安装新应用。在卸载的过程中,应用在android系统中所保存的设置信息(SavedPreferences)将被删除,以保护应用本地保存的资料不被盗取。

  • 如果包名和签名一样,就直接覆盖,认为是同一个app。
  • 如果包名一样,但签名不一样,会提示是否删除之前的。
  • 如果两者都不一样,就会认为是两个不同的app。

根据现有应用市场的升级规则,包名一致,才会提醒升级,升级时,签名不一致,无法升级

检测到包名一致且版本不一致 ——> 提示升级 ——> 签名不一致 ——> 升级失败。

包名一致签名一致,就升级成功了。

HBuilderX 1.6.5 起,uni-app 支持生成 App 资源升级包wgt

二、wgt 资源升级包升级

wgt文件称为使用浏览器作为一个小型的Web应用程序部件,这些文件包含有关部件配置,图像,索引,样式表,JavaScript等信息,通常是在一个压缩归档格式。解压后的文件目录结构如下:

在这里插入图片描述

全量apk包目录结构如下:

在这里插入图片描述

2.1 修改版本号

首先,更新 manifest.json 中的版本号。比如之前是 1.0.0,那么新版本应该是 1.0.11.1.0

在这里插入图片描述

2.2 发行

然后,在 HBuilderX 中生成升级包(wgt)。

菜单 -> 发行 -> 原生App-制作移动App资源升级包

在这里插入图片描述

生成结束会在控制台告知升级包的输出位置。

在这里插入图片描述

2.3 安装资源升级包

应用升级需要服务端与客户端配合完成,下面以本地测试过程中的操作举例说明:

存放资源
%appid%.wgt 文件存放在服务器的 static 目录下,即http://www.example.com/static/UNI832D722.wgt

服务端接口
约定检测升级的接口,地址为:http://www.example.com/update/

传入参数

  • name String ‘’ 客户端读取到的应用名称,定义这个参数可以方便多个应用复用接口。
  • version String ‘’ 客户端读取到的版本号信息

返回参数

  • update Boolean false 是否有更新
  • wgtUrl String wgt 包的下载地址,用于 wgt 方式更新。
  • pkgUrl String apk/ipa 包下载地址或 AppStore 地址,用于整包升级的方式。

2.3.1 代码示例

下面是一个简单的服务端判定的示例,仅做参考,实际开发中根据自身业务需求处理。

var express = require('express');  
var router = express.Router();  
var db = require('./db');  // TODO 查询配置文件或者数据库信息来确认是否有更新  
function checkUpdate(params, callback) {  db.query('一段SQL', function(error, result) {  // 这里简单判定下,不相等就是有更新。  var currentVersions = params.appVersion.split('.');  var resultVersions = result.appVersion.split('.');  if (currentVersions[0] < resultVersions[0]) {  // 说明有大版本更新  callback({  update: true,  wgtUrl: '',  pkgUrl: result.pkgUrl  })  } else {  // 其它情况均认为是小版本更新  callback({  update: true,  wgtUrl: result.wgtUrl,  pkgUrl: ''  })  }  });  
}  router.get('/update/', function(req, res) {  var appName = req.query.name;  var appVersion = req.query.version;  checkUpdate({  appName: appName,  appVersion: appVersion  }, function(error, result) {  if (error) {  throw error;  }  res.json(result);  });  
});

注意事项⚠️:

  • 服务端的具体判定逻辑,请根据自身的业务逻辑灵活处理。
  • 应用中的路径尽量不要包含特殊符号。

客户端检测升级
App.vueonLaunch 中检测升级,代码如下:

// #ifdef APP-PLUS  
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {  uni.request({  url: 'http://www.example.com/update/',  data: {  version: widgetInfo.version,  name: widgetInfo.name  },  success: (result) => {  var data = result.data;  if (data.update && data.wgtUrl) {  uni.downloadFile({  url: data.wgtUrl,  success: (downloadResult) => {  if (downloadResult.statusCode === 200) {  plus.runtime.install(downloadResult.tempFilePath, {  force: false  }, function() {  console.log('install success...');  plus.runtime.restart();  }, function(e) {  console.error('install fail...');  });  }  }  });  }  }  });  
});  
// #endif

不支持资源升级包情况如下:

  • SDK 部分有调整,比如新增了 Maps 模块等,不可通过此方式升级,必须通过整包的方式升级。
  • 原生插件的增改,同样不能使用此方式。
  • 对于老的非自定义组件编译模式,这种模式已经被淘汰下线。但以防万一也需要说明下,老的非自定义组件编译模式,如果之前工程没有 nvue 文件,但更新中新增了 nvue 文件,不能使用此方式。因为非自定义组件编译模式如果没有nvue文件是不会打包weex引擎进去的,原生引擎无法动态添加。自定义组件模式默认就含着weex引擎,不管工程下有没有nvue文件。

注意事项⚠️

  • 条件编译,仅在 App 平台执行此升级逻辑。
  • appid 以及版本信息等,在 HBuilderX 真机运行开发期间,均为 HBuilder 应用的信息,因此需要打包自定义基座或正式包测试升级功能。
  • plus.runtime.version 或者 uni.getSystemInfo() 读取到的是 apk/ipa 包的版本号,而非 manifest.json 资源中的版本信息,所以这里用 plus.runtime.getProperty() 来获取相关信息。
  • ⚠️安装 wgt 资源包成功后,必须执行 plus.runtime.restart(),否则新的内容并不会生效。
  • 如果App的原生引擎不升级,只升级wgt包时,需要注意测试wgt资源和原生基座的兼容性⚠️。平台默认会对不匹配的版本进行提醒,如果自测没问题,可以在manifest.json中配置忽略提示。
  • ⚠️应用市场为了防止开发者不经市场审核许可,给用户提供违法内容,对热更新大多持排斥态度。

但实际上热更新使用非常普遍,不管是原生开发中还是跨平台开发。

Apple曾经禁止过jspatch,但没有打击其他的热更新方案,包括cordovar、react native、DCloud。封杀jspatch其实是因为jspatch有严重安全漏洞,可以被黑客利用,造成黑客可篡改其他App的数据。

使用热更新需要注意⚠️:

  • 🙅‍♂️上架审核期间不要弹出热更新提示;
  • ⚠️热更新内容使用https下载,避免被三方网络劫持;
  • 🙅不要更新违法内容、不要通过热更新破坏应用市场的利益,比如iOS的虚拟支付要老老实实给Apple分钱。

2.3.2 小结

用户对于热更新及整包更新的感知几乎是无差别的,同样需要主动触发用户下载安装,只不过包的大小不一致。

三、整包升级

接口约定
如下数据接口约定仅为示例,开发者可以自定义接口参数。

请求地址:https://www.example.com/update

请求方法:GET

请求数据:

{  "appid": plus.runtime.appid,  "platform": platformFlag,"version": plus.runtime.version  
}  

其中,platformFlag为手机系统标识,可通过如下方法获取:

async initSystemInfo() {uni.getSystemInfo({success(e) {console.log('The system info e is: ', e)// #ifndef MPgetApp().globalData.deviceInfo = eVue.prototype.StatusBar = e.statusBarHeight;if (e.platform === 'android') {getApp().globalData.deviceInfo.platformFlag = '0' // Android系统标识Vue.prototype.CustomBar = e.statusBarHeight + 50;} else {getApp().globalData.deviceInfo.platformFlag = '1' // IOS系统标识Vue.prototype.CustomBar = e.statusBarHeight + 43;}// #endif// #ifdef MP-WEIXINVue.prototype.StatusBar = e.statusBarHeight;const custom = wx.getMenuButtonBoundingClientRect();Vue.prototype.Custom = custom;Vue.prototype.CustomBar = custom.top - e.statusBarHeight;// #endif// #ifdef MP-ALIPAYVue.prototype.StatusBar = e.statusBarHeight;Vue.prototype.CustomBar = e.statusBarHeight + e.titleBarHeight;// #endif}});
},

响应数据:

{  "status":1,//升级标志,1:需要升级;0:无需升级  `在这里插入代码片`"note": "修复bug1;\n修复bug2;",//release notes  "url": "http://www.example.com/uniapp.apk" //更新包下载地址  
} 

3.1 客户端实现

App启动时,向服务端上报当前版本号,服务端判断是否提示升级。

App.vueonLaunch中,发起升级检测请求,如下:

onLaunch: function () {  //#ifdef APP-PLUS  var server = "https://www.example.com/update"; //检查更新地址  var req = { //升级检测数据  "appid": plus.runtime.appid,  "version": plus.runtime.version  };  uni.request({  url: server,  data: req,  success: (res) =&gt; {  if (res.statusCode == 200 &amp;&amp; res.data.status === 1) {  uni.showModal({ //提醒用户更新  title: "更新提示",  content: res.data.note,  success: (res) =&gt; {  if (res.confirm) {  switch (uni.getSystemInfoSync().platform) {case 'android':// 开始下载任务const downloadTask = uni.downloadFile({url: data.url,// 接口调用成功success: (downloadResult) => {uni.hideLoading();console.log('----------------downloadResult----------------', downloadResult)if (downloadResult.statusCode === 200) {// uni.showLoading({// 	mask:true,// 	title: '安装中...'// });plus.runtime.install(downloadResult.tempFilePath, {force: false}, function() {// uni.hideLoading();console.log('install success...');plus.runtime.restart();}, function(e) {console.error('install fail...');});}},// 接口调用失败fail: (err) => {console.log('----------------Fail----------------', err);uni.showToast({icon:'none',mask:true,title: '安装失败,请重新下载',});},// 接口调用结束complete: () => {console.log('----------------Complete----------------:', downloadTask)downloadTask.offProgressUpdate(); //取消监听加载进度}});//监听下载进度downloadTask.onProgressUpdate(res => {// _self.percent = res.progress;state.percent = res.progress;// console.log('下载进度百分比:' + res.progress); // 下载进度百分比// console.log('已经下载的数据长度:' + res.totalBytesWritten); // 已经下载的数据长度,单位 Bytes// console.log('预期需要下载的数据总长度:' + res.totalBytesExpectedToWrite); // 预期需要下载的数据总长度,单位 Bytes});break;case 'ios':// 跳转至Apple Storelet appleId=1549638327 //app的appleIdplus.runtime.launchApplication({action: `itms-apps://itunes.apple.com/cn/app/id${appleId}?mt=8`}, function(e) {console.log('Open system default browser failed: ' + e.message);});break;}}  }  })  }  }  })  //#endif  
}  

注意⚠️:App的升级检测代码必须使用条件编译,否则在微信环境由于不存在plus相关API,将会报错。

3.2 数据表实现

需维护一张数据表,用于维护APP版本信息,主要字段信息如下:

字段名称数据类型数据说明
AppIDvarcharmobile AppID
versionvarchar应用市场版本号
notesvarchar版本更新说明
urlvarchar应用市场下载URL。 注意:⚠️根据谷歌、App Store应用市场审核规范,应用升级只能通过提交应用市场更新,不能通过下载apkIPA安装方式更新应用。

3.3 服务端实现

根据客户端接收的版本号,比对服务端最新版本号,决定是否需要升级,若需升级则返回升级信息(rlease notes更新包地址等)

开发者可以根据服务端开发语言,自己实现升级检测逻辑,如下是一个php示例代码:

header("Content-type:text/json");  
$appid = $_GET["appid"];  
$version = $_GET["version"]; //客户端版本号  
$rsp = array("status" =&gt; 0); //默认返回值,不需要升级  
if (isset($appid) &amp;&amp; isset($version)) {  if ($appid === "__UNI__123456") { //校验appid  if ($version !== "1.0.1") { //这里是示例代码,真实业务上,最新版本号及relase notes可以存储在数据库或文件中  $rsp["status"] = 1;  $rsp["note"] = "修复bug1;\n修复bug2;"; //release notes  $rsp["url"] = "http://www.example.com/uniapp.apk"; //应用升级包下载地址  }  }  
}   
echo json_encode($rsp);  
exit;  

注意事项⚠️:

  • plus.runtime.appidplus.runtime.versionplus.runtime.openURL() 在真机环境下才有效。
  • 版本检测需要打包app,真机运行基座无法测试。因为真机运行的plus.runtime.version是固定值。
  • 根据谷歌应用市场的审核规范,应用升级只能通过提交应用市场更新,不能通过下载apk安装方式更新应用。apk安装失败可能是因为缺少android.permission.INSTALL_PACKAGESandroid.permission.REQUEST_INSTALL_PACKAGES权限导致,注意:添加上面两个权限无法通过谷歌审核。

3.4 发版配置

APP发版时,应注意维护manifest.jsonversionNameversionCode字段,以免影响版本升级。

在这里插入图片描述

3.5 注意事项

  • plus.runtime.version 为属性方式同步获取,拿到的是编译阶段manifest.json中设置的apk/ipa版本号,整包更新后的版本号,在manifest.json中配置时需要提交到App云端打包后才能生效。

  • plus.runtime.getProperty 为异步方法调用获取,拿到的当前应用的版本号,如果热更新过就是热更新后的版本号。

plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) {console.log(widgetInfo.version);
})

四、Uni-app 版本升级中心

uni-app提供了一整套版本维护框架,包含升级中心uni-upgrade-center - Admin、前台检测更新uni-upgrade-center-app

4.1 升级中心 uni-upgrade-center - Admin

uni-app提供了版本维护后台应用升级中心uni-upgrade-center - Admin,升级中心是一款uni-admin插件,负责App版本更新业务。包含后台管理界面、更新检查逻辑,App内只要调用弹出提示即可。

在这里插入图片描述

在上传安装包界面填写此次发版信息,其中包地址可以选择手动上传一个文件到云存储,会自动将地址填入该项。

也可以手动填写一个地址(例如:https://appgallery.huawei.com/app/C10764638),就可以不用再上传文件。

⚠️如果是发布苹果版本,包地址则为应用在AppStore的链接。

在这里插入图片描述

升级中心有以下功能点:

  • 云储存安装包CDN加速,使安装包下载的更快、更稳定
  • 应用管理,对App的信息记录和应用版本管理。
  • 版本管理,可以发布新版,也可方便直观的对当前App历史版本以及线上发行版本进行查看、编辑和删除操作。
  • 版本发布信息管理,包括更新标题内容版本号,静默更新,强制更新,灵活上线发行的设置和修改。
  • 原生App安装包,发布Apk更新,用于App的整包更新,可设置是否强制更新。
  • wgt资源包,发布wgt更新,用于App的热更新,可设置是否强制更新,静默更新。
  • App管理列表及App版本记录列表搜索。
  • 只需导入插件,初始化数据库即可拥有上述功能。
  • 也可以自己修改逻辑自定义数据库字段,和随意定制 UI 样式。

4.2 前台检测更新 uni-upgrade-center-app

uni-upgrade-center-app 负责前台检查升级更新。

项目结构如下图所示:
在这里插入图片描述

检测更新视图如下图所示:

在这里插入图片描述 在这里插入图片描述

该插件提供如下功能:

  • 统一管理AppAppAndroidiOS平台上App安装包和wgt资源包的发布升级。
  • 基于uni-upgrade-center一键式检查更新,统一整包与 wgt 资源包更新。
  • 自行根据传参完成校验,判断此次更新使用哪种方式。
  • 一键式升级。已集成弹框、下载、安装、是否强制重启等逻辑。
  • 下载完成如果取消升级自动缓存安装包,下次进入判断是否符合安装条件,判断不通过则自动清除。
  • 美观,实用,可自定义扩展。

注意:⚠️在手机基座上运行时获取到的版本号appidhbuilderhbuilder的版本需要在文件里面手动设置。

4.3 工作原理

升级中心uni-upgrade-center - Admin负责维护版本信息,并将版本信息维护至数据库中。
前台检测更新插件uni-upgrade-center-app负责提供调用云函数读取数据库维护的版本信息一键式检查更新。

4.4 疑问

  • 前台检测更新插件 uni-upgrade-center-app 应用云函数实现版本检测,当应用部署至内网后,应如何实现?

五、拓展阅读

  • 《DCloud 升级中心 uni-upgrade-center》
  • 《uni-app 条件编译》
  • 《App资源在线升级更新说明文档》
  • 《HTML5+ API Reference》
  • 《跨平台应用开发进阶(六十):uniapp 获取设备唯一标识信息》

http://chatgpt.dhexx.cn/article/sFBwkwP4.shtml

相关文章

STM32 IAP 在线升级原理全解析

点击左上角的“关注”&#xff0c;定期更新 STM32 最新资讯&#xff0c;总有你想要的信息&#xff01; STM32 IAP 在线升级原理全解析 1. 什么是 IAP&#xff1f; IAP&#xff08;In-Application Programming&#xff09;是用户自己的程序在运行过程中对 User Flash 部分的区域…

ESP8266实现在线升级OTA

今天总结一下我实现ESP8266实现在线升级&#xff08;OTA&#xff09;的经验 关于理论介绍我这里不多讲&#xff0c;大家可以参考以下文章&#xff1a; 1.一个网友总结的经验&#xff08;我这篇文章主要也是对该文章做进一步补充&#xff09;&#xff1a;https://www.cnblogs.c…

stm32在线升级方案

目录 下载固件流程&#xff1a; Bootloader程序设计流程 普通工程改为APP工程的步骤 背景&#xff1a;当嵌入式软件需要固件升级时&#xff0c;有时需要拆卸设备&#xff0c;较为麻烦&#xff0c;为方便升级&#xff0c;提供远程升级的功能&#xff0c;可通过网络或其他通讯…

串口在线升级步骤

串口在线升级步骤 一、查看工程文件的Config.h 二、确定本地地址和目标地址 三、打开在线升级工具 四、配置串口参数 串口配置可以波查询代码与PC通讯的UART设置的参数。 五、填写本机地址和目标地址 本机地址为0xf3 243 主板目标地址为0xf5 245 PMT板目标地址为0x13 19 …

mariadb数据库在线升级版本

mariadb----在线版本升级 我之前的数据库版本号是5.5 一&#xff1a;备份数据库和数据库配置 mysqldump -u root -p --all-databases > /home/mydb.sql mv /etc/my.cnf /etc/my.cnf.bak 二&#xff1a;添加mariadb yum库 vim /etc/yum.repos.d/MariaDB.repo [mariadb] na…

FPGA远程固件在线升级

FPGA远程固件在线升级 1.摘要 对最近做的FPGA远程更新/在线升级做一个总结。一般在代码开发阶段&#xff0c;我们使用JTAG烧写代码&#xff0c;但当产品投入到实际使用过程中&#xff0c;难以再用JTAG进行固件更新。所以需要开发远程/在线更新的功能&#xff0c;即使用产品自…

固件在线升级流程

从事硬件开发&#xff0c;为了方便维护&#xff0c;免不了对模块进行固件升级&#xff0c;所以对于固件升级&#xff0c;简单整理了一下完整的在线升级的实现思路&#xff0c;该思路适用于所有带通讯总线的模块。 需要注意的是&#xff0c;需要额外的上位机配合。 下位机在线…

php 在线升级

php 在线升级 功能 目前已修改为通用解决方案 点击下方链接下载 此为最新优化过的版本 之后的贴图 说明 仅用来做思路参考 我就不再修改了 下面是思路解析思路一思路二升级程序服务器检测版本至此整个升级程序已经结束 感谢大家参考有任何问题都可以直接联系我咨询 一定不吝赐教…

软件在线升级系统设计

需求描述 一直用Qt开发PC版本的程序&#xff0c;常用的方法都是打包发布。目前开发的程序比较复杂&#xff0c;涉及到上百个独立的进程以及4000多个相关文件&#xff0c;采用原来的打包发布就变得很麻烦&#xff0c;第一改动比较频繁&#xff0c;打包次数过多&#xff1b;第二…

Nginx在线升级

1、查看当前nginx版本&#xff0c;nginx -v&#xff08;小写v&#xff09; 2、下载最新版本nginx包&#xff0c;nginx-1.23.1.tar.gz 3、解压tar -zxvf nginx-1.23.1.tar.gz 4、进入解压目录cd nginx-1.23.1.tar.gz 5、查看nginx当前配置&#xff0c;nginx -V注意这里是大写…

在线升级:OTA升级的原理和实现方式

目录 1、OTA 在线升级 2、实现方式 3、操作方式 3.1、后台式升级 3.2、非后台式式更新 4、STM32 的在线升级 4.1、划分 Flash 区域 4.2、实操1 - Flash空间地址的划分 4.3、实操2 - 设置工程 4.4、实操3 - 接收固件更新包 4.5、实操4 - 拷贝程序至Flash 4.6、实操5 - 跳转至 Ap…

halcon 彩色图转灰度图

read_image (Image, jiao1.bmp) //读取图像 get_image_size (Image, Width, Height) //获取宽高 dev_close_window () //关闭图形窗口 rgb1_to_gray (Image, GrayImage) //彩色图转灰度图 dev_open_window (0, 0, Width, Height, black, WindowHandle) //打开图形窗口 d…

Python中使用PIL快速实现灰度图

效果 原图 效果图 实现 新建文件夹grayImage&#xff0c;在此文件夹下新建gray.py from PIL import Image imgImage.open(1111.jpg) imgimg.convert(L) img.save(灰度图.jpg) 其中1111.jpg是原图&#xff0c;将其放在同目录下。 运行即可。 源码以及资源下载 https://do…

计算机灰度分析,计算机中的256级灰度图像

【建议1】使用GltraEdit软件观察字符“((Z20享有声望的学校联盟)”的内部代码. 以下说法正确 A. 字符“(”的内部代码占用两个字节 B. 字符“ Lian”的代码值的二进制表示形式是11010001 10101010 C. 图片中有5个ASCⅡ字符,其中字符“ 2”的代码值的十六进制表示为32 D. 字符“…

C++-灰度图上色GrayToColor

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 场景需求 最近有客户提出&#xff0c;想要将解包裹图像转化为有颜色的图像&#xff0c;具备更佳的视觉效果。解包裹图是一个floa…

灰度图与二值化

图像处理的灰度化和二值化 在图像处理中&#xff0c;用RGB三个分量&#xff08;R&#xff1a;Red&#xff0c;G&#xff1a;Green&#xff0c;B&#xff1a;Blue&#xff09;&#xff0c;即红、绿、蓝三原色来表示真彩色&#xff0c;R分量&#xff0c;G分量&#xff0c;B分量的…

opencv学习5:cvtColor RGB图像转灰度图像原理

简介 将彩色图像转化成为灰度图像的过程成为图像的灰度化处理。彩色图像中的每个像素的颜色有R、G、B三个分量决定&#xff0c;而每个分量有255中值可取&#xff0c;这样一个像素点可以有1600多万&#xff08;255*255*255&#xff09;的颜色的变化范围。而灰度图像是R、G、…

Matplotlib显示灰度图

引言 matplotlib中的imshow()函数不能自动显示灰度图像&#xff0c;这一点应该是众所周知的&#xff0c;需要调用cmap“gray"以进行设置&#xff0c;但是cmap"gray"实际上并不是如opencv中的imshow函数一样将单通道图显示为灰度图&#xff0c;私以为是引入了灰度…

python显示灰度图像,Python读取图像并显示灰度图的实现

python读取图像 原图: import cv2 # 利用opencv读取图像 import numpy as np # 利用matplotlib显示图像 import matplotlib.pyplot as plt img cv2.imread("./lena.png") #读取图像 # 显示图像 plt.imshow(img) plt.axis(off) plt.show() 效果&#xff1a; 问&#…

OpenCV灰度图

什么是灰度图&#xff1a; 百度百科 什么是灰度图 #include <opencv2/opencv.hpp> #include <iostream>using namespace cv; using namespace std;int main(int argc, char** argv) {Mat src Mat(4,4,CV_8UC3,Scalar(28,128,228));cout << src << en…