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

Opencv源码解析(2)算法

目录

一,直方图均衡

1,直方图统计

2,灰度变换

3,直方图均衡

二,可分离滤波器

1,可分离滤波器的工厂

2,ocvSepFilter、sepFilter2D

3,Sobel

三,相位相关法 phaseCorrelate

1,phaseCorrelate

2,汉宁窗

四,匹配器

1,纯虚类DescriptorMatcher

2,子类FlannBasedMatcher

3,knnMatch算法


一,直方图均衡

opencv-4.2.0\modules\imgproc\src\histogram.cpp 中的代码:

1,直方图统计

class EqualizeHistCalcHist_Invoker : public cv::ParallelLoopBody
{
public:enum {HIST_SZ = 256};EqualizeHistCalcHist_Invoker(cv::Mat& src, int* histogram, cv::Mutex* histogramLock): src_(src), globalHistogram_(histogram), histogramLock_(histogramLock){ }void operator()( const cv::Range& rowRange ) const CV_OVERRIDE{int localHistogram[HIST_SZ] = {0, };const size_t sstep = src_.step;int width = src_.cols;int height = rowRange.end - rowRange.start;if (src_.isContinuous()){width *= height;height = 1;}for (const uchar* ptr = src_.ptr<uchar>(rowRange.start); height--; ptr += sstep){int x = 0;for (; x <= width - 4; x += 4){int t0 = ptr[x], t1 = ptr[x+1];localHistogram[t0]++; localHistogram[t1]++;t0 = ptr[x+2]; t1 = ptr[x+3];localHistogram[t0]++; localHistogram[t1]++;}for (; x < width; ++x)localHistogram[ptr[x]]++;}cv::AutoLock lock(*histogramLock_);for( int i = 0; i < HIST_SZ; i++ )globalHistogram_[i] += localHistogram[i];}static bool isWorthParallel( const cv::Mat& src ){return ( src.total() >= 640*480 );}private:EqualizeHistCalcHist_Invoker& operator=(const EqualizeHistCalcHist_Invoker&);cv::Mat& src_;int* globalHistogram_;cv::Mutex* histogramLock_;
};

类继承了ParallelLoopBody,可以做并行加速。

灰度级HIST_SZ = 256

构造函数保存三个参数。

仿函数是统计直方图。

isWorthParallel函数是判断是否启用并行加速。

2,灰度变换

class EqualizeHistLut_Invoker : public cv::ParallelLoopBody
{
public:EqualizeHistLut_Invoker( cv::Mat& src, cv::Mat& dst, int* lut ): src_(src),dst_(dst),lut_(lut){ }void operator()( const cv::Range& rowRange ) const CV_OVERRIDE{const size_t sstep = src_.step;const size_t dstep = dst_.step;int width = src_.cols;int height = rowRange.end - rowRange.start;int* lut = lut_;if (src_.isContinuous() && dst_.isContinuous()){width *= height;height = 1;}const uchar* sptr = src_.ptr<uchar>(rowRange.start);uchar* dptr = dst_.ptr<uchar>(rowRange.start);for (; height--; sptr += sstep, dptr += dstep){int x = 0;for (; x <= width - 4; x += 4){int v0 = sptr[x];int v1 = sptr[x+1];int x0 = lut[v0];int x1 = lut[v1];dptr[x] = (uchar)x0;dptr[x+1] = (uchar)x1;v0 = sptr[x+2];v1 = sptr[x+3];x0 = lut[v0];x1 = lut[v1];dptr[x+2] = (uchar)x0;dptr[x+3] = (uchar)x1;}for (; x < width; ++x)dptr[x] = (uchar)lut[sptr[x]];}}static bool isWorthParallel( const cv::Mat& src ){return ( src.total() >= 640*480 );}private:EqualizeHistLut_Invoker& operator=(const EqualizeHistLut_Invoker&);cv::Mat& src_;cv::Mat& dst_;int* lut_;
};

构造函数保存三个参数。

仿函数是根据灰度变换表lut,把原图变成目标图。

3,直方图均衡

