[HTML5]快速掌握canvas

news2025/6/5 1:15:59

背景

canvas 是 html5 标准中提供的一个标签, 顾名思义是定义在浏览器上的画布

  1. 通过其强大的绘图接口,我们可以实现各种各样的图形,炫酷的动画,
  2. 甚至可以利用他开发小游戏,包括市面上很流行的数据可视化框架底层都用到了Canvas。
  3. 既然他这么强大,那我们还有什么理由不去学习它呢?

基础

渲染上下文

<canvas>是一个HTML元素,我们可以将它简单理解为一个画板,通过Canvas提供的绘制api我们就可以绘制出各种图形。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    /**
     * 获取画笔
     * 可选参数: 
     * 2d: 获取平面画笔, 绘制2d图形
     * webgl: 获取3d画笔, 绘制3d图形 
     * 
    */
    const ctx = c.getContext("2d")

  </script>
</body>

</html>

canvas中的坐标系和html中的坐标系一样

  1. 坐标: 控制图形画在什么位置
  2. 尺寸: 控制图形画多大

绘制图形

1.1. 线(线, 三角形, 矩形)

重要的API

  • 绘制: moveTo, lineTo,stroke
  • 设置样式: lineWidth,strokeStyle
  • 路径: beginPath,closePath
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    /**
     * 获取画笔
    */
    const ctx = c.getContext("2d")

    /**
     * 绘制线条 
     */
    ctx.moveTo(0, 10) // 确定画笔位置
    ctx.lineTo(200, 10) // 线的终点
    ctx.lineWidth = 50 // 设置线的宽度
    ctx.strokeStyle = 'red' // 设置画笔的颜色 (画笔是全局唯一实例)
    ctx.stroke() // 完成绘制

    /**
    * 绘制线条 
    */
    ctx.beginPath() // 新建路径, 不影响其他路径
    ctx.moveTo(0, 50)
    ctx.lineTo(200, 50)
    ctx.lineWidth = 10
    ctx.strokeStyle = 'blue'
    ctx.stroke() // stroke的绘制以beginPath为界

    /**
    * 绘制三角形
    */
    ctx.beginPath()
    ctx.moveTo(0, 70)
    ctx.lineTo(200, 70)
    ctx.lineTo(50, 200)
    // ctx.lineTo(0, 70) // 手动画线完成路径闭合
    ctx.closePath() // 让路径自动闭合

    ctx.lineWidth = 1
    ctx.fillStyle = 'green' // 设置填充颜色
    ctx.fill() // 完成填充

    ctx.strokeStyle = 'red' // 设置画笔颜色
    ctx.stroke() // 完成绘制

    /**
   * 绘制矩形1
   */
    ctx.beginPath()
    // 上定义矩形: 四个参数分别表示矩形左上角的 x 坐标、y 坐标,以及矩形的宽度和高度。
    ctx.rect(0, 220, 200, 100)
    ctx.strokeStyle = 'green'
    ctx.stroke()

    /**
   * 绘制矩形2
   */
   ctx.beginPath()
   // 绘制矩形并设置填充色
   ctx.fillStyle = 'red'
   ctx.fillRect(10, 350, 150 ,100)
   // 绘制矩形并设置边框颜色
   ctx.strokeStyle = 'green'
   ctx.strokeRect(50, 460, 150, 100)


  </script>
</body>

</html>

1.2. 弧线(弧, 圆弧, 圆)

arcTo(x1, y1, x2, y2, radius);

  1. x1和y1: 画笔的坐标
  2. x2和y2: 两个辅助点
  3. radius: 控制内切圆的半径, 半径越大弧越大
  4. 三个点相连组成角, 根据半径计算内切圆, 圆和三角相交的地方叫切点
  5. 切点相连就画出了一个弧, 弧与起点相连, 就是最终得到的弧线
  6. 示例
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    // 获取画笔
    const ctx = c.getContext("2d")

    // 画弧线
    ctx.beginPath()
    ctx.moveTo(200, 10) // 画笔位置就是起点
    ctx.arcTo(200, 300, 0, 10, 80) // 画弧
    ctx.lineWidth = 5
    ctx.strokeStyle = 'green'
    ctx.stroke()

    // 画辅助线帮助理解
    ctx.strokeStyle = 'red'
    ctx.lineWidth = 1
    ctx.beginPath()
    ctx.moveTo(200, 10)
    ctx.lineTo(200, 300)
    ctx.lineTo(200, 300)
    ctx.lineTo(0, 10)
    ctx.closePath()
    ctx.stroke()


  </script>
