当前位置: 首页 > news >正文

【视觉SLAM】 十四讲ch5习题

1.*寻找一个相机(你手机或笔记本的摄像头即可),标定它的内参。你可能会用到标定板,或者自己打印一张标定用的棋盘格。

参考我之前写过的这篇博客:【OpenCV】 相机标定 calibrateCamera

Code来源是《学习OpenCV3》18.01的例程,笔者做了注释补充,Code如下:

// Example 18-1. Reading a chessboard’s width and height, reading and collecting
// the requested number of views, and calibrating the camera
#include <iostream>
#include <opencv2/opencv.hpp>using std::vector;
using std::cout;
using std::cerr;
using std::endl;void help(char **argv) {  // todo rewrite thiscout << "\n\n"<< "Example 18-1:\nReading a chessboard’s width and height,\n"<< "              reading and collecting the requested number of views,\n" << "              and calibrating the camera\n\n" << "Call:\n" << argv[0] << " <board_width> <board_height> <number_of_boards> <if_video,_delay_between_framee_capture> <image_scaling_factor>\n\n"<< "Example:\n" << argv[0] << " 9 6 15 500 0.5\n"<< "-- to use the checkerboard9x6.png provided\n\n"<< " * First it reads in checker boards and calibrates itself\n" << " * Then it saves and reloads the calibration matricies\n"<< " * Then it creates an undistortion map and finally\n"<< " * It displays an undistorted image\n"<< endl;
}int main(int argc, char *argv[]) {int n_boards = 0;           // will be set by input listfloat image_sf = 0.5f;      // image scaling factorfloat delay = 1.f;int board_w = 0;int board_h = 0;if (argc < 4 || argc > 6) {cout << "\nERROR: Wrong number of input parameters\n";help(argv);return -1;}board_w = atoi(argv[1]);board_h = atoi(argv[2]);n_boards = atoi(argv[3]);if (argc > 4) {delay = atof(argv[4]);}if (argc > 5) {image_sf = atof(argv[5]);}/*image_sf是一个用来缩放图像的尺度因子(scale factor)。            角点检测的稳定性: 通过缩放图像,可以在一定程度上增强棋盘格角点检测的稳定性。有时候,一些图像处理算法对于图像的尺寸大小比较敏感,通过调整图像的尺寸可以帮助算法更好地检测到棋盘格角点。提高匹配精度: 调整图像的尺寸可以使棋盘格角点在缩小或放大后仍然保持一定的像素间距,有助于提高匹配的准确性。这样在后续的相机标定过程中,可以更准确地匹配到对应的图像坐标和三维空间坐标。加快算法速度: 在某些情况下,缩小图像的尺寸可以减少计算量,从而加快算法的执行速度。特别是对于较大分辨率的图像,通过缩小尺寸可以降低处理的复杂度,提高算法的效率。*/int board_n = board_w * board_h;cv::Size board_sz = cv::Size(board_w, board_h);cv::VideoCapture capture(0);if (!capture.isOpened()) {cout << "\nCouldn't open the camera\n";help(argv);return -1;}// ALLOCATE STORAGE//vector<vector<cv::Point2f> > image_points;vector<vector<cv::Point3f> > object_points;// Capture corner views: loop until we've got n_boards successful// captures (all corners on the board are found).//double last_captured_timestamp = 0;cv::Size image_size;while (image_points.size() < (size_t)n_boards) {cv::Mat image0, image;capture >> image0;image_size = image0.size();cv::resize(image0, image, cv::Size(), image_sf, image_sf, cv::INTER_LINEAR);// Find the board//vector<cv::Point2f> corners;bool found = cv::findChessboardCorners(image, board_sz, corners);// Draw it//drawChessboardCorners(image, board_sz, corners, found);// If we got a good board, add it to our data//double timestamp = static_cast<double>(clock()) / CLOCKS_PER_SEC;if (found && timestamp - last_captured_timestamp > 1) {last_captured_timestamp = timestamp;image ^= cv::Scalar::all(255);/*代码使用了异或运算符 ^,并且将图像 image 与所有像素值为255的白色 cv::Scalar 进行异或操作。换句话说,这行代码将图像中所有像素值与255进行逐位异或操作,实现了反转图像像素的效果。具体来说,对于每个像素的每个通道,如果像素值为0,异或255后为255;如果像素值为255,异或255后为0。因此,总体上就是将原图像中的亮度值取反,白色变为黑色,黑色变为白色,实现了一种图像反色的效果。这种操作常常用于在图像处理中实现一些效果,比如图像的反色展示或者图像的二值化处理。*/cv::Mat mcorners(corners);/*将存储棋盘格角点的corners向量转换为cv::Mat类型的mcorners矩阵,并对矩阵中的数据进行缩放操作。具体解释如下:cv::Mat mcorners(corners);: 这一行代码通过将corners向量作为参数,创建了一个新的cv::Mat类型的mcorners矩阵。这将导致mcorners矩阵拥有与corners向量相同的数据内容。mcorners *= (1.0 / image_sf);: 这行代码对mcorners矩阵中的所有元素进行缩放操作。具体地,每个元素除以image_sf,这样就实现了对角点坐标的缩放操作。这是由于之前将图像缩放了image_sf倍,而角点坐标也需要相应进行缩放处理。通过这两行代码,将角点坐标存储在corners向量中的数据转换为了cv::Mat类型的矩阵,并对矩阵中的数据进行了缩放操作。这是为了保持角点坐标和图像坐标的一致性。*/// 后续似乎没有用到// do not copy the datamcorners *= (1.0 / image_sf);// scale the corner coordinatesimage_points.push_back(corners);object_points.push_back(vector<cv::Point3f>());vector<cv::Point3f> &opts = object_points.back();opts.resize(board_n);for (int j = 0; j < board_n; j++) {opts[j] = cv::Point3f(static_cast<float>(j / board_w),static_cast<float>(j % board_w), 0.0f);}cout << "Collected our " << static_cast<uint>(image_points.size())<< " of " << n_boards << " needed chessboard images\n" << endl;}cv::imshow("Calibration", image);// show in color if we did collect the imageif ((cv::waitKey(30) & 255) == 27)return -1;}// END COLLECTION WHILE LOOP.cv::destroyWindow("Calibration");cout << "\n\n*** CALIBRATING THE CAMERA...\n" << endl;// CALIBRATE THE CAMERA!//cv::Mat intrinsic_matrix, distortion_coeffs;double err = cv::calibrateCamera(object_points, image_points, image_size, intrinsic_matrix,distortion_coeffs, cv::noArray(), cv::noArray(),cv::CALIB_ZERO_TANGENT_DIST | cv::CALIB_FIX_PRINCIPAL_POINT);/*err表示相机标定的平均重投影误差。在 OpenCV 中,calibrateCamera 函数会返回相机标定的重投影误差,即用标定结果对相机拍摄的图像进行重投影并计算误差的平均值。*//*一些常见的重投影误差标准范围:一般标准: 对于一般应用,重投影误差在0.1到1像素之间可以被接受。精度要求高: 对于需要高精度测量的应用,重投影误差应该控制在0.1像素以下。实时应用: 对于实时图像处理或运动跟踪等应用,重投影误差在1到2像素之间可能是可以接受的。*/// SAVE THE INTRINSICS AND DISTORTIONScout << " *** DONE!\n\nReprojection error is " << err<< "\nStoring Intrinsics.xml and Distortions.xml files\n\n";cv::FileStorage fs("intrinsics.xml", cv::FileStorage::WRITE);fs << "image_width" << image_size.width << "image_height" << image_size.height<< "camera_matrix" << intrinsic_matrix << "distortion_coefficients"<< distortion_coeffs;fs.release();// EXAMPLE OF LOADING THESE MATRICES BACK IN:fs.open("intrinsics.xml", cv::FileStorage::READ);cout << "\nimage width: " << static_cast<int>(fs["image_width"]);cout << "\nimage height: " << static_cast<int>(fs["image_height"]);cv::Mat intrinsic_matrix_loaded, distortion_coeffs_loaded;fs["camera_matrix"] >> intrinsic_matrix_loaded;fs["distortion_coefficients"] >> distortion_coeffs_loaded;cout << "\nintrinsic matrix:" << intrinsic_matrix_loaded;cout << "\ndistortion coefficients: " << distortion_coeffs_loaded << endl;// Build the undistort map which we will use for all// subsequent frames.//cv::Mat map1, map2;cv::initUndistortRectifyMap(intrinsic_matrix_loaded, distortion_coeffs_loaded,cv::Mat(), intrinsic_matrix_loaded, image_size,CV_16SC2, map1, map2);// Just run the camera to the screen, now showing the raw and// the undistorted image.//for (;;) {cv::Mat image, image0;capture >> image0;if (image0.empty()) {break;}cv::remap(image0, image, map1, map2, cv::INTER_LINEAR,cv::BORDER_CONSTANT, cv::Scalar());cv::imshow("Undistorted", image);if ((cv::waitKey(30) & 255) == 27) {break;}}return 0;
}