void cv::equalizeHist( InputArray _src, OutputArray _dst )
{CV_INSTRUMENT_REGION();CV_Assert( _src.type() == CV_8UC1 );if (_src.empty())return;CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),ocl_equalizeHist(_src, _dst))Mat src = _src.getMat();_dst.create( src.size(), src.type() );Mat dst = _dst.getMat();CV_OVX_RUN(!ovx::skipSmallImages<VX_KERNEL_EQUALIZE_HISTOGRAM>(src.cols, src.rows),openvx_equalize_hist(src, dst))Mutex histogramLockInstance;const int hist_sz = EqualizeHistCalcHist_Invoker::HIST_SZ;int hist[hist_sz] = {0,};int lut[hist_sz];EqualizeHistCalcHist_Invoker calcBody(src, hist, &histogramLockInstance);EqualizeHistLut_Invoker      lutBody(src, dst, lut);cv::Range heightRange(0, src.rows);if(EqualizeHistCalcHist_Invoker::isWorthParallel(src))parallel_for_(heightRange, calcBody);elsecalcBody(heightRange);int i = 0;while (!hist[i]) ++i;int total = (int)src.total();if (hist[i] == total){dst.setTo(i);return;}float scale = (hist_sz - 1.f)/(total - hist[i]);int sum = 0;for (lut[i++] = 0; i < hist_sz; ++i){sum += hist[i];lut[i] = saturate_cast<uchar>(sum * scale);}if(EqualizeHistLut_Invoker::isWorthParallel(src))parallel_for_(heightRange, lutBody);elselutBody(heightRange);
}

先是直方图统计,然后是对于纯色图片的特殊处理(直方图均衡结果等于原图),再是计算灰度变换表lut,最后把原图变成目标图。

二,可分离滤波器

1,可分离滤波器的工厂

Ptr<FilterEngine> createSeparableLinearFilter(int _srcType, int _dstType,InputArray __rowKernel, InputArray __columnKernel,Point _anchor, double _delta,int _rowBorderType, int _columnBorderType,const Scalar& _borderValue)
{Mat _rowKernel = __rowKernel.getMat(), _columnKernel = __columnKernel.getMat();_srcType = CV_MAT_TYPE(_srcType);_dstType = CV_MAT_TYPE(_dstType);int sdepth = CV_MAT_DEPTH(_srcType), ddepth = CV_MAT_DEPTH(_dstType);int cn = CV_MAT_CN(_srcType);CV_Assert( cn == CV_MAT_CN(_dstType) );int rsize = _rowKernel.rows + _rowKernel.cols - 1;int csize = _columnKernel.rows + _columnKernel.cols - 1;if( _anchor.x < 0 )_anchor.x = rsize/2;if( _anchor.y < 0 )_anchor.y = csize/2;int rtype = getKernelType(_rowKernel,_rowKernel.rows == 1 ? Point(_anchor.x, 0) : Point(0, _anchor.x));int ctype = getKernelType(_columnKernel,_columnKernel.rows == 1 ? Point(_anchor.y, 0) : Point(0, _anchor.y));Mat rowKernel, columnKernel;bool isBitExactMode = false;int bdepth = std::max(CV_32F,std::max(sdepth, ddepth));int bits = 0;if( sdepth == CV_8U &&((rtype == KERNEL_SMOOTH+KERNEL_SYMMETRICAL &&ctype == KERNEL_SMOOTH+KERNEL_SYMMETRICAL &&ddepth == CV_8U) ||((rtype & (KERNEL_SYMMETRICAL+KERNEL_ASYMMETRICAL)) &&(ctype & (KERNEL_SYMMETRICAL+KERNEL_ASYMMETRICAL)) &&(rtype & ctype & KERNEL_INTEGER) &&ddepth == CV_16S)) ){int bits_ = ddepth == CV_8U ? 8 : 0;bool isValidBitExactRowKernel = createBitExactKernel_32S(_rowKernel, rowKernel, bits_);bool isValidBitExactColumnKernel = createBitExactKernel_32S(_columnKernel, columnKernel, bits_);if (!isValidBitExactRowKernel){CV_LOG_DEBUG(NULL, "createSeparableLinearFilter: bit-exact row-kernel can't be applied: ksize=" << _rowKernel.total());}else if (!isValidBitExactColumnKernel){CV_LOG_DEBUG(NULL, "createSeparableLinearFilter: bit-exact column-kernel can't be applied: ksize=" << _columnKernel.total());}else{bdepth = CV_32S;bits = bits_;bits *= 2;_delta *= (1 << bits);isBitExactMode = true;}}if (!isBitExactMode){if( _rowKernel.type() != bdepth )_rowKernel.convertTo( rowKernel, bdepth );elserowKernel = _rowKernel;if( _columnKernel.type() != bdepth )_columnKernel.convertTo( columnKernel, bdepth );elsecolumnKernel = _columnKernel;}int _bufType = CV_MAKETYPE(bdepth, cn);Ptr<BaseRowFilter> _rowFilter = getLinearRowFilter(_srcType, _bufType, rowKernel, _anchor.x, rtype);Ptr<BaseColumnFilter> _columnFilter = getLinearColumnFilter(_bufType, _dstType, columnKernel, _anchor.y, ctype, _delta, bits );return Ptr<FilterEngine>( new FilterEngine(Ptr<BaseFilter>(), _rowFilter, _columnFilter,_srcType, _dstType, _bufType, _rowBorderType, _columnBorderType, _borderValue ));
}

