使用opencv实现图像的畸形矫正:仿射变换

1 仿射变换

1.1 什么是仿射变换

在图像处理中,经常需要对图像进行各种操作如平移、缩放、旋转、翻转等,这些都是图像的仿射变换。图像仿射变换又称为图像仿射映射,是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间。通常图像的旋转加上拉升就是图像仿射变换,仿射变换需要一个M矩阵实现,但是由于仿射变换比较复杂,很难找到这个M矩阵.

1.2 仿射变换的数学表达

仿射变换也称仿射投影,是指几何中,对一个向量空间进行线性变换并接上一个平移,变换为另一个向量空间。所以,仿射变换其实也就是再讲如何来进行两个向量空间的变换
假设有一个向量空间k:

还有一个向量空间j:

 如果我们想要将向量空间由k变为j,可以通过下面的公式进行变换

将上式进行拆分可得

 

我们再将上式转换为矩阵的乘法 

通过参数矩阵M就可以实现两个向量空间之间的转换,在进行仿射变换的时候我们也只需要一个矩阵M就可以实现平移、缩放、旋转和翻转变换。

1.3 opencv中的仿射变换

OpenCV中使用warpAffine函数来实现仿射变换

cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
  • src:输入的图像数组
  • M:仿射变换矩阵
  • dsize:变换后图像的大小
  • flags:使用的插值算法
  • borderValue:边界的填充值

1.3.1 图像平移

在平面坐标系有点P(x,y)和点P′(x′,y′),如果我们想要将P点移动到P',通过下面的变换就可以实现

 其中Δx和Δy就是x方向上和y方向上的偏移量,我们将其转换为矩阵的形式

 上面的矩阵M就是仿射变换的平移参数,使用OpenCV中的warpAffine函数实现如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt


def show_cmp_img(original_img,transform_img):
    _, axes = plt.subplots(1, 2)
    # 显示图像
    axes[0].imshow(original_img)
    axes[1].imshow(transform_img)
    # 设置子标题
    axes[0].set_title("original image")
    axes[1].set_title("transform image")
    plt.show()


# 定义一个图像平移矩阵
# x向左平移(负数向左,正数向右)100
# y向下平移(负数向上,正数向下)200个像素
M = np.array([[1, 0, -100], [0, 1, 200]], dtype=np.float)

# 读取需要平移的图像
img = cv2.imread("../data/girl02.jpg")

# 将图片由BGR转为RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 定义平移后图像的大小,保持和原图大小一致
dsize = img.shape[:2][::-1]

# 便于大家观察这里采用白色来填充边界
translation_img = cv2.warpAffine(img, M, dsize, borderValue=(255, 255, 255))

# 显示图像
show_cmp_img(img, translation_img)

运行结果显示如下:

1.3.2 图像翻转

使用opencv的仿射变换实现图像的水平翻转、垂直翻转、镜像反转(同时进行水平和垂直翻转)

上图中的A、B、C、D表示图像的四个顶点,如果我们需要对图像进行水平翻转,那么我们就需要将 A点和B点进行交换,C点和D点进行交换,沿着x轴的中线进行对称交换位置,通过下面的式子可以实现水平翻转

上式中的w表示图像的宽度,同理可得垂直翻转的实现公式

上式中的h表示的是图像的高图像翻转的变换矩阵:

使用OpenCV中的warpAffine函数实现如下:

import cv2
import matplotlib.pyplot as plt
import numpy as np


def show_cmp_img(original_img,transform_img):
    _, axes = plt.subplots(1, 2)
    # 显示图像
    axes[0].imshow(original_img)
    axes[1].imshow(transform_img)
    # 设置子标题
    axes[0].set_title("original image")
    axes[1].set_title("transform image")
    plt.show()


horizontal_flip = True
vertical_flip = True

img = cv2.imread("../data/girl02.jpg")

# 获取输入图片的宽和高
height,width = img.shape[:2]

# 初始化变换矩阵
M = np.array([[0, 0, 0], [0, 0, 0]], dtype=np.float)

# 水平翻转
if horizontal_flip:
    M[0] = [-1, 0, width]

