OpenCV实战(6)——OpenCV策略设计模式

news2024/11/17 6:33:38

OpenCV实战(6)——OpenCV策略设计模式

    • 0. 前言
    • 1. 策略设计模式颜色识别
      • 1.1 颜色比较
      • 1.2 策略设计模式
      • 1.3 实现颜色比较
      • 1.4 ColorDetector 类
      • 1.4 计算两个颜色向量之间的距离
    • 2. 使用 OpenCV 函数
    • 3. 函子或函数对象
    • 4. OpenCV 算法的基类
    • 小结
    • 系列链接

0. 前言

良好的计算机视觉程序始于良好的编程实践,构建无错误的应用程序只是一个开始。我们真正想要的是一个能够随着新需求的出现而轻松适应和发展的应用程序。本节将介绍如何充分利用一些面向对象的编程原则以构建高质量的软件程序,我们将学习一些重要的设计模式,帮助我们使用易于测试、维护和可重用的组件构建应用程序。
设计模式是软件工程中的一个常见概念,设计模式是针对软件设计中经常出现的通用问题的可靠的、可重用的解决方案。当前有许多设计模式在软件设计中被引入,我们应该对现有设计模式有所了解。

1. 策略设计模式颜色识别

1.1 颜色比较

假设我们想要构建一个简单的算法来识别图像中具有给定颜色的所有像素。为了达到目的,算法需要接受图像和颜色作为输入,并返回二值图像,其中在输入图像中与指定颜色相同的像素位置值为 1,否则为 0,例如,输入图像中位置 (1,1) 处的像素值与指定颜色相同,则在二值图像的 (1,1) 位置处像素值为 1。同时,函数也可以接受颜色容差作为参数。

1.2 策略设计模式

为了实现颜色比较,本节将使用策略设计模式,这种面向对象的设计模式将算法封装在类中。这比用另一种算法替换给定算法或将几种算法链接在一起以构建更复杂的过程更容易。此外,这种模式通过隐藏尽可能多的复杂性来简化算法的部署。
一旦使用策略设计模式将算法封装在一个类中,就可以通过创建该类的实例来部署它。通常,实例在程序初始化时创建。在构造的时候,类实例会用它们的默认值初始化算法的不同参数,也可以使用合适的方法读取和设置算法的参数值。对于具有 GUI 的应用程序,可以使用不同的小部件(文本、滑块等)来显示和修改这些参数。

1.3 实现颜色比较

接下来,我们将介绍 Strategy 类的结构。在此之前,我们编写一个简单的 main 函数来运行上述颜色检测算法。

(1) 首先,在 main 函数中,我们必须为类 ColorDetector 创建一个实例(对于类的具体代码,我们将在下一节中介绍):

// 创建图像处理器对象
ColorDetector cdetect;

(2) 读取图像进行处理:

// 读取输入图像
cv::Mat image = cv::imread("1.png");

(3)empty() 函数检查我们是否正确加载了图像,如果图像为空,则退出应用程序:

if (image.empty()) return 0;

(4) 使用 ColorDetector 的新实例设置目标颜色(该函数是在类中定义的):

cdetect.setTargetColor(230, 190, 130);

(5) 创建一个窗口显示图像处理结果。因此,我们必须使用 ColorDetector 实例的 process 函数:

// 处理图像并显示结果
cv::namedWindow("Result");
cv::Mat result = cdetect.process(image);
cv::imshow("Result", result);
6. 最后,在退出之前等待用户按键操作:
cv::waitKey();
return 0;

运行此程序,可以得到以下输出:

颜色比较结果
在上图中,白色像素表示图像中与给定颜色相同的像素,黑色表示图像中与给定颜色不同的像素。我们封装在 ColorDetector 类中的算法比较简单(仅由一个扫描循环和一个容差参数组成)。当要实现的算法更复杂、步骤较多且包含多个参数时,策略设计模式也会变得更加有用。

1.3.1 完整代码