</body>

</html>

arc(x, y,radius, startAngle, endAngle, anticlockwise);

  1. 参数x, y: 圆心的坐标
  2. 参数radius: 圆的半径
  3. 参数startAngle, endAngle: 起始角度和终止角度
  4. 参数anticlockwise: 顺时针还是逆时针, 默认顺时针
  5. 示例代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")
    // 获取画笔
    const ctx = c.getContext("2d")

    // 画弧
    ctx.beginPath()
    ctx.arc(400, 400, 100, 0, Math.PI / 6, true)
    ctx.strokeStyle = "red"
    ctx.stroke()

  </script>
</body>

</html>

1.3. 贝塞尔曲线

贝塞尔曲线二阶

quadraticCurveTo(cpx, cpy, x, y);

  1. 参数说明
  • cpx, cpy 是控制点的坐标
  • x,y 是结束点的坐标
  • 通过调整控制点, 就可以生成各种曲线
  1. 二次贝塞尔曲线调试工具:

Canvas Quadratic Curve Example

  1. 示例代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    // 获取画笔
    const ctx = c.getContext("2d")

    // ==================================
    // 画二阶
    ctx.beginPath()
    ctx.moveTo(100, 100) // 起始点坐标
    ctx.quadraticCurveTo(200, 500, 400, 400)
    ctx.stroke()

    // 辅助点
    ctx.fillStyle = 'red'
    ctx.fillRect(100, 100, 10, 10)
    ctx.fillRect(200, 500, 10, 10)
    ctx.fillRect(400, 400, 10, 10)
    // ==================================


  </script>
</body>

</html>

贝塞尔曲线三阶

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

  1. 参数说明
  • 三阶就是比二阶多了一个控制点
  • cpx1, cpy1 是控制点1的坐标
  • cpx2, cpy2 是控制点2的坐标
  • x,y 是结束点的坐标
  • 通过调整控制点, 就可以生成各种曲线
  1. 三次贝塞尔调试工具:

Canvas Bézier Curve Example

  1. 示例代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    // 获取画笔
    const ctx = c.getContext("2d")

    // ==================================
    // 画三阶
    ctx.beginPath()
    ctx.moveTo(20, 20)
    ctx.bezierCurveTo(20, 700, 200, 100, 700, 500)
    ctx.stroke()
    // ==================================

  </script>
</body>

</html>

绘图样式

a. 线条样式

  1. lineWidth: 设置线条的宽度
  2. lineCap: 设置线条两端的形状

  1. setLineDash: 设置线条为虚线
  2. 代码示例
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    // 获取画笔
    const ctx = c.getContext("2d")

    // 线段样式
    ctx.lineWidth = 15
    ctx.lineCap = 'round'

    ctx.beginPath()
    ctx.moveTo(50, 50)
    ctx.lineTo(300, 50)
    ctx.stroke()

    // 绘制虚线
    ctx.beginPath()
    ctx.moveTo(50, 150)
    // 参数的是数组, 控制一组线段
    // 20是第一个线段长度,40是间隔距离, 50是第二个线段长度 
    ctx.setLineDash([20, 40, 50])
    ctx.lineWidth = 1;
    ctx.lineTo(500, 150)
    ctx.stroke()

  </script>
</body>

</html>