# 垂直翻转
if vertical_flip:
    M[1] = [0, -1, height]

# 将图片由BGR转为RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 定义缩放后图片的大小
img_flip = cv2.warpAffine(img, M, (width, height))

show_cmp_img(img, img_flip)

运行结果显示如下:

OpenCV的flip函数翻转图像

flip函数参数:

  • src:输入的图像数组
  • flipCode:图像翻转参数,1表示水平翻转,0表示垂直翻转,-1表示镜像翻转
img = cv2.imread("../data/girl02.jpg")

#水平翻转
horizontal_flip_img = cv2.flip(img,1)

#垂直翻转
vertical_flip_img = cv2.flip(img,0)

#镜像翻转
mirror_flip_img = cv2.flip(img,-1)

numpy的索引翻转图像

img = cv2.imread("../data/girl02.jpg")

#水平翻转
horizontal_flip_img = img[:,::-1]

#垂直翻转
vertical_flip_img = img[::-1]

#镜像翻转
mirror_flip_img = img[::-1,::-1]

 1.3.3 图像缩放

如果我们想要对坐标系的P点进行缩放操作,通过下面的公式就可以实现

 通过,在x和y前面添加一个缩放系数即可,同样我们将其转换为矩阵形式

通过上面的矩阵M我们就可以实现对图片的缩放,使用OpenCV中的warpAffine函数实现如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt


def show_cmp_img(original_img,transform_img):
    _, axes = plt.subplots(1, 2)
    # 显示图像
    axes[0].imshow(original_img)
    axes[1].imshow(transform_img)
    # 设置子标题
    axes[0].set_title("original image")
    axes[1].set_title("transform image")
    plt.show()


# 定义宽缩放的倍数
fx = 0.5

# 定义高缩放的倍数
fy = 2

# 定义一个图像缩放矩阵
M = np.array([[fx, 0, 0], [0, fy, 0]], dtype=np.float)

# 读取图像
img = cv2.imread("../data/girl02.jpg")

# 获取图片的宽和高
height, width = img.shape[:2]

# 将图片由BGR转为RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 定义缩放后图片的大小
scale_img = cv2.warpAffine(img, M, (int(width*fx), int(height*fy)))

# 显示图像
show_cmp_img(img, scale_img)

结果显示如下:

opencv中的resize函数也能实现一样的效果。

1.3.4 图像旋转

围绕原点旋转:我们先来看看一个二维平面上的点在围绕原点是如何旋转的

上图中点v在围绕原点旋转θ度之后得到了点v′,我们将坐标点用极坐标的形式来表示可以得到 v(rcosϕ,rsinϕ),所以v′(rcos(θ+ϕ),rsin(θ+ϕ))利用正弦和余弦将其展开可得

然后再将上式用矩阵M表示,可得

特别注意:我们在建立直角坐标系的时候是以左下角为原点建立的,然而对于图像而言是以左上角为原点建立的,所以我们需要对角度θ进行取反,结合三角函数的特性,M矩阵的表达式如下

还需要注意的是这里的角度都是弧度制,所以我们还需要对其进行转换,转换代码如下

#将角度转换为弧度制
radian_theta = theta/180 * np.pi

将图片围绕原点进行逆时针旋转θ度,opencv的代码实现如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt


def show_cmp_img(original_img,transform_img):
    _, axes = plt.subplots(1, 2)
    # 显示图像
    axes[0].imshow(original_img)
    axes[1].imshow(transform_img)
    # 设置子标题
    axes[0].set_title("original image")
    axes[1].set_title("transform image")
    plt.show()


theta = 30

# 将角度转换为弧度制
radian_theta = theta/180 * np.pi

# 定义围绕原点旋转的变换矩阵
M = np.array([[np.cos(radian_theta), np.sin(radian_theta), 0],
             [-np.sin(radian_theta), np.cos(radian_theta), 0]])
# 读取图像
img = cv2.imread("../data/girl02.jpg")

# 定义旋转后图片的宽和高
height, width = img.shape[:2]