完整代码 (colorDetector.cpp) 如下所示:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include "colordetector.h"
#include <vector>

int main() {
    // 创建图像处理器对象
    ColorDetector cdetect;
    // 读取输入图像
    cv::Mat image = cv::imread("1.png");
    if (image.empty()) return 0;
    cv::namedWindow("Original Image");
    cv::imshow("Original Image", image);
    // 设置输入参数
    cdetect.setTargetColor(230, 190, 130);
    // 处理图像并显示结果
    cv::namedWindow("Result");
    cv::Mat result = cdetect.process(image);
    cv::imshow("Result", result);
    // 或者使用函子
    ColorDetector colordetector(230, 190, 130, 45, true);
    cv::namedWindow("Result (functor)");
    result = colordetector(image);
    cv::imshow("Result (functor)", result);
    // floodfill函数
    cv::floodFill(image,        // 输入/输出图像
        cv::Point(100, 50),     // 种子位置
        cv::Scalar(255, 255, 255),  // 重绘制的颜色
        (cv::Rect*)0,           //  重绘制的像素集的边框 
        cv::Scalar(35, 35, 35), // 低差异阈值
        cv::Scalar(35, 35, 35), // 高差异阈值
        cv::FLOODFILL_FIXED_RANGE   // 像素与种子位置颜色进行比较
    );
    cv::namedWindow("Flood fill result");
    result = colordetector(image);
    cv::imshow("Flood fill result", image);
    // 创建图像,演示颜色空间属性
    cv::Mat colors(100, 300, CV_8UC3, cv::Scalar(100, 200, 150));
    cv::Mat range = colors.colRange(0, 100);
    range = range + cv::Scalar(10, 10, 10);
    range = colors.colRange(200, 300);
    range = range + cv::Scalar(-10, -10, -10);
    cv::namedWindow("3 colors");
    cv::imshow("3 colors", colors);
    
    cv::Mat labImage(100, 300, CV_8UC3, cv::Scalar(100, 200, 150));
    cv::cvtColor(labImage, labImage, cv::COLOR_BGR2Lab);
    range = colors.colRange(0, 100);
    range = range + cv::Scalar(10, 10, 10);
    range = colors.colRange(200, 300);
    range = range + cv::Scalar(-10, -10, -10);
    cv::cvtColor(labImage, labImage, cv::COLOR_Lab2BGR);
    cv::namedWindow("3 colors (Lab)");
    cv::imshow("3 colors (Lab)", colors);

    cv::Mat grayLevels(100, 256, CV_8UC3);
    for (int i=0; i<256; i++) {
        grayLevels.col(i) = cv::Scalar(i, i, i);
    }
    range = grayLevels.rowRange(50, 100);
    cv::Mat channels[3];
    cv::split(range, channels);
    channels[1] = 128;
    channels[2] = 128;
    cv::merge(channels, 3, range);
    cv::cvtColor(range, range, cv::COLOR_Lab2BGR);
    cv::namedWindow("Luminance vs Brightness");
    cv::imshow("Luminance vs Brightness", grayLevels);
    cv::waitKey();
    return 0;
}

1.4 ColorDetector 类

颜色比较算法的核心过程很容易实现,通过一个简单的扫描循环,遍历每个像素,将其颜色与给定目标颜色进行比较:

// 迭代器
cv::Mat_<cv::Vec3b>::const_iterator it = image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator itend = image.end<cv::Vec3b>();
cv::Mat_<uchar>::iterator itout = result.begin<uchar>();
if (useLab) {
    it = converted.begin<cv::Vec3b>();
    itend = converted.end<cv::Vec3b>();
}
for (; it != itend; ++it, ++itout) {
    if (getDistanceToTargetColor(*it) < maxDist) {
        *itout = 255;
    } else {
        *itout = 0;
    }
}

