OpenCV17-图像形态学操作

news2024/11/16 11:42:17

OpenCV17-图像形态学操作

  • 1.形态学操作
    • 1.1腐蚀
    • 1.2膨胀
  • 2.形态学应用
    • 2.1开运算
    • 2.2闭运算
    • 2.3形态学梯度
    • 2.4顶帽运算
    • 2.5黑帽运算
    • 2.6击中击不中变换
    • 2.7形态学应用示例


1.形态学操作

1.1腐蚀

图像腐蚀(Image erosion)可用于减小图像中物体的大小、填充孔洞或者分离邻近的物体。腐蚀操作通过对图像中的每个像素应用结构元素(也称为腐蚀内核)来实现。

腐蚀操作的原理是将结构元素与图像进行逐像素的比较。如果结构元素的所有像素与图像中对应位置的像素都匹配,那么该像素保持不变。否则,该像素被腐蚀为背景像素。这样,腐蚀操作将使物体边界向内收缩,并且可以消除小的物体或连接物体之间的细小连接。

下面是一种常见的图像腐蚀算法的伪代码表示:

对于图像中的每个像素(x, y):
    对于结构元素中的每个像素(i, j):
        如果结构元素的中心与图像中的像素(x, y)对齐:
            如果结构元素的所有像素与图像中对应位置的像素都匹配:
                继续下一步
            否则:
                将图像中的像素(x, y)设置为背景像素
                中断内层循环

腐蚀就是寻找图像中能够将结构元素全部包含的像素点。对于输出图像中的每个像素位置(x, y),将结构元素B的中心与输入图像I的对应位置(x, y)对齐,然后在结构元素B覆盖的区域内选择输入图像中的最小像素值作为输出图像中的像素值。

OpenCV提供了 getStructuringElement() 函数用于生成常用的矩形结构元素、十字结构元素和椭圆结构元素。

Mat getStructuringElement(
    int shape,  // 生成结构元素的形状
    Size ksize, // 结构元素的尺寸
    Point anchor = Point(-1,-1)
);

//! shape of the structuring element
enum MorphShapes {
    MORPH_RECT    = 0, //矩形结构元素,所有元素都为1
    MORPH_CROSS   = 1, //十字结构元素,中间的列和行元素为1
    MORPH_ELLIPSE = 2  //椭圆结构元素,矩形的内接椭圆元素为1
};

OpenCV提供了 erode() 函数用于图像腐蚀:

void erode(
    InputArray src, 
    OutputArray dst, 
    InputArray kernel,  // 结构元素
    Point anchor = Point(-1,-1), 
    int iterations = 1, // 腐蚀的次数,默认为1
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue = morphologyDefaultBorderValue() // 使用边界不变外推法时的边界值
);

该函数根据结构元素对输入图像进行腐蚀,在腐蚀多通道图像时,每个通道独立进行腐蚀运算。

需要注意的是,该函数的腐蚀过程只针对图像中的非零像素,因此如果图像是以0像素为背景(黑底),那么腐蚀操作后会看到图像中的内容变得更瘦更小;如果图像是以255像素为背景(白底),那么腐蚀操作后看到的图像中的内容变得更粗更大。(与下面的膨胀相反)

下面代码中演示了腐蚀的效果,实现对原图中米粒进行计数,通过结果可以发现,腐蚀操作可以去除由噪声引起的较小的连通域,得到了正确的米粒数:

#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no log

using namespace cv;
using namespace std;