# 将图片由BGR转为RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 围绕原点逆时针旋转\theta度
rotate_img = cv2.warpAffine(img, M, (width, height))

# 显示图像
show_cmp_img(img,rotate_img)

 运行结果显示如下:

1.3.5 围绕任意点旋转

下图的v点在围绕点(a,b)旋转90度得到v′。可以将其等价于先将v点平移到v1​点,然后再将v1​点围绕原点旋转90度得到v2​点,最后再将v2​点沿着v点平移的反方向平移相同长度,最终得到v′。这样我们就将围绕任意坐标点旋转的问题转换成了围绕原点旋转的问题

我们来回顾一下,围绕原点旋转坐标的变换公式:

 

在围绕原点旋转变换公式的基础上,我们将其改进为围绕任意点c(a,b)旋转,我们现在原来的坐标进行平移,得到变换后的坐标,最后再沿着之前平移的反方向进行平移,就得到围绕任意点旋转的变换公式:

将其展开可得

 

将上式用矩阵M表示: 

上式中的c(a,b)表示旋转中心,因为坐标系问题需要对θ进行取反,最终M矩阵的表达式如下

使用opencv的代码如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt


def show_cmp_img(original_img,transform_img):
    _, axes = plt.subplots(1, 2)
    # 显示图像
    axes[0].imshow(original_img)
    axes[1].imshow(transform_img)
    # 设置子标题
    axes[0].set_title("original image")
    axes[1].set_title("transform image")
    plt.show()


img = cv2.imread("../data/girl02.jpg")

theta = 30
height, width = img.shape[:2]

# 定义围绕图片的中心旋转
point_x, point_y = int(width/2), int(height/2)

# 将角度转换为弧度制
radian_theta = theta / 180 * np.pi

# 定义围绕任意点旋转的变换矩阵
M = np.array([[np.cos(radian_theta), np.sin(radian_theta),
               (1-np.cos(radian_theta))*point_x-point_y*np.sin(radian_theta)],
              [-np.sin(radian_theta), np.cos(radian_theta),
               (1-np.cos(radian_theta))*point_y+point_x*np.sin(radian_theta)]])

# 将图片由BGR转为RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 定义旋转后图片的宽和高
height, width = img.shape[:2]

# 围绕原点逆时针旋转\theta度
rotate_img = cv2.warpAffine(img, M, (width, height))

# 显示图像
show_cmp_img(img, rotate_img)

运行结果显示如下:

围绕图像中心旋转后的图片部分被裁剪掉了,如果我们想让旋转之后的图片仍然是完整,代码如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt


def show_cmp_img(original_img,transform_img):
    _, axes = plt.subplots(1, 2)
    # 显示图像
    axes[0].imshow(original_img)
    axes[1].imshow(transform_img)
    # 设置子标题
    axes[0].set_title("original image")
    axes[1].set_title("transform image")
    plt.show()


img = cv2.imread("../data/girl02.jpg")

theta = 30
is_completed = True
height, width = img.shape[:2]

# 定义围绕图片的中心旋转
point_x, point_y = int(width/2), int(height/2)

# 将角度转换为弧度制
radian_theta = theta / 180 * np.pi

# 定义围绕任意点旋转的变换矩阵
M = np.array([[np.cos(radian_theta), np.sin(radian_theta),
               (1-np.cos(radian_theta))*point_x-point_y*np.sin(radian_theta)],
              [-np.sin(radian_theta), np.cos(radian_theta),
               (1-np.cos(radian_theta))*point_y+point_x*np.sin(radian_theta)]])
# 将图片由BGR转为RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 定义旋转后图片的宽和高
height, width = img.shape[:2]

# 判断旋转之后的图片是否需要保持完整
if is_completed:
    # 增大旋转之后图片的宽和高,防止被裁剪掉
    new_height = height * np.cos(radian_theta) + width * np.sin(radian_theta)
    new_width = height * np.sin(radian_theta) + width * np.cos(radian_theta)

    # 增大变换矩阵的平移参数
    M[0, 2] += (new_width - width) * 0.5
    M[1, 2] += (new_height - height) * 0.5
    height = int(np.round(new_height))
    width = int(np.round(new_width))