b. 渐变

  1. 线性渐变 ctx.createLinearGradient(x0,y0,x1, y1);
  • 参数说明
  • x0,y0是渐变的起点坐标
  • x1, y1是渐变的终点坐标
  • 有了起点和终点就确定了渐变的方向
  1. 径向渐变 ctx.createRadialGradient(x0,y0,r0, x1, y1, r1)
  • 参数说明
  • x0, y0是第一个圆的坐标(圆心), r0是半径
  • x1, y1是第二个圆的坐标(圆心), r1是半径
  1. 示例代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    // 获取画笔
    const ctx = c.getContext("2d")

    // 线性渐变
    let gradient = ctx.createLinearGradient(0, 0, 200, 0) // 设置渐变
    gradient.addColorStop(0, 'green') // 设置渐变点和颜色值
    gradient.addColorStop(1, 'blue')  // 设置渐变点和颜色值
    ctx.fillStyle = gradient
    ctx.fillRect(50, 200, 200, 100) // 绘制矩形

    // 径向渐变
    let gradient2 = ctx.createRadialGradient(150, 450, 150, 150, 450, 0) // 设置渐变
    gradient2.addColorStop(0, 'white')
    gradient2.addColorStop(1, 'green')
    ctx.fillStyle = gradient2
    ctx.fillRect(50, 350, 200, 200)

  </script>
</body>

</html>

c. 纹理样式

  1. ctx.createPattern(image, repetition);

参数说明

  • image: 把图片作为纹理进行填充
  • repetition: 是否重复

代码示例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    // 获取画笔
    const ctx = c.getContext("2d")

    // 纹理样式
    let img = new Image()
    img.src = 'images/DE.jpg'
    img.onload = function () {
      let pattern = ctx.createPattern(img, 'repeat')
      ctx.fillStyle = pattern
      ctx.fillRect(50, 200, 300, 100)
    }

  </script>
</body>

</html>

绘制文本

绘制方式

  • 轮廓文本 stokeText()
  • 填充文本 fillText()

绘制样式

  • font、textAlign(设置水平对齐方式)、direction(设置文字方向)、textBaseline(设置垂直对齐方式)
  • 阴影: shadowOffsetX和shadowOffsetY、shadowBlur、shadowColor

示例代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    // 获取画笔
    const ctx = c.getContext("2d")

    // 设置文字样式 (字号: 88px 字体: 罗马字体)
    ctx.font = "88px Times New Roman"
    // 设置阴影
    ctx.shadowOffsetX = 2 //偏移
    ctx.shadowOffsetY = 2 //偏移
    ctx.shadowBlur = 2    //模糊度
    ctx.shadowColor = "rgba(255,0,0,0.5)"
    // 绘制文本
    ctx.fillText('hello canvas', 100, 100)


    // 纹理背景文字
    let img = new Image()
    img.src = 'images/DE.jpg'
    img.onload = function () {
      let pattern = ctx.createPattern(img, 'repeat')
      ctx.fillStyle = pattern
      ctx.fillText('hello canvas2', 100, 400)
    }

  </script>
</body>

</html>

绘制图片

drawimage用法

  1. drawlmage(image, dx, dy);
  2. drawlmage(image, dx, dy, dWidth, dHeight);
  3. drawlmage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")

    // 获取画笔
    const ctx = c.getContext("2d")

    // 绘制图片
    let img = new Image()
    img.src = 'images/DE.jpg'
    img.onload = function () {
      // 1. 在指定位置画一张图
      // drawlmage(image, dx, dy); 
      ctx.drawImage(img, 0, 0)

      // 2.在指定位置画一张图, 并设置图的尺寸
      // drawlmage(image, dx, dy, dWidth, dHeight);
      ctx.drawImage(img, 0, 120, 50, 50)


      // 3.指定一张图(image), 选择抠图的位置(sx, sy), 设置抠取的尺寸(sWidth, sHeight), 把抠出来的图放在哪(dx, dy), 放多大(dWidth, dHeight)
      // drawlmage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
      ctx.drawImage(img, 0, 0, 80, 80, 100, 200, 50, 50)
    }
  </script>
</body>

</html>

进阶

变形

  1. 平移, 旋转, 缩放

平移(translate)、旋转(rotate)、缩放(scale)

