OpenCV | 入门

OpenCV | 入门

安装

参考教程

基础知识

V G A = 640 × 480 VGA = 640 \times 480 VGA=640×480
H D = 1280 × 720 HD = 1280 \times 720 HD=1280×720
F H D = 1920 × 1080 FHD = 1920 \times 1080 FHD=1920×1080
4 K = 3840 × 2160 4K = 3840 \times 2160 4K=3840×2160
这些都表示了固定的像素,例如 VGA,代表在宽度上 640 像素(px),在高度上 480 像素。我们可以把这些像素看成一个一个框。
对于黑白图像 Binary Image, 用 0 代表黑色,用 1 代表白色。

对于 8 位,可以表示 2 8 = 256 2^8 = 256 28=256 个级别,也就是 0 ~ 255。一个灰度图像(Gray Scale Image) 也就是 8 Bit or 256 Level 的。
OpenCV学习笔记——HSV颜色空间超极详解&inRange函数用法及实战

显示图像

图片与代码放在同个目录下。

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
    /* Importing Images */
    string path = "../dog.jpeg";
    Mat img = imread(path);

    imshow("Image", img);
    waitKey(0);
}

播放视频

#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
    string path = "../Megamind.avi";

    VideoCapture cap(path);

    Mat img;

    while(1)
    {
        cap.read(img);
        
        imshow("Image", img);

        waitKey(3); // 添加延时
    }

    return 0;
}

将图片转换为灰度图像

string path = "../dog.jpeg";
Mat img = imread(path);
Mat imgGray;

/* 转换图像颜色 */
cvtColor(img, imgGray, COLOR_BGR2GRAY);

imshow("Image", img);
imshow("Image Gray", imgGray);
waitKey(0);

模糊图像

Mat imgBlur;
GaussianBlur(img, imgBlur, Size(7, 7), 5, 0);
imshow("Image Blur", imgBlur);

边缘检测

Mat imgCanny;
Canny(imgBlur, imgCanny, 50, 150);
imshow("Image Canny", imgCanny);


对于 Canny 函数

void cv::Canny(InputArray image, OutputArray edges, double lowThreshold, double highThreshold, int apertureSize = 3);

/*
image:输入图像,应该是灰度图像。 
edges:输出图像,即检测到的边缘图像。 
lowThreshold:低阈值,用于双阈值检测。 
highThreshold:高阈值,用于双阈值检测。 
apertureSize:指定Sobel算子的大小,默认为3。
*/

图像膨胀

Mat imgDil;
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
dilate(imgCanny, imgDil, kernel);
imshow("Image Dilate", imgDil);


getStructuringElement 函数返回一个结构元素(卷积核)。

Mat kernel = cv2.getStructuringElement(a,b,c);

/*
a 设定卷积核的形状,不同卷积核(形状、大小)对图形的腐蚀、膨胀操作效果不同。
	MORPH_RECT(函数返回矩形卷积核)  
	MORPH_CROSS(函数返回十字形卷积核)  
	MORPH_ELLIPSE(函数返回椭圆形卷积核)
b 设定卷积核的大小
	用 (x, y) 表示,表示卷积核有 x 行 y 列。
c 表示描点的位置,一般 c = 1,表示位于中心。
*/

图像腐蚀

Mat imgErode;
erode(imgDil, imgErode, kernel);
imshow("Image Erode", imgErode);

调整图片大小

输出图片的尺寸

cout << img.size() << endl;


对其进行增大

Mat imgResize;

resize(img, imgResize, Size(640, 480));

imshow("Image Resize", imgResize);


如果使用比例进行缩小,缩小到 二分之一

resize(img, imgResize, Size(), 0.5, 0.5);

裁剪图片

用 Rect 裁剪一块矩形

Mat imgCrop;

Rect roi(300, 300, 250, 150); // x 坐标 y 坐标 宽度 高度
imgCrop = img(roi);

