【opencv】教程代码 —ShapeDescriptors

检测和显示图像的轮廓

在图像中搜索并显示轮廓边缘多边形、轮廓矩形和包围圆

获取包含检测到的轮廓的椭圆和旋转的矩形

图像轮廓检测和轮廓凸包

计算图像中的轮廓的矩(包括面积、重心等)并进行显示

创建和绘制一个多边形图像然后计算并显示图像上每个点到这个多边形的距离

1. findContours_demo.cpp 检测和显示图像的轮廓

6efdb6772fa527a33874acbd6e87befa.gif

b1649a014a26d49e2750d16f0fef0e2d.png

这段代码是使用OpenCV库来检测和显示图像的轮廓。这段代码中包含两个主要函数:main函数和thresh_callback函数。

1. main函数用于加载图像,将其转换为灰度图像并对其进行模糊处理,然后在窗口中显示原始图像并创建一个滑块来调整Canny边缘检测的阈值。主要步骤如下:

  • 加载图像:使用OpenCV函数imread加载图像。

  • 转换图像:使用cvtColor函数将图像从BGR色彩空间转换为灰度空间。之后,使用blur函数对图像进行模糊处理以消除噪声。

  • 创建并显示窗口:使用namedWindow和imshow函数创建窗口并显示源图像

  • 创建滑块:使用createTrackbar函数创建一个滑块来调整边缘检测的阈值

  • 调用thresh_callback函数。

2. thresh_callback函数用于边缘检测,找到并绘制轮廓。主要步骤如下:

  • 边缘检测:通过Canny函数检测边缘。

  • 找到轮廓:使用findContours函数找到图像中的轮廓。

  • 绘制轮廓:初始化一个与原图大小、类型相同的全零矩阵。然后在该矩阵上绘制找到的轮廓。每个轮廓有不同的颜色。

  • 显示窗口:调用imshow函数显示绘制过的轮廓图像。
    最后,代码中还编写了一些错误处理机制,例如,如果找不到图像,则返回-1并退出程序。

/**
 * @function findContours_Demo.cpp
 * @brief 这是一个演示如何在图像中找到轮廓的示例代码
 * @author OpenCV团队
 */


#include "opencv2/imgcodecs.hpp" // 引入opencv图像编解码库
#include "opencv2/highgui.hpp" // 引入opencv高级GUI库
#include "opencv2/imgproc.hpp" // 引入opencv图像处理库
#include <iostream> // 引入标准输入输出库


using namespace cv; // 使用cv命名空间,该命名空间包含所有OpenCV函数和类
using namespace std; // 使用std命名空间,该命名空间包含所有标准C++库函数和类


Mat src_gray; // 声明全局变量src_gray,用于存储灰度图像
int thresh = 100; // 声明全局变量thresh,设定轮廓检测的阈值
RNG rng(12345); // 初始化随机数生成器


/// 函数声明
void thresh_callback(int, void* );


/**
 * @function main
 */
int main( int argc, char** argv ) // 主函数
{
    /// 加载源图像
    CommandLineParser parser( argc, argv, "{@input | HappyFish.jpg | input image}" ); // 创建命令行解析器,解析输入的图像文件路径
    Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) ); // 读取图像文件
    if( src.empty() ) // 如果读取的图像为空
    {
      cout << "Could not open or find the image!\n" << endl; // 输出错误信息
      cout << "Usage: " << argv[0] << " <Input image>" << endl; // 输出正确的使用方法
      return -1;
    }


    /// 将图像转换为灰度图并进行模糊处理
    cvtColor( src, src_gray, COLOR_BGR2GRAY ); // 将图像转换为灰度图
    blur( src_gray, src_gray, Size(3,3) ); // 对图像进行模糊处理,减少噪声


    /// 创建窗口
    const char* source_window = "Source"; // 源图像窗口的名称
    namedWindow( source_window ); // 创建源图像窗口
    imshow( source_window, src ); // 显示源图像


    const int max_thresh = 255; // 设定最大阈值
    createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback ); // 创建滑动条,调节Canny检测器的阈值
    thresh_callback( 0, 0 ); // 调用thresh_callback函数,进行轮廓检测


    waitKey(); // 等待用户按键,以便可以看到图像
    return 0;
}


/**
 * @function thresh_callback
 * 轮廓检测回调函数
 */
void thresh_callback(int, void* )
{
    /// 使用Canny算子检测边缘
    Mat canny_output; // 声明变量,存储Canny检测结果
    Canny( src_gray, canny_output, thresh, thresh*2 ); // 运用Canny算子进行边缘检测


    /// 查找轮廓
    vector<vector<Point> > contours; // 存储找到的轮廓
    vector<Vec4i> hierarchy; // 存储轮廓的层级信息
    findContours( canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE ); // 查找轮廓


    /// 绘制轮廓
    Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); // 创建空白画布,用来绘制轮廓
    for( size_t i = 0; i< contours.size(); i++ ) // 遍历找到的所有轮廓
    {
        Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) ); // 生成随机颜色
        drawContours( drawing, contours, (int)i, color, 2, LINE_8, hierarchy, 0 ); // 在drawing上绘制轮廓
    }


    /// 显示在窗口中
    imshow( "Contours", drawing ); // 显示绘制轮廓后的画面
}

这段代码主要功能是载入一个图像进行灰度和模糊处理,然后使用Canny算子进行边缘检测,并找出图像的轮廓,最后将轮廓在窗口中显示出来。图像的路径可以通过命令行参数传入,如果没有参数则默认加载名为"HappyFish.jpg"的图像。在检测轮廓的过程中,可以通过滑动条实时调整Canny算子的阈值,以达到最佳的轮廓检测效果。

83dee4d9b43cfd02735832deac29381a.png

38729636d2592496dbb15969bd6471fb.png

2. generalContours_demo1.cpp在图像中搜索并显示轮廓边缘多边形、轮廓矩形和包围圆

ea4c380adf2f8b538ebbf0884d281ca3.gif

c590768d0e6f1ea49562850db828c411.png

这段代码主要用于在图像中寻找轮廓。作者使用OpenCV库编写了代码。下面是我对您提供的代码片段的详细解析和总结:

整个代码中包含两个主要函数:"main" 和 "thresh_callback"。

  1. "main" 函数:

该函数的主要任务是加载图片,将图片转换为灰度图像,模糊处理,并创建窗口显示源图像。接着创建了一个滑条用于调节阈值。完成以上设置后,程序将调用“thresh_callback”回调函数处理边缘检测和轮廓提取。最后,通过waitKey()函数等待用户按键操作。