平移改变的是画布的坐标系位置

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")
    // 获取画笔
    const ctx = c.getContext("2d")

    //==================================
    // 测试平移的效果
    // 画个矩形
    ctx.fillStyle = 'red'
    ctx.fillRect(0, 0, 100, 100)

    // 平移坐标后再画一个矩形
    ctx.translate(400, 400)
    ctx.fillRect(0, 0, 100, 100)

    // 把坐标平移回原点, 再画一个矩形
    ctx.translate(-400, -400)
    ctx.fillStyle = 'black'
    ctx.fillRect(0, 0, 50, 50)

  </script>
</body>

</html>

旋转和缩放是对图形的操作

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")
    // 获取画笔
    const ctx = c.getContext("2d")

    // 旋转图形
    ctx.fillStyle = 'yellow'
    ctx.rotate(Math.PI / 6) // 旋转60度
    ctx.fillRect(100, 0, 100, 100)
    ctx.restore()

    // 缩放图形
    ctx.fillStyle = 'blue'
    ctx.scale(0.5, 0.5)
    ctx.fillRect(400, 400, 100, 100)
    ctx.restore()

  </script>
</body>

</html>

  1. 状态的保存和恢复 (栈结构)

画布的状态是可以保存和恢复的

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")
    // 获取画笔
    const ctx = c.getContext("2d")

    // 上案例的写法需要不断平移坐标, 比较麻烦
    // 通过保存和恢复画布状态, 简化对画布的操作

    // 画个矩形
    ctx.fillStyle = 'red'
    ctx.fillRect(0, 0, 100, 100)

    // 平移前先保存画布的状态信息
    ctx.save()
    // 平移坐标后再画一个矩形
    ctx.translate(400, 400)
    ctx.fillRect(0, 0, 100, 100)
    // 绘制完平移的图形后,恢复之前的状态信息
    ctx.restore()

    // 再绘制图形就不受平移的影响了
    ctx.fillStyle = 'black'
    ctx.fillRect(0, 0, 50, 50)

  </script>
</body>

</html>

  1. transform, setTransform

矩阵变换

语法: transform(a, b, c, d, e, f);

参数:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")
    // 获取画笔
    const ctx = c.getContext("2d")

    // 矩阵变换-平移
    ctx.transform(1, 0, 0, 1, 400, 400)
    ctx.fillStyle = 'red'
    ctx.fillRect(0, 0, 100, 100)
    ctx.restore()

    // 矩阵变换-缩放
    ctx.transform(0.5, 0, 0, 0.5, 10, 10)
    ctx.fillStyle = 'green'
    ctx.fillRect(0, 0, 100, 100)
    ctx.restore()

    // 矩阵变换-倾斜
    ctx.transform(1, 0.2, 0.2, 1, 10, 10)
    ctx.fillStyle = 'blue'
    ctx.fillRect(0, 0, 100, 100)
    ctx.restore()

  </script>
</body>

</html>

合成

Canvas 提供了26 种图片混排模式

  1. 语法: ctx.globalCompositeOperation = type;
  2. 重点参数: destination-out, 可以实现镂空效果

  1. 其他的合成模式

  1. 示例代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")
    // 获取画笔
    const ctx = c.getContext("2d")


    ctx.fillStyle = 'blue'
    ctx.fillRect(10, 10, 100, 100)

    // source-over: 默认值, 后绘制的图形覆盖先绘制的图形
    // ctx.globalCompositeOperation = 'source-over'

    // destination-over: 先绘制的图形覆盖后绘制的图形
    // ctx.globalCompositeOperation = 'destination-over'

    // destination-out: 图形相交的部分镂空
    ctx.globalCompositeOperation = 'destination-out'

    ctx.fillStyle = 'red'
    ctx.fillRect(50, 50, 100, 100)

  </script>
</body>

</html>

裁剪

clip() 需要配置路径使用

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .canvas {
      background-color: pink;
    }
  </style>
</head>

<body>
  <canvas id="canvas" width="600" height="600" class="canvas" />

  <script>
    // 获取画布
    const c = document.getElementById("canvas")
    // 获取画笔
    const ctx = c.getContext("2d")

    ctx.rect(0, 0, 200, 100) // 矩形区域
    ctx.clip() // 超出矩形区域的文字会被裁剪

    ctx.fillStyle = 'red'
    ctx.font = '44px Times New Roman'
    ctx.fillText('hello canvas', 50, 50)

  </script>