前2个参数是输入输出图像的格式,接下来2个参数是核分离出来的行向量和列向量。

函数返回一个FilterEngine对象,其中保存了一些需要的信息。

2,ocvSepFilter、sepFilter2D

static void ocvSepFilter(int stype, int dtype, int ktype,uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,int width, int height, int full_width, int full_height,int offset_x, int offset_y,uchar * kernelx_data, int kernelx_len,uchar * kernely_data, int kernely_len,int anchor_x, int anchor_y, double delta, int borderType)
{Mat kernelX(Size(kernelx_len, 1), ktype, kernelx_data);Mat kernelY(Size(kernely_len, 1), ktype, kernely_data);Ptr<FilterEngine> f = createSeparableLinearFilter(stype, dtype, kernelX, kernelY,Point(anchor_x, anchor_y),delta, borderType & ~BORDER_ISOLATED);Mat src(Size(width, height), stype, src_data, src_step);Mat dst(Size(width, height), dtype, dst_data, dst_step);f->apply(src, dst, Size(full_width, full_height), Point(offset_x, offset_y));
};

先创建FilterEngine对象,然后调用它的apply方法进行滤波。

void sepFilter2D(int stype, int dtype, int ktype,uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,int width, int height, int full_width, int full_height,int offset_x, int offset_y,uchar * kernelx_data, int kernelx_len,uchar * kernely_data, int kernely_len,int anchor_x, int anchor_y, double delta, int borderType)
{bool res = replacementSepFilter(stype, dtype, ktype,src_data, src_step, dst_data, dst_step,width, height, full_width, full_height,offset_x, offset_y,kernelx_data, kernelx_len,kernely_data, kernely_len,anchor_x, anchor_y, delta, borderType);if (res)return;ocvSepFilter(stype, dtype, ktype,src_data, src_step, dst_data, dst_step,width, height, full_width, full_height,offset_x, offset_y,kernelx_data, kernelx_len,kernely_data, kernely_len,anchor_x, anchor_y, delta, borderType);
}

调用ocvSepFilter

3,Sobel