//绘制包含区域函数
void drawState(Mat& img, int number, Mat centroids, Mat stats, String str) {
	RNG rng(10086);
	vector<Vec3b> colors;
	for (int i = 0; i < number; i++)
	{
		//使用均匀分布的随机数确定颜色
		Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
		colors.push_back(vec3);
	}

	for (int i = 1; i < number; i++)
	{
		// 中心位置
		int center_x = centroids.at<double>(i, 0);
		int center_y = centroids.at<double>(i, 1);
		//矩形边框
		int x = stats.at<int>(i, CC_STAT_LEFT);
		int y = stats.at<int>(i, CC_STAT_TOP);
		int w = stats.at<int>(i, CC_STAT_WIDTH);
		int h = stats.at<int>(i, CC_STAT_HEIGHT);

		// 中心位置绘制
		circle(img, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);
		// 外接矩形
		Rect rect(x, y, w, h);
		rectangle(img, rect, colors[i], 1, 8, 0);
		putText(img, format("%d", i), Point(center_x, center_y),
			FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);
	}
	imshow(str, img);
}

int main()
{
	cout << "OpenCV Version: " << CV_VERSION << endl;
	utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);

	//生成用于腐蚀的原图像
	Mat src = (Mat_<uchar>(6, 6) <<
		0, 0, 0, 0, 255, 0,
		0, 255, 255, 255, 255, 255,
		0, 255, 255, 255, 255, 0,
		0, 255, 255, 255, 255, 0,
		0, 255, 255, 255, 255, 0,
		0, 0, 0, 0, 0, 0);
	Mat struct1, struct2;
	struct1 = getStructuringElement(MORPH_RECT, Size(3, 3));  //矩形结构元素
	struct2 = getStructuringElement(MORPH_CROSS, Size(3, 3));  //十字结构元素

	Mat erodeSrc;  //存放腐蚀后的图像
	erode(src, erodeSrc, struct2);
	namedWindow("src", WINDOW_GUI_NORMAL);
	namedWindow("erodeSrc", WINDOW_GUI_NORMAL);
	imshow("src", src);
	imshow("erodeSrc", erodeSrc);

	Mat LearnCV_black = imread("black_white_handwritten.jpg", IMREAD_ANYCOLOR);
	Mat LearnCV_write = imread("white_black_handwritten.jpg", IMREAD_ANYCOLOR);
	Mat erode_black1, erode_black2, erode_write1, erode_write2;
	//黑背景图像腐蚀
	erode(LearnCV_black, erode_black1, struct1);
	erode(LearnCV_black, erode_black2, struct2);
	imshow("LearnCV_black", LearnCV_black);
	imshow("erode_black1", erode_black1);
	imshow("erode_black2", erode_black2);

	//白背景腐蚀
	erode(LearnCV_write, erode_write1, struct1);
	erode(LearnCV_write, erode_write2, struct2);
	imshow("LearnCV_write", LearnCV_write);
	imshow("erode_write1", erode_write1);
	imshow("erode_write2", erode_write2);

	//验证腐蚀对小连通域的去除
	Mat img = imread("rice.png");
	if (img.empty())
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}
	Mat img2;
	copyTo(img, img2, img);  //克隆一个单独的图像,用于后期图像绘制
	Mat rice, riceBW;

	//将图像转成二值图像,用于统计连通域
	cvtColor(img, rice, COLOR_BGR2GRAY);
	threshold(rice, riceBW, 50, 255, THRESH_BINARY);

	Mat out, stats, centroids;
	//统计图像中连通域的个数
	int number = connectedComponentsWithStats(riceBW, out, stats, centroids, 8, CV_16U);
	cout << "未腐蚀:" << number << endl; // 27
	drawState(img, number, centroids, stats, "未腐蚀时统计连通域");  //绘制图像

	erode(riceBW, riceBW, struct1);  //对图像进行腐蚀
	number = connectedComponentsWithStats(riceBW, out, stats, centroids, 8, CV_16U);
	cout << "腐蚀后:" << number << endl; // 26
	drawState(img2, number, centroids, stats, "腐蚀后统计连通域");  //绘制图像

	waitKey(0);
	return 0;
}

在这里插入图片描述

在这里插入图片描述

1.2膨胀

图像膨胀(Image dilation)是一种图像处理操作,通常用于增加图像中物体的大小或填充物体的空隙,其目标是扩展和增强图像中的图形特征。