2.叙述相机内参的物理意义。如果一个相机的分辨率变成两倍而其他地方不变,它的内参如何变化?


3.搜索特殊的相机(鱼眼或全景)相机的标定方法。它们与普通的针孔模型有何不同?

鱼眼相机模型和普通针孔相机模型的标定流程类似,但是鱼眼相机在结构上比普通相机的透镜更多,引入了更大的径向畸变。

因为,鱼眼相机的投影模型为了将尽可能大的场景投影到有限的图像平面内,允许了相机畸变的存在。并且由于鱼眼相机的径向畸变非常严重,所以鱼眼相机主要的是考虑径向畸变,而忽略其余类型的畸变。

为了将尽可能大的场景投影到有限的图像平面内,鱼眼相机会按照一定的投影函数来设计。根据投影函数的不同,鱼眼相机的设计模型大致能被分为四种:等距投影模型、等立体角投影模型、正交投影模型和体视投影模型。

总的来说,就是在标定时采用的畸变模型不同。以OpenCV为例,OpenCV求解相机参数分为两步:1、求解焦距和偏移,2、求解畸变参数。鱼眼相机与普通相机第一步大致相同,但鱼眼相机标定时畸变模型一般使用,五元素形式(k1,k2,p1,p2和k3)。详细请参考【OpenCV】 相机标定 calibrateCamera和鱼眼相机成像模型以及基于OpenCV标定鱼眼镜头

笔者没有接触过全景相机,请参考【计算机视觉】全景相机标定(MATLAB/opencv)

4.调研全局快门相机(global shutter)和卷帘快门相机(rolling shutter)的异同。它们在SLAM 中有何优缺点?

全局快门相机通过整幅场景在同一时间曝光实现的(CCD是全局快门)。Sensor所有像素点同时收集光线,同时曝光。即在曝光开始的时候,Sensor开始收集光线;在曝光结束的时候,光线收集电路被切断。然后Sensor值读出即为一幅照片。全局快门曝光时间更短,容易产生噪点。由于硬件成本,帧率一般比同价位的卷帘快门低。尤其是对于抓拍高速运动的物体有劣势:由于技术限制,很难将巨大的数据量同时处理。

卷帘快门相机通过Sensor逐行曝光的方式实现的(CMOS大多是卷帘快门)。在曝光开始的时候,Sensor逐行扫描逐行进行曝光,直至所有像素点都被曝光。当然,所有的动作在极短的时间内完成。不同行像元的曝光时间不同。大多数CMOS传感器采用这一快门。当物体或者相机在高速运动时会出现果冻效应。

果冻效应

用卷帘快门方式拍摄,逐行扫描速度不够,拍摄结果就可能出现"倾斜"、"摇摆不定"或"部分曝光"等情况。这种卷帘快门方式拍摄出现的现象,就定义为果冻效应。