关键过程如下:
- 加载图像: 使用imread函数读取输入的图像文件。
- 灰度转换: 调用cvtColor函数将RGB图像转化为灰度图像。
- 模糊处理: 使用blur函数对灰度图像进行模糊处理,以去除图像中的噪声。
- 显示窗口: 使用namedWindow创建一个图像窗口,imshow在该窗口中显示源图像。
- 创建滑条: 使用createTrackbar函数创建了滑动条,可以调节Canny边缘检测阈值。

  1. "thresh_callback" 函数:

这个函数执行的主要任务是使用Canny算法进行边缘检测,接着找到图像的轮廓。最后,通过绘制多边形轮廓,包围矩形和圆,将处理后的图像显示在窗口中。

关键过程如下:
- 边缘检测: 调用Canny函数对图像进行边缘检测,生成边缘图像。
- 轮廓提取: 使用findContours函数在二值化图像canny_output中寻找轮廓。
- 对轮廓进行处理: 利用approxPolyDP将轮廓近似为多边形,使用boundingRect获取轮廓的最小外接矩形,使用minEnclosingCircle获取轮廓的最小外接圆。
- 绘制结果:绘制所有的包围矩形,圆和对应的多边形轮廓到图像上。
- 结果展示: 使用imshow函数在窗口中展示处理结果。

/**
 * @function generalContours_demo1.cpp
 * @brief Demo code to find contours in an image(用于在图片中找到轮廓的演示代码)
 * @author OpenCV team (OpenCV团队)
 */


#include "opencv2/imgcodecs.hpp"  // 引入处理图像编码的头文件
#include "opencv2/highgui.hpp"    // 引入GUI的头文件
#include "opencv2/imgproc.hpp"    // 引入处理图像的头文件
#include <iostream>               // 引入基础输入输出流的头文件


using namespace cv;               // 使用cv命名空间
using namespace std;              // 使用std命名空间


Mat src_gray;                     // 声明灰度图像对象
int thresh = 100;                 // 设置阈值
RNG rng(12345);                   // 初始化随机数生成器


/// Function header
void thresh_callback(int, void* );// 声明阈值处理函数


/**
 * @function main
 */
int main( int argc, char** argv ) // 主函数开始
{
    /// Load source image (加载源图片)
    CommandLineParser parser( argc, argv, "{@input | stuff.jpg | input image}" );
    Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );
    if( src.empty() ) // 如果无法加载图片,则输出错误信息并返回-1退出程序
    {
        cout << "Could not open or find the image!\n" << endl;
        cout << "usage: " << argv[0] << " <Input image>" << endl;
        return -1;
    }


    /// Convert image to gray and blur it (将图片转为灰度并进行模糊处理)
    cvtColor( src, src_gray, COLOR_BGR2GRAY ); // BGR转换成灰度
    blur( src_gray, src_gray, Size(3,3) );  // 对灰度图进行模糊处理


    /// Create Window (创建窗口)
    const char* source_window = "Source";
    namedWindow( source_window );
    imshow( source_window, src );  // 展示原图


    /// Create Trackbar (创建滑动条)
    const int max_thresh = 255;
    createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
    thresh_callback( 0, 0 );  // 调用阈值处理函数


    waitKey();  // 等待用户操作
    return 0;   // 程序正常退出
}


/**
 * @function thresh_callback
 */
void thresh_callback(int, void* ) // 阈值处理函数定义
{
    /// Detect edges using Canny (使用Canny算法进行边缘检测)
    Mat canny_output; 
    Canny( src_gray, canny_output, thresh, thresh*2 ); 


    /// Find contours (查找轮廓)
    vector<vector<Point> > contours;
    findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE ); 


    /// Approximate contours to polygons + get bounding rects and circles (将轮廓近似为多边形,并找到它们的边界矩形和圆)
    vector<vector<Point> > contours_poly( contours.size() );   // 用于存储多边形轮廓的向量
    vector<Rect> boundRect( contours.size() );                // 用于存储边界矩形的向量
    vector<Point2f>centers( contours.size() );                // 用于存储圆心的向量
    vector<float>radius( contours.size() );                   // 用于存储半径的向量


    for( size_t i = 0; i < contours.size(); i++ )  // 遍历每一个轮廓
    {
        approxPolyDP( contours[i], contours_poly[i], 3, true );  // 近似多边形
        boundRect[i] = boundingRect( contours_poly[i] );         // 计算边界矩形
        minEnclosingCircle( contours_poly[i], centers[i], radius[i] ); // 计算最小闭合圆
    }


    Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );   // 创建一个全零矩阵,用于绘制结果图


    /// Draw polygonal contour + bonding rects + circles (绘制多边形轮廓、边界矩形和圆)
    for( size_t i = 0; i< contours.size(); i++ )
    {
        Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) ); //生成随机颜色
        drawContours( drawing, contours_poly, (int)i, color );  // 绘制轮廓
        rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2 ); // 绘制矩形
        circle( drawing, centers[i], (int)radius[i], color, 2 ); // 绘制圆
    }


    /// Show in a window (显示结果图)
    imshow( "Contours", drawing );  // 显示轮廓图
}

这段代码是一个在图像中搜索并显示轮廓的OpenCV程序,它首先将给定图像转换为灰度图像,然后使用Canny算法检测其边缘,进而使用函数findContours查找这些边缘。找到的边缘以多边形形式近似,并计算其边界矩形和包围圆。最后,所有的轮廓、边框矩形和包围圆都绘制在一张空白图像上并显示出来。

3. generalContours_demo2.cpp 获取包含检测到的轮廓的椭圆和旋转的矩形

8bdb95084a0191e99d52d84c8e6d5365.gif

dec9b4028e5b2c7e50596db55d82ecc2.png

这段代码是一个OpenCV的演示程序,用于获取包含检测到的轮廓的椭圆和旋转的矩形。主要包含以下函数:

  1. thresh_callback: 该函数用于检测边缘及寻找轮廓,并通过minAreaRectfitEllipse方法获取每个轮廓的旋转矩阵和椭圆,然后绘制轮廓、椭圆和旋转矩形。

  2. main: 该函数用于加载源图像并转换为灰度图,然后进行模糊处理,最后创建一个窗口并在其中显示源图像。还在窗口中创建了一个跟踪条,用于调整Canny算法的阈值参数。