在定义结构元素之后,将结构元素的中心点依次放到图像中每一个非零元素处,如果原图中某个元素被结构元素覆盖,但是该像素的像素值不与结构元素中心点对应的像素点的像素值相同,那么将原图中该像素的像素值修改为结构元素中心点对应点的像素值。(将结构元素覆盖的所有区域,修改为1)

OpenCV提供了 dilate() 函数用于图像膨胀。

void dilate(
    InputArray src, 
    OutputArray dst, 
    InputArray kernel,
    Point anchor = Point(-1,-1), 
    int iterations = 1,
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue = morphologyDefaultBorderValue()
);

该函数用法同 erode() 。第三个参数是结构元素尺寸,在图像膨胀操作中,结构元素的形状和大小起着关键作用。较大的结构元素将导致更强的膨胀效果,而较小的结构元素则会产生细微的膨胀效果。第五个参数是使用结构元素膨胀的次数,膨胀次数越多效果越明显。

需要注意的是,该函数的膨胀过程只针对图像中的非零像素,因此如果图像是以0像素为背景(黑底),那么膨胀操作后会看到图像中的内容变得更粗和更大;如果图像是以255像素为背景(白底),那么膨胀操作后看到的图像中的内容变得更细和更小。(与上面的腐蚀相反)

下面代码示例,代码最后为了验证膨胀与腐蚀效果之间的关系,求取黑色背景图像的复试结果与白色背景图像的膨胀结果进行逻辑“与”、“异或”运算,证明两个过程的相反性。

#include <opencv2\opencv.hpp>
#include <opencv2/core/utils/logger.hpp> // debug no log

using namespace cv;
using namespace std;

int main()
{
	cout << "OpenCV Version: " << CV_VERSION << endl;
	utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);

	//生成用于腐蚀的原图像
	Mat src = (Mat_<uchar>(6, 6) <<
		0, 0, 0, 0, 255, 0,
		0, 255, 255, 255, 255, 255,
		0, 255, 255, 255, 255, 0,
		0, 255, 255, 255, 255, 0,
		0, 255, 255, 255, 255, 0,
		0, 0, 0, 0, 0, 0);
	Mat struct1, struct2;
	struct1 = getStructuringElement(0, Size(3, 3));  //矩形结构元素
	struct2 = getStructuringElement(1, Size(3, 3));  //十字结构元素

	Mat erodeSrc;  //存放膨胀后的图像
	dilate(src, erodeSrc, struct2);
	namedWindow("src", WINDOW_GUI_NORMAL);
	namedWindow("dilateSrc", WINDOW_GUI_NORMAL);
	imshow("src", src);
	imshow("dilateSrc", erodeSrc);

	Mat LearnCV_black = imread("black_white_handwritten.jpg", IMREAD_ANYCOLOR);
	Mat LearnCV_write = imread("white_black_handwritten.jpg", IMREAD_ANYCOLOR);
	if (LearnCV_black.empty() || LearnCV_write.empty())
	{
		cout << "请确认图像文件名称是否正确" << endl;
		return -1;
	}

	Mat dilate_black1, dilate_black2, dilate_write1, dilate_write2;
	//黑背景图像膨胀
	dilate(LearnCV_black, dilate_black1, struct1);
	dilate(LearnCV_black, dilate_black2, struct2);
	imshow("LearnCV_black", LearnCV_black);
	imshow("dilate_black1", dilate_black1);
	imshow("dilate_black2", dilate_black2);

	//白背景图像膨胀
	dilate(LearnCV_write, dilate_write1, struct1);
	dilate(LearnCV_write, dilate_write2, struct2);
	imshow("LearnCV_write", LearnCV_write);
	imshow("dilate_write1", dilate_write1);
	imshow("dilate_write2", dilate_write2);

	//比较膨胀和腐蚀的结果
	Mat erode_black1, resultXor, resultAnd;
	erode(LearnCV_black, erode_black1, struct1);
	bitwise_xor(erode_black1, dilate_write1, resultXor);
	bitwise_and(erode_black1, dilate_write1, resultAnd);
	imshow("resultXor", resultXor);
	imshow("resultAnd", resultAnd);

	waitKey(0);
	return 0;
}