</body>

</html>

实战

1. 放大镜效果

技术点: 离屏渲染

将一个canvas对象绘制到另一个canvas对象上 (离开用户可视范围内进行染)

2. 刮刮乐效果

技术点: 图像合成

利用图像合成让绘制的内容与原矩形重合部分清空

3. 滤镜效果

技术点: 单位像素处理

这里我们主要借用 getlmageData 函数,他返回每个像素的 RGBA 值。借助图像处理公式,操作像素进行相应的、数学运算即可。

  • getlmageData()
  • putlmageData()

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

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

相关文章

Gartner《Emerging Patterns for Building LLM-Based AIAgents》学习心得

一、AI代理概述 2024年,AI代理成为市场热点,它们能自主规划和行动以实现用户目标,与仅能感知、决策、行动和达成目标的AI助手及聊天机器人有本质区别。Gartner定义的AI代理是使用AI技术在数字或物理环境中自主或半自主运行的软件实体。 二、LLM基础AI代理的特性和挑战 优势…

STM32 单片机启动过程全解析:从上电到主函数的旅程

一、为什么要理解启动过程&#xff1f; STM32 的启动过程就像一台精密仪器的开机自检&#xff0c;它确保所有系统部件按既定方式初始化&#xff0c;才能顺利运行我们的应用代码。对初学者而言&#xff0c;理解启动过程能帮助解决常见“程序跑飞”“不进 main”“下载后无反应”…

4.RV1126-OPENCV 图像轮廓识别

一.图像识别API 1.图像识别作用 它常用于视觉任务、目标检测、图像分割等等。在 OPENCV 中通常使用 Canny 函数、findContours 函数、drawContours 函数结合在一起去做轮廓的形检测。 2.常用的API findContours 函数&#xff1a;用于寻找图片的轮廓&#xff0c;并把所有的数…

WEB3——开发者怎么查看自己的合约日志记录

在区块链中查看合约的日志信息&#xff08;也叫事件 logs&#xff09;&#xff0c;主要有以下几种方式&#xff0c;具体方法依赖于你使用的区块链平台&#xff08;如 Ethereum、BSC、Polygon 等&#xff09;和工具&#xff08;如 Etherscan、web3.js、ethers.js、Hardhat 等&am…

TDengine 集群容错与灾备

简介 为了防止数据丢失、误删操作&#xff0c;TDengine 提供全面的数据备份、恢复、容错、异地数据实时同步等功能&#xff0c;以保证数据存储的安全。本节简要说明 TDengine 中的容错与灾备。 容错 TDengine 支持 WAL 机制&#xff0c;实现数据的容错能力&#xff0c;保证数…

MG影视登录解锁永久VIP会员 v8.0 支持手机电视TV版影视直播软件

MG影视登录解锁永久VIP会员 v8.0 支持手机电视TV版影视直播软件 MG影视App电视版是一款资源丰富、免费便捷、且专为大屏优化的影视聚合应用&#xff0c;聚合海量资源&#xff0c;畅享电视直播&#xff0c;是您电视盒子和…

【多线程初阶】内存可见性问题 volatile

文章目录 再谈线程安全问题内存可见性问题可见性问题案例编译器优化 volatileJava内存模型(JMM) 再谈线程安全问题 如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该有的结果,则说这个程序是线程安全的,反之,多线程环境中,并发执行后,产生bug就是线程不安全…

C++ 类模板三参数深度解析:从链表迭代器看类型推导与实例化(为什么迭代器类模版使用三参数?实例化又会是怎样?)

本篇主要续上一篇的list模拟实现遇到的问题详细讲解&#xff1a;<传送门> 一、引言&#xff1a;模板参数的 "三角锁钥" 在 C 双向链表实现中&#xff0c;__list_iterator类模板的三个参数&#xff08;T、Ref、Ptr&#xff09;如同精密仪器的调节旋钮&#x…