imshow("Image Crop", imgCrop);

创建图片

创建一张蓝色的图片

Mat img(512, 512, CV_8UC3, Scalar(255, 0, 0));

imshow("Image", img);

绘制图形

绘制圆圈

// White Image
Mat img(512, 512, CV_8UC3, Scalar(255, 255, 255));

circle(img, Point(256, 256), 155, Scalar(0, 69, 255));

imshow("Image", img);

增加圆圈的厚度
circle(img, Point(256, 256), 155, Scalar(0, 69, 255), 10);

填满圆圈
circle(img, Point(256, 256), 155, Scalar(0, 69, 255), FILLED);

绘制矩形

rectangle(img, Point(130, 226), Point(382, 286), Scalar(255, 255, 255), 3);
// 两个 Point 分别代表矩形左上角坐标和右下角坐标

将矩形填满
rectangle(img, Point(130, 226), Point(382, 286), Scalar(255, 255, 255), FILLED);

绘制一条线

line(img, Point(130, 296), Point(382, 296), Scalar(255, 255, 255), 2);

添加文字

putText(img, "Birdy's Workshop", Point(137, 262), FONT_HERSHEY_DUPLEX, 0.75, Scalar(0, 69, 255));

给文字添加厚度
putText(img, "Birdy's Workshop", Point(137, 262), FONT_HERSHEY_DUPLEX, 0.75, Scalar(0, 69, 255), 2);

Warp images

原图像:

int main()
{   
    string path = "../image/cards.jpg";

    float w = 250, h = 350;

    Mat img = imread(path);
    Mat matrix, imgWarp;

    Point2f src[4] = {{529, 142}, {779, 190}, {405, 395}, {674, 457}};
    Point2f dst[4] = {{0.0f, 0.0f}, {w, 0.0f}, {0.0f, h}, {w, h}};

    matrix = getPerspectiveTransform(src, dst);
    warpPerspective(img, imgWarp, matrix, Point(w, h));
 
    imshow("Image", img);
    imshow("Image Warp", imgWarp);

    waitKey(0);

    return 0;
}

圈出选中的四个角

for(int i = 0; i < 4; i ++)
    {
        circle(img, src[i], 10, Scalar(0, 0, 255), FILLED);
    }
 
imshow("Image", img);

颜色检测

原图像

HSV 颜色系统

Hue 色相
Saturation 饱和度
Value 色调、纯度

转换 HSV

将图像转换为 hsv 空间可以更容易识别颜色。

Mat imgHSV;

cvtColor(img, imgHSV, COLOR_BGR2HSV);

imshow("Image HSV", imgHSV);

Mask

Mat mask;

int hmin = 0, smin = 110, vmin = 153;
int hmax = 19, smax= 240, vmax = 255;

Scalar lower(hmin, smin, vmin);
Scalar upper(hmax, smax, vmax);
inRange(imgHSV, lower, upper, mask);

imshow("Image Mask", mask);


上述代码中的 hmin、smin、vim … 一系列的值如果通过每次手动修改去找到适合的就会非常麻烦。可以通过创建轨道的方式进行动态修改。

int main()
{
    string path = "../image/lambo.png";

    Mat img = imread(path);
    Mat imgHSV, mask;

    cvtColor(img, imgHSV, COLOR_BGR2HSV);

    int hmin = 0, smin = 110, vmin = 153;
    int hmax = 19, smax= 240, vmax = 255;

    namedWindow("Trackbars", (640, 200));
    createTrackbar("Hue Min", "Trackbars", &hmin, 179);
    createTrackbar("Hue Max", "Trackbars", &hmax, 179);
    createTrackbar("Sat Min", "Trackbars", &smin, 255);
    createTrackbar("Sat Max", "Trackbars", &smax, 255);
    createTrackbar("Val Min", "Trackbars", &vmin, 255);
    createTrackbar("Val Max", "Trackbars", &vmax, 255);

    while(1)
    {
        Scalar lower(hmin, smin, vmin);
        Scalar upper(hmax, smax, vmax);
        inRange(imgHSV, lower, upper, mask);

        imshow("Image", img);
        imshow("Image HSV", imgHSV);
        imshow("Image Mask", mask);

        waitKey(1);
    }

    return 0;
}