cv::Mat 变量 image 指输入图像,而 result 是指二值输出图像。因此,第一步需要设置所需的迭代器,使扫描循环易于实现。在每次迭代时评估当前像素颜色和给定目标颜色之间的距离,以检查它们之间的距离是否在 maxDist 定义的容差参数范围内。如果在容差范围内,则将输出图像像素值设为 255 (白色);否则,将其值设为 0 (黑色)。我们可以使用 getDistanceToTargetColor 方法计算当前像素颜色与给定目标颜色之间的距离,OpenCV 中也有许多不同的方法来计算距离。例如,可以计算包含 RGB 颜色值的向量之间的欧几里得距离,或对 RGB 值之间差值的绝对值求和(这也称为城市街区距离)。在现代架构中,浮点欧几里得距离的计算速度比城市街区距离更快。为了获得更高的灵活性,我们根据 getColorDistance 方法编写 getDistanceToTargetColor 方法:

// 计算与目标颜色的距离
int getDistanceToTargetColor(const cv::Vec3b& color) const {
    return getColorDistance(color, target);
}
// 计算两种颜色之间的城市街区距离
int getColorDistance(const cv::Vec3b& color1, const cv::Vec3b& color2) const {
    return abs(color1[0] - color2[0]) + abs(color1[1] - color2[1]) + abs(color1[2] - color2[2]);
}

我们使用 cv::Vec3d 保存表示 RGB 值的三个无符号字符。target 变量是指给定的目标颜色,它在我们定义的类算法中定义为类 (class) 变量。对于类方法 process,其根据提供的输入图像,扫描图像完成后返回结果:

cv::Mat ColorDetector::process(const cv::Mat& image) {
    result.create(image.size(), CV_8U);
// 循环处理过程 
...
    return result;
}

每次调用此方法时,需要检查包含结果二值图的输出图像是否需要重新分配内存以匹配输入图像的大小,这就是我们使用 cv::Matcreate 方法的原因。需要注意的是,只有在指定的大小和深度(图像深度是指存储每个像素所用的位数)与当前图像结构不对应时,此方法才会进行重新分配。
定义了核心处理方法之后,我们需要继续添加一些额外的类方法来部署算法。由于我们已经确定了算法需要哪些输入和输出数据,因此,我们首先定义保存这些数据的类属性:

class ColorDetector {
    private:
        // 容差
        int maxDist;
        // 目标颜色
        cv::Vec3b target;
        // 结果二值图像
        cv::Mat result;

为了创建封装算法的类的实例(命名为 ColorDetector),我们需要定义一个构造函数,策略设计模式的目标之一是使算法部署尽可能简单。可以定义的最简单的构造函数是空构造函数,它将创建一个有效的类算法实例。然后,我们令构造函数将所有输入参数初始化为其默认值,在此算法中,我们将通常是可接受的容差参数设为 100;此外,我们还需要设置默认的目标颜色。用于确保我们总是从可预测和有效的输入值开始测试算法:

// 空构造函数
// 默认参数初始化
ColorDetector() : maxDist(100), target(0, 0, 0) {}

创建类算法实例的后,我们可以使用有效图像调用 process 方法并获得有效输出,这是策略模式的另一个目标,即确保算法始终以有效参数运行。显然,使用这个类时,我们会需要使用自定义参数,这可以通过提供相应的 gettersetter 方法实现。以颜色容差参数为例:

// 设置颜色阈值距离
void setColorDistanceThreshold(int distance) {
    if (distance < 0) distance = 0;
    maxDist = distance;
}
// 获取颜色阈值距离
int getColorDistanceThreshold() const {
    return maxDist;
}

需要注意的是,我们首先需要检查输入的有效性,这是为了确保我们的算法永远不会在无效状态下运行。我们也可以用类似的方式设置给定目标颜色参数:

// 设置颜色阈值距离
void setColorDistanceThreshold(int distance) {
    if (distance < 0) distance = 0;
    maxDist = distance;
}
// 获取颜色阈值距离
int getColorDistanceThreshold() const {
    return maxDist;
}

在以上代码中,我们提供了 setTargetColor 方法的两个定义。在定义的第一个版本中,三个颜色分量被指定为三个参数,而在第二个版本中,使用 cv::Vec3b 保存颜色值,目标是便于类算法的使用,以方便在使用时选择最适合的 setter
本节介绍了如何使用策略设计模式将算法封装在类中,本节我们使用颜色比较算法识别足够接近指定目标颜色的图像像素。此外,策略设计模式的实现可以通过使用函数对象进行补充。

1.3.1 完整代码

完整代码 (colordetector.h) 如下所示:

#if !defined COLORDETECT
#define COLORDETECT

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

class ColorDetector {
    private:
        // 容差
        int maxDist;
        // 目标颜色
        cv::Vec3b target;
        // 转换色彩后的图像
        cv::Mat converted;
        bool useLab;
        // 结果二进制图像
        cv::Mat result;
    public:
        // 空构造函数
        // 默认参数初始化
        ColorDetector() : maxDist(100), target(0, 0, 0), useLab(false) {}
        // Lab颜色空间的额外构造函数 
        ColorDetector(bool useLab) : maxDist(100), target(0, 0, 0), useLab(true) {}
        // 完整构造函数
        ColorDetector(uchar blue, uchar green, uchar red, int maxDist=100, bool useLab=false) : maxDist(maxDist), useLab(useLab) {
            // 目标颜色
            setTargetColor(blue, green, red);
        }
        // 计算与目标颜色的距离
        int getDistanceToTargetColor(const cv::Vec3b& color) const {
            return getColorDistance(color, target);
        }
        // 计算两种颜色之间的城市街区距离
        int getColorDistance(const cv::Vec3b& color1, const cv::Vec3b& color2) const {
            return abs(color1[0] - color2[0]) + abs(color1[1] - color2[1]) + abs(color1[2] - color2[2]);
            // 或者
            // return static_cast<int>(cv::norm<int,3>(cv::Vec3i(color1[0]-color2[0],color1[1]-color2[1],color1[2]-color2[2])));
            // 或者
            // cv::Vec3b dist;
            // cv::absdiff(color1, color2, dist);
            // return cv::sum(dist)[0];
        }
        // 处理图像,返回单通道二进制图像
        cv::Mat process(const cv::Mat& image);
        
        cv::Mat operator()(const cv::Mat& image) {
            cv::Mat input;
            if (useLab) {
                cv::cvtColor(image, input, cv::COLOR_BGR2Lab);
            } else {
                input = image;
            }
            cv::Mat output;
            cv::absdiff(input, cv::Scalar(target), output);
            // 分割图像通道
            std::vector<cv::Mat> images;
            cv::split(output, images);
            // 对三个通道进行加法运算
            output = images[0] + images[1] + images[2];
            // 应用阈值
            cv::threshold(output,   // 输入图像
                output,             // 输出图像
                maxDist,            // 阈值
                255,                // 最大值
                cv::THRESH_BINARY_INV  // 阈值运算类型
            );
            return output;
        }