void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,int ksize, double scale, double delta, int borderType )
{CV_INSTRUMENT_REGION();int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);if (ddepth < 0)ddepth = sdepth;int dtype = CV_MAKE_TYPE(ddepth, cn);_dst.create( _src.size(), dtype );int ktype = std::max(CV_32F, std::max(ddepth, sdepth));Mat kx, ky;getDerivKernels( kx, ky, dx, dy, ksize, false, ktype );if( scale != 1 ){// usually the smoothing part is the slowest to compute,// so try to scale it instead of the faster differentiating partif( dx == 0 )kx *= scale;elseky *= scale;}CV_OCL_RUN(ocl::isOpenCLActivated() && _dst.isUMat() && _src.dims() <= 2 && ksize == 3 &&(size_t)_src.rows() > ky.total() && (size_t)_src.cols() > kx.total(),ocl_sepFilter3x3_8UC1(_src, _dst, ddepth, kx, ky, delta, borderType));CV_OCL_RUN(ocl::isOpenCLActivated() && _dst.isUMat() && _src.dims() <= 2 && (size_t)_src.rows() > kx.total() && (size_t)_src.cols() > kx.total(),ocl_sepFilter2D(_src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType))Mat src = _src.getMat();Mat dst = _dst.getMat();Point ofs;Size wsz(src.cols, src.rows);if(!(borderType & BORDER_ISOLATED))src.locateROI( wsz, ofs );CALL_HAL(sobel, cv_hal_sobel, src.ptr(), src.step, dst.ptr(), dst.step, src.cols, src.rows, sdepth, ddepth, cn,ofs.x, ofs.y, wsz.width - src.cols - ofs.x, wsz.height - src.rows - ofs.y, dx, dy, ksize, scale, delta, borderType&~BORDER_ISOLATED);CV_OVX_RUN(true,openvx_sobel(src, dst, dx, dy, ksize, scale, delta, borderType))//CV_IPP_RUN_FAST(ipp_Deriv(src, dst, dx, dy, ksize, scale, delta, borderType));sepFilter2D(src, dst, ddepth, kx, ky, Point(-1, -1), delta, borderType );
}

前三个参数是输入图像、输出图像及深度,接下来2个参数是微分的阶。

三,相位相关法 phaseCorrelate

phaseCorrelate函数是利用相位相关法,给两张图片做频域配准。

1,phaseCorrelate

modules\imgproc\src\phasecorr.cpp

cv::Point2d cv::phaseCorrelate(InputArray _src1, InputArray _src2, InputArray _window, double* response)
{CV_INSTRUMENT_REGION();Mat src1 = _src1.getMat();Mat src2 = _src2.getMat();Mat window = _window.getMat();CV_Assert( src1.type() == src2.type());CV_Assert( src1.type() == CV_32FC1 || src1.type() == CV_64FC1 );CV_Assert( src1.size == src2.size);if(!window.empty()){CV_Assert( src1.type() == window.type());CV_Assert( src1.size == window.size);}int M = getOptimalDFTSize(src1.rows);int N = getOptimalDFTSize(src1.cols);Mat padded1, padded2, paddedWin;if(M != src1.rows || N != src1.cols){copyMakeBorder(src1, padded1, 0, M - src1.rows, 0, N - src1.cols, BORDER_CONSTANT, Scalar::all(0));copyMakeBorder(src2, padded2, 0, M - src2.rows, 0, N - src2.cols, BORDER_CONSTANT, Scalar::all(0));if(!window.empty()){copyMakeBorder(window, paddedWin, 0, M - window.rows, 0, N - window.cols, BORDER_CONSTANT, Scalar::all(0));}}else{padded1 = src1;padded2 = src2;paddedWin = window;}Mat FFT1, FFT2, P, Pm, C;// perform window multiplication if availableif(!paddedWin.empty()){// apply window to both images before proceeding...multiply(paddedWin, padded1, padded1);multiply(paddedWin, padded2, padded2);}// execute phase correlation equation// Reference: http://en.wikipedia.org/wiki/Phase_correlationdft(padded1, FFT1, DFT_REAL_OUTPUT);dft(padded2, FFT2, DFT_REAL_OUTPUT);mulSpectrums(FFT1, FFT2, P, 0, true);magSpectrums(P, Pm);divSpectrums(P, Pm, C, 0, false); // FF* / |FF*| (phase correlation equation completed here...)idft(C, C); // gives us the nice peak shift location...fftShift(C); // shift the energy to the center of the frame.// locate the highest peakPoint peakLoc;minMaxLoc(C, NULL, NULL, NULL, &peakLoc);// get the phase shift with sub-pixel accuracy, 5x5 window seems about right here...Point2d t;t = weightedCentroid(C, peakLoc, Size(5, 5), response);// max response is M*N (not exactly, might be slightly larger due to rounding errors)if(response)*response /= M*N;// adjust shift relative to image center...Point2d center((double)padded1.cols / 2.0, (double)padded1.rows / 2.0);return (center - t);
}