总结:对于高速移动的物体来说,卷帘快门容易出现扭曲现象(果冻效应)。用Global shutter方式拍摄,假如曝光时间过长,照片会产生像糊现象。而且由于技术限制,很难将巨大的数据量同时处理。


5.RGB-D 相机是如何标定的?以Kinect 为例,需要标定哪些参数?

(参照GitHub - code-iai/iai_kinect2: Tools for using the Kinect One (Kinect v2) in ROS.)

Kinect2由普通RGB相机、红外相机和红外投射器组成,其中红外相机和红外投射器共同组成深度相机。

根据Kinect2结构,所以需要标定参数比普通RGB相机多出来红外相机的相机内参和畸变参数以及普通RGB相机、红外相机的外参(位姿变换矩阵)和深度图的深度值校准。

故需要标定参数为:

RGB相机:相机内参和畸变参数;

红外相机:相机内参和畸变参数;

RGB相机和红外相机的外参(位姿变换矩阵);

深度图的深度值校准;

Kinect2标定原理详情请参考:RGB-D相机的标定与图像配准


6.除了示例程序演示的遍历图像的方式,你还能举出哪些遍历图像的方法?

《OpenCV3编程入门》配套示例程序提供了14种之多。

Code如下:

//--------------------------------------【程序说明】-------------------------------------------
//		程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序24
//		程序描述:来自一本国外OpenCV2书籍的示例-遍历图像像素的14种方法
//		测试所用IDE版本:Visual Studio 2010
//		测试所用OpenCV版本:	2.4.9
//		2014年11月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------/*------------------------------------------------------------------------------------------*\This file contains material supporting chapter 2 of the cookbook:Computer Vision Programming using the OpenCV Library.by Robert Laganiere, Packt Publishing, 2011.This program is free software; permission is hereby granted to use, copy, modify,and distribute this source code, or portions thereof, for any purpose, without fee,subject to the restriction that the copyright notice may not be removedor altered from any source or altered source distribution.The software is released on an as-is basis and without any warranties of any kind.In particular, the software is not guaranteed to be fault-tolerant or free from failure.The author disclaims all warranties with regard to this software, any use,and any consequent failure, is purely the responsibility of the user.Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name
\*------------------------------------------------------------------------------------------*///---------------------------------【头文件、命名空间包含部分】-----------------------------
//		描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;//---------------------------------【宏定义部分】---------------------------------------------
//		描述:包含程序所使用宏定义
//-------------------------------------------------------------------------------------------------
#define NTESTS 14
#define NITERATIONS 20//----------------------------------------- 【方法一】-------------------------------------------
//		说明:利用.ptr 和 []
//-------------------------------------------------------------------------------------------------
void colorReduce0(Mat& image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量for (int j = 0; j < nl; j++){uchar* data = image.ptr<uchar>(j);for (int i = 0; i < nc; i++){//-------------开始处理每个像素-------------------data[i] = data[i] / div * div + div / 2;//-------------结束像素处理------------------------} //单行处理结束                  }
}//-----------------------------------【方法二】-------------------------------------------------
//		说明:利用 .ptr 和 * ++ 
//-------------------------------------------------------------------------------------------------
void colorReduce1(Mat& image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量for (int j = 0; j < nl; j++){uchar* data = image.ptr<uchar>(j);for (int i = 0; i < nc; i++){//-------------开始处理每个像素-------------------*data++ = *data / div * div + div / 2;//-------------结束像素处理------------------------} //单行处理结束              }
}//-----------------------------------------【方法三】-------------------------------------------
//		说明:利用.ptr 和 * ++ 以及模操作
//-------------------------------------------------------------------------------------------------
void colorReduce2(Mat& image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量for (int j = 0; j < nl; j++){uchar* data = image.ptr<uchar>(j);for (int i = 0; i < nc; i++){//-------------开始处理每个像素-------------------int v = *data;*data++ = v - v % div + div / 2;//-------------结束像素处理------------------------} //单行处理结束                   }
}//----------------------------------------【方法四】---------------------------------------------
//		说明:利用.ptr 和 * ++ 以及位操作
//----------------------------------------------------------------------------------------------------
void colorReduce3(Mat& image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 对于 div=16, mask= 0xF0for (int j = 0; j < nl; j++) {uchar* data = image.ptr<uchar>(j);for (int i = 0; i < nc; i++) {//------------开始处理每个像素-------------------*data++ = *data & mask + div / 2;//-------------结束像素处理------------------------}  //单行处理结束            }
}//----------------------------------------【方法五】----------------------------------------------
//		说明:利用指针算术运算
//---------------------------------------------------------------------------------------------------
void colorReduce4(Mat& image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));int step = image.step; //有效宽度//掩码值uchar mask = 0xFF << n; // e.g. 对于 div=16, mask= 0xF0//获取指向图像缓冲区的指针uchar* data = image.data;for (int j = 0; j < nl; j++){for (int i = 0; i < nc; i++){//-------------开始处理每个像素-------------------*(data + i) = *data & mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束              data += step;  // next line}
}//---------------------------------------【方法六】----------------------------------------------
//		说明:利用 .ptr 和 * ++以及位运算、image.cols * image.channels()
//-------------------------------------------------------------------------------------------------
void colorReduce5(Mat& image, int div = 64) {int nl = image.rows; //行数int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 例如div=16, mask= 0xF0for (int j = 0; j < nl; j++){uchar* data = image.ptr<uchar>(j);for (int i = 0; i < image.cols * image.channels(); i++){//-------------开始处理每个像素-------------------*data++ = *data & mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束            }
}// -------------------------------------【方法七】----------------------------------------------
//		说明:利用.ptr 和 * ++ 以及位运算(continuous)
//-------------------------------------------------------------------------------------------------
void colorReduce6(Mat& image, int div = 64) {int nl = image.rows; //行数int nc = image.cols * image.channels(); //每行元素的总元素数量if (image.isContinuous()){//无填充像素nc = nc * nl;nl = 1;  // 为一维数列}int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 比如div=16, mask= 0xF0for (int j = 0; j < nl; j++) {uchar* data = image.ptr<uchar>(j);for (int i = 0; i < nc; i++) {//-------------开始处理每个像素-------------------*data++ = *data & mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束                   }
}//------------------------------------【方法八】------------------------------------------------
//		说明:利用 .ptr 和 * ++ 以及位运算 (continuous+channels)
//-------------------------------------------------------------------------------------------------
void colorReduce7(Mat& image, int div = 64) {int nl = image.rows; //行数int nc = image.cols; //列数if (image.isContinuous()){//无填充像素nc = nc * nl;nl = 1;  // 为一维数组}int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 比如div=16, mask= 0xF0for (int j = 0; j < nl; j++) {uchar* data = image.ptr<uchar>(j);for (int i = 0; i < nc; i++) {//-------------开始处理每个像素-------------------*data++ = *data & mask + div / 2;*data++ = *data & mask + div / 2;*data++ = *data & mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束                    }
}// -----------------------------------【方法九】 ------------------------------------------------
//		说明:利用Mat_ iterator
//-------------------------------------------------------------------------------------------------
void colorReduce8(Mat& image, int div = 64) {//获取迭代器Mat_<Vec3b>::iterator it = image.begin<Vec3b>();Mat_<Vec3b>::iterator itend = image.end<Vec3b>();for (; it != itend; ++it) {//-------------开始处理每个像素-------------------(*it)[0] = (*it)[0] / div * div + div / 2;(*it)[1] = (*it)[1] / div * div + div / 2;(*it)[2] = (*it)[2] / div * div + div / 2;//-------------结束像素处理------------------------}//单行处理结束  
}//-------------------------------------【方法十】-----------------------------------------------
//		说明:利用Mat_ iterator以及位运算
//-------------------------------------------------------------------------------------------------
void colorReduce9(Mat& image, int div = 64) {// div必须是2的幂int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 比如 div=16, mask= 0xF0// 获取迭代器Mat_<Vec3b>::iterator it = image.begin<Vec3b>();Mat_<Vec3b>::iterator itend = image.end<Vec3b>();//扫描所有元素for (; it != itend; ++it){//-------------开始处理每个像素-------------------(*it)[0] = (*it)[0] & mask + div / 2;(*it)[1] = (*it)[1] & mask + div / 2;(*it)[2] = (*it)[2] & mask + div / 2;//-------------结束像素处理------------------------}//单行处理结束  
}//------------------------------------【方法十一】---------------------------------------------
//		说明:利用Mat Iterator_
//-------------------------------------------------------------------------------------------------
void colorReduce10(Mat& image, int div = 64) {//获取迭代器Mat_<Vec3b> cimage = image;Mat_<Vec3b>::iterator it = cimage.begin();Mat_<Vec3b>::iterator itend = cimage.end();for (; it != itend; it++) {//-------------开始处理每个像素-------------------(*it)[0] = (*it)[0] / div * div + div / 2;(*it)[1] = (*it)[1] / div * div + div / 2;(*it)[2] = (*it)[2] / div * div + div / 2;//-------------结束像素处理------------------------}
}//--------------------------------------【方法十二】--------------------------------------------
//		说明:利用动态地址计算配合at
//-------------------------------------------------------------------------------------------------
void colorReduce11(Mat& image, int div = 64) {int nl = image.rows; //行数int nc = image.cols; //列数for (int j = 0; j < nl; j++){for (int i = 0; i < nc; i++){//-------------开始处理每个像素-------------------image.at<Vec3b>(j, i)[0] = image.at<Vec3b>(j, i)[0] / div * div + div / 2;image.at<Vec3b>(j, i)[1] = image.at<Vec3b>(j, i)[1] / div * div + div / 2;image.at<Vec3b>(j, i)[2] = image.at<Vec3b>(j, i)[2] / div * div + div / 2;//-------------结束像素处理------------------------} //单行处理结束                 }
}//----------------------------------【方法十三】----------------------------------------------- 
//		说明:利用图像的输入与输出
//-------------------------------------------------------------------------------------------------
void colorReduce12(const Mat& image, //输入图像Mat& result,      // 输出图像int div = 64) {int nl = image.rows; //行数int nc = image.cols; //列数//准备好初始化后的Mat给输出图像result.create(image.rows, image.cols, image.type());//创建无像素填充的图像nc = nc * nl;nl = 1;  //单维数组int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g.比如div=16, mask= 0xF0for (int j = 0; j < nl; j++) {uchar* data = result.ptr<uchar>(j);const uchar* idata = image.ptr<uchar>(j);for (int i = 0; i < nc; i++) {//-------------开始处理每个像素-------------------*data++ = (*idata++) & mask + div / 2;*data++ = (*idata++) & mask + div / 2;*data++ = (*idata++) & mask + div / 2;//-------------结束像素处理------------------------} //单行处理结束                   }
}//--------------------------------------【方法十四】------------------------------------------- 
//		说明:利用操作符重载
//-------------------------------------------------------------------------------------------------
void colorReduce13(Mat& image, int div = 64) {int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//掩码值uchar mask = 0xFF << n; // e.g. 比如div=16, mask= 0xF0//进行色彩还原image = (image & Scalar(mask, mask, mask)) + Scalar(div / 2, div / 2, div / 2);
}//-----------------------------------【ShowHelpText( )函数】-----------------------------
//		描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
void ShowHelpText()
{//输出欢迎信息和OpenCV版本printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");printf("\n\n\t\t\t此为本书OpenCV2版的第24个配套示例程序\n");printf("\n\n\t\t\t   当前使用的OpenCV版本为:" CV_VERSION);printf("\n\n  ----------------------------------------------------------------------------\n");printf("\n\n正在进行存取操作,请稍等……\n\n");
}//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main()
{int64 t[NTESTS], tinit;Mat image0;Mat image1;Mat image2;//system("color 4F");ShowHelpText();image0 = imread("1.png");if (!image0.data)return 0;//时间值设为0for (int i = 0; i < NTESTS; i++)t[i] = 0;// 多次重复测试int n = NITERATIONS;for (int k = 0; k < n; k++){cout << k << " of " << n << endl;image1 = imread("1.png");//【方法一】利用.ptr 和 []tinit = getTickCount();colorReduce0(image1);t[0] += getTickCount() - tinit;//【方法二】利用 .ptr 和 * ++ image1 = imread("1.png");tinit = getTickCount();colorReduce1(image1);t[1] += getTickCount() - tinit;//【方法三】利用.ptr 和 * ++ 以及模操作image1 = imread("1.png");tinit = getTickCount();colorReduce2(image1);t[2] += getTickCount() - tinit;//【方法四】 利用.ptr 和 * ++ 以及位操作image1 = imread("1.png");tinit = getTickCount();colorReduce3(image1);t[3] += getTickCount() - tinit;//【方法五】 利用指针的算术运算image1 = imread("1.png");tinit = getTickCount();colorReduce4(image1);t[4] += getTickCount() - tinit;//【方法六】利用 .ptr 和 * ++以及位运算、image.cols * image.channels()image1 = imread("1.png");tinit = getTickCount();colorReduce5(image1);t[5] += getTickCount() - tinit;//【方法七】利用.ptr 和 * ++ 以及位运算(continuous)image1 = imread("1.png");tinit = getTickCount();colorReduce6(image1);t[6] += getTickCount() - tinit;//【方法八】利用 .ptr 和 * ++ 以及位运算 (continuous+channels)image1 = imread("1.png");tinit = getTickCount();colorReduce7(image1);t[7] += getTickCount() - tinit;//【方法九】 利用Mat_ iteratorimage1 = imread("1.png");tinit = getTickCount();colorReduce8(image1);t[8] += getTickCount() - tinit;//【方法十】 利用Mat_ iterator以及位运算image1 = imread("1.png");tinit = getTickCount();colorReduce9(image1);t[9] += getTickCount() - tinit;//【方法十一】利用Mat Iterator_image1 = imread("1.png");tinit = getTickCount();colorReduce10(image1);t[10] += getTickCount() - tinit;//【方法十二】 利用动态地址计算配合atimage1 = imread("1.png");tinit = getTickCount();colorReduce11(image1);t[11] += getTickCount() - tinit;//【方法十三】 利用图像的输入与输出image1 = imread("1.png");tinit = getTickCount();Mat result;colorReduce12(image1, result);t[12] += getTickCount() - tinit;image2 = result;//【方法十四】 利用操作符重载image1 = imread("1.png");tinit = getTickCount();colorReduce13(image1);t[13] += getTickCount() - tinit;//------------------------------}//输出图像   imshow("原始图像", image0);imshow("结果", image2);imshow("图像结果", image1);// 输出平均执行时间cout << endl << "-------------------------------------------" << endl << endl;cout << "\n【方法一】利用.ptr 和 []的方法所用时间为 " << 1000. * t[0] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法二】利用 .ptr 和 * ++ 的方法所用时间为" << 1000. * t[1] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法三】利用.ptr 和 * ++ 以及模操作的方法所用时间为" << 1000. * t[2] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法四】利用.ptr 和 * ++ 以及位操作的方法所用时间为" << 1000. * t[3] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法五】利用指针算术运算的方法所用时间为" << 1000. * t[4] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法六】利用 .ptr 和 * ++以及位运算、channels()的方法所用时间为" << 1000. * t[5] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法七】利用.ptr 和 * ++ 以及位运算(continuous)的方法所用时间为" << 1000. * t[6] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法八】利用 .ptr 和 * ++ 以及位运算 (continuous+channels)的方法所用时间为" << 1000. * t[7] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法九】利用Mat_ iterator 的方法所用时间为" << 1000. * t[8] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十】利用Mat_ iterator以及位运算的方法所用时间为" << 1000. * t[9] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十一】利用Mat Iterator_的方法所用时间为" << 1000. * t[10] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十二】利用动态地址计算配合at 的方法所用时间为" << 1000. * t[11] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十三】利用图像的输入与输出的方法所用时间为" << 1000. * t[12] / getTickFrequency() / n << "ms" << endl;cout << "\n【方法十四】利用操作符重载的方法所用时间为" << 1000. * t[13] / getTickFrequency() / n << "ms" << endl;waitKey();return 0;
}

运行结果

其中:方法5利用指针算术、方法八利用 .ptr 和*++ 以及位运算(continuous+channels)以及方法14利用操作符重载的方法最佳。

7.学习OpenCV基本用法

推荐两本学习OpenCV基本用法参考书:

1、《学习OpenCV3》

2、《OpenCV3编程入门》

相关文章:

【视觉SLAM】 十四讲ch5习题

1.*寻找一个相机&#xff08;你手机或笔记本的摄像头即可&#xff09;&#xff0c;标定它的内参。你可能会用到标定板&#xff0c;或者自己打印一张标定用的棋盘格。 参考我之前写过的这篇博客&#xff1a;【OpenCV】 相机标定 calibrateCamera Code来源是《学习OpenCV3》18.…...

Webpack基础学习-Day01

Webpack基础学习-Day01 1.1 webpack 是什么 webpack 是一种前端资源构建工具&#xff0c;一个静态模块打包器(module bundler)。 在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理。 它将根据模块的依赖关系进行静态分析&#xff0c;打包生成…...

如何防止热插拔烧坏单片机

大家都知道一般USB接口属于热插拔&#xff0c;实际任意带电进行连接的操作都可以属于热插拔。我们前面讲过芯片烧坏的原理&#xff0c;那么热插拔就是导致芯片烧坏的一个主要原因之一。 在电子产品的整个装配过程、以及产品使用过程经常会面临接口热插拔或者类似热插拔的过程。…...

JQuery+HTML+JavaScript:实现地图位置选取和地址模糊查询

本文详细讲解了如何使用 JQueryHTMLJavaScript 实现移动端页面中的地图位置选取功能。本文逐步展示了如何构建基本的地图页面&#xff0c;如何通过点击地图获取经纬度和地理信息&#xff0c;以及如何实现模糊查询地址并在地图上标注。最后&#xff0c;提供了完整的代码示例&…...

ArcGIS Pro SDK (九)几何 13 多部件

ArcGIS Pro SDK &#xff08;九&#xff09;几何 13 多部件 文章目录 ArcGIS Pro SDK &#xff08;九&#xff09;几何 13 多部件1 获取多部分要素的各个部分2 获取多边形的最外层环 环境&#xff1a;Visual Studio 2022 .NET6 ArcGIS Pro SDK 3.0 1 获取多部分要素的各个部分…...

【Node】npm i --legacy-peer-deps,解决依赖冲突问题

文章目录 &#x1f356; 前言&#x1f3b6; 一、问题描述✨二、代码展示&#x1f3c0;三、运行结果&#x1f3c6;四、知识点提示 &#x1f356; 前言 npm i --legacy-peer-deps&#xff0c;解决依赖冲突问题 &#x1f3b6; 一、问题描述 node执行安装指令时出现报错&#xff…...

h5点击电话号跳转手机拨号

需要使用到h5的 <a>标签 我们首先在<head>标签中添加代码 <meta name"format-detection" content"telephoneyes"/>然后再想要的位置添加代码 <a href"tel:10086"> 点击拨打&#xff1a;10086 </a> 这样功能就实现…...

从数据湖到湖仓一体:统一数据架构演进之路

文章目录 一、前言二、什么是湖仓一体&#xff1f;起源概述 三、为什么要构建湖仓一体&#xff1f;1. 成本角度2. 技术角度 四、湖仓一体实践过程阶段一&#xff1a;摸索阶段(仓、湖并行建设)阶段二&#xff1a;发展阶段方式一、湖上建仓(湖在下、仓在上)方式二&#xff1a;仓外…...

Electron 渲染进程直接调用主进程的API库@electron/remote引用讲解

背景 remote是个老库&#xff0c;早期Electron版本中有个remote对象&#xff0c;这个对象可以横跨所有进程&#xff0c;随意通信&#xff0c;后来官方认为不安全&#xff0c;被干掉了&#xff0c;之后有人利用Electron的IPC通信&#xff0c;底层通过Promise的await能力&#x…...

在python中使用正则表达式

正则表达式是什么&#xff1f;就是要寻找的数据的规律&#xff0c;使用正则表达式的步骤有三 第一&#xff0c;寻找规律&#xff0c;第二使用正则符号表示规律&#xff0c;第三&#xff0c;提取信息 看下面的代码 import re wenzhang (小草偷偷地从土里钻出来&#xff0c;嫩…...

华清数据结构day4 24-7-19

链表的相关操作 linklist.h #ifndef LINKLIST_H #define LINKLIST_H #include <myhead.h> typedef int datatype; typedef struct Node {union{int len;datatype data;};struct Node *next; } Node, *NodePtr;NodePtr list_create(); NodePtr apply_node(datatype e); …...

【深度学习图像】拼接图的切分

用户常常将多张图拼成一张图。 如果将这张图拆为多个子图&#xff0c;下面是一种opencv的办法&#xff0c;后面要训练一个模型来识别边缘更为准确。 import osimport cv2 import numpy as npdef detect_lines(image_path):# 读取图片image cv2.imread(image_path)if image i…...

Covalent(CXT)运营商网络规模扩大 42%,以满足激增的需求

Covalent Network&#xff08;CXT&#xff09;是领先的人工智能模块化数据基础设施&#xff0c;网络集成了超过 230 条链并积累了数千名客户&#xff0c;目前 Covalent Network&#xff08;CXT&#xff09;网络迎来了五位新运营商的加入&#xff0c;包括 Graphyte Labs、PierTw…...

Java 集合框架:HashMap 的介绍、使用、原理与源码解析

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 020 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…...

单周期CPU(三)译码模块(minisys)(verilog)(vivado)

timescale 1ns / 1ps //module Idecode32 (input reset,input clock,output [31:0] read_data_1, // 输出的第一操作数output [31:0] read_data_2, // 输出的第二操作数input [31:0] Instruction, // 取指单元来的指令input [31:0] …...

理想化相机模型的相机内参

文章目录 理想化相机模型的相机内参计算1. 相机内参定义2. 根据视角和图像分辨率计算相机内参2.1 计算焦距 fx 和 fy2.2 计算主点 cx 和 cy3. 示例计算3.1 计算 fx3.2 假设 fy = fx(因为没有垂直视场角的信息)3.3 计算主点4. 相机内参矩阵理想化相机模型的相机内参计算 在理…...

【数据脱敏】⭐️SpringBoot 整合 Jackson 实现隐私数据加密

目录 &#x1f378;前言 &#x1f37b;一、Jackson 序列化库 &#x1f37a;二、方案实践 2.1 环境准备 2.2 依赖引入 2.3 代码编写 &#x1f49e;️三、接口测试 &#x1f379;四、章末 &#x1f378;前言 小伙伴们大家好&#xff0c;最近也是很忙啊&#xff0c;上次的文章…...

骑砍2霸主MOD开发(18)-多人联机模式开发环境搭建

一.多人联机模式网络拓扑图 二.专用服务器搭建(DedicatedServer) <1.Token生成(用于LobbyServer的校验): 进入多人联机大厅,ALT~打开RGL控制台,输入customserver.gettoken Token文件路径:C:\Users\taohu\Documents\Mount and Blade II Bannerlord\Tokens <2.启动专用服务…...

【HZHY-AI300G智能盒试用连载体验】在华为IoTDA平台上建立设备

目录 华为IoTDA平台 注册IoTDA实例 创建产品 添加设备 本文首发于&#xff1a;【HZHY-AI300G智能盒试用连载体验】 智能工业互联网网关 - 北京合众恒跃科技有限公司 - 电子技术论坛 - 广受欢迎的专业电子论坛! 在上一篇博文中介绍了如何在HZHY-AI300G智能盒创建南向设备&a…...

【LLM】-05-提示工程-部署Langchain-Chat

目录 1、软硬件要求 1.1、软件要求 1.2、硬件要求 1.3、个人配置参考 2、创建cuda环境 3、下载源码及模型 4、配置文件修改 5、初始化知识库 5.1、训练自己的知识库 6、启动 7、API接口调用 7.1、使用openai 参考官方wiki&#xff0c;本文以Ubuntu20.04_x64&#xf…...

【漏洞复现】Next.js框架存在SSRF漏洞(CVE-2024-34351)

0x01 产品简介 ZEIT Next.js是ZEIT公司的一款基于Vue.js、Node.js、Webpack和Babel.js的开源Web应用框架。 0x02 漏洞概述 ZEIT Next.js 13.4版本至14.1.1之前版本存在代码问题漏洞&#xff0c;该漏洞源于存在服务器端请求伪造 (SSRF) 漏洞 0x03 搜索引擎 body"/_nex…...

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 小区小朋友统计(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…...

Vuex看这一篇就够了

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…...

Kafka集群创建

这样就创建好了docker4个镜像&#xff0c;三个node&#xff0c;一个manager。 其中&#xff0c;浏览器访问的是manager对应的那个url&#xff0c;直接在里面加Cluster...

2024.7.22 作业

1.将双向链表和循环链表自己实现一遍&#xff0c;至少要实现创建、增、删、改、查、销毁工作 循环链表 looplinklist.h #ifndef LOOPLINKLIST_H #define LOOPLINKLIST_H#include <myhead.h>typedef int datatype;typedef struct Node {union {int len;datatype data;}…...

如何使用aiohttp或requests-async等库并发地执行多个HTTP请求

在Python中&#xff0c;要并发地执行多个HTTP请求&#xff0c;可以使用aiohttp这样的异步HTTP客户端库&#xff0c;因为它支持异步编程&#xff0c;能够显著提高IO密集型任务的性能&#xff0c;比如网络请求。requests-async并不是一个广泛认知的库&#xff08;虽然可能存在类似…...

Golang | Leetcode Golang题解之第257题二叉树的所有路径

题目&#xff1a; 题解&#xff1a; func binaryTreePaths(root *TreeNode) []string {paths : []string{}if root nil {return paths}nodeQueue : []*TreeNode{}pathQueue : []string{}nodeQueue append(nodeQueue, root)pathQueue append(pathQueue, strconv.Itoa(root.V…...

关于css中flex布局垂直居中失效问题的原因

项目中遇到用flex进行页面布局后&#xff0c;使用上下居中设置&#xff1a;align-item: center; 目标效果如下&#xff1a; 但是失效&#xff0c;不起作用&#xff0c;如下图所示&#xff1a; 各种排查过后发现设置了子模块 align-self 属性&#xff0c;这会覆盖容器上的 al…...

用Redisson写一个库存扣减的方法

使用Redisson来处理库存操作可以确保在高并发环境下库存数据的一致性和完整性。以下是使用Redisson实现库存管理的一些通用方法&#xff0c;包括获取库存、扣减库存、设置库存等。我们将使用Redisson的ReentrantLock来确保并发安全。 首先&#xff0c;确保你已经正确设置了Red…...

第2节课:文本内容与格式化——HTML中的文本处理技巧

目录 文本内容与格式化&#xff1a;段落和标题&#xff1a;构建文本基础段落 <p>标题 <h1> 到 <h6> 格式化&#xff1a;强调和样式加粗 <b>斜体 <i>下划线 <u> 列表&#xff1a;组织内容无序列表 <ul>有序列表 <ol>定义列表 &…...

temu平台电池/锂电池UN38.3资质合规解析

UN38.3资质合规解析 为满足相关法律法规和商品运输安全需求含锂电池商品需要提供对应的UN38.3资质。截至7月29日&#xff0c;相关类目下UN38.3资质待上传或上传失败的商品可能面临下架。 -01什么是UN38.3- 1&#xff09;UN38.3是指由联合国危险货物运输专家委员会编写的《试验…...

Huawei、Cisco 路由中 RIP 协议 summary 的用法

华为路由中 RIP summary summary用来使能 RIP 有类聚合&#xff0c;聚合后的路由以使用自然掩码的路由形式发布。undo summary用来取消有类聚合以便在子网之间进行路由&#xff0c;此时&#xff0c;子网的路由信息就会被发布出去。路由聚合降低了路由表中路由信息量。说明 有类…...

智能图像信息提取(飞桨OCR+ERNIE-Layout)

嘿&#xff0c;技术大佬们&#xff0c;今天我要分享的是一个超级棒的OCR技术方案&#xff0c;它结合了飞桨OCR和ERNIE-Layout&#xff0c;绝对是图像信息提取的利器&#xff01; 线上体验地址&#xff1a;智能图像信息提取(飞桨OCRERNIE-Layout) 它基于ERNIE -Layout和多版本Pa…...

Ubuntu 24.04 LTS Noble安装 FileZilla Server

FileZilla Server 是一款使用图形用户界面快速创建 FTP 服务器的软件。它有助于测试需要 FTP 服务器功能的各种项目。虽然早期的 FileZilla FTP 服务器仅适用于 Windows 和 macOS&#xff0c;但现在我们也可以在 Linux&#xff08;例如 Ubuntu 24.04&#xff09;上安装 FileZil…...

【关于使用swoole的知识点整理】

目录 &#xff08;1&#xff09;Swoole 如何理解&#xff0c;能解决你项目中的哪些痛点&#xff1f; &#xff08;2&#xff09;Swoole里的协程是什么&#xff0c;怎么用&#xff1f;为什么协程可以提高并发&#xff1f; &#xff08;3&#xff09;简述Swoole有哪些优点&…...

迁移学习:目标检测的加速器

迁移学习&#xff1a;目标检测的加速器 在深度学习领域&#xff0c;目标检测是一项至关重要的任务&#xff0c;广泛应用于从视频监控到自动驾驶等众多领域。然而&#xff0c;训练一个高性能的目标检测模型不仅需要大量的标注数据&#xff0c;还需要大量的计算资源和时间。迁移…...

gitee的怎么上传项目

前提 1.先下载Git Bash (如果没有下载的宝子们下载连接如下: 链接: link ) 项目上传到Gitee步骤 1.在Gitee上建立远程仓库 2.填写相关信息 3.进入本地你想要上传的文件目录下&#xff0c;右键单击空白处&#xff0c;点击Git Bash Here 4.配置你的用户名和邮箱 git con…...

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(二十三)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 33 节&#xff09; P33《32.通知-进度条通知》 下载按钮对应的逻辑&#xff1a; 取消按钮对应的逻辑&#xff1a; 暂停按钮对应的…...

.NET C# 配置 Options

.NET C# 配置 Options 使用 options 模式可以带来许多好处&#xff0c;包括清晰的配置管理、类型安全、易于测试和灵活性。但在使用过程中&#xff0c;也需要注意配置复杂性、性能开销和依赖框架等问题。通过合理设计和使用&#xff0c;可以充分发挥 options 模式的优势&#…...

42、PHP 实现把二叉树打印成多行

题目&#xff1a; PHP 实现把二叉树打印成多行 描述&#xff1a; 从上到下按层打印二叉树&#xff0c;同一层结点从左至右输出。每一层输出一行。 <?php/*class TreeNode{var $val;var $left NULL;var $right NULL;function __construct($val){$this->val $val;} }…...

verilog bug记录——正点原子spi_drive存在的问题

verilog bug记录——正点原子spi_drive存在的问题 问题概述代码修改—spi_drive.v遗留问题 问题概述 因为项目需求&#xff0c;需要利用spi对flash进行擦除和写入操作&#xff0c;所使用的开发板是正电原子的达芬奇开发板&#xff0c;我事先往Flash里面存了两个bit&#xff0c…...

vue+watermark-dom实现页面水印效果

前言 页面水印大家应该都不陌生&#xff0c;它可以用于验证数字媒体的来源和完整性&#xff0c;还可以用于版权保护和信息识别&#xff0c;这些信息可以在不影响媒体质量的情况下嵌入&#xff0c;‌并在需要时进行提取。‌本文将通过 vue 结合 watermark-dom 库&#xff0c;教大…...

为什么要学习网安技术?

学习网络安全&#xff08;网安&#xff09;技术在当今社会变得尤为重要&#xff0c;这主要源于以下几个方面的原因&#xff1a; 保护个人隐私&#xff1a;随着互联网的普及&#xff0c;个人信息如姓名、地址、电话号码、甚至银行账户信息等都在网络上留下了痕迹。学习网安技术可…...

2024春秋杯网络安全联赛夏季赛Crypto(AK)解题思路及用到的软件

2024春秋杯网络安全联赛夏季赛Crypto(AK) 2024春秋杯网络安全联赛夏季赛Crypto解题思路以及用到的软件 所有题用到的软件 1.vm(虚拟机kali)和Ubuntu&#xff0c;正常配置即可B站有很多。 2.Visual Studio Code(里面要配置python&#xff0c;crypto库和Sagemath数学软件系统S…...

vue2 使用代码编辑器插件 vue-codemirror

vue 使用代码编辑器插件 vue-codemirror 之前用过一次&#xff0c;当时用的一知半解的&#xff0c;所以也没有成文&#xff0c;前几天又因为项目有需求&#xff0c;所以说有用了一次&#xff0c;当然&#xff0c;依旧是一知半解&#xff0c;但是还是稍微写一下子吧&#xff01;…...

自动驾驶系列—智能巡航辅助功能中的横向避让功能介绍

自动驾驶系列—智能巡航辅助功能中的车道中央保持功能介绍 自动驾驶系列—智能巡航辅助功能中的车道变换功能介绍 自动驾驶系列—智能巡航辅助功能中的横向避让功能介绍 自动驾驶系列—智能巡航辅助功能中的路口通行功能介绍 文章目录 1. 背景介绍2. 功能定义3. 功能原理4. 传感…...

通过this.$options.data()重置变量时,会影响到引用了props或methods的变量

之前的文章我有提到过通过this.$options.data().具体某个值来将该值进行初始化 但我在项目中遇到了一个问题&#xff1a; 具体情况是&#xff1a;在data中定义一个变量时有用到methods中的一个方法&#xff0c;在后续的方法中我通过this. $options.data.值去重置了另一个数据&…...

[PM]产品运营

生命周期 运营阶段 主要工作 拉新 新用户的定义 冷启动 拉新方式 促活 用户活跃的原因 量化活跃度 运营社区化/内容化 留存 用户流失 培养用户习惯 用户挽回 变现 变现方式 付费模式 广告模式 数据变现 变现指标 传播 营销 认识营销 电商营销中心 拼团活动 1.需求整理 2.…...

流程控制语句

目录 前言 一、SET 语句 二、BEGIN END 语句 三、IF ELSE 语句 四、CASE 语句 五、WHILE 语句 六、GOTO 语句 七、RETURN 语句 前言 T-SQL 提供了用于编写过程性代码的语法结构&#xff0c;可用来进行顺序、分支、循环、存储过程等程序设计&#xff0c;编写结构化的模…...

杰发科技AC7840——SENT数据解析及软件Sent发送的实现

0. 测试环境 AC7840官方Demo板&#xff1b; 图莫斯0503 DSlogic U2Basic 使用引脚 输出脚&#xff1a;PB1 时钟&#xff1a;PB2&#xff0c;其他引脚可以不初始化&#xff0c;不接线 1. 数据解析 以下是SENT数据的格式&#xff08;1tick以3us为例&#xff09;&#…...