        // 设置颜色阈值距离
        void setColorDistanceThreshold(int distance) {
            if (distance < 0) distance = 0;
            maxDist = distance;
        }
        // 获取颜色阈值距离
        int getColorDistanceThreshold() const {
            return maxDist;
        }
        // 设置BGR颜色空间中给定的待检测颜色
        void setTargetColor(uchar blue, uchar green, uchar red) {
            target = cv::Vec3b(blue, green, red);
            if (useLab) {
                cv::Mat tmp(1, 1, CV_8UC3);
                tmp.at<cv::Vec3b>(0, 0) = cv::Vec3b(blue, green, red);
                // 将目标颜色转换到 Lab 色彩空间
                cv::cvtColor(tmp, tmp, cv::COLOR_BGR2Lab);
                target = tmp.at<cv::Vec3b>(0, 0);
            }
        }
        // 设置待检测颜色
        void setTargetColor(cv::Vec3b color) {
            target = color;
        }
        // 获取待检测颜色
        cv::Vec3b getTargetColor() const {
            return target;
        }
};

cv::Mat ColorDetector::process(const cv::Mat& image) {
    result.create(image.size(), CV_8U);
    // 转换色彩空间
    if (useLab) cv::cvtColor(image, converted, cv::COLOR_BGR2Lab);
    // 迭代器
    cv::Mat_<cv::Vec3b>::const_iterator it = image.begin<cv::Vec3b>();
    cv::Mat_<cv::Vec3b>::const_iterator itend = image.end<cv::Vec3b>();
    cv::Mat_<uchar>::iterator itout = result.begin<uchar>();
    if (useLab) {
        it = converted.begin<cv::Vec3b>();
        itend = converted.end<cv::Vec3b>();
    }
    for (; it != itend; ++it, ++itout) {
        if (getDistanceToTargetColor(*it) < maxDist) {
            *itout = 255;
        } else {
            *itout = 0;
        }
    }
    return result;
}

#endif

1.4 计算两个颜色向量之间的距离

为了计算两个颜色向量之间的距离,我们可以使用以下公式:

return abs(color1[0] - color2[0]) + abs(color1[1] - color2[1]) + abs(color1[2] - color2[2]);

但是,OpenCV 中也包含了用于计算向量欧几里得范数的函数。因此,我们可以按如下方式计算距离:

return static_cast<int>(cv::norm<int,3>(cv::Vec3i(color1[0]-color2[0],color1[1]-color2[1],color1[2]-color2[2])));

根据以上方式使用 getDistance 方法,可以得到获得相似的结果。在以上代码中,我们使用 cv::Vec3i (三向量整数数组),因为减法的结果是整数值。
由于 OpenCV 矩阵和向量数据结构包括基本算术运算符。因此,我们也可以使用以下方法计算距离:

return static_cast<int>(cv::norm<uchar,3>(color-target)); // wrong!

以上语法初看之下很容易误以为是正确的,但并非如此。这是因为 OpenCV 中运算符包含对 saturate_cast 的调用以确保结果保持在输入类型的域内(以上代码中为 uchar)。因此,在给定目标颜色大于当前图像颜色值的情况下,结果为 0 而非预期的负值。正确的计算方法如下:

cv::Vec3b dist;
cv::absdiff(color1, color2, dist);
return cv::sum(dist)[0];

但是,使用两个函数来计算两个三元向量数组之间的距离的效率较低。

2. 使用 OpenCV 函数

在上一节中,我们将使用带有迭代器的循环来执行颜色比较计算。我们也可以通过调用一系列 OpenCV 函数来得到相同的结果,使用 OpenCV 函数重写以上颜色检测方法:

cv::ColorDetector::process(const cv::Mat& image) {
    cv::Mat output;
    // 计算与目标颜色的绝对差值
    cv::absdiff(image, cv::Scalar(target), output);
    // 分割图像通道
    std::vector<cv::Mat> images;
    cv::split(output, images);
    // 对通道进行加法运算
    output = images[0] + images[1] + images[2];
    // 应用阈值
    cv::threshold(output, output, maxDist, 255, cv::THRESH_BINARY_INV);
    return output;
}

此方法使用 absdiff() 函数计算图像像素之间的绝对差,以上代码计算图像与标量值 cv::Scalar(target) 之间的距离,除了标量值外,我们也可以提供另一个图像作为 absdiff 函数的第二个参数,在这种情况下,将逐像素计算像素差;因此,两个图像必须具有相同的尺寸大小。使用 split 函数提取图像的各个通道,以便将各通道像素值相加,当计算结果结果大于 255 时,由于应用饱和运算 cv::saturate_cast,结果将被限制为 255。最后,使用 threshold() 函数创建二值图像,该函数通常用于将所有像素与阈值(第三个参数,必须小于 256)进行比较,在常规阈值模式 (cv::THRESH_BINARY) 下,将所有大于阈值的像素设为定义的最大值(第四个参数),而其他值设为 0;在逆模式 (cv::THRESH_BINARY_INV) 下,将所有低于或等于阈值的像素设为定义的最大值;而 cv::THRESH_TOZEROcv::THRESH_TOZERO_INV 模式令大于或小于阈值的像素保持不变。
使用 OpenCV 函数可以快速构建复杂的应用程序并减少出错的可能性,并且通常更高效。但是,当使用多个中间步骤时,可能会消耗较多内存。

3. 函子或函数对象

使用 C++ 运算符重载,可以创建一个类,其实例的行为类似于函数。为此,我们可以重载 operator() 方法,这样对类处理方法的调用就像函数调用一样简单。生成的类实例称为函数对象或函子 (functor),通常,函子包含一个完整的构造函数,这样它就可以在创建后立即使用。例如,我们可以将以下构造函数添加到 ColorDetector 类中:

// 完整构造函数
ColorDetector(uchar blue, uchar green, uchar red, int maxDist=100, bool useLab=false) : maxDist(maxDist), useLab(useLab) {
    // 目标颜色
    setTargetColor(blue, green, red);
}

显然,我们仍然可以使用之前定义的 settergetter。函子方法可以定义如下:

cv::Mat operator()(const cv::Mat& image) {
// 色彩检测代码
...
}

要使用此函子方法检测给定颜色,只需使用以下代码:

ColorDetector colordetector(230, 190, 130, 100);
cv::Mat result= colordetector(image);	// 调用函子

如上所示,对颜色检测方法的调用与函数调用一样。事实上,colordetector 变量可以像函数一样使用。

4. OpenCV 算法的基类

OpenCV 提供了许多执行各种计算机视觉任务的算法。为了方便它们的使用,这些算法中的大多数属于通用基类 cv::Algorithm 的子类,这实现了策略设计模式所规定的一些概念。所有这些算法都是动态创建的,使用专门的静态方法来确保算法始终在有效状态下创建(即未指定参数时应具有有效的默认值)。例如,子类 cv::ORB 是一个兴趣点算子(本节我们将其用作算法的说明性示例,关于此算子的详细用法将在之后的学习中详细介绍)。cv::ORB 算法的实例创建如下:

cv::Ptr<cv::ORB> ptrORB = cv::ORB::create();

创建完成后,就可以使用该算法。例如,通用方法 readwrite 可用于加载或存储算法的状态。这些算法也有专门的方法(例如,在 ORB 中,可以使用 detectcompute 方法来触发其主要计算单元);算法也有专门的 setter 方法指定它们的内部参数。我们可以将指针声明为 cv::Ptr<cv::Algorithm>,但在这种情况下,我们无法使用其专用方法。

小结

设计模式是软件工程中的一个常见概念,设计模式是针对软件设计中经常出现的通用问题的可靠的、可重用的解决方案。良好的计算机视觉程序始于良好的编程实践,我们需要应用程序能够随着新需求的出现而轻松适应和扩展。本节中,我们介绍了如何充分利用一些面向对象的编程原则以构建高质量的软件程序,我们学习了一些重要的设计模式,帮助我们使用易于测试、维护和可重用的组件构建应用程序。

系列链接

OpenCV实战(1)——OpenCV与图像处理基础
OpenCV实战(2)——OpenCV核心数据结构
OpenCV实战(3)——图像感兴趣区域
OpenCV实战(4)——像素操作
OpenCV实战(5)——图像运算详解

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文带你攻克JDK新特性

1.Java8 新特性介绍 1.1 实验介绍 在国内&#xff0c;Java8 是当之无愧的普及率最高的 JDK 版本&#xff0c;从笔者工作开始&#xff0c; 就一直使用的是 JDK8 的版本&#xff0c;虽然现在 JDK19 即将面世&#xff0c;但是似乎依旧无法 动摇 JDK8 在国内的地位。这里面最主要…

leetcode-10:还原排列的最少操作步数

原题描述如下&#xff1a; 给你一个偶数 n​​​​​​ &#xff0c;已知存在一个长度为 n 的排列 perm &#xff0c;其中 perm[i] i​&#xff08;下标 从 0 开始 计数&#xff09;。 一步操作中&#xff0c;你将创建一个新数组 arr &#xff0c;对于每个 i &#xff1a; 如…

蓝桥杯-地宫取宝

算法分类&#xff1a; 动态规划 dp 问题描述 X 国王有一个地宫宝库&#xff0c;是 nm 个格子的矩阵&#xff0c;每个格子放一件宝贝&#xff0c;每个宝贝贴着价值标签。 地宫的入口在左上角&#xff0c;出口在右下角。 小明被带到地宫的入口&#xff0c;国王要求他只能向右…

使用DBeaver 连接时序数据库TDengine

介绍 TDengine 是一款高性能、分布式、支持 SQL 的时序数据库 (Database)。 DBeaver 是一款流行、开源的数据库管理工具以及 SQL 客户端&#xff0c;其功能强大&#xff0c;并且支持任何拥有 JDBC-Driver 的数据库&#xff08;这意味着几乎所有数据库都支持&#xff09;。 只…

Java面试常见问题-JVM篇

JVM面试问题汇总①什么是字节码&#xff0c;采用字节码的好处是什么⭐java类加载器有哪些⭐双亲委派模型⭐⭐GC是如何判断对象可以被回收总结了目前主流平台中常见的面试题&#xff0c;标⭐为重点&#xff01; 第一次更新节点&#xff1a;2023.1.8 什么是字节码&#xff0c;采用…

用nvidia-smi查看GPU的状态时,能耗pwr显示为ERR!

用nvidia-smi查看GPU的状态时&#xff0c;能耗pwr显示为ERR&#xff01; 解决方式&#xff1a; 以下代码查看具体的报错: dmesg -l err 如果有: NVRM:***说明硬件问题&#xff0c;需要更换 如果无错误&#xff0c;则参考如下&#xff1a; 1. 将你的工作站或者服务器报错的…

车载激光雷达赛道「新窗口」

车载激光雷达的降本逻辑&#xff0c;除了前装量产规模的加速&#xff0c;还有背后核心供应链的驱动。这也被视为激光雷达新周期的核心竞争力。 Lumotive是一家由微软创始人比尔盖茨投资的初创公司&#xff0c;为激光雷达公司提供基于波束转向技术的核心元器件&#xff0c;采用液…

【寒假每日一题】DAY1.水仙花数

一、题目描述 求0&#xff5e;100000之间的所有“水仙花数”并输出。 什么是水仙花数&#xff1a; “水仙花数”是指一个n位数&#xff0c;其各位数字的n次方之和确好等于该数本身&#xff0c;如:153&#xff1d;1^3&#xff0b;5^3&#xff0b;3^3&#xff0c;则153是一个“水…

前端vue中ts无法识别引入的vue文件,提示找不到xxx.vue模块的解决【引入新建页面或者通过router引入时报错】

一、文章引导 #mermaid-svg-7KdCeocZ1DbrWrKC {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-7KdCeocZ1DbrWrKC .error-icon{fill:#552222;}#mermaid-svg-7KdCeocZ1DbrWrKC .error-text{fill:#552222;stroke:#55222…

联合证券|“仰望”概念爆发,多股涨停!人气龙头股罕见“炸板”

今日涨停股中&#xff0c;以封单金额核算&#xff0c;今飞凯达、联泓新科、灵通动力等涨停板封单资金最多。 涨停家数回落 1月6日&#xff0c;沪深两市股价收盘涨停的有37只&#xff0c;跌停股有14只。下午盘面震动&#xff0c;炸板数量增多&#xff0c;兔宝宝、中远海科、久其…

64. 锚框

1. 锚框 锚框是用来预测真实的边缘框。 2. loU-交并比 ioU用来计算两个框之间的相似度 0表示无重叠&#xff0c;1表示重合 这是Jacquard指数的一个特殊情况 给定两个集合A和B&#xff1a; 杰卡德系数&#xff08;Jaccard&#xff09;可以衡量两组之间的相似性。 给定集合A和…

D. Boris and His Amazing Haircut(线段树)

传送门题意&#xff1a;给定长度为 n 的数组 A &#xff0c;代表 Boris 现在的头发长度&#xff0c;和一个长度为 n 的数组 B &#xff0c;代表他希望的发型的头发长度。理发师手里有 m 把剪刀&#xff0c;每个都只能用一次&#xff0c;剪刀的所剪的高度用 xi 给出。 对于每一把…

ASO优化之苹果和安卓的优化思路

大家都知道&#xff0c;ASO优化是指应用商店的搜索优化&#xff0c;其目的就是通过关键词的覆盖&#xff0c;让APP的搜索排名靠前&#xff0c;带来更多的曝光和用户下载量。 安卓ASO优化的思路: 1&#xff0c;关键词的覆盖。由于现在大部分的安卓商店为了商业化,所以后台几乎…

【C语言进阶】指针经典笔试题

作者:匿名者Unit 目录指针笔试题eg1.eg2.eg3.eg4.指针笔试题 eg1. 我们先来看第一题: int main() {int a[4] { 1, 2, 3, 4 };int *ptr1 (int *)(&a 1);int *ptr2 (int *)((int)a 1);printf( "%x,%x", ptr1[-1], *ptr2);return 0; }我们先来分析ptr1&…

初级篇Nginx笔记

第一章、Nginx的目录结构以及运行原理Nginx的目录结构[rootlocalhost ~]# tree /usr/local/nginx/usr/local/nginx├── client_body_temp # POST 大文件暂存目录├── conf # Nginx所有配置文件的目录│ ├── fastcgi.conf # fastcgi相关参数的配置文件│ ├── fastcgi.…

在maven项目当中创建第一个jdbc程序

大家好&#xff0c;今天给大家分享在Maven环境中创建jdbc程序 这是Maven项目的创建方式 跟着一步一步做就可以了 然后&#xff0c;创建好的Maven项目应该是这样的 导入相关的依赖 <dependencies><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-ja…

PHP date() 函数

PHP date() 函数用于格式化时间/日期。 PHP date() 函数 PHP date() 函数可把时间戳格式化为可读性更好的日期和时间。 时间戳是一个字符序列&#xff0c;表示一定的事件发生的日期/时间。 语法 string date ( string $format [, int $timestamp ] ) 参数描述format必需。规…

Python下载ts文件视频且合并

目录 一、ts文件的由来 二、下载ts文件 1.下载index.m3u8&#xff0c;并做相应处理 2.下载ts文件 三、合并ts文件 一、ts文件的由来 ts文件&#xff0c;ts即"Transport Stream"的缩写&#xff0c;特点就是要求从视频流的任一片段开始都是可以独立解码的&#xff…

Pytorch 权重衰减

目录 1、权重衰减 2、L2正则化和L1正则化 3、高维线性回归演示权重衰减 1、权重衰减 一般来说&#xff0c;我们总是可以通过去收集更多的训练数据来缓解过拟合。 但这可能成本很高&#xff0c;耗时颇多&#xff0c;或者完全超出我们的控制&#xff0c;因而在短期内不可能做到…

OpenTelemetry日志体系

前言 OpenTelemetry为了实现其可观测性有三大体系&#xff1a;Trace&#xff0c;Metrics和Log。本文将对于OpenTelemetry实现的日志体系进行详细的讲述。 日志 说到日志相比大家都能侃侃而谈&#xff1a;帮助快速定位出现的问题&#xff0c;数据追踪&#xff0c;性能分析等等…