调节之后:

检测不同颜色物体

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
    string path = "../image/shapes.png";

    Mat img = imread(path);
    Mat imgHSV, mask;

    int hmin = 0, smin = 0, vmin = 0;
    int hmax = 179, smax= 255, vmax = 255;
    
    cvtColor(img, imgHSV, COLOR_BGR2HSV);
    namedWindow("Trackbars", (640, 200));
    createTrackbar("Hue Min", "Trackbars", &hmin, 179);
    createTrackbar("Hue Max", "Trackbars", &hmax, 179);
    createTrackbar("Sat Min", "Trackbars", &smin, 255);
    createTrackbar("Sat Max", "Trackbars", &smax, 255);
    createTrackbar("Val Min", "Trackbars", &vmin, 255);
    createTrackbar("Val Max", "Trackbars", &vmax, 255);

    while(1)
    {
        Scalar lower(hmin, smin, vmin);
        Scalar upper(hmax, smax, vmax);
        inRange(imgHSV, lower, upper, mask);

        imshow("Image", img);
        imshow("Image HSV", imgHSV);
        imshow("Image Mask", mask);

        waitKey(1);
    }

    waitKey(0);

    return 0;
}


检测轮廓、形状

#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
    string path = "../image/shapes.png";

    Mat img = imread(path);
    Mat imgGray, imgBlur, imgCanny, imgDil, imgErode; 

    cvtColor(img, imgGray, COLOR_BGR2GRAY);
    GaussianBlur(imgGray, imgBlur, Size(3, 3), 3, 0);
    Canny(imgBlur, imgCanny, 25, 75);
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
    dilate(imgCanny, imgDil, kernel);

    imshow("Image", img);
    imshow("Image Gray", imgGray);
    imshow("Image Blur", imgBlur);
    imshow("Image Canny", imgCanny);
    imshow("Image Dil", imgDil);

    waitKey(0);

    return 0;
}


当我们放大 ImgCanny 也就是边缘检测的图像,会发现三角形边有很明显的毛躁和缝隙。

而放大膨胀后的图像,发现这些毛躁和缝隙变少,所以一般用膨胀后的图像来作为边缘检测的图像。

绘制轮廓

#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;

void getContours(Mat imgDil, Mat img)
{
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;

    findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    drawContours(img, contours, -1, Scalar(255, 0, 255), 2);
}

int main()
{
    string path = "../image/shapes.png";

    Mat img = imread(path);
    Mat imgGray, imgBlur, imgCanny, imgDil, imgErode; 

    // Preprocessing
    cvtColor(img, imgGray, COLOR_BGR2GRAY);
    GaussianBlur(imgGray, imgBlur, Size(3, 3), 3, 0);
    Canny(imgBlur, imgCanny, 25, 75);
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
    dilate(imgCanny, imgDil, kernel);

    getContours(imgDil, img);

    imshow("Image", img);
    // imshow("Image Gray", imgGray);
    // imshow("Image Blur", imgBlur);
    // imshow("Image Canny", imgCanny);
    // imshow("Image Dil", imgDil);

    waitKey(0);

    return 0;
}


但是我们发现,小噪点也被勾勒了轮廓。
我们想去除这些噪点的轮廓。

打印每个图形面积

for(int i = 0; i < contours.size(); i ++)
    {
        int area = contourArea(contours[i]);
        cout << area << endl;
    }

通过输出每个图形的面积,我们发现,噪点面积为 185.

我们可以简单设置如果面积在 1000 以上才回绘制轮廓