在这里插入图片描述

2.形态学应用

图像形态学腐蚀可以将细小的噪声区域去除,但是会将图像主要区域的面积缩小,造成主要区域的形状发生改变。图像形态学膨胀可以扩充每一个区域的面积,填充较小的空洞,但是会增加噪声的面积。根据两者的特性,将图像腐蚀和膨胀适当结合,便可以既去除图像中的噪声,又不缩小图像中主要区域的面积;既填充较小的空洞,又不增加噪声的面积。

2.1开运算

图像开运算可以去除图像中的噪声,消除较小连通域,保留较大连通域,同时能够在两个物体纤细的连接处将两个物体分离,并且在不明显改变较大连通区域面积的同时能够平滑连通域的边界。

开运算:先腐蚀,消除图像中的噪声和较小的连通域;后膨胀,弥补较大的连通域因腐蚀而造成的面积减小。

开运算是对图像腐蚀和膨胀的结合,OpenCV中没有通过只用于图像开运算的函数,而是提供了图像腐蚀和膨胀运算不同组合形式的 morphologyEx() 函数,以实现开运算、闭运算、形态学梯度、顶帽运算、黑帽运算以及击中击不中变换。

void morphologyEx(
    InputArray src, 
    OutputArray dst,
    int op,  // 形态学操作类型标志,如下
    InputArray kernel, // 结构元素
    Point anchor = Point(-1,-1), 
    int iterations = 1,// 处理次数
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue = morphologyDefaultBorderValue()
);

该函数根据结构元素对输入图像进行多种形态学操作,在处理多通道图像时,每个通道独立进行处理。

第三个参数是形态学操作类型的标志:

//! type of morphological operation
enum MorphTypes{
    MORPH_ERODE    = 0, //腐蚀
    MORPH_DILATE   = 1, //膨胀
    MORPH_OPEN     = 2, //开运算
    MORPH_CLOSE    = 3, //闭运算
    MORPH_GRADIENT = 4, //形态学梯度
    MORPH_TOPHAT   = 5, //顶帽运算
    MORPH_BLACKHAT = 6, //黑帽运算
    MORPH_HITMISS  = 7  //击中击不中bian
};

2.2闭运算

图像闭运算可以去除连通域内的小型空洞,平滑物体轮廓,连接两个临近的连通域。闭运算,先膨胀,填充连通域内小型空洞,扩大连通域边界,将临近的两个连通域连接;后腐蚀,减少由膨胀运算引起的连通域边界的扩大以及面积的增加。

闭运算是对图像膨胀和腐蚀的结合,可以使用 morphologyEx() 函数选择闭运算参数 MORPH_CLOSE 实现闭运算。

2.3形态学梯度

形态学梯度能够描述目标的边界,根据图象腐蚀和膨胀与原图之间的关系计算得到,形态学梯度可以分为基本梯度、内部梯度和外部梯度。

基本梯度:膨胀后图像与腐蚀后图像差值。

内部梯度:原图像与腐蚀后图像差值。

外部梯度:膨胀后图像与原图像差值。

OpenCV提供的 morphologyEx() 函数可以选择形态学梯度参数 MORPH_GRADIENT 实现图像的基本梯度。如果需要计算图像的内部梯度和外部梯度,需要自己通过程序实现。

2.4顶帽运算

顶帽运算是原图像与开运算结果之间的差值,往往用来分离比临近点亮一些的斑块。因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域。

顶帽先对图像进行开运算,之后用原图减去开运算计算的结果。使用 morphologyEx() 函数选择顶帽运算的参数 MORPH_TOPHAT

2.5黑帽运算