# 围绕原点逆时针旋转\theta度
rotate_img = cv2.warpAffine(img, M, (width, height))
# 显示图像
show_cmp_img(img, rotate_img)

运行结果显示如下:

2 使用opencv实现图像的畸形矫正

在日常处理图片过程中,我们经常遇到扭曲的图片,首先我们要对扭曲的图片进行校正,然后在送入深度模型进行处理,扭曲的图片如下所示:

为实现将倾斜的目标矫正过来,首先,我们需要使用轮廓检测等方法获取到目标的4个关键点坐标值;然后利用相应的变换获取到新的4个坐标点;接着利用这4对关键点计算出仿射变换矩阵M;最后应用仿射变换矩阵到目标中即可。步骤如下:

  • 读取输入图片;
  • 获取原始目标的4个坐标点(左上,左下,右上,右下);
  • 通过4个坐标点计算出新的坐标点;
  • 使用opencv计算仿射变换矩阵M;
  • 应用仿射变换进行变换并进行结果显示。

2.1 获取四个顶点坐标

def get4points(img: np.ndarray, thed, n):
    # 灰度和二值化
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, binary = cv2.threshold(gray, thed, 255, cv2.THRESH_BINARY)

    # 搜索轮廓
    contours, hierarchy = cv2.findContours(
        binary,
        cv2.RETR_LIST,
        cv2.CHAIN_APPROX_SIMPLE)

    # 按轮廓长度选取需要轮廓
    len_list = []
    for i in range(len(contours)):
        len_list.append(len(contours[i]))

    # 选第二长的
    sy = np.argsort(np.array(len_list))[-n]

    # 寻找顶点
    sum_list = []
    dif_list = []
    for i in contours[sy]:
        sum = i[0][0]+i[0][1]
        sum_list.append(sum)
        dif_list.append(i[0][0]-i[0][1])

    id_lb = np.argsort(np.array(sum_list))
    id_lb2 = np.argsort(np.array(dif_list))
    lu_id , rd_id = id_lb[0], id_lb[-1]
    ld_id , ru_id = id_lb2[0], id_lb2[-1]

    points = np.array([contours[sy][lu_id][0], contours[sy][rd_id][0],
                       contours[sy][ld_id][0], contours[sy][ru_id][0]])

    return points, contours, sy

2.2 仿射变换

def four_point_transform(image, pts):
    # 获取坐标点,并将它们分离开来
    rect = order_points(pts)
    (tl, tr, br, bl) = rect
    # 计算新图片的宽度值,选取水平差值的最大值
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA), int(widthB))

    # 计算新图片的高度值,选取垂直差值的最大值
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA), int(heightB))

    # 构建新图片的4个坐标点
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype="float32")

    # 获取仿射变换矩阵并应用它
    M = cv2.getPerspectiveTransform(rect, dst)
    # 进行仿射变换
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

    # 返回变换后的结果
    return warped

2.3 完整代码

# coding=utf-8
import numpy as np
import cv2
import matplotlib.pyplot as plt


def get4points(img: np.ndarray, thed, n):
    # 灰度和二值化
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, binary = cv2.threshold(gray, thed, 255, cv2.THRESH_BINARY)

    # 搜索轮廓
    contours, hierarchy = cv2.findContours(
        binary,
        cv2.RETR_LIST,
        cv2.CHAIN_APPROX_SIMPLE)

    # 按轮廓长度选取需要轮廓
    len_list = []
    for i in range(len(contours)):
        len_list.append(len(contours[i]))

    # 选第二长的
    sy = np.argsort(np.array(len_list))[-n]

    # 寻找顶点
    sum_list = []
    dif_list = []
    for i in contours[sy]:
        sum = i[0][0]+i[0][1]
        sum_list.append(sum)
        dif_list.append(i[0][0]-i[0][1])

    id_lb = np.argsort(np.array(sum_list))
    id_lb2 = np.argsort(np.array(dif_list))
    lu_id , rd_id = id_lb[0], id_lb[-1]
    ld_id , ru_id = id_lb2[0], id_lb2[-1]

    points = np.array([contours[sy][lu_id][0], contours[sy][rd_id][0],
                       contours[sy][ld_id][0], contours[sy][ru_id][0]])

    return points, contours, sy