具体来讲,我来详细解释下这两个函数的工作流程与方法:

  • main: 首先加载输入的图像,并将其转换为灰度图像,然后对该灰度图像进行模糊处理。然后创建一个窗口在其中显示转换后的图像,并在这个窗口中创建一个跟踪条,来调整使用Canny方法进行边缘检测的阈值。在跟踪条的回调函数中,调用了thresh_callback方法进行边缘检测和轮廓寻找。

  • thresh_callback: 在这个函数中,首先使用Canny方法进行边缘检测。然后使用findContours方法寻找图像的轮廓。接着使用minAreaRect方法获取每个轮廓的最小面积旋转矩形,如果轮廓的点数大于5,则使用fitEllipse方法获取该轮廓的拟合椭圆。然后创建一个全零的Mat对象,然后在这个Mat对象上绘制轮廓、椭圆及旋转矩形。最后将这个Mat对象在窗口中显示。

该程序主要用于练习边缘检测、寻找轮廓以及如何在寻找到的轮廓上拟合旋转矩形和椭圆。

/** 
* @function generalContours_demo2.cpp 
* @brief   这是一个演示代码,用于获取包含检测到的轮廓的椭圆和旋转矩形 
* @author  OpenCV 团队 
*/ 


#include "opencv2/imgcodecs.hpp"   // 包括OpenCV的读写头文件
#include "opencv2/highgui.hpp"     // 包括OpenCV的GUI头文件
#include "opencv2/imgproc.hpp"     // 包括OpenCV的图像处理头文件
#include <iostream>                // 包括输入输出流头文件


using namespace cv;               // 声明使用OpenCV的命名空间
using namespace std;              // 声明使用标准模板库命名空间


Mat src_gray;                     // 创建一个空的Mat对象,用于存放灰度图像
int thresh = 100;                 // 设定初始阈值为100
RNG rng(12345);                   // 创建一个随机数生成器对象


/// 函数声明
void thresh_callback(int, void* );


/**
 * @function main
 */
int main( int argc, char** argv )
{
    /// 加载源图像并转化为灰度 
    CommandLineParser parser( argc, argv, "{@input | stuff.jpg | input image}" );
    Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );
    if( src.empty() )                  // 检查读取的图像是否为空
    {
        cout << "Could not open or find the image!\n" << endl;         // 输出错误信息
        cout << "Usage: " << argv[0] << " <Input image>" << endl;      // 提示正确的使用方式
        return -1;
    }


    /// 将图像转化为灰度图并模糊处理
    cvtColor( src, src_gray, COLOR_BGR2GRAY );       // 将图像从BGR色彩空间转化为灰度空间
    blur( src_gray, src_gray, Size(3,3) );           // 对图像进行模糊(平滑)处理


    /// 创建窗口 
    const char* source_window = "Source";
    namedWindow( source_window );
    imshow( source_window, src );


    const int max_thresh = 255;                      // 设定阈值调节的最大值
    createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
    thresh_callback( 0, 0 );


    waitKey();                              // 等待键盘操作
    return 0;
}


/**
 * @function thresh_callback
 */
void thresh_callback(int, void* )
{
    /// 用Canny算子进行边缘检测
    Mat canny_output;
    Canny( src_gray, canny_output, thresh, thresh*2 );


    /// 找到轮廓
    vector<vector<Point> > contours;
    findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );


    /// 计算每个轮廓对应的旋转矩形和椭圆形状
    vector<RotatedRect> minRect( contours.size() );           // 创建一个旋转矩形的向量,数量等于轮廓数量
    vector<RotatedRect> minEllipse( contours.size() );        // 创建一个轮廓对应椭圆的向量,数量等于轮廓数量
    for( size_t i = 0; i < contours.size(); i++ )             // 遍历每一个轮廓
    {
        minRect[i] = minAreaRect( contours[i] );              // 计算每个轮廓的最小区域旋转矩形
        if( contours[i].size() > 5 )                          // 当轮廓包含的点多于5个时,即可以拟合为椭圆
        {
            minEllipse[i] = fitEllipse( contours[i] );         // 计算每个轮廓的拟合椭圆
        }
    }


    /// 画出轮廓 + 旋转矩形 + 椭圆
    Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );     // 创建一个空白画布,尺寸与canny_output相同
    for( size_t i = 0; i< contours.size(); i++ )
    {
        Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );   // 生成一个随机颜色
        // 画出轮廓
        drawContours( drawing, contours, (int)i, color );
        // 画出椭圆
        ellipse( drawing, minEllipse[i], color, 2 );
        // 画出旋转矩形
        Point2f rect_points[4];
        minRect[i].points( rect_points );
        for ( int j = 0; j < 4; j++ )
        {
            line( drawing, rect_points[j], rect_points[(j+1)%4], color );
        }
    }


    /// 在窗口中展示结果 
    imshow( "Contours", drawing );
}

此代码段是一个 OpenCV 的示例,演示了如何查找图像中的所有轮廓并查找每个轮廓的最小区域旋转矩形和拟合椭圆。在迭代访问每个轮廓的过程中,根据轮廓大小检查是否可以拟合椭圆(轮廓中的点数大于5)。最后,它会在新创建的 Mat 对象上绘制轮廓、旋转的矩形和椭圆,然后在窗口中显示这个 Mat 对象。

4. hull_demo.cpp 图像轮廓检测和轮廓凸包

7fb85f235b40cf7e93815b6ba8242432.gif

e1015637517e7bfdcf93ec1d9a5c2f0e.png

/**
 * @function hull_demo.cpp   // 声明hull_demo.cpp这个函数
 * @brief Demo code to find contours in an image    // 对图像进行轮廓检测的演示代码
 * @author OpenCV team   // 作者为OpenCV团队
 */


#include "opencv2/imgcodecs.hpp"  // 导入编解码库
#include "opencv2/highgui.hpp"  // 导入高级GUI库
#include "opencv2/imgproc.hpp"  // 导入图像处理库
#include <iostream>   // 导入输入输出库


using namespace cv;
using namespace std;


Mat src_gray;    // 定义源图像的灰度图
int thresh = 100;    // 定义阈值为100
RNG rng(12345);  // 定义一个随机数


/// Function header
void thresh_callback(int, void* );   // 声明一个阈值回调函数


/**
 * @function main   // 主函数
 */
int main( int argc, char** argv )
{
    /// Load source image and convert it to gray  // 加载源图像并转化为灰度图
    CommandLineParser parser( argc, argv, "{@input | stuff.jpg | input image}" );
    Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );
    if( src.empty() )
    {
        cout << "Could not open or find the image!\n" << endl;
        cout << "Usage: " << argv[0] << " <Input image>" << endl;
        return -1;
    }


    /// Convert image to gray and blur it // 将图像转为灰度并进行模糊处理
    cvtColor( src, src_gray, COLOR_BGR2GRAY );
    blur( src_gray, src_gray, Size(3,3) );


    /// Create Window // 创建窗口
    const char* source_window = "Source";
    namedWindow( source_window );
    imshow( source_window, src );


    const int max_thresh = 255; // 定义阈值上限
    createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback ); // 创建滑动条
    thresh_callback( 0, 0 );


    waitKey(); // 等待用户按键退出
    return 0;
}