前两个参数是传2张图片,第三个是应用窗函数去除图像的边界效应,文档中推荐使用汉宁窗。

2,汉宁窗

void cv::createHanningWindow(OutputArray _dst, cv::Size winSize, int type)
{CV_INSTRUMENT_REGION();CV_Assert( type == CV_32FC1 || type == CV_64FC1 );CV_Assert( winSize.width > 1 && winSize.height > 1 );_dst.create(winSize, type);Mat dst = _dst.getMat();int rows = dst.rows, cols = dst.cols;AutoBuffer<double> _wc(cols);double* const wc = _wc.data();double coeff0 = 2.0 * CV_PI / (double)(cols - 1), coeff1 = 2.0f * CV_PI / (double)(rows - 1);for(int j = 0; j < cols; j++)wc[j] = 0.5 * (1.0 - cos(coeff0 * j));if(dst.depth() == CV_32F){for(int i = 0; i < rows; i++){float* dstData = dst.ptr<float>(i);double wr = 0.5 * (1.0 - cos(coeff1 * i));for(int j = 0; j < cols; j++)dstData[j] = (float)(wr * wc[j]);}}else{for(int i = 0; i < rows; i++){double* dstData = dst.ptr<double>(i);double wr = 0.5 * (1.0 - cos(coeff1 * i));for(int j = 0; j < cols; j++)dstData[j] = wr * wc[j];}}// perform batch sqrt for SSE performance gainscv::sqrt(dst, dst);
}

四,匹配器

opencv-4.2.0\modules\features2d\src\matchers.cpp中的代码:

1,纯虚类DescriptorMatcher

内含3种匹配算法:

class CV_EXPORTS_W DescriptorMatcher : public Algorithm
{
public:
CV_WRAP void match( InputArray queryDescriptors, InputArray trainDescriptors,CV_OUT std::vector<DMatch>& matches, InputArray mask=noArray() ) const;
CV_WRAP void knnMatch( InputArray queryDescriptors, InputArray trainDescriptors,CV_OUT std::vector<std::vector<DMatch> >& matches, int k,InputArray mask=noArray(), bool compactResult=false ) const;
CV_WRAP void radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors,CV_OUT std::vector<std::vector<DMatch> >& matches, float maxDistance,InputArray mask=noArray(), bool compactResult=false ) const;
CV_WRAP void match( InputArray queryDescriptors, CV_OUT std::vector<DMatch>& matches,InputArrayOfArrays masks=noArray() );
CV_WRAP void knnMatch( InputArray queryDescriptors, CV_OUT std::vector<std::vector<DMatch> >& matches, int k,InputArrayOfArrays masks=noArray(), bool compactResult=false );
CV_WRAP void radiusMatch( InputArray queryDescriptors, CV_OUT std::vector<std::vector<DMatch> >& matches, float maxDistance,InputArrayOfArrays masks=noArray(), bool compactResult=false );
。。。。。。
};

DescriptorMatcher内含纯虚函数clone()

match里面还是调knnMatch,所以实际上是knnMatch和radiusMatch两种算法。

2,子类FlannBasedMatcher

继承DescriptorMatcher

class CV_EXPORTS_W FlannBasedMatcher : public DescriptorMatcher
{
public:CV_WRAP FlannBasedMatcher( const Ptr<flann::IndexParams>& indexParams=makePtr<flann::KDTreeIndexParams>(),const Ptr<flann::SearchParams>& searchParams=makePtr<flann::SearchParams>() );
......
};

(1)clone

创建一个实例

(2)算法

算法没有重载,也没有重写,直接是父类的函数。

3,knnMatch算法