void getContours(Mat imgDil, Mat img)
{
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;

    findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	// drawContours(img, contours, i, Scalar(255, 0, 255), 2);

    for(int i = 0; i < contours.size(); i ++)
    {
        int area = contourArea(contours[i]);
        cout << area << endl;

        if(area > 1000) 
        {
            drawContours(img, contours, i, Scalar(255, 0, 255), 2);
        }
    }
}

可以发现噪点没有被绘制轮廓。

图像轮廓点进行多边形拟合

approxPolyDP 函数主要功能是把一个连续光滑曲线折线化,对图像轮廓点进行多边形拟合。

void getContours(Mat imgDil, Mat img)
{
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;

    findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    
    vector<vector<Point>> conPoly(contours.size());

    for(int i = 0; i < contours.size(); i ++)
    {
        int area = contourArea(contours[i]);
        cout << area << endl;

        if(area > 1000) 
        {
            float peri = arcLength(contours[i], true);

            approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);

            drawContours(img, conPoly, i, Scalar(255, 0, 255), 2);

            cout << conPoly[i].size() << endl;
        }
    }
}

可以看到它绘制了很多点,然后将它们连接,而不是绘制圆

输出每个图形点的个数:

图形边界矩形

void getContours(Mat imgDil, Mat img)
{
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;

    findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

	vector<vector<Point>> conPoly(contours.size());
	vector<Rect> boundRect(contours.size());

    for(int i = 0; i < contours.size(); i ++)
    {
        int area = contourArea(contours[i]);
        cout << area << endl;

        if(area > 1000) 
        {
            float peri = arcLength(contours[i], true);

            approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);

            drawContours(img, conPoly, i, Scalar(255, 0, 255), 2);

            cout << conPoly[i].size() << endl;

            boundRect[i] = boundingRect(conPoly[i]);
            rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 5);
        }
    }
}

输出形状名称

void getContours(Mat imgDil, Mat img)
{
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;

    findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

	vector<vector<Point>> conPoly(contours.size());
	vector<Rect> boundRect(contours.size());
    for(int i = 0; i < contours.size(); i ++)
    {
        int area = contourArea(contours[i]);
        cout << area << endl;

        string objectType;

        if(area > 1000) 
        {
            float peri = arcLength(contours[i], true);

            approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);

            drawContours(img, conPoly, i, Scalar(255, 0, 255), 2);

            cout << conPoly[i].size() << endl;

            boundRect[i] = boundingRect(conPoly[i]);
            rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 5);
        
            int objCor = (int)conPoly[i].size();

            if(objCor == 3) {
                objectType = "Tri"; // 如果点数为 3
            }
            else if(objCor == 4) {
                objectType = "Rect"; // 点数为 4
            }
            else {
                objectType = "Circle";
            }

            putText(img, objectType, {boundRect[i].x, boundRect[i].y - 5}, FONT_HERSHEY_DUPLEX, 0.75, Scalar(0, 69, 255)); // 显示文本
        }
    }
}


但是上述代码知识简单将长方形和正方形都定义为矩形,那么该如何分辨长方形和正方形呢?
我们用宽高比来判断。

else if(objCor == 4) {
	// objectType = "Rect";
	float aspRatio = (float)boundRect[i].width / (float)boundRect[i].height;
	if(aspRatio > 0.95 && aspRatio < 1.05)
		objectType = "Square";
	else
		objectType = "Rectangle";
}


OPENCV——C++版图像形状简单识别

人脸识别

#include<opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
    string path = "../image/test.png";

    Mat img = imread(path);

    CascadeClassifier faceCascade;
    faceCascade.load("../haarcascade_frontalface_default.xml");

    if(faceCascade.empty())
        puts("None!");
    
    vector<Rect> faces;
    faceCascade.detectMultiScale(img, faces, 1.1, 10);

    for(int i = 0; i < faces.size(); i ++)
    {
        rectangle(img, faces[i].tl(), faces[i].br(), Scalar(255, 0, 255), 3);
    }

    imshow("Image", img);
    waitKey(0);

    return 0;
}

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

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