def order_points(pts):
    # 初始化坐标点
    rect = np.zeros((4, 2), dtype = "float32")

    # 获取左上角和右下角坐标点
    s = pts.sum(axis = 1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]

    # 分别计算左上角和右下角的离散差值
    diff = np.diff(pts, axis = 1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]

    return rect


def four_point_transform(image, pts):
    # 获取坐标点,并将它们分离开来
    rect = order_points(pts)
    (tl, tr, br, bl) = rect
    # 计算新图片的宽度值,选取水平差值的最大值
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA), int(widthB))

    # 计算新图片的高度值,选取垂直差值的最大值
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA), int(heightB))

    # 构建新图片的4个坐标点
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype="float32")

    # 获取仿射变换矩阵并应用它
    M = cv2.getPerspectiveTransform(rect, dst)
    # 进行仿射变换
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

    # 返回变换后的结果
    return warped


def show_cmp_img(original_img, transform_img):
    _, axes = plt.subplots(1, 2)
    # 显示图像
    axes[0].imshow(original_img)
    axes[1].imshow(transform_img)
    # 设置子标题
    axes[0].set_title("original image")
    axes[1].set_title("transform image")
    plt.show()


# 读取图片
image = cv2.imread('../data/warp01.png')

points, _, _ = get4points(image, 127, 1)

# 获取原始的坐标点
pts = np.array(points, dtype="float32")

# 对原始图片进行变换
warped = four_point_transform(image, pts)

show_cmp_img(image, warped)

运行结果显示如下:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Git分支与Git标签详解

目录 前言 一、Git分支(Branch) 1.分支的概念 2.分支的常用操作 3.Git 分支管理 二、Git标签(Tag) 1.标签的概念 2.标签的类型 3.标签的常用操作 4.Git标签管理 前言 在软件开发过程中,版本管理是非常重要的一…

asp.net图书管理系统

asp.net图书管理系统 基本操作图书管理 读者管理 借书 修改资料 修改密码 说明文档 运行前附加数据库.mdf(或sql生成数据库) 主要技术: 基于C#winform架构和sql server数据库 功能模块: 图书管理 读者管理 借书 修改资料 修改…

C/C++交换输出 2021年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C交换输出 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C交换输出 2021年9月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 输入两个整数a,b,将它们交换输出 2、输入输…

【系统安装】ubuntu20.04启动盘制作,正经教程,小白安装教程,百分百成功安装

1.所需材料: 64GBU盘(其实8g和16g也可以) 2.制作U盘启动盘 使用windows制作ubuntu 20.04启动盘 1)下载制作工具:Rufus:Rufus - 轻松创建 USB 启动盘 2)插入用来做启动盘的U盘 3&#xff0…

【Vue】过滤器Filters

hello,我是小索奇,精心制作的Vue系列持续发放,涵盖大量的经验和示例,如对您有用,可以点赞收藏哈 过滤器 filters过滤器已从Vue 3.0中删除,不再支持了,这里可以作为了解进行学习 vue3要精简代码&…

指标类型(一):北极星指标、虚荣指标

每个产品都有很多指标,每个指标都反映了对应业务的经营情况。但是在实际业务经营中,却要求我们在不同的产品阶段寻找到合适的指标,让这个指标可以代表当前产品阶段的方向和目标,让这个指标不仅对业务经营团队,而且对产…

GCN代码讲解