void DescriptorMatcher::knnMatch( InputArray queryDescriptors, InputArray trainDescriptors,std::vector<std::vector<DMatch> >& matches, int knn,InputArray mask, bool compactResult ) const
{CV_INSTRUMENT_REGION();Ptr<DescriptorMatcher> tempMatcher = clone(true);tempMatcher->add(trainDescriptors);tempMatcher->knnMatch( queryDescriptors, matches, knn, std::vector<Mat>(1, mask.getMat()), compactResult );
}
void DescriptorMatcher::knnMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,InputArrayOfArrays masks, bool compactResult )
{CV_INSTRUMENT_REGION();if( empty() || queryDescriptors.empty() )return;CV_Assert( knn > 0 );checkMasks( masks, queryDescriptors.size().height );train();knnMatchImpl( queryDescriptors, matches, knn, masks, compactResult );
}

核心功能用impl技术存在knnMatchImpl里面了。

相关文章:

Opencv源码解析(2)算法

目录 一&#xff0c;直方图均衡 1&#xff0c;直方图统计 2&#xff0c;灰度变换 3&#xff0c;直方图均衡 二&#xff0c;可分离滤波器 1&#xff0c;可分离滤波器的工厂 2&#xff0c;ocvSepFilter、sepFilter2D 3&#xff0c;Sobel 三&#xff0c;相位相关法 phase…...

让Mac菜单栏变得更加美观整洁——Bartender 5

Bartender 5是一款Mac电脑上的菜单栏图标管理软件&#xff0c;能够帮助您把菜单栏上的图标整理得更加美观、整洁和易于使用。如果您的菜单栏上充斥着许多图标&#xff0c;导致视觉上很不舒适和疲劳&#xff0c;那么Bartender 5就是解决这一问题的最佳选择&#xff01; Bartend…...

服务器迁移:无缝过渡指南

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…...

安卓开发中ViewBinding的使用

在安卓开发中&#xff0c;ViewBing 的作用就是简化 findViewById() 代码的写法。 看看下面的替换&#xff1a; etbinding.text //etfindViewById(R.id.text) 下面就看看怎么用的&#xff0c; 首先&#xff0c;打开app模块的build.gradle&#xff0c;然后添加如下代码&…...

【初阶数据结构】树(tree)的基本概念——C语言

目录 一、树&#xff08;tree&#xff09; 1.1树的概念及结构 1.2树的相关概念 1.3树的表示 1.4树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 二、二叉树的概念及结构 2.1二叉树的概念 2.2现实中真正的二叉树 2.3特殊的二叉树 2.4二叉树的性质…...

二叉树知识点

1.霍夫曼编码 这位作者写的很清楚 哈夫曼编码详解——图解真能看了秒懂_已知字符集abcdef,若各字符出现的次数_Young_IT的博客-CSDN博客 2.满二叉树与完全二叉树 满二叉树是指每层数量是pow(2,n-1)个节点&#xff0c;总节点数是pow(2,n)-1; 而完全二叉树是指最后一层不一定…...

Day69:283. 移动零、11. 盛最多水的容器、42. 接雨水

283. 移动零 leetcode链接&#xff1a;https://leetcode.cn/problems/move-zeroes/ 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。示例 1:…...

tensorrt的安装和使用

安装 提前安装好 CUDA 和 CUDNN&#xff0c;登录 NVIDIA 官方网站下载和主机 CUDA 版本适配的 TensorRT 压缩包即可。 以 CUDA 版本是 10.2 为例&#xff0c;选择适配 CUDA 10.2 的 tar 包&#xff0c;然后执行类似如下的命令安装并测试&#xff1a; #安装c版本 cd /the/pat…...

电压放大器在电子测试中的应用有哪些方面

电压放大器是一种常见的电子设备&#xff0c;广泛应用于各种测试和测量应用中。以下是电压放大器在电子测试中的几个主要方面应用的简要介绍。 信号采集与处理&#xff1a;电压放大器通常用于信号采集和处理&#xff0c;在测试过程中将低电平信号放大到适合进一步处理或分析的水…...

39.地址算术运算