/**
 * @function thresh_callback // 阈值回调函数
 */
void thresh_callback(int, void* )
{
    /// Detect edges using Canny  // 使用Canny方法进行边缘检测
    Mat canny_output;
    Canny( src_gray, canny_output, thresh, thresh*2 );


    /// Find contours // 寻找轮廓
    vector<vector<Point> > contours;
    findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );


    /// Find the convex hull object for each contour // 对每个轮廓寻找凸包物体
    vector<vector<Point> >hull( contours.size() );
    for( size_t i = 0; i < contours.size(); i++ )
    {
        convexHull( contours[i], hull[i] );
    }


    /// Draw contours + hull results // 将轮廓和凸包结果绘制出来
    Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
    for( size_t i = 0; i< contours.size(); i++ )
    {
        Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
        drawContours( drawing, contours, (int)i, color );
        drawContours( drawing, hull, (int)i, color );
    }


    /// Show in a window // 在窗口中显示结果
    imshow( "Hull demo", drawing );
}

上述代码是一个使用OpenCV进行图像轮廓检测的示例。主函数中先将图像从彩色图转化为灰度图,并进行了模糊处理,然后通过Canny边缘检测器寻找图像的边缘,定义阈值滑动条来动态改变Canny检测的阈值。接着通过findContours函数找到所有的轮廓,convexHull函数找到每个轮廓的凸包物体,最后将所有的轮廓和凸包物体绘制在一个全黑的图像上,颜色随机生成,然后在窗口中展示出来。

5. moments_demo.cpp计算图像中的轮廓的矩(包括面积、重心等)并进行显示

3faad7270ef112785b695643105a7817.gif

3187088d8e0fddb5a5417e3c3ee80711.png

此源文件是用来演示如何使用OpenCV库进行图像轮廓分析的。其中定义了两个函数:mainthresh_callback

  1. main函数是程序的入口函数。尝试从命令行参数中读取输入的图像文件(如果没有给出图像,则默认读取stuff.jpg),然后将图像转化为灰度图,最后对其进行模糊处理。创建一个窗口显示原始图像,并创建一个滑动条来调整Canny算子阈值。然后调用thresh_callback函数对图像进行处理,并等待用户关闭窗口。

  2. thresh_callback函数负责接受Canny算子阈值,并使用该值对灰度图像进行边缘检测。然后,它找到检测到的边缘的轮廓,并计算出这些轮廓的几何中心。最后,它在一个新的图像上绘制出这些轮廓,并在每个轮廓的几何中心处画一个圆点。画出的图像会在一个新窗口中显示出来。然后,此函数将根据计算出来的几何中心,对于每一个轮廓,打印其面积(即轮廓内部的像素点数)以及轮廓的长度(即轮廓上的像素点数)。

/**
 * @function moments_demo.cpp
 * @brief 演示如何计算图像的矩
 * @author OpenCV团队
 */


#include "opencv2/imgcodecs.hpp"       // 引入OpenCV中用于图像编码解码的函数库
#include "opencv2/highgui.hpp"         // 引入OpenCV中用于创建GUI界面的函数库
#include "opencv2/imgproc.hpp"         // 引入OpenCV的图像处理库
#include <iostream>                    // 引入C++标准库中提供的函数对象来进行输入/输出的库
#include <iomanip>                     // 


using namespace cv;                   // 使用OpenCV中的所有函数和类
using namespace std;                  // 使用C++标准库中的所有函数和类


Mat src_gray;                         // 定义存储灰度图的Mat类型变量
int thresh = 100;                     // 定义阈值
RNG rng(12345);                       // 定义随机数生成器


/// 函数声明
void thresh_callback(int, void* );


/**
 * @function main
 * 主函数
 */
int main( int argc, char** argv )
{
    /// 加载源图片
    CommandLineParser parser( argc, argv, "{@input | stuff.jpg | input image}" );
    // 读取图片
    Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );


    if( src.empty() ) // 如果图片为空
    {
        cout << "Could not open or find the image!\n" << endl; // 打印错误信息
        cout << "usage: " << argv[0] << " <Input image>" << endl; // 打印使用说明
        return -1; // 返回-1退出
    }


    /// 将图片转换为灰度图并进行模糊处理
    cvtColor( src, src_gray, COLOR_BGR2GRAY ); // 转为灰度图
    blur( src_gray, src_gray, Size(3,3) );     // 进行模糊处理


    /// 创建窗口
    const char* source_window = "Source";      // 定义窗口名称
    namedWindow( source_window );              // 创建窗口
    imshow( source_window, src );              // 在窗口中显示图像


    const int max_thresh = 255;                // 定义最大阈值
    // 创建阈值滑动条,并绑定thresh_callback函数
    createTrackbar( "Canny thresh:", source_window, &thresh, max_thresh, thresh_callback );
    // 调用thresh_callback函数
    thresh_callback( 0, 0 );


    // 等待用户动作
    waitKey();
    return 0;
}


/**
 * @function thresh_callback
 * 阈值回调函数
 */
void thresh_callback(int, void* )
{
    /// 使用Canny算子检测边缘
    Mat canny_output;                       // 声明一个Mat对象用来存储Canny检测的结果
    Canny( src_gray, canny_output, thresh, thresh*2, 3 ); // 执行Canny边缘检测


    /// 寻找轮廓
    vector<vector<Point> > contours; // 定义容器存储寻找到的轮廓
    // 使用findContours函数在二值图像中寻找轮廓
    findContours( canny_output, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );


    /// 计算矩
    vector<Moments> mu(contours.size() ); // 定义一个容器存储所有轮廓的矩
    for( size_t i = 0; i < contours.size(); i++ ) // 遍历所有的轮廓
    {
        mu[i] = moments( contours[i] );   // 计算每一个轮廓的矩
    }


    /// 获取质心
    vector<Point2f> mc( contours.size() ); // 申明一个容器存储每一个轮廓的质心
    for( size_t i = 0; i < contours.size(); i++ ) // 遍历所有轮廓
    {
        // 计算每个轮廓的质心,避免零除错误
        mc[i] = Point2f( static_cast<float>(mu[i].m10 / (mu[i].m00 + 1e-5)),
                         static_cast<float>(mu[i].m01 / (mu[i].m00 + 1e-5)) );
        cout << "mc[" << i << "]=" << mc[i] << endl; // 输出计算结果
    }


    /// 画出轮廓
    Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 ); // 创建一个用于绘制轮廓的黑色画布
    for( size_t i = 0; i< contours.size(); i++ ) // 遍历所有轮廓
    {
        // 随机生成颜色值
        Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
        drawContours( drawing, contours, (int)i, color, 2 ); // 将轮廓画到画布上
        circle( drawing, mc[i], 4, color, -1 );  // 将质心画到画布上
    }


    /// 在窗口中显示结果
    imshow( "Contours", drawing );


    /// 使用矩的00计算面积,并与OpenCV函数的结果比较
    cout << "\t Info: Area and Contour Length \n";
    for( size_t i = 0; i < contours.size(); i++ ) // 遍历所有轮廓
    {
        cout << " * Contour[" << i << "] - Area (M_00) = " << std::fixed << std::setprecision(2) << mu[i].m00
             << " - Area OpenCV: " << contourArea(contours[i]) << " - Length: " << arcLength( contours[i], true ) << endl;
    }
}