相关文章

AI-数学-高中52-离散型随机变量概念及其分布列、两点分布

原作者视频&#xff1a;【随机变量】【一数辞典】2离散型随机变量及其分布列_哔哩哔哩_bilibili 离散型随机变量分布列&#xff1a;X表示离散型随机变量可能在取值&#xff0c;P:对应分布在概率&#xff0c;P括号里X1表示事件的名称。 示例&#xff1a;

机器学习的指标评价

之前在学校的小发明制作中&#xff0c;在终期答辩的时候&#xff0c;虽然整个项目的流程都答的很流畅。 在老师提问的过程中&#xff0c;当老师问我recall,precision,accuracy等指标是如何计算的&#xff0c;又能够表示模型的哪方面指标做得好。我听到这个问题的时候&#xff…

使用FPGA实现串-并型乘法器

介绍 其实我们知道&#xff0c;用FPGA实现乘法器并不是一件很简单的事&#xff0c;而且在FPGA中也有乘法器的IP核可以直接调用&#xff0c;我这里完全就是为了熟悉一些FPGA的语法然后写了这样一个电路。 串-并型乘法器模块 从字面上看&#xff0c;串-并乘法器就是其中一个乘数…

深入学习Redis(1):Redis内存模型

Redis的五个对象类型 字符串&#xff0c;哈希&#xff0c;列表&#xff0c;集合&#xff0c;有序集合 本节有关redis的内存模型 1.估算redis的内存使用情况 目前内存的价格比较的高&#xff0c;如果对于redis的内存使用情况能够进行计算&#xff0c;就可以选用合适的设备进…

初识webpack项目

新建一个空的工程 -> % mkdir webpack-project 为了方便追踪执行每一个命令&#xff0c;最终产生了哪些变更&#xff0c;将这个空工程初始化成git项目 -> % cd webpack-project/-> % git init Initialized empty Git repository in /Users/lixiang/frontworkspace/…

多级留言/评论的功能实现——SpringBoot3后端篇

目录 功能描述数据库表设计后端接口设计实体类entity 完整实体类dto 封装请求数据dto 封装分页请求数据vo 请求返回数据 Controller控制层Service层接口实现类 Mapper层Mybatis 操作数据库 补充&#xff1a;返回的数据结构自动创建实体类 最近毕设做完了&#xff0c;开始来梳理…

https自签名ssl证书生成流程

准备工作&#xff1a; 0.安装完整版的openssl openssl下载官网 安装到C:\OpenSSL32&#xff0c;也可以安装到其它盘&#xff0c;不要包含空格和中文 打开openssl.exe所在目录如:C:\OpenSSL32\bin&#xff0c;输入cmd.exe打开cmd控制台 1.创建ca文件夹 ,证书文件夹 mkdir …

二维泊松方程(三角形区域)Matlab有限元编程求解|案例源码+说明文本

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

【Linux 进程】 自定义shell

目录 关于shell 1.打印提示符&&获取用户命令字符​编辑 2.分割字符串 3.检查是否为内建命令 cd命令 export命令 echo命令 1.输出最后一个执行的命令的状态退出码&#xff08;返回码&#xff09; 2.输出指定环境变量 4.执行外部命令 关于shell Shell 是计算机操…

C语言数组介绍

文章目录 一、数组的概念二、一维数组1.一维数组的创建2.一维数组的初始化3.数组的类型4.一维数组的使用5.一维数组在内存中的存储6.sizeof计算数组元素个数 三、二维数组1.二维数组的概念2.二维数组的创建3.二维数组的初始化4.二维数组的使用5.二维数组的输入和输出6.二维数组…

【教学类-50-09】20240505“数一数”图片样式09:数一数(几何图案——透明颜色重叠+纯黑边框+黑框粗细)

