OpenCV 库来捕获和处理视频输入和相似度测量(73)
返回:OpenCV系列文章目录(持续更新中......)
上一篇:OpenCV的周期性噪声去除滤波器(70)
下一篇 :使用 OpenCV 创建视频(74)

目标
如今,拥有数字视频录制系统供您使用是很常见的。因此,您最终会遇到不再处理一批图像,而是处理视频流的情况。这些可能有两种类型:实时图像馈送(在网络摄像头的情况下)或预先录制的硬盘驱动器存储文件。幸运的是,OpenCV以相同的方式处理这两者,使用相同的C++类。因此,以下是您将在本教程中学到的内容:
- 如何打开和阅读视频流
- 检查图像相似度的两种方法:PSNR 和 SSIM
C++源代码
作为使用 OpenCV 展示这些内容的测试用例,我创建了一个小程序,可以读取两个视频文件并在它们之间执行相似性检查。您可以使用它来检查新的视频压缩算法的工作情况。让我们有一个参考(原始)视频,比如这个小的 Megamind 剪辑和它的压缩版本。您还可以在 OpenCV 源库的文件夹samples/data中找到源代码和这些视频文件。
#include <iostream> // for standard I/O
#include <string> // for strings
#include <iomanip> // for controlling float print precision
#include <sstream> // string to number conversion#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat, Scalar)
#include <opencv2/imgproc.hpp> // Gaussian Blur
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp> // OpenCV window I/Ousing namespace std;
using namespace cv;double getPSNR ( const Mat& I1, const Mat& I2);
Scalar getMSSIM( const Mat& I1, const Mat& I2);static void help()
{cout<< "------------------------------------------------------------------------------" << endl<< "This program shows how to read a video file with OpenCV. In addition, it "<< "tests the similarity of two input videos first with PSNR, and for the frames "<< "below a PSNR trigger value, also with MSSIM." << endl<< "Usage:" << endl<< "./video-input-psnr-ssim <referenceVideo> <useCaseTestVideo> <PSNR_Trigger_Value> <Wait_Between_Frames> " << endl<< "--------------------------------------------------------------------------" << endl<< endl;
}int main(int argc, char *argv[])
{help();if (argc != 5){cout << "Not enough parameters" << endl;return -1;}stringstream conv;const string sourceReference = argv[1], sourceCompareWith = argv[2];int psnrTriggerValue, delay;conv << argv[3] << endl << argv[4]; // put in the stringsconv >> psnrTriggerValue >> delay; // take out the numbersint frameNum = -1; // Frame counterVideoCapture captRefrnc(sourceReference), captUndTst(sourceCompareWith);if (!captRefrnc.isOpened()){cout << "Could not open reference " << sourceReference << endl;return -1;}if (!captUndTst.isOpened()){cout << "Could not open case test " << sourceCompareWith << endl;return -1;}Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),(int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),uTSi = Size((int) captUndTst.get(CAP_PROP_FRAME_WIDTH),(int) captUndTst.get(CAP_PROP_FRAME_HEIGHT));if (refS != uTSi){cout << "Inputs have different size!!! Closing." << endl;return -1;}const char* WIN_UT = "Under Test";const char* WIN_RF = "Reference";// WindowsnamedWindow(WIN_RF, WINDOW_AUTOSIZE);namedWindow(WIN_UT, WINDOW_AUTOSIZE);moveWindow(WIN_RF, 400 , 0); //750, 2 (bernat =0)moveWindow(WIN_UT, refS.width, 0); //1500, 2cout << "Reference frame resolution: Width=" << refS.width << " Height=" << refS.height<< " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;cout << "PSNR trigger value " << setiosflags(ios::fixed) << setprecision(3)<< psnrTriggerValue << endl;Mat frameReference, frameUnderTest;double psnrV;Scalar mssimV;for(;;) //Show the image captured in the window and repeat{captRefrnc >> frameReference;captUndTst >> frameUnderTest;if (frameReference.empty() || frameUnderTest.empty()){cout << " < < < Game over! > > > ";break;}++frameNum;cout << "Frame: " << frameNum << "# ";psnrV = getPSNR(frameReference,frameUnderTest);cout << setiosflags(ios::fixed) << setprecision(3) << psnrV << "dB";if (psnrV < psnrTriggerValue && psnrV){mssimV = getMSSIM(frameReference, frameUnderTest);cout << " MSSIM: "<< " R " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[2] * 100 << "%"<< " G " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[1] * 100 << "%"<< " B " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[0] * 100 << "%";}cout << endl;imshow(WIN_RF, frameReference);imshow(WIN_UT, frameUnderTest);char c = (char)waitKey(delay);if (c == 27) break;}return 0;
}// ![get-psnr]
double getPSNR(const Mat& I1, const Mat& I2)
{Mat s1;absdiff(I1, I2, s1); // |I1 - I2|s1.convertTo(s1, CV_32F); // cannot make a square on 8 bitss1 = s1.mul(s1); // |I1 - I2|^2Scalar s = sum(s1); // sum elements per channeldouble sse = s.val[0] + s.val[1] + s.val[2]; // sum channelsif( sse <= 1e-10) // for small values return zeroreturn 0;else{double mse = sse / (double)(I1.channels() * I1.total());double psnr = 10.0 * log10((255 * 255) / mse);return psnr;}
}
// ![get-psnr]// ![get-mssim]Scalar getMSSIM( const Mat& i1, const Mat& i2)
{const double C1 = 6.5025, C2 = 58.5225;/***************************** INITS **********************************/int d = CV_32F;Mat I1, I2;i1.convertTo(I1, d); // cannot calculate on one byte large valuesi2.convertTo(I2, d);Mat I2_2 = I2.mul(I2); // I2^2Mat I1_2 = I1.mul(I1); // I1^2Mat I1_I2 = I1.mul(I2); // I1 * I2/*************************** END INITS **********************************/Mat mu1, mu2; // PRELIMINARY COMPUTINGGaussianBlur(I1, mu1, Size(11, 11), 1.5);GaussianBlur(I2, mu2, Size(11, 11), 1.5);Mat mu1_2 = mu1.mul(mu1);Mat mu2_2 = mu2.mul(mu2);Mat mu1_mu2 = mu1.mul(mu2);Mat sigma1_2, sigma2_2, sigma12;GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);sigma1_2 -= mu1_2;GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);sigma2_2 -= mu2_2;GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);sigma12 -= mu1_mu2;Mat t1, t2, t3;t1 = 2 * mu1_mu2 + C1;t2 = 2 * sigma12 + C2;t3 = t1.mul(t2); // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))t1 = mu1_2 + mu2_2 + C1;t2 = sigma1_2 + sigma2_2 + C2;t1 = t1.mul(t2); // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))Mat ssim_map;divide(t3, t1, ssim_map); // ssim_map = t3./t1;Scalar mssim = mean(ssim_map); // mssim = average of ssim mapreturn mssim;
}
// ![get-mssim]
如何读取视频流(在线摄像机或离线文件)?
从本质上讲,视频操作所需的所有功能都集成在 cv::VideoCapture C++ 类中。这本身是建立在 FFmpeg 开源库之上的。这是 OpenCV 的基本依赖项,因此您无需担心这一点。视频由一系列图像组成,我们在文献中将这些图像称为帧。对于视频文件,有一个帧速率指定两帧之间的长度。虽然对于摄像机来说,它们通常每秒可以数字化多少帧是有限制的,但这个属性并不那么重要,因为摄像机在任何时候都能看到世界的当前快照。
您需要执行的第一个任务是将其源代码分配给 cv::VideoCapture 类。您可以通过 cv::VideoCapture::VideoCapture 或其 cv::VideoCapture::open 函数执行此操作。如果此参数为整数,则将类绑定到相机、设备。此处传递的数字是设备的 ID,由操作系统分配。如果您的系统连接了单个摄像头,则其 ID 可能为零,并且从那里开始进一步增加。如果传递给这些参数的参数是字符串,它将引用视频文件,并且字符串指向文件的位置和名称。例如,对于上面的源代码,有效的命令行是:
video/Megamind.avi video/Megamind_bug.avi 35 10
我们进行相似性检查。这需要参考和测试用例视频文件。前两个参数指的是这一点。这里我们使用一个相对地址。这意味着应用程序将查看其当前工作目录并打开视频文件夹,并尝试在其中查找Megamind.avi和Megamind_bug.avi。
const string sourceReference = argv[1],sourceCompareWith = argv[2];VideoCapture captRefrnc(sourceReference);
// or
VideoCapture captUndTst;
captUndTst.open(sourceCompareWith);
若要检查类与视频源的绑定是否成功,请使用 cv::VideoCapture::isOpened 函数:
if ( !captRefrnc.isOpened()){cout << "Could not open reference " << sourceReference << endl;return -1;}
调用对象析构函数时,自动关闭视频。但是,如果要在此之前关闭它,则需要调用其 cv::VideoCapture::release 函数。视频的帧只是简单的图像。因此,我们只需要从 cv::VideoCapture 对象中提取它们并将它们放入 Mat 对象中。视频流是连续的。您可以通过 cv::VideoCapture::read 或重载的 >> 运算符一个接一个地获取帧:
Mat frameReference, frameUnderTest;
captRefrnc >> frameReference;
captUndTst.read(frameUnderTest);
如果无法获取任何帧(导致视频流关闭或视频文件末尾),则上面的读取操作将空 Mat 对象。如果出现以下情况,我们可以通过一个简单的方法来检查这一点:
if( frameReference.empty() || frameUnderTest.empty())
{// exit the program
}
读取方法由帧抓取和应用的解码组成。可以使用 cv::VideoCapture::grab 和 cv::VideoCapture::retrieve 函数显式调用这两个函数。
除了帧的内容之外,视频还附加了许多信息。这些通常是数字,但在某些情况下,它可能是短字符序列(4 个字节或更少)。因此,为了获取这些信息,有一个名为 cv::VideoCapture::get 的通用函数返回包含这些属性的双精度值。使用按位运算对有效值仅为整数的双精度类型和转换中的字符进行解码。它的单个参数是查询属性的 ID。例如,这里我们得到参考和测试用例视频文件中的帧大小;加上参照内部的帧数。
Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),(int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),cout << "Reference frame resolution: Width=" << refS.width << " Height=" << refS.height<< " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
在处理视频时,您可能经常希望自己控制这些值。为此,有一个 cv::VideoCapture::set 函数。它的第一个参数仍然是要更改的属性的名称,第二个参数是包含要设置的值的 double 类型。如果成功,它将返回 true,否则返回 false。很好的例子是在视频文件中寻找给定的时间或帧:
captRefrnc.set(CAP_PROP_POS_MSEC, 1.2); // go to the 1.2 second in the video
captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
// now a read operation would read the frame at the set position
对于可以读取和更改的属性,请查看 cv::VideoCapture::get 和 cv::VideoCapture::set 函数的文档。
图像相似度 - PSNR 和 SSIM
我们想检查我们的视频转换操作有多难以察觉,因此我们需要一个系统来逐帧检查相似性或差异性。最常用的算法是PSNR(又名峰值信噪比)。最简单的定义是从均方误差开始的。假设有两个图像:I1 和 I2;具有二维大小的 i 和 j,由 c 个通道组成。