这段代码是使用OpenCV的C++接口进行图像处理的示例程序,它主要的功能是计算图像中的轮廓的矩(包括面积、重心等)并进行显示。具体步骤包括:读入图像、转成灰度图、进行模糊处理、使用Canny算法进行边缘检测、寻找和绘制轮廓、计算轮廓的矩并获取质心、比较矩计算的面积和OpenCV函数计算的面积。

终端输出:

mc[0]=[328.222, 331.944]
mc[1]=[334.476, 323.523]
mc[2]=[213.035, 312.397]
mc[3]=[194.211, 171.352]
mc[4]=[75.8505, 101.182]
mc[5]=[75.9116, 101.259]
mc[6]=[197.533, 57.6664]
mc[7]=[197.166, 64.3331]
mc[8]=[225.274, 57.9121]
         Info: Area and Contour Length
 * Contour[0] - Area (M_00) = 9.00 - Area OpenCV: 9.00 - Length: 148.08
 * Contour[1] - Area (M_00) = 7.00 - Area OpenCV: 7.00 - Length: 140.77
 * Contour[2] - Area (M_00) = 23.50 - Area OpenCV: 23.50 - Length: 176.75
 * Contour[3] - Area (M_00) = 269.00 - Area OpenCV: 269.00 - Length: 1217.62
 * Contour[4] - Area (M_00) = 233.00 - Area OpenCV: 233.00 - Length: 80.91
 * Contour[5] - Area (M_00) = 207.50 - Area OpenCV: 207.50 - Length: 72.67
 * Contour[6] - Area (M_00) = 2.50 - Area OpenCV: 2.50 - Length: 35.56
 * Contour[7] - Area (M_00) = 3.00 - Area OpenCV: 3.00 - Length: 38.97
 * Contour[8] - Area (M_00) = 64.50 - Area OpenCV: 64.50 - Length: 511.63
mc[0]=[328.22, 331.94]
mc[1]=[334.48, 323.52]
mc[2]=[213.04, 312.40]
mc[3]=[194.21, 171.35]
mc[4]=[75.85, 101.18]
mc[5]=[75.91, 101.26]
mc[6]=[197.53, 57.67]
mc[7]=[197.17, 64.33]
mc[8]=[225.27, 57.91]
         Info: Area and Contour Length
 * Contour[0] - Area (M_00) = 9.00 - Area OpenCV: 9.00 - Length: 148.08
 * Contour[1] - Area (M_00) = 7.00 - Area OpenCV: 7.00 - Length: 140.77
 * Contour[2] - Area (M_00) = 23.50 - Area OpenCV: 23.50 - Length: 176.75
 * Contour[3] - Area (M_00) = 269.00 - Area OpenCV: 269.00 - Length: 1217.62
 * Contour[4] - Area (M_00) = 233.00 - Area OpenCV: 233.00 - Length: 80.91
 * Contour[5] - Area (M_00) = 207.50 - Area OpenCV: 207.50 - Length: 72.67
 * Contour[6] - Area (M_00) = 2.50 - Area OpenCV: 2.50 - Length: 35.56
 * Contour[7] - Area (M_00) = 3.00 - Area OpenCV: 3.00 - Length: 38.97
 * Contour[8] - Area (M_00) = 64.50 - Area OpenCV: 64.50 - Length: 511.63
mc[0]=[328.22, 331.94]
mc[1]=[334.48, 323.52]
mc[2]=[213.04, 312.40]
mc[3]=[194.21, 171.35]
mc[4]=[75.85, 101.18]
mc[5]=[75.91, 101.26]
mc[6]=[197.53, 57.67]
mc[7]=[197.17, 64.33]
mc[8]=[225.27, 57.91]
         Info: Area and Contour Length
 * Contour[0] - Area (M_00) = 9.00 - Area OpenCV: 9.00 - Length: 148.08
 * Contour[1] - Area (M_00) = 7.00 - Area OpenCV: 7.00 - Length: 140.77
 * Contour[2] - Area (M_00) = 23.50 - Area OpenCV: 23.50 - Length: 176.75
 * Contour[3] - Area (M_00) = 269.00 - Area OpenCV: 269.00 - Length: 1217.62
 * Contour[4] - Area (M_00) = 233.00 - Area OpenCV: 233.00 - Length: 80.91
 * Contour[5] - Area (M_00) = 207.50 - Area OpenCV: 207.50 - Length: 72.67
 * Contour[6] - Area (M_00) = 2.50 - Area OpenCV: 2.50 - Length: 35.56
 * Contour[7] - Area (M_00) = 3.00 - Area OpenCV: 3.00 - Length: 38.97
 * Contour[8] - Area (M_00) = 64.50 - Area OpenCV: 64.50 - Length: 511.63
mc[0]=[328.22, 331.94]
mc[1]=[334.48, 323.52]
mc[2]=[213.04, 312.40]
mc[3]=[194.21, 171.35]
mc[4]=[75.85, 101.18]
mc[5]=[75.91, 101.26]
mc[6]=[197.53, 57.67]
mc[7]=[197.17, 64.33]
mc[8]=[225.27, 57.91]
         Info: Area and Contour Length
 * Contour[0] - Area (M_00) = 9.00 - Area OpenCV: 9.00 - Length: 148.08
 * Contour[1] - Area (M_00) = 7.00 - Area OpenCV: 7.00 - Length: 140.77
 * Contour[2] - Area (M_00) = 23.50 - Area OpenCV: 23.50 - Length: 176.75
 * Contour[3] - Area (M_00) = 269.00 - Area OpenCV: 269.00 - Length: 1217.62
 * Contour[4] - Area (M_00) = 233.00 - Area OpenCV: 233.00 - Length: 80.91
 * Contour[5] - Area (M_00) = 207.50 - Area OpenCV: 207.50 - Length: 72.67
 * Contour[6] - Area (M_00) = 2.50 - Area OpenCV: 2.50 - Length: 35.56
 * Contour[7] - Area (M_00) = 3.00 - Area OpenCV: 3.00 - Length: 38.97
 * Contour[8] - Area (M_00) = 64.50 - Area OpenCV: 64.50 - Length: 511.63