如果p是一个指向数组中某个元素的指针&#xff0c;那么p将会对p进行自增运算并指向下一个元素&#xff0c;而pi将对p进行加i的增量运算&#xff0c;使其指向指针p当前所指向的元素之后的第i个元素。这类运算时指针或地址算术运算中最简单的形式。 allocbuf中的空间使用状况也是…...

没有外网的麒麟系统上搭建GitLab服务并且无需客户端账号密码验证

要在没有外网的麒麟系统上搭建GitLab服务并且无需客户端账号密码验证&#xff0c;可以按照以下步骤进行操作&#xff1a; 安装必要的依赖包和软件 sudo yum install curl policycoreutils-python openssh-server openssh-clients sudo systemctl enable sshd sudo systemctl …...

微服务生态系统:使用Spring Cloud构建分布式系统

文章目录 什么是微服务&#xff1f;为什么选择Spring Cloud&#xff1f;Spring Cloud的关键组件示例&#xff1a;构建一个简单的微服务步骤1&#xff1a;创建Spring Boot项目步骤2&#xff1a;配置Eureka服务发现步骤3&#xff1a;创建REST控制器步骤4&#xff1a;运行项目步骤…...

DIY 一个汽车方向盘游戏外设(MMOS OSW DIY)

OSW-MMOS直驱方向盘DIY过程记录 - 简书 (jianshu.com) DIY 一个汽车方向盘游戏外设&#xff08;MMOS OSW DIY&#xff09; 首先讲一下这个直驱系统大概的框架&#xff0c;首先是电脑&#xff0c;电脑里装MMOS的软件(这个软件国内高手把它汉化了的)&#xff0c;电脑通过USB线&a…...

校园网络技术需求分析

路由技术&#xff1a; 路由协议工作在 OSI 参考模型的第 3 层&#xff0c;因此它的作用主要是在通信 子网间路由数据包。路由器具有在网络中传递数据时选择最佳路径的能力。 除了可以完成主要的路由任务&#xff0c;利用访问控制列表&#xff08;Access Control List&#x…...

计算机网络(二):TCP篇

文章目录 1. TCP头部包含哪些内容&#xff1f;2. 为什么需要 TCP 协议&#xff1f; TCP 工作在哪一层&#xff1f;3. 什么是 TCP &#xff1f;4. 什么是 TCP 连接&#xff1f;5. 如何唯一确定一个 TCP 连接呢&#xff1f;6. UDP头部大小是多少&#xff1f;包含哪些内容&#xf…...

测试登录界面:Python

import unittest from selenium import webdriver class LoginTest(unittest.TestCase): def setUp(self): self.driver webdriver.Chrome() def test_login(self): # 打开登录页面 self.driver.get("http://example.com/login") # 输入用户名和密码 user…...

Rust踩雷笔记(7)——两个链表题例子初识裸指针

目录 leetcode 234leetcode 19 leetcode 234 题目在这https://leetcode.cn/problems/palindrome-linked-list/&#xff0c;leetcode 234的回文链表&#xff0c;思路很简单&#xff0c;就是fast和slow两个指针&#xff0c;fast一次移动两个、slow一次一个&#xff0c;最后slow指…...

用什么命令看Linux系统的体系架构

要查看Linux系统的体系架构&#xff0c;可以使用uname命令。在终端中运行以下命令&#xff1a; uname -m该命令将返回系统的体系架构&#xff0c;例如x86_64表示64位系统&#xff0c;i686表示32位系统。 uname 使用方法 uname命令用于获取操作系统的相关信息。它可以用于显示…...

消息中间件大揭秘:选择之前你必须知道的关键信息

Hello大家好&#xff01;我是小米&#xff0c;很高兴再次和大家见面&#xff01;今天的话题非常精彩&#xff0c;我们将深入探讨消息中间件&#xff0c;并了解一些常见的消息队列&#xff1a;RabbitMQ、RocketMQ、Kafka以及Redis。如果你正在准备面试&#xff0c;或者只是对这些…...

【Unity基础】4.动画Animation

【Unity基础】4.动画Animation 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity基础系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;Unity动画编辑器 &#xff08;1&#xff09;Animation组件 这一张我们要学习如何在unity编辑器中&…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...