背景需求&#xff1a; 【教学类-50-03】20240408“数一数”图片样式03&#xff1a;透明图形与边框不相交&#xff0c;透明图形和其他透明图形重叠-CSDN博客文章浏览阅读867次&#xff0c;点赞28次&#xff0c;收藏25次。【教学类-50-03】20240408“数一数”图片样式03&#xf…

银行ETL-监管报送

1104报表 1104报表主要包括&#xff1a;资产负债&#xff0c;表外业务、流动性风险、贷款质量、投向行业和地区、重点客户等。 1104报表分类 普通报表、机构特色类报表。 反洗钱 大额交易、可疑交易。标签分类&#xff1a;疑似犯罪、疑似毒品、疑似传销。 反洗钱—接口报…

tomcat+maven+java+mysql图书管理系统2-完善项目结构,添加相关依赖

1.创建java目录 接着选择java&#xff0c;回车&#xff0c;则创建成功&#xff0c;成功后在左侧栏能看见 2.修改pom.xml文件,(添加依赖) <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi…

pandas读取文件导致jupyter内核崩溃如何解决

读取execl文件出现以下问题: str_name "D:\\cao_use\\2017_2021(new).xlsx" train_df pd.read_excel(str_name, usecols[0])崩溃的指示图如下所示: bug原因:读入的文件太大&#xff0c;所需时间过长&#xff0c;在读取的过程中&#xff0c;使用中断按钮暂停会直…

mac监听 linux服务器可视化(Grafana+Promethus+Node_exporter)

Grafana和promethus(普罗米修斯)的安装和使用 监控系统的Prometheus类似于一个注册中心&#xff0c;我们可以只需要配置一个Prometheus,而在其他服务器&#xff0c;只需要安装node_exporter,它们的数据流转就是通过exporter采集数据信息&#xff0c;然后告诉prometheus它的位置…

AI视频教程下载:用 ChatGPT 和 WordPress 创建赚钱网站

您是否有兴趣开设网站&#xff08;博客&#xff09;&#xff0c;但不知道从何入手&#xff1f; 或者您已经开设了网站&#xff08;博客&#xff09;&#xff0c;但难以从中获利&#xff1f; 别找啦&#xff01; 本课程旨在教授您使用 WordPress 创建成功盈利网站&#xff08;博…

OpenCV(五) —— 人脸识别模型训练与 Windows 下的人脸识别

本文主要内容&#xff1a; 如何训练 OpenCV 的人脸识别模型如何在 Windows 下利用 OpenCV 进行人脸识别 1、概述 人脸识别需要人脸模型&#xff08;特征集合&#xff09;的支持&#xff0c;人脸定位的速度与准确度取决于模型。 OpenCV 提供了已经训练好的模型&#xff0c;无…

【莫比乌斯变换-04】求解莫比乌斯变换系数

求解莫比乌斯变换系数 文章目录 一、说明二、如何确定双线性变换系数2.1 变换基本形式2.2 通过三点确定 三、一般情况的变换3.1 最简单的情况&#xff1a;无穷大3.2 处理无穷大 四、Python 代码 一、说明 上一篇文章是对双线性变换的视觉介绍&#xff0c;又名莫比乌斯变换或分…

ThreeJS:补间动画与Tween.JS

补间动画 补间动画指的是做FLASH动画时&#xff0c;在两个关键帧中间需要做“补间动画”&#xff0c;才能实现图画的运动&#xff1b;插入补间动画后两个关键帧之间的插补帧是由计算机自动运算而得到的。 ——摘自《百度百科&#xff1a;补间动画_百度百科》 Tween.js Tween.js…

Python-VBA函数之旅-oct函数

目录 一、oct函数的常见应用场景 二、oct函数使用注意事项 三、如何用好oct函数&#xff1f; 1、oct函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a;神奇夜光杯-CSDN博客 一、oct函数的常见应用场景 oc…