与顶帽运算不同,黑帽运算是原图像与闭运算结果之间的差值,往往用来分离比邻近点暗一些的斑块。黑帽运算先对图像进行闭运算,之后从闭运算结果减去原图。使用 morphologyEx() 函数选择黑帽运算的参数 MORPH_BLACKHAT

2.6击中击不中变换

击中击不中变换(Hit-or-Miss Transform)利用两个结构元素,一个称为"击中"元素(Hit element),另一个称为"不中"元素(Miss element)。

击中击不中变换的目的是通过将击中元素与图像进行腐蚀(erosion)操作和将不中元素与图像进行膨胀(dilation)操作,来检测指定形状在图像中的位置。

输出图像中的白色像素表示原始图像中存在与击中元素形状相匹配的区域,黑色像素表示不匹配的区域。

使用 morphologyEx() 函数选择击中击不中变换的参数 MORPH_HITMISS

2.7形态学应用示例

//#include <opencv2/core.hpp>
//#include <opencv2/highgui.hpp>
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	cout << "OpenCV Version: " << CV_VERSION << endl;
	utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);

	//用于验证形态学应用的二值化矩阵
	Mat src = (Mat_<uchar>(9, 12) <<
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,
		0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
		0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
		0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0,
		0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
		0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,
		0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	namedWindow("src", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸
	imshow("src", src);
	//3×3矩形结构元素
	Mat kernel = getStructuringElement(0, Size(3, 3));

	//对二值化矩阵进行形态学操作
	Mat open, close, gradient, tophat, blackhat, hitmiss;

	//对二值化矩阵进行开运算
	morphologyEx(src, open, MORPH_OPEN, kernel);
	namedWindow("open", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸
	imshow("open", open);

	//对二值化矩阵进行闭运算
	morphologyEx(src, close, MORPH_CLOSE, kernel);
	namedWindow("close", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸
	imshow("close", close);

	//对二值化矩阵进行梯度运算
	morphologyEx(src, gradient, MORPH_GRADIENT, kernel);
	namedWindow("gradient", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸
	imshow("gradient", gradient);

	//对二值化矩阵进行顶帽运算
	morphologyEx(src, tophat, MORPH_TOPHAT, kernel);
	namedWindow("tophat", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸
	imshow("tophat", tophat);

	//对二值化矩阵进行黑帽运算
	morphologyEx(src, blackhat, MORPH_BLACKHAT, kernel);
	namedWindow("blackhat", WINDOW_NORMAL);   //可以自由调节显示图像的尺寸
	imshow("blackhat", blackhat);

	//对二值化矩阵进行击中击不中变换
	morphologyEx(src, hitmiss, MORPH_HITMISS, kernel);
	namedWindow("hitmiss", WINDOW_NORMAL);  //可以自由调节显示图像的尺寸
	imshow("hitmiss", hitmiss);

	//用图像验证形态学操作效果
	Mat keys = imread("keys.jpg", IMREAD_GRAYSCALE);
	imshow("原图像", keys);
	threshold(keys, keys, 80, 255, THRESH_BINARY);
	imshow("二值化后的keys", keys);

	//5×5矩形结构元素
	Mat kernel_keys = getStructuringElement(0, Size(5, 5));
	Mat open_keys, close_keys, gradient_keys, tophat_keys, blackhat_keys, hitmiss_keys;

	//对图像进行开运算
	morphologyEx(keys, open_keys, MORPH_OPEN, kernel_keys);
	imshow("open_keys", open_keys);

	//对图像进行闭运算
	morphologyEx(keys, close_keys, MORPH_CLOSE, kernel_keys);
	imshow("close_keys", close_keys);

	//对图像进行梯度运算
	morphologyEx(keys, gradient_keys, MORPH_GRADIENT, kernel_keys);
	imshow("gradient_keys", gradient_keys);

	//对图像进行顶帽运算
	morphologyEx(keys, tophat_keys, MORPH_TOPHAT, kernel_keys);
	imshow("tophat_keys", tophat_keys);

	//对图像进行黑帽运算
	morphologyEx(keys, blackhat_keys, MORPH_BLACKHAT, kernel_keys);
	imshow("blackhat_keys", blackhat_keys);

	//对图像进行击中击不中变换
	morphologyEx(keys, hitmiss_keys, MORPH_HITMISS, kernel_keys);
	imshow("hitmiss_keys", hitmiss_keys);

	int k = waitKey(0); // Wait for a keystroke in the window
	return 0;
}

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

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

相关文章

高压放大器有哪些实际应用场景

高压放大器是一种特殊类型的放大器&#xff0c;用于放大高电压信号。它在各种实际应用场景中发挥着重要作用。在本文中&#xff0c;安泰电子将介绍高压放大器的主要应用场景&#xff0c;让我们更好地了解这些关键技术的实际应用。 医疗设备领域&#xff1a; 高压放大器在医疗设…

2023最新短视频配音软件~

随着互联网的迅猛发展&#xff0c;网络平台上的影视剧配音逐渐成为一种热门赚钱方式。那么&#xff0c;想要参与影视剧配音赚钱&#xff0c;就需要拥有一款好用的配音软件。下面我就为大家介绍一款最新的影视剧配音神器&#xff01; 悦音配音 这是一款大家都在用的配音工具&am…

TSINGSEE烟火识别算法的技术原理是什么?如何应用在视频监控中?

AI烟火识别算法是基于深度学习技术的一种视觉识别算法&#xff0c;主要用于在视频监控场景中自动检测和识别烟雾、火焰的行为。该技术基于深度学习神经网络技术&#xff0c;可以动态识别烟雾和火焰从有到无、从小到大、从大到小、从小烟到浓烟的状态转换过程。 1、技术原理 1…

企业微信设置可信域名

可信域名的验证文件注意一定放在域名所在的根目录下。 以cloud studio为例&#xff0c;工作区新建终端的路径就是域名在的根目录&#xff0c;而不是服务器的根目录

[DRAFT] LLVM ThinLTO原理分析

我们在《论文阅读&#xff1a;ThinLTO: Scalable and Incremental LTO》中介绍了ThinLTO论文的主要思想&#xff0c;这里我们介绍下LLVM ThinLTO是如何实现的。本文主要分为如下几个部分&#xff1a; LLVM ThinLTO Object 含有哪些内容&#xff1f;LLVM ThinLTO 是如何做优化的…

Splashtop 与 Canopy 携手共同增强对物联网设备的远程管理

2023年10月17日 加利福尼亚州库比蒂诺 Splashtop 在安全远程访问解决方案领域处于领先地位&#xff0c;Canopy 则是用于复杂硬件部署的领先 RMM 平台&#xff0c;双方今天宣布达成战略合作伙伴关系&#xff0c;以进一步增强和简化对物联网设备的远程管理。通过此次合作&#x…

react实现一维表格、键值对数据表格key value表格

UI画的需求很抽象&#xff0c;直接把数据铺开&#xff0c;不能直接用antd组件了 上一行是name&#xff0c;下一行是value&#xff0c;总数不定&#xff0c;最后前端还要显示求和 class OneDimensionTable extends React.Component { render() {const { data } this.props;le…

C++基础系列(一) 对象指针

一. 函数指针和指针函数 1.1 函数指针 这两个是C语言里两个比较绕的概念&#xff0c;我们先说一下函数指针 函数指针本质是一个指针&#xff0c;该指针的地址指向了一个函数。 在程序中定义了一个函数&#xff0c;那么在编译时系统就会为这个函数代码分配一段存储空间&#xf…

金融机器学习方法:K-均值算法

目录 1.算法介绍 2.算法原理 3.python实现示例 1.算法介绍 K均值聚类算法是机器学习和数据分析中常用的无监督学习方法之一&#xff0c;主要用于数据的分类。它的目标是将数据划分为几个独特的、互不重叠的子集或“集群”&#xff0c;以使得同一集群内的数据点彼此相似&…

window.location对象实例详解

一、前言 Window.location 只读属性返回一个 Location 对象&#xff0c;其中包含当前标签页文档的网页地址信息。 Window.location 是一个只读 Location 对象&#xff0c;但是我们仍然可以去重新赋值更改对象值。 下面就让我们详细介绍一下location的常用属性和方法&#xf…

基于springboot实现滴答拍摄影项目【项目源码+论文说明】

摘要 拍摄能让人放开自我、因看到不同的美景都想留下美好的记忆&#xff0c;有些人喜欢拍摄静物来表现宁静的氛围&#xff0c;通过小品类的照片&#xff0c;传达内心的情绪。而我更喜欢另一种方式&#xff0c;就是用长时间曝光把波动的海水或湖水雾化&#xff0c;拍摄出来的作…

为什么产品经理都要考NPDP?

最近很多宝子问我&#xff0c;产品经理适合考什么证书&#xff1f;那必然是NPDP啊&#xff01;作为国际产品专业认证&#xff0c;NPDP证书是现如今最炙手可热且含金量相对较高的证书了&#xff0c;下面胖圆讲给大家详细介绍一下NPDP证书的具体信息。 1&#xff09;NPDP是什么&…

Win10下基于VS2015编译SQLite3源码

一、下载SQLite SQLite SQLite Download Page 下载红框部分的3个文件 提示&#xff1a;这里有个 sglite-autoconf-3420000.tar.gz 是免编译版&#xff0c;想省事就下载这个&#xff0c;但我自己用这个老是编译不过 所以我这里不推荐这个了 二、配置SQLite 打开vs 2015或者其他…

vscode中快速生成vue3模板

步骤&#xff1a;设置 -> 用户代码片段 -> vue.json&#xff08;没有vue.json,选vue也可&#xff09;-> 定义自己所需的代码段 代码段 如下&#xff0c; {"Print to console": {"prefix": "vue3", //键入该值&#xff0c;按tab…

自定义类型(结构体 , 枚举 , 联合)详解

文章目录 结构体结构体变量初始化结构体内存对齐结构体的对齐规则:为什么存在内存对齐 修改默认对齐数结构体实现位段(位段的填充&可移植性)什么是位段(位是二进制位)位段的内存分配位段的跨平台问题 实现offsetof&#xff08;计算结构体成员相较于起始位置的偏移量&#x…

Netty入门指南之基础介绍

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Netty应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献介绍为什么…

报错:AttributeError: module ‘tensorflow‘ has no attribute ‘flags‘

改成如下&#xff1a; 报错原因&#xff1a;tensorflow1.x与2.x版本问题不兼容

重装操作系统后 gitee:Failed to create Gitee Repository

错误描述 重装系统后&#xff0c;提交项目代码到gitee程序报错&#xff1a; 11:21 Failed to create Gitee Repositorydetected dubious ownership in repository at E:/Workspaces/SpringBoot/saTokenE:/Workspaces/SpringBoot/saToken is owned by:S-1-5-21-1301660696-421…

【已解决】ubuntu耳机单侧有声音

背景 台式机&#xff0c;双系统&#xff1a;win10 ubuntu 20.04&#xff1b;ubuntu 系统当中&#xff0c;左侧耳机有声音&#xff0c;右侧没有&#xff1b; 解决方法 终端输入&#xff1a;alsamixer&#xff0c;显示下面的图片&#xff1a; 调整方法&#xff1a;键盘上下左…

微信native-v3版支付对接流程及demo

1.将p12证书转为pem证书&#xff0c;得到商户私钥 openssl pkcs12 -in apiclient_cert.p12 -out apiclient_cert.pem -nodes 密码是&#xff1a;商户id 2.将获取到的apiclient_cert.pem证书&#xff0c;复制出这一块内容&#xff0c;其他的不要 3.下载这个工具包 https://gi…