这里写的有点抽象,所以具体的可以参照下面代码块中的注释: def load_data(path"../data/cora/", dataset"cora"):"""Load citation network dataset (cora only for now)"""print(Loading {} datase…

Git忽略文件.gitignore的使用

1.为什么使用? 当你使用git add .的时候有没有遇到把你不想提交的文件也添加到了缓存中去?比如项目的本地配置信息,如果你上传到Git中去其他人pull下来的时候就会和他本地的配置有冲突,所以这样的个性化配置文件我们一般不把它推送到git服务…

C++编写的多线程自动爬虫程序

以下是一个使用C编写的爬虫程序&#xff0c;用于爬取Python进行多线程跑数据的内容。本示例使用了Python的requests库来发送HTTP请求&#xff0c;并使用cheeseboy的爬虫ipIP库来设置爬虫ip信息。以下是详细代码和步骤&#xff1a; #include <iostream> #include <stri…

MySQL 人脸向量,欧几里得距离相似查询

前言 如标题&#xff0c;就是通过提取的人脸特征向量&#xff0c;写一个欧几里得 SQL 语句&#xff0c;查询数据库里相似度排前 TOP_K 个的数据记录。做法虽然另类&#xff0c;业务层市面上有现成的面部检索 API&#xff0c;技术层现在有向量数据库。 用 MySQL 关系型存储 128 …

人工智能基础_机器学习026_L1正则化_套索回归权重衰减梯度下降公式_原理解读---人工智能工作笔记0066

然后我们继续来看套索回归,也就是线性回归,加上了一个L1正则化对吧,然后我们看这里 L1正则化的公式是第二个,然后第一个是原来的线性回归,然后 最后一行紫色的,是J= J0+L1 对吧,其实就是上面两个公式加起来 然后我们再去看绿色的 第一行,其实就是原来线性回归的梯度下降公式…

uniapp 小程序 身份证 和人脸视频拍摄

使用前提&#xff1a; 已经在微信公众平台的用户隐私协议&#xff0c;已经选择配置“摄像头&#xff0c;录像”等权限 开发背景&#xff1a;客户需要使用带有拍摄边框的摄像头 &#xff0c;微信小程序的方法无法支持&#xff0c;使用camera修改 身份证正反面&#xff1a; <…

ROS 通信机制

ROS是一个分布式框架&#xff0c;为用户提供多节点&#xff08;进程&#xff09;之间的通信服务&#xff0c;所有软件和功能都建立在这种分布式通信机制上&#xff0c;ROS的通信机制是最底层也是最核心的技术。 一、话题通信机制 话题在 ROS 中使用最为频繁&#xff0c;其通信…

计算机毕业设计选题推荐-公共浴池微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

本地跑项目解决跨域问题

跨域问题&#xff1a; 指的是浏览器不能执行其他网站的脚本&#xff0c;它是由浏览器的同源策略造成的&#xff0c;是浏览器对 javascript 施加的安全限制。 同源策略&#xff1a; 是指协议&#xff08;protocol&#xff09;、域名&#xff08;host&#xff09;、端口号&…

使用validator实现枚举类型校验

使用validator实现枚举类型校验 前言&#xff1a; 在前端调用后端接口传递参数的过程中&#xff0c;我们往往需要对前端传递过来的参数进行校验&#xff0c;比如说我们此时需要对用户的状态进行更新&#xff0c;而用户的状态只有正常和已删除&#xff0c;并且是在代码中通过枚…

云流量回溯的重要性和应用

云流量回溯是指利用云计算和相关技术来分析网络流量、数据传输或应用程序操作的过程。这个过程包括了对数据包、通信模式和应用程序性能的审查和跟踪。本文将介绍云流量回溯重要性和应用! 1、网络安全: 云流量回溯是网络安全的重要组成部分。通过监测和回溯网络流量&#xff0c…

ArcGIS实现矢量区域内所有要素的统计计算

1、任务需求&#xff1a;统计全球各国所有一级行政区相关属性的总和。 &#xff08;1&#xff09;有一个全球一级行政区的矢量图&#xff0c;包含以下属性&#xff08;洪灾相关属性 province.shp&#xff09; &#xff08;2&#xff09;需要按照国家来统计各个国家各属性的总值…

探索STM32系列微控制器的特性和性能

STM32系列微控制器是意法半导体&#xff08;STMicroelectronics&#xff09;公司开发的一款强大的嵌入式微控制器系列。该系列微控制器以其丰富的特性和卓越的性能&#xff0c;成为了嵌入式系统开发领域的首选。本文将深入探索STM32系列微控制器的特性和性能&#xff0c;并结合…