MySQL强化关键_018_MySQL 优化手段及性能分析工具

目 录 一、优化手段 二、SQL 性能分析工具 1.查看数据库整体情况 &#xff08;1&#xff09;语法格式 &#xff08;2&#xff09;说明 2.慢查询日志 &#xff08;1&#xff09;说明 &#xff08;2&#xff09;开启慢查询日志功能 &#xff08;3&#xff09;实例 3.s…

ASP.NET MVC添加模型示例

ASP.NET MVC高效构建Web应用ASP.NET MVC 我们总在谈“模型”&#xff0c;那到底什么是模型&#xff1f;简单说来&#xff0c;模型就是当我们使用软件去解决真实世界中各种实际问题的时候&#xff0c;对那些我们关心的实际事物的抽象和简化。比如&#xff0c;我们在软件系统中设…

【Part 3 Unity VR眼镜端播放器开发与优化】第二节|VR眼镜端的开发适配与交互设计

文章目录 《VR 360全景视频开发》专栏Part 3&#xff5c;Unity VR眼镜端播放器开发与优化第一节&#xff5c;基于Unity的360全景视频播放实现方案第二节&#xff5c;VR眼镜端的开发适配与交互设计一、Unity XR开发环境与设备适配1.1 启用XR Plugin Management1.2 配置OpenXR与平…

第1天:认识RNN及RNN初步实验(预测下一个数字)

RNN&#xff08;循环神经网络&#xff09; 是一种专门设计用来处理序列数据的人工神经网络。它的核心思想是能够“记住”之前处理过的信息&#xff0c;并将其用于当前的计算&#xff0c;这使得它非常适合处理具有时间顺序或上下文依赖关系的数据。 核心概念&#xff1a;循环连…

树莓派安装openwrt搭建软路由(ImmortalWrt固件方案)

&#x1f923;&#x1f449;我这里准备了两个版本的openwrt安装方案给大家参考使用&#xff0c;分别是原版的OpenWrt固件以及在原版基础上进行改进的ImmortalWrt固件。推荐使用ImmortalWrt固件&#xff0c;当然如果想直接在原版上进行开发也可以&#xff0c;看个人选择。 &…

电子电气架构 --- 如何应对未来区域式电子电气(E/E)架构的挑战?

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

易学探索助手-个人记录(十二)

近期我完成了古籍处理板块页面升级&#xff0c;补充完成原文、句读、翻译的清空、保存和编辑&#xff08;其中句读仅可修改标点&#xff09;功能&#xff0c;新增原文和句读的繁简体切换功能 一、古籍处理板块整体页面升级 将原来一整个页面呈现的布局改为分栏呈现&#xff0…

Python窗体编程技术详解

文章目录 1. Tkinter简介示例代码优势劣势 2. PyQt/PySide简介示例代码(PyQt5)优势劣势 3. wxPython简介示例代码优势劣势 4. Kivy简介示例代码优势劣势 5. PySimpleGUI简介示例代码优势劣势 技术对比总结选择建议 Python提供了多种实现图形用户界面(GUI)编程的技术&#xff0c…

NVMe协议简介之AXI总线更新

更新AXI4总线知识 AXI4总线协议 AXI4总线协议是由ARM公司提出的一种片内总线协议 &#xff0c;旨在实现SOC中各模块之间的高效可靠的数据传输和管理。AXI4协议具有高性能、高吞吐量和低延迟等优点&#xff0c;在SOC设计中被广泛应用 。随着时间的推移&#xff0c;AXI4的影响不…

设计模式——责任链设计模式(行为型)

摘要 责任链设计模式是一种行为型设计模式&#xff0c;旨在将请求的发送者与接收者解耦&#xff0c;通过多个处理器对象按链式结构依次处理请求&#xff0c;直到某个处理器处理为止。它包含抽象处理者、具体处理者和客户端等核心角色。该模式适用于多个对象可能处理请求的场景…

基于Android的医院陪诊预约系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;没有什么华丽的语言&#xff0…

基于Spring Boot 电商书城平台系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…