mc[0]=[328.22, 331.94]
mc[1]=[334.48, 323.52]
mc[2]=[213.04, 312.40]
mc[3]=[194.21, 171.35]
mc[4]=[75.85, 101.18]
mc[5]=[75.91, 101.26]
mc[6]=[197.53, 57.67]
mc[7]=[197.17, 64.33]
mc[8]=[225.27, 57.91]
         Info: Area and Contour Length
 * Contour[0] - Area (M_00) = 9.00 - Area OpenCV: 9.00 - Length: 148.08
 * Contour[1] - Area (M_00) = 7.00 - Area OpenCV: 7.00 - Length: 140.77
 * Contour[2] - Area (M_00) = 23.50 - Area OpenCV: 23.50 - Length: 176.75
 * Contour[3] - Area (M_00) = 269.00 - Area OpenCV: 269.00 - Length: 1217.62
 * Contour[4] - Area (M_00) = 233.00 - Area OpenCV: 233.00 - Length: 80.91
 * Contour[5] - Area (M_00) = 207.50 - Area OpenCV: 207.50 - Length: 72.67
 * Contour[6] - Area (M_00) = 2.50 - Area OpenCV: 2.50 - Length: 35.56
 * Contour[7] - Area (M_00) = 3.00 - Area OpenCV: 3.00 - Length: 38.97
 * Contour[8] - Area (M_00) = 64.50 - Area OpenCV: 64.50 - Length: 511.63
mc[0]=[328.22, 331.94]
mc[1]=[334.48, 323.52]
mc[2]=[213.04, 312.40]
mc[3]=[194.21, 171.35]
mc[4]=[75.88, 101.20]
mc[5]=[75.91, 101.26]
mc[6]=[197.53, 57.67]
mc[7]=[197.17, 64.33]
mc[8]=[225.27, 57.91]
         Info: Area and Contour Length
 * Contour[0] - Area (M_00) = 9.00 - Area OpenCV: 9.00 - Length: 148.08
 * Contour[1] - Area (M_00) = 7.00 - Area OpenCV: 7.00 - Length: 140.77
 * Contour[2] - Area (M_00) = 23.50 - Area OpenCV: 23.50 - Length: 174.75
 * Contour[3] - Area (M_00) = 269.00 - Area OpenCV: 269.00 - Length: 1217.62
 * Contour[4] - Area (M_00) = 232.50 - Area OpenCV: 232.50 - Length: 79.50
 * Contour[5] - Area (M_00) = 207.50 - Area OpenCV: 207.50 - Length: 72.67
 * Contour[6] - Area (M_00) = 2.50 - Area OpenCV: 2.50 - Length: 35.56
 * Contour[7] - Area (M_00) = 3.00 - Area OpenCV: 3.00 - Length: 38.97
 * Contour[8] - Area (M_00) = 64.50 - Area OpenCV: 64.50 - Length: 511.63

6. pointPolygonTest_demo.cpp 创建和绘制一个多边形图像然后计算并显示图像上每个点到这个多边形的距离

c20a5376d0b2c50103c2a58037a81fc2.png

这段代码是一个C++程序,使用了OpenCV库,主要实现了创建和绘制一个多边形图像然后计算并显示图像上每个点到这个多边形的距离