然后 PSNR 表示为:

这里的 (MAX_I)是像素的最大有效值。对于简单的单字节图像,每个通道每像素,这是 255。当两个图像相同时,MSE 将给出零,从而导致 PSNR 公式中的除以零运算无效。在这种情况下,PSNR 是未定义的,因此我们需要单独处理这种情况。之所以过渡到对数刻度,是因为像素值具有非常宽的动态范围。所有这些都转换为 OpenCV,函数如下所示:
double getPSNR(const Mat& I1, const Mat& I2)
{Mat s1;absdiff(I1, I2, s1); // |I1 - I2|s1.convertTo(s1, CV_32F); // cannot make a square on 8 bitss1 = s1.mul(s1); // |I1 - I2|^2Scalar s = sum(s1); // sum elements per channeldouble sse = s.val[0] + s.val[1] + s.val[2]; // sum channelsif( sse <= 1e-10) // for small values return zeroreturn 0;else{double mse = sse / (double)(I1.channels() * I1.total());double psnr = 10.0 * log10((255 * 255) / mse);return psnr;}
}
通常,视频压缩的结果值介于 30 到 50 之间,越高越好。如果图像明显不同,您将得到更低的图像,例如 15 左右。这种相似性检查计算起来既简单又快捷,但在实践中,它可能与人眼感知有些不一致。结构相似性算法旨在纠正这一点。
描述这些方法远远超出了本教程的目的。为此,我邀请您阅读介绍它的文章。尽管如此,您可以通过查看下面的 OpenCV 实现来获得它的良好图像。
注意
SSIM在以下文章中进行了更深入的描述:“Z. Wang, A. C. Bovik, H. R. Sheikh and E. P. Simoncelli,“图像质量评估:从错误可见性到结构相似性”,IEEE Transactions on Image Processing,第 13 卷,第 4 期,第 600-612 页,2004 年 4 月。
Scalar getMSSIM( const Mat& i1, const Mat& i2)
{const double C1 = 6.5025, C2 = 58.5225;/***************************** INITS **********************************/int d = CV_32F;Mat I1, I2;i1.convertTo(I1, d); // cannot calculate on one byte large valuesi2.convertTo(I2, d);Mat I2_2 = I2.mul(I2); // I2^2Mat I1_2 = I1.mul(I1); // I1^2Mat I1_I2 = I1.mul(I2); // I1 * I2/*************************** END INITS **********************************/Mat mu1, mu2; // PRELIMINARY COMPUTINGGaussianBlur(I1, mu1, Size(11, 11), 1.5);GaussianBlur(I2, mu2, Size(11, 11), 1.5);Mat mu1_2 = mu1.mul(mu1);Mat mu2_2 = mu2.mul(mu2);Mat mu1_mu2 = mu1.mul(mu2);Mat sigma1_2, sigma2_2, sigma12;GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);sigma1_2 -= mu1_2;GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);sigma2_2 -= mu2_2;GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);sigma12 -= mu1_mu2;Mat t1, t2, t3;t1 = 2 * mu1_mu2 + C1;t2 = 2 * sigma12 + C2;t3 = t1.mul(t2); // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))t1 = mu1_2 + mu2_2 + C1;t2 = sigma1_2 + sigma2_2 + C2;t1 = t1.mul(t2); // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))Mat ssim_map;divide(t3, t1, ssim_map); // ssim_map = t3./t1;Scalar mssim = mean(ssim_map); // mssim = average of ssim mapreturn mssim;
}
这将返回图像每个通道的相似性索引。此值介于 0 和 1 之间,其中 1 对应于完全拟合。不幸的是,许多高斯模糊的成本非常高,因此虽然 PSNR 可以在实时环境中工作(每秒 24 帧),但这比实现类似的性能结果要多得多。
因此,本教程开头提供的源代码将对每个帧执行 PSNR 测量,并且仅对 PSNR 低于输入值的帧执行 SSIM。出于可视化目的,我们在 OpenCV 窗口中显示两个图像,并将 PSNR 和 MSSIM 值打印到控制台。期待看到类似的东西:
您可以在 YouTube 上观察此操作时实例。
相关文章:
OpenCV 库来捕获和处理视频输入和相似度测量(73)
返回:OpenCV系列文章目录(持续更新中......) 上一篇:OpenCV的周期性噪声去除滤波器(70) 下一篇 :使用 OpenCV 创建视频(74) 目标 如今,拥有数字视频录制系统供您使用是很常见的。因此,您最终会遇到不再处理一批图像…...
了解TMS运输管理系统,实现物流高效运转
TMS运输管理系统(Transportation Management System)是一种集成物流和信息技术的解决方案,通过优化运输流程、实时跟踪货物信息和自动化管理操作,提高物流效率,降低运营成本,实现高效运输。 TMS运输管理系…...
数据库原理与应用实验三 嵌套查询
实验目的和要求 加深和掌握对嵌套查询的理解和应用 实验环境 Windows10 SQLServer 实验内容与过程 图书(书号,书名,价格,出版社) 读者(卡号,姓名,年龄,所属单位&a…...
LeetCode 110.平衡二叉树(Java/C/Python3/Go实现含注释说明,Easy)
标签 树深度优先搜索递归 题目描述 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡的二叉树定义为: 一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。 原题:LeetCode 110.平衡二叉树 思路及…...
【SQL】ACID事务与隔离级别
数据库事务 数据库事务具有ACID这4个特性: A:Atomicity,原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;C:Consistency,一致性,事务完…...
深度神经网络中的不确定性研究综述
A.单一确定性方法 对于确定性神经网络,参数是确定的,每次向前传递的重复都会产生相同的结果。对于不确定性量化的单一确定性网络方法,我们总结了在确定性网络中基于单一正向传递计算预测y *的不确定性的所有方法。在文献中,可以找…...
实用的Chrome浏览器命令
Google Chrome 是一款广泛使用的网络浏览器,它提供了许多实用的快捷键和命令,可以帮助用户更高效地浏览网页。以下是一些常用的 Chrome 浏览器命令: 1. 新标签页: Ctrl T (Windows/Linux) 或 Command T (Mac) 2. 关闭当前标签: Ctrl W 或…...
无人作业控制器--4G/5G通信
一、环境 开发环境:ubuntu 22 ros2 humble 发布运行环境:地平线旭日x3派、arm64 4G 模组: 移远EC20模块 5G 模组:移远RG200U-CN 网络通信模组根据需要选择其中一款, 前期我们使用4G模组,后续迭代因为…...
动态规划-两个数组的dp问题2
文章目录 1. 不同的子序列(115)2. 通配符匹配(44) 1. 不同的子序列(115) 题目描述: 状态表示: 根据题意这里的dp数组可以定义为二维,并且dp[i][j]表示字符串t的0到i的…...
如何设置并行度 ——《OceanBase 并行执行》系列 2
并行度(degree of parallelism,简称 DOP),是指在执行过程中所使用的工作线程数量。设计并行执行的初衷在于充分利用多核资源以提升效率。OceanBase 的并行执行框架支持多种设定并行度的方式,既允许用户手动设置&#x…...
python直接发布到网站wordpress之三批量发布图片
在前面的文章中,实现了使用python操作wordpress发布文字内容和图片内容。 python直接发布到网站wordpress之一只发布文字-CSDN博客 python直接发布到网站wordpress之二发布图片-CSDN博客 不过,此时发布图片的数量只能是一张图片。但在实际应用中&…...
C#面:ADO.NET 相对于ADO等主要有什么改进
C# ADO.NET 是微软为.NET平台开发的一套数据访问技术,相对于传统的ADO(ActiveX Data Objects)等,它有以下几个主要改进: 面向对象:ADO.NET 是面向对象的数据访问技术,它使用.NET框架中的类和对…...
web前端学习笔记7-iconfont使用
7. iconfont的使用流程 字体图标使用较多的是阿里巴巴iconfont图标库,它是阿里巴巴体验团队推出的图标库和图标管理平台,提供了大量免费和可定制的矢量图标,以满足网页设计、平面设计、UI设计、应用程序开发和其他创意项目的需求。 官方网站:https://www.iconfont.cn/ 使用…...
国内小白用什么方法充值使用ChatGPT4.0?
首先说一下IOS礼品卡订阅,目前最经济实惠的订阅方式,具体操作步骤 使用IOS设备充值,用 App Stroe 兑换券 1、支付宝地址切换旧金山,在里面买app store 的兑换卷 2、美区Apple ID登陆app store ,充值兑换券 3、IOS设…...
富格林:正确杜绝欺诈实现出金
富格林悉知,现货黄金一直以来都是投资者们追逐的热门品种之一。其安全性和避险特性吸引着广大投资者。但在现货黄金市场中要想实现出金其实并不简单,是需要我们通过一定的技巧和方法去正确杜绝欺诈套路。下面为了帮助广大投资者正确杜绝欺诈实现出金&…...
基于java,SpringBoot和VUE的求职招聘简历管理系统设计
摘要 基于Java, Spring Boot和Vue的求职招聘管理系统是一个为了简化求职者与雇主间互动流程而设计的现代化在线平台。该系统后端采用Spring Boot框架,以便快速搭建具有自动配置、安全性和事务管理等特性的RESTful API服务,而前端则使用Vue.js框架构建动…...
sqlserver数据库日志文件log.ldf文件占用过大清除的办法
sqlserver数据库日志文件log.ldf文件占用过大清除的办法 技术交流 http://idea.coderyj.com/ 1.清除数据库日志的方法 --- 查看数据库日志文件名 USE cs GO SELECT file_id, name,size,* FROM sys.database_files;ps 可以看到其中name字段为数据库日志名称"数据库日志名称…...
【Python小技巧】matplotlib不显示图像竟是numpy惹的祸
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、问题:df.plot() 显示不出图像二、尝试各种解决办法1. 增加matplotlib.use,设定GUI2. 升级matplotlib版本 三、numpy是个重要的库1. …...
【AIGC】1、爆火的 AIGC 到底是什么 | 全面介绍
文章目录 一、AIGC 的简要介绍二、AIGC 的发展历程三、AIGC 的基石3.1 基本模型3.2 基于人类反馈的强化学习3.3 算力支持 四、生成式 AI(Generative AI)4.1 单模态4.1.1 生成式语言模型(Generative Language Models,GLM࿰…...
云计算技术概述_3.云计算的部署方式
根据NIST的定义,云计算从部署模式上看可以分为公有云、社区云、私有云和混合云四种类型。 注:NIST(美国国家标准与技术研究院)是美国商务部下属的一个物理科学实验室和非监管机构。 其任务是促进创新和行业竞争力。 NIST 将其活动…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
React核心概念:State是什么?如何用useState管理组件自己的数据?
系列回顾: 在上一篇《React入门第一步》中,我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目,并修改了App.jsx组件,让页面显示出我们想要的文字。但是,那个页面是“死”的,它只是静态…...