主要步骤如下:

  1. 创建一个4r x 4r的全零矩阵作为图像(r=100,因此图像的大小为400x400;

  2. 定义一个六边形的顶点,并将几何图形画在图像上;

  3. 使用 findContours 方法从图像中提取轮廓;

  4. 计算图像上每个点到轮廓的距离,并存储在一个单独的矩阵中;

  5. 查找离多边形最远和最近的点,获取最大和最小的距离值;

  6. 为距离图像上色,表示点到多边形的距离,其中蓝色表示该点在多边形内部,红色表示在外部,白色表示在边界上;

  7. 在距离最远的点处画一个圆,圆心为此点,半径为最大距离;

  8. 最后展示原始图像和距离图像。

典型的方法和数据结构包括:

  1. Mat:是OpenCV库中的一个主要数据结构,用于存储图像和矩阵数据;

  2. Point:OpenCV中的一个数据结构,储存2D点的坐标(x,y);

  3. findContours:OpenCV的一个函数,用于在二值图像中查找轮廓;

  4. pointPolygonTest:OpenCV中的一个函数,用于计算2D点到一个多边形的最短距离;

  5. imshow:OpenCV的一个函数,用于显示图像;

  6. waitKey:OpenCV的一个函数,用于等待用户按键,如果没有这行代码,imshow显示的图像窗口会立即消失;如果参数为0,表示窗口将持续显示,直到用户关闭它为止。

同时需要注意的是,这段代码只针对单通道黑白图像进行处理。如果要处理多通道图像,还需要进行相应的修改。

/**
 * @function pointPolygonTest_demo.cpp     //定义了程序的入口函数main函数
 * @brief Demo用来距离检测函数示例——相当简单         //描述了这段代码的主要功能
 * @author OpenCV team    //说明这段代码的作者
 */


// 导入opencv的用户选择界面(UI)库和图像处理库
#include "opencv2/highgui.hpp"        
#include "opencv2/imgproc.hpp"


// 导入C++标准输入输出库
#include <iostream>                     


// 名字空间的定义,方便在代码中使用opencv和std库的函数和对象
using namespace cv;                   
using namespace std;                  


/**
 * @function main   //定义了程序的入口函数main函数
 */
int main( void )                     //定义了程序的入口函数main函数
{
    /// 创建一个图像
    // 初始化图像src的大小与类型 
    const int r = 100;                                       //定义了一个常量r,用于确定绘制图形边长的依赖参数
    Mat src = Mat::zeros( Size( 4*r, 4*r ), CV_8U );         //使用opencv的Mat类创建一个4r*4r大小的8位无符号整型全黑色(所有像素值都为0)图像,作为绘制六边形的画布


    /// 创建一系列的坐标点来生成一个轮廓
    // 建立一个包含6个Point2f对象的vert数组,用于存储六边形的六个顶点坐标
    vector<Point2f> vert(6);


    // 为数组的每个元素赋值,确定各顶点的坐标
    vert[0] = Point( 3*r/2, static_cast<int>(1.34*r) ); 
    vert[1] = Point( 1*r, 2*r );
    vert[2] = Point( 3*r/2, static_cast<int>(2.866*r) );
    vert[3] = Point( 5*r/2, static_cast<int>(2.866*r) );
    vert[4] = Point( 3*r, 2*r );
    vert[5] = Point( 5*r/2, static_cast<int>(1.34*r) );


    /// 在src上绘制图形
    // 对vert数组中的每个元素都执行循环操作,用line函数在src图像上绘制从第i个顶点到下一个顶点的线段,颜色为白色,线条粗细为3。总的效果就是在src上绘制了一个白色边框的六边形
    for( int i = 0; i < 6; i++ )
    {
        line( src, vert[i],  vert[(i+1)%6], Scalar( 255 ), 3 );
    }


    /// 获取轮廓
    // 建立一个contours二维数组,作为存储src中所有轮廓的容器
    vector<vector<Point> > contours;


    // 使用findContours方法在src图像中寻找轮廓,findContours会先使用阈值将图像二值化,然后寻找二值化图像中的轮廓。经过该操作后,contours中将包含src图像中所有轮廓的顶点坐标的列表
    findContours( src, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);


    /// 计算到轮廓的最短距离
    // 创建raw_dist图像,用于存储src中每个点到最近轮廓的最短距离
    Mat raw_dist( src.size(), CV_32F );


    // 对src中的每个像素都执行循环操作:
    for( int i = 0; i < src.rows; i++ )
    {
        for( int j = 0; j < src.cols; j++ )
        {
            // 使用pointPolygonTest方法计算src中点(j,i)到最近轮廓的最短距离,然后将计算结果存入raw_dist相应位置
            raw_dist.at<float>(i,j) = (float)pointPolygonTest( contours[0], Point2f((float)j, (float)i), true );
        }
    }


    // 创建minVal和maxVal两个变量,作为存储raw_dist中的最小值和最大值的容器
    double minVal, maxVal;


    // 创建maxDistPt对象,作为存储最大距离对应坐标的容器
    Point maxDistPt;


    // minMaxLoc方法会在raw_dist矩阵中寻找最小和最大值,然后分别赋值给minVal和maxVal。同时,minMaxLoc找到的最大值的坐标将赋值给maxDistPt
    minMaxLoc(raw_dist, &minVal, &maxVal, NULL, &maxDistPt);


    // minVal和maxVal都取绝对值
    minVal = abs(minVal);
    maxVal = abs(maxVal);
    
    // 创建drawing空白图像,用于后续的绘制操作
    Mat drawing = Mat::zeros( src.size(), CV_8UC3 );


    // 对于src图像中的每个像素,依次执行以下操作
    for( int i = 0; i < src.rows; i++ )
    {
        for( int j = 0; j < src.cols; j++ )
        {
            // 如果raw_dist中存储的距离值小于零,则在drawing中的对应位置绘制蓝色,蓝色程度按照距离值的绝对值的大小确定
            if( raw_dist.at<float>(i,j) < 0 )
            {
                drawing.at<Vec3b>(i,j)[0] = (uchar)(255 - abs(raw_dist.at<float>(i,j)) * 255 / minVal);
            }
            // 如果raw_dist中存储的距离值大于零,则在drawing中的对应位置绘制红色,红色程度按照距离值的大小确定
            else if( raw_dist.at<float>(i,j) > 0 )
            {
                drawing.at<Vec3b>(i,j)[2] = (uchar)(255 - raw_dist.at<float>(i,j) * 255 / maxVal);
            }
            // 如果raw_dist中存储的距离值等于零,则在drawing中的对应位置绘制白色
            else
            {
                drawing.at<Vec3b>(i,j)[0] = 255;
                drawing.at<Vec3b>(i,j)[1] = 255;
                drawing.at<Vec3b>(i,j)[2] = 255;
            }
        }
    }


    // 绘制一个以最大距离所在的点为圆心,最大距离为半径的白色圆形
    circle(drawing, maxDistPt, (int)maxVal, Scalar(255,255,255));


    /// 旋轉圖像
    imshow( "Source", src );                   //显示原始图像
    imshow( "Distance and inscribed circle", drawing ); //显示带距离颜色及内切圆或者外接圆的图像


    // 一直等待,直到用户按下任意键
    waitKey();
    // 返回程序退出状态值
    return 0;
}

以上提供了代码,主要是在OpenCV中使用pointPolygonTest函数来计算点和多边形之间的最短距离,并且在图中绘制了点和多边形的关系。该代码中使用了C++和OpenCV库,是一个实际的图像处理过程,具有一定的实用价值,尤其是在图像处理、机器视觉等领域。点到线的距离往往是一个重要的参考因素,可以用于轮廓识别、影像匹配和匹配评分等任务

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

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

相关文章

浮点数(小数)在计算机中如何用二进制存储?

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/137182814 出自【进步*于辰的博客】 注&#xff1a;为了阐述更加严谨&#xff0c;本篇文章中将使…

c语言例题,计算字符串长度,递归思想

c语言中&#xff0c;计算字符串长度算是一个比较经典的题了&#xff0c;而今天我们运用两种不同的求解方法来写出不同的程序来实现计算字符串的功能。 主函数 先看到主函数&#xff0c;主函数中设置了一串7个字符的字符串&#xff0c;而后面接下来定义了两个变量len1和len2&am…

【键值皆有序map 线段树 数学 】100240. 最小化曼哈顿距离

本文涉及知识点 键值皆有序map 线段树 数学 LeetCode100240. 最小化曼哈顿距离 给你一个下标从 0 开始的数组 points &#xff0c;它表示二维平面上一些点的整数坐标&#xff0c;其中 points[i] [xi, yi] 。 两点之间的距离定义为它们的曼哈顿距离。 请你恰好移除一个点&am…

【蓝桥杯第十三届省赛B】(部分详解)

九进制转十进制 #include <iostream> #include<math.h> using namespace std; int main() {cout << 2*pow(9,3)0*pow(9,2)2*pow(9,1)2*pow(9,0) << endl;return 0; }顺子日期 #include <iostream> using namespace std; int main() {// 请在此…

SOC内部集成网络MAC外设+ PHY网络芯片方案:MII/RMII 接口与 MDIO 接口

一. 简介 本文来了解一下常用的一种网络硬件方案&#xff1a;SOC内部集成网络MAC外设 PHY网络芯片方案。 其中涉及的 MII接口&#xff0c;RMII接口&#xff08;MII接口与RMII接口二选一&#xff09;&#xff0c;MDIO接口&#xff0c;RJ45。 二. MII/RMII 接口&#xff0c;M…

unity学习(74)——服务器Dispose异常

1.返回的1 2 11是怪物初始化&#xff0c;源代码中也没有 2. 3.客户端中的网络连接初始化如下&#xff1a; 4.不是因为超时&#xff0c;设置10s为超时期限后&#xff0c;客户端和服务器有时依然会报错&#xff01; 5.我感觉就是update中发包给弄坏的&#xff01; 6.不在“帧”…

【prometheus】k8s集群部署Grafana安装并接入Promethues数据源

目录 一、概述 1.1 优点 1.2 特点 二、grafana部署 三、grafana接入Promethues数据源 四、grafana可视化展示物理节点指标数据 五、grafana可视化展示k8s组件指标数据 5.1 kube-state-metrics简介 5.2 安装kube-state-metrics组件 一、概述 Grafana是一款用Go语言开发…

CodeTON Round 8 D. Learning to Paint 【DP求前k大】

D. Learning to Paint 题意 有一个 n n n 个格子长度的条带&#xff0c;格子从左到右编号为 1 → n 1 \rarr n 1→n&#xff0c;可以选择若干子段&#xff08;或不选&#xff09;的格子&#xff0c;给定一个二维数组 a a a 每选择一个 [ l i , r i ] [l_i,r_i] [li​,ri​…

5G无线接入网和接口协议

**部分笔记** 4.3无线协议架构 NR无线协议分为两个平面&#xff1a;用户面和控制面。 用户面&#xff08;UP&#xff09;:协议栈及用户数据采用的协议 控制面(Control Plane&#xff0c;CP)协议栈即系统的控制信令传输采用的协议簇。 虚线标注的是信令数据的流向。一个UE在…

[计算机效率] 文件加密工具:Lockdir

3.11 文件加密工具&#xff1a;Lockdir Lockdir是一款安全性高、使用简单、体积极小的便携式文件夹加密器&#xff0c;无需安装&#xff0c;一键加密&#xff0c;一键解密&#xff0c;加密算法高&#xff0c;是优秀的加密工具。其主要特点包括&#xff1a; 加密操作简易&#…

遥感动态监测技术

很多人对动态监测和动态检测两个名词有疑惑。我们可以这样理解&#xff0c;动态监测是一个广义的名词&#xff0c;泛指数据预处理、变化信息发现与提取、变化信息挖掘与应用等&#xff0c;以对整个流程的叙述。动态检测是一个狭义的名词&#xff0c;主要指部分数据预处理、变化…

Python | Leetcode Python题解之第4题寻找两个正序数组的中位数

题目&#xff1a; 题解&#xff1a; class Solution:def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:def getKthElement(k):"""- 主要思路&#xff1a;要找到第 k (k>1) 小的元素&#xff0c;那么就取 pivot1 nums1[k…

需要给Word文档中的汉字注音,拼音要在汉字的右边 要怎么操作?两种方法一学就会

在Word文档中&#xff0c;为字体添加拼音是一个常见的需求&#xff0c;特别是在处理包含生僻字或需要标注拼音的文本时。下面&#xff0c;我们将详细介绍如何在Word文档中将拼音加到字体的右边。 方法一&#xff1a;使用“汇帮注音大师”给汉字加拼音加到右边 第一步&#xf…

快速排序---算法

1、算法概念 快速排序&#xff1a;通过一趟排序将待排记录分隔成独立的两部分&#xff0c;其中一部分记录的数据均比另一部分的数据小&#xff0c;则可分别对这两部分记录继续进行排序&#xff0c;以达到震哥哥序列有序。 快速排序的最坏运行情况是O()&#xff0c;比如说顺序数…

整数删除,蓝桥杯训练题

题目描述: 给定一个长度为 N 的整数数列&#xff1a;A1,A2,…,AN。 你要重复以下操作 K 次&#xff1a; 每次选择数列中最小的整数&#xff08;如果最小值不止一个&#xff0c;选择最靠前的&#xff09;&#xff0c;将其删除&#xff0c;并把与它相邻的整数加上被删除的数值。 …

【前端面试3+1】06继承方式及优缺点、缓存策略、url输入到渲染全过程、【二叉树中序遍历】

一、继承有哪些方式&#xff1f;以及优缺点 继承的方式包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承和组合式继承。 1.原型链继承&#xff1a; 实现方式&#xff1a;将子类的原型指向父类的实例来实现继承。优点&#xff1a;简单易懂&#xff0c;代码量少。…

linux 一些命令

文章目录 linux 一些命令fdisk 磁盘分区parted 分区文件系统mkfs 格式化文件系统fsck 修复文件系统 mount 挂载swap 交换分区清除linux缓存df du 命令raid 命令基本原理硬raid 和 软raid案例raid 10 故障修复&#xff0c;重启与卸载 lvm逻辑卷技术LVM的使用方式LVM 常见名词解析…

wavedec2函数及使用

在MATLAB中&#xff0c;进行小波分解及其逆运算是处理图像的一种常见方法&#xff0c;尤其适用于图像分析、压缩和去噪等场景。wavedec2函数可以对二维信号&#xff08;例如图像&#xff09;进行多级小波分解&#xff0c;而waverec2函数则用于进行相应的逆运算。以下是如何使用…

【树状数组专题】【蓝桥杯备考训练】:数星星、动态求连续区间和、一个简单的整数问题、一个简单的整数问题2【已更新完成】

目录 1、数星星&#xff08;《信息学奥赛一本通》 & ural 1028&#xff09; 思路&#xff1a; 基本思路&#xff1a; 树状数组经典三函数&#xff1a; 1、lowbit()函数 2、query()函数 3、add()函数 最终代码&#xff1a; 2、动态求连续区间和&#xff08;《信息学奥赛一本…

笔记本三屏异显方案——更新中,是否能够在FPGA上实现,淘宝购物的价格太贵

三屏是&#xff08;笔记本电脑屏幕&#xff0c;两个显示器屏幕&#xff09;&#xff0c;异显是采用屏幕的扩展功能&#xff0c;这样能够左边看视频文章&#xff0c;右边control cv代码。 一、 电脑有一个HDMI口的时候&#xff0c;只需要买一个TypeC&#xff08;雷电接口&#x…