OpenCV入门(四)——边缘检测

2023-05-16

目录

0x01 梯度算子

0x02 一阶微分算子

0x03 二阶微分算子

0x04 图像差分运算

0x05 非极大值抑制

0x06 基本边缘算子——Sobel

0x07 基本边缘算子——Laplace

0x08 基本边缘检测算子——Roberts

0x09 基本边缘检测算子——Prewitt


边缘检测的概念:检测识别出图像图像中亮度变化剧烈的像素点构成的集合。

目标物体形成边缘存在以下几种情形:

  • 目标物呈现在图像上的不同物体平面上,深度不连续。

  • 目标物本身平面不同,表面方向不连续。

  • 目标物材料不均匀,表面反射光不同。

  • 目标物受外部场景光影响不一。

根据边缘形成的原理,对图像的各像素点进行求微分或二阶微分可以检测出灰度变化明显的点。通常情况下边缘检测分为以下三个类型:

  • 一阶微分为基础的边缘检测:通过计算图像的梯度值来检测图像边缘。

Sobel算子、Prewitt算子、Roberts算子以及差分边缘检测。

  • 二阶微分为基础的边缘检测:通过寻求二阶导数中的过零点来检测边缘。

    拉普拉斯算子、高斯拉普拉斯算子、Canny算子边缘检测图。

  • 混合一阶与二阶微分为基础的边缘检测:综合利用一阶微分与二阶微分特征

    Marr-Hildreth边缘检测算子。

0x01 梯度算子

数字图像的简单一阶微分运算,由于其具有固定的方向性,只能检测特定的某一方向的边缘,所以不具有普遍性。

克服以上一阶导数的缺点,我们定义图像的梯度为梯度算子,它是图像处理中最常用的一阶微分算法。图像梯度最重要的性质是梯度的方向是在图像灰度最大变化率上,恰好可以反映出图像边缘上的灰度变化。

梯度算子总是指向变换最剧烈的方向,在图像处理中,梯度向量总是与边缘正交,梯度方向为:

0x02 一阶微分算子

利用了图像在边缘处的阶跃性,即图像梯度在边缘处取得极大值的特性来进行边缘检测。对于一幅二维的数字图像而言,它需要完成x与y两个方向上的微分,所以就有如下的公式分别求出x和y两个方向上的偏微分,最终得到的梯度是一个矢量,具有方向与模:

0x03 二阶微分算子

图像的边缘时图像的一阶微分极大值的像素点值,根据函数微分特性,该像素点值的二阶微分为0。图像边缘检测中根据二阶微分在边缘处出现零点这个特性来实现边缘检测。用拉普拉斯算子计算:

0x04 图像差分运算

 看看差分边缘检测的实现:

void diffOperation(const cv::Mat srcImage, cv::Mat& edgeXImage, cv::Mat& edgeYImage)
{
	cv::Mat tempImage = srcImage.clone();
	int nRows = tempImage.rows;
	int nCols = tempImage.cols;
	for (int i = 0; i < nRows - 1; i++)
	{
		for (int j = 0; j < nCols - 1; j++)
		{
			//计算垂直边缘
			edgeXImage.at<uchar>(i, j) = abs(tempImage.at<uchar>(i + 1, j) - tempImage.at<uchar>(i, j));
			//计算水平边缘
			edgeYImage.at<uchar>(i, j) = abs(tempImage.at<uchar>(i, j + 1) - tempImage.at<uchar>(i, j));
		}
	}
}

cv::Mat edgeXImage(image_reduced.size(),image_reduced.type());
cv::Mat edgeYImage(image_reduced.size(),image_reduced.type());
//计算差分图像
diffOperation(image_reduced, edgeXImage, edgeYImage);
cv::imshow("edgeXImage", edgeXImage);
cv::imshow("edgeYImage", edgeYImage);
cv::Mat edgeImage(image_reduced.size(),image_reduced.type());
//水平与垂直边缘图像叠加
cv::addWeighted(edgeXImage,0.5, edgeYImage,0.5,0.0, edgeImage);
cv::imshow("Together", edgeImage);

本质其实就是找到阈值变化在x方向和y方向上的突变点,也就是与相邻的点进行做差比较,将变化较大的点画出来。

0x05 非极大值抑制

图像梯度矩阵中的元素值越大,说明图像中该点的梯度值越大,但这并不能将其判断为该点处的边缘。(存在误差)非极大值一直操作可以剔除伪边缘信息,被广泛应用于图像边缘检测中。

原理:是通过像素邻域的局部最优值,将非极大值点所对应的灰度值设为背景像素点,如像素邻域区域满足梯度值局部最优值则判断为该像素的边缘,对其余非极大值的相关信息进行抑制,利用该准则可以剔除大部分非边缘点。

就比如说我们取中间点p0,梯度方向与其邻域交点为PM、PN,根据非极大值抑制原理,我们需要先确定P0像素值是否满足领域内最大,需要判断P0与邻域像素值和梯度方向PM与PN对应的值。所以我们要把当前位置的梯度值,在邻域内先比较一圈,如果是最大的,那么就开始下一步,我们比较P0与PM与PN的最大值,同时还得考虑梯度方向的变化。

总结来说:若满足P0像素值是邻域内的最大值且梯度值最大,可判断该点是边缘像素点,否则P0像素点不是局部最优值,可剔除伪边缘。(这样就可以确定到底是不是真的边界了)

0x06 基本边缘算子——Sobel

Sobel算子是应用广泛的离散微分算子之一,常用于图像处理中的边缘检测,计算图像灰度函数的近似梯度。利用图像像素点Sobel算子计算出相应的梯度向量及向量的范数,基于图像卷积来实现在水平方向与垂直方向检测对应方向上的边缘。对于源图像与奇数Sobel水平核Gx、垂直核Gy进行卷积可计算水平与垂直变换,当内核大小为3*3时,Gx与Gy为下式:

 对图像中每一点结合卷积后的结果求出近似梯度幅度G:

Sobel算子在进行边缘检测时效率较高,当对精度要求不是很高时,是一种较为常用的边缘检测方法。

缺点在于:

Sobel算子对沿x轴和y轴的排列表示得较好,但是对于其他角度得表示却不够精确,这时候我们可以使用Scharr滤波器。Scharr滤波器得水平和垂直核因子:

(一)实现非极大值抑制Sobel检测

实现步骤:非极大值抑制实现Sobel竖直细化边缘

  • 将图像转为32位浮点型数据,定义水平或垂直方向的Sobel算子。

  • 使用filter2D完成图像与算子的卷积操作,计算卷积结果的梯度幅值。

  • 自适应计算出梯度幅值阈值,阈值设置不梯度幅值的均乘以4,根据阈值对水平或垂直的领域区梯度进行比较。

  • 判断当前邻域梯度是否大于水平或垂直邻域梯度,自适应完成边缘检测出二值化图像的操作。

bool SobelVerEdge(cv::Mat srcImage, cv::Mat& resultImage)
{
    CV_Assert(srcImage.channels() == 1);
	srcImage.convertTo(srcImage, CV_32FC1);
	// 水平方向的 Sobel 算子
	cv::Mat sobelx = (cv::Mat_<float>(3,3) << -0.125, 0, 0.125,
		-0.25, 0, 0.25,
		-0.125, 0, 0.125); 
	cv::Mat ConResMat;
    // 卷积运算
	cv::filter2D(srcImage, ConResMat, srcImage.type(), sobelx);
	// 计算梯度的幅度
	cv::Mat graMagMat;
	cv::multiply(ConResMat, ConResMat, graMagMat);
	// 根据梯度幅度及参数设置阈值
    int scaleVal = 4;
	double thresh = scaleVal * cv::mean(graMagMat).val[0];
	cv::Mat resultTempMat = cv::Mat::zeros(
        graMagMat.size(), graMagMat.type());
	float* pDataMag = (float*)graMagMat.data;
	float* pDataRes = (float*)resultTempMat.data;
    const int nRows = ConResMat.rows;
    const int nCols = ConResMat.cols;
	for (int i = 1; i != nRows - 1; ++i) {
		for (int j = 1; j != nCols - 1; ++j) {
            // 计算该点梯度与水平或垂直梯度值大小比较结果
			bool b1 = (pDataMag[i * nCols + j] > pDataMag[i * 
              nCols + j - 1]);
			bool b2 = (pDataMag[i * nCols + j] > pDataMag[i * 
              nCols + j + 1]);
			bool b3 = (pDataMag[i * nCols + j] > pDataMag[(i - 1)
              * nCols + j]);
			bool b4 = (pDataMag[i * nCols + j] > pDataMag[(i + 1) 
             * nCols + j]);
            // 判断邻域梯度是否满足大于水平或垂直梯度
            // 并根据自适应阈值参数进行二值化
			pDataRes[i * nCols + j] = 255 * ((pDataMag[i * 
              nCols + j] > thresh) &&
				((b1 && b2) || (b3 && b4)));   
		}
	}
	resultTempMat.convertTo(resultTempMat, CV_8UC1);
    resultImage = resultTempMat.clone();
	return true;
}

(二)实现图像直接卷积实现Sobel:

原理:图像直接卷积Sobel边缘检测实现比较简单,首先定义水平或垂直方向的Sobel核因子,直接对源图像进行窗遍历,计算窗内的领域梯度幅值,然后根据梯度模场进行二值化操作,完成图像的水平或垂直方向的边缘检测。

//图像直接卷积
bool sobelEdge(const cv::Mat& scrImage, cv::Mat& resultImage, uchar threshold)
{
	CV_Assert(scrImage.channels() == 1);
	//初始化水平核因子
	cv::Mat sobelx = (cv::Mat_<double>(3, 3) << 1, 0, -1, 2, 0, -2, 1, 0, -1);
	//初始化垂直因子
	cv::Mat sobely = (cv::Mat_<double>(3, 3) << 1, 2, 1, 0, 0, 0, -1, -2, -1);
	resultImage = cv::Mat::zeros(scrImage.rows - 2, scrImage.cols - 2, scrImage.type());
	double edgeX = 0;
	double edgeY = 0;
	double graMag = 0;
	for (int k = 1; k < scrImage.rows - 1; ++k)
	{
		for (int n = 1; n < scrImage.cols - 1; ++n)
		{
			edgeX = 0;
			edgeY = 0;
			//遍历计算水平与垂直梯度
			for (int i = -1; i <= 1; ++i)
			{
				for (int j = -1; j <= 1; ++j)
				{
					edgeX += scrImage.at<uchar>(k + 1, n + j) * sobelx.at<double>(1 + i, 1 + j);
					edgeY += scrImage.at<uchar>(k + i, j + i) * sobely.at<double>(1 + i, 1 + j);
				}
			}
			//计算梯度模长
			graMag = sqrt(pow(edgeY, 2) + pow(edgeX, 2));
			//二值化
			resultImage.at<uchar>(k - 1, n - 1) = ((graMag > threshold) ? 255 : 0);
		}
	}
	return 0;
}

(三)实现图像卷积下非极大值抑制Sobel:

非极大值抑制虽然能够较好地剔除虚假边缘点,但对于某些特定场景下的边缘并不使用,例如污损文本字符识别。

bool sobelOptaEdge(const cv::Mat& srcImage, cv::Mat& resultImage, int flag)
{
    CV_Assert(srcImage.channels() == 1);
    // 初始化sobel水平核因子
    cv::Mat sobelX = (cv::Mat_<double>(3, 3) << 1, 0, -1,
        2, 0, -2,
        1, 0, -1);
    // 初始化sebel垂直核因子
    cv::Mat sobelY = (cv::Mat_<double>(3, 3) << 1, 2, 1,
        0, 0, 0,
        -1, -2, -1);
    // 计算水平与垂直卷积
    cv::Mat edgeX, edgeY;
    filter2D(srcImage, edgeX, CV_32F, sobelX);
    filter2D(srcImage, edgeY, CV_32F, sobelY);
    // 根据传入参数确定计算水平或垂直边缘
    int paraX = 0;
    int paraY = 0;
    switch (flag)
    {
    case 0: paraX = 1;
        paraY = 0;
        break;
    case 1:  paraX = 0;
        paraY = 1;
        break;
    case 2:  paraX = 1;
        paraY = 1;
        break;
    default: break;
    }
    edgeX = abs(edgeX);
    edgeY = abs(edgeY);
    cv::Mat graMagMat = paraX * edgeX.mul(edgeX) + paraY * edgeY.mul(edgeY);
    // 计算阈值 
    int scaleVal = 4;
    double thresh = scaleVal * cv::mean(graMagMat).val[0];
    resultImage = cv::Mat::zeros(srcImage.size(), srcImage.type());
    for (int i = 1; i < srcImage.rows - 1; i++)
    {
        float* pDataEdgeX = edgeX.ptr<float>(i);
        float* pDataEdgeY = edgeY.ptr<float>(i);
        float* pDataGraMag = graMagMat.ptr<float>(i);
        // 阈值化和极大值抑制
        for (int j = 1; j < srcImage.cols - 1; j++)
        {
            if (pDataGraMag[j] > thresh && (
                (pDataEdgeX[j] > paraX * pDataEdgeY[j] && pDataGraMag[j] >
                    pDataGraMag[j - 1] && pDataGraMag[j] > pDataGraMag[j + 1]) ||
                (pDataEdgeY[j] > paraY * pDataEdgeX[j] && pDataGraMag[j] >
                    pDataGraMag[j - 1] && pDataGraMag[j] > pDataGraMag[j + 1])))
                resultImage.at<uchar>(i, j) = 255;
        }
    }
    return true;
}

以上就是三种sobel算法。可以根据实际场景的需求来实现相应的sobel边缘功能。第二种方法的伪边缘比较多,所以得出非极大值抑制可以有效地解决这一问题的结论。

如何使用:

cv::Mat image(608, 608,CV_8UC3);
	image = cv::imread("./image/labixiaoxin.jpg", cv::IMREAD_GRAYSCALE); //
	//灰度图像
	cv::namedWindow("原图",cv::WINDOW_FREERATIO);
	cv::imshow("原图", image);
	cv::Mat resultImage;
	//非极大值抑制细化数值sobel检测
	SobelVerEdge(image, resultImage);
	cv::namedWindow("非极大值抑制", cv::WINDOW_FREERATIO);
	cv::imshow("非极大值抑制", resultImage);
	//图像直接卷积
	cv::Mat resultImage2;
	sobelEdge(image,resultImage2,100);
	cv::namedWindow("非极大值抑制", cv::WINDOW_FREERATIO);
	cv::imshow("图像直接卷积", resultImage2);
	//图像卷积下非极大值抑制
	cv::Mat resultImage3;
	sobelEdge(image, resultImage3,2);
	cv::imshow("图像卷积+非极大值", resultImage3);

效果:

 

 

 Opencv提供的Sobel函数:

void sobel(InputArray src,		//输入图像
			OutputArray dst,	//输出图像
			int ddepth,			//输出图像深度
			int dx,				//x方向的导数运算参数
			int dy,				//y方向的导数运算参数
			int ksize = 3,		//内核大小,设置为奇数
			double scale = 1,	//缩放导数的比例常数
			double delta = 0,	//可选的增量常数
			int borderType = BORDER_DEFAULT	//判断图像边界模式
			)

sobel核因子大小为3,内核因子计算会产生一定的误差,opencv也有提供更精确的内核因子以及Scharr函数,其计算的时间复杂度与sobel差不多。

0x07 基本边缘算子——Laplace

拉普拉斯算子是最简单的各向同性二阶微分算子,具有旋转不变性。根据函数微分特性,该像素点值的二阶微分为0的点为边缘点,也就是边界点(因为在这个时候的阈值跳变为最大值,二次求导为0),对于二维图像f(x,y),它的二阶导数定义为:

对于二维离散图像而言,图像的Laplace可表示为下式:

 根据离散的Laplace的表达式,可以得到其模板的表现形式:

这种算法常用于锐化处理,对于图像中灰度变化剧烈的区域,拉普拉斯算子能实现其边缘检测;拉普拉斯算子利用二次微分特性与峰值间的过零点来确定边缘的位置,对奇异点或边界的更为敏感。

那么针对原始图像f(x,y),瑞华操作可以通过拉普拉斯算子对源图像进行处理,进行微分运算操作后产生描述灰度突变的图像,再将拉普拉斯图像与原始图像叠加进而产生锐化图像。

 其中t为领域中心比较系数,拉普拉斯算子锐化操作通过比较领域的中心像素与他所在的领域内的其他像素的平均灰度来确定相应的变换方式。当t<=0时,中心像素的灰度被进一步降低;相反,当t>0,中心像素的灰度被进一步提高。

cv::Mat image(608, 608,CV_8UC3);
image = cv::imread("./image/cross.jpg", cv::IMREAD_GRAYSCALE); 
cv::namedWindow("原图",cv::WINDOW_FREERATIO);
cv::imshow("原图", image);
cv::Mat resultImage;
//高斯平滑
cv::GaussianBlur(image, image,cv::Size(3,3),0,0,cv::BORDER_DEFAULT);
//拉普拉斯变换
cv::Laplacian(image, resultImage,CV_16S,3);
cv::convertScaleAbs(resultImage, resultImage);
cv::imshow("after",resultImage);

0x08 基本边缘检测算子——Roberts

Roberts算子是利用局部差分寻找边缘的一种算子,是最简单的边缘检测算子。Roberts算子利用对角线方向相邻两像素之差近似梯度幅值来检测边缘,检测垂直边缘的效果要优于其他方向边缘,定位精度高,但对噪声的抑制能力比较若,边缘检测算子检查每个像素的领域并对灰度变化了进行量化,同时也包含方向的确定

对于原始图像f(x,y),Roberts边缘检测输出图像为g(x,y),图像的Roberts边缘检测可用下式来表示: 

 根据上面的公式,可以得到Roberts算子模板为:

 代码如下:

cv::Mat roberts(cv::Mat srcImage)
{
    cv::Mat dstImage = srcImage.clone();
    int nRows = dstImage.rows;
    int nCols = dstImage.cols;
    for(int i=0;i<nRows-1;i++)
    {
        for(int j=0;j<nCols-1;j++)
        {
            //根据公式计算
            int t1 = (srcImage.at<uchar>(i,j)-srcImage.at<uchar>(i+1,j+1)*(srcImage.at<uchar>(i,j)-srcImage.at<uchar>(i+1,j+1));
            int t2 = (srcImage.at<uchar>(i+1,j)-srcImage.at<uchar>(i,j+1)*(srcImage.at<uchar>(i+i,j)-srcImage.at<uchar>(i,j+1));
          	//计算对角线像素差
          	dstImage.at<uchar>(i,j)=(uchar)sqrt(t1+t2);
        }
    }
  	return dstImage;
}

0x09 基本边缘检测算子——Prewitt

Prewitt算子是一阶边缘检测微分算子,对噪声具有抑制作用。原理与sobel相似,都是在图像空间利用两个方向模板与图像进行领域卷积来完成,分别对水平与垂直方向边缘进行检测。这个算法,边缘定位精度不如Roberts算子,实现方法与sobel类似,但是实现的功能的差距很大。。所以,一带而过吧。

对于最后的输出边缘图像,可根据G=max(Gx,Gy)G=Gx+Gy得到,凡灰度新值大于或等于阈值的像素点就认为是边缘点,即选择适当的阈值T。若G>=T,则对应像素点为边缘点。

其实我觉得这个方法不大实际,给一个固定的阈值,往往都是容易出错的。。模板算子:

 

不写代码了,用不上。。


那就先介绍完这些基本的算子吧,其实我觉得对于像跑比赛等小型赛道,用上面的处理就应该可以了,对于复杂一些的图像,才需要用到我下一篇要总结的一些成熟的算子。那么就到这吧,希望以后写博客效率高一点!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenCV入门(四)——边缘检测 的相关文章

  • 如何解决 Python 'Pyzbar' 库的导入错误?

    我刚刚开始熟悉 Pyzbar 库 但是当使用decode方法我得到一个错误 这是代码 import cv2 import numpy as np import pyzbar code image cv2 imread C Users Ace
  • 使用 openCV 和 python 检测物体

    我正在尝试使用 OpenCV 和 Python 检测下图中的白点 我尝试使用函数 cv2 HoughCircles 但没有成功 我需要使用不同的方法吗 这是我的代码 import cv2 cv import numpy as np impo
  • 如何使用 OpenCV 检测图像帧中的对象?

    我正在使用 Raspberry Pi 开发一个漫游器 它将清扫房间并捡起掉落在地上的物体 为了检测物体 我使用了在流动站操作开始时拍摄的参考图像 以及每 10 秒单击一次的图像 新图像 为了确定图像帧是否发生变化 我在参考图像和新图像之间进
  • opencv中矩阵的超快中值(与matlab一样快)

    我正在 openCV 中编写一些代码 想要找到一个非常大的矩阵数组 单通道灰度 浮点数 的中值 我尝试了几种方法 例如对数组进行排序 使用 std sort 和选择中间条目 但与 matlab 中的中值函数相比 它非常慢 准确地说 在 ma
  • OpenCV:视频结束后如何重新启动?

    我正在播放视频文件 但播放完毕后如何再次播放 Javier 如果您想一遍又一遍地重新启动视频 也称为循环播放 可以通过在帧数达到时使用 if 语句来实现cap get cv2 cv CV CAP PROP FRAME COUNT 然后重置帧
  • Opencv未找到所有轮廓

    我试图找到该图像的轮廓 但是该方法查找轮廓只返回1轮廓 轮廓突出显示image 2 我正在努力寻找all外部轮廓就像这些圆圈 里面有数字 我究竟做错了什么 我可以做什么来实现它 image 1 image 2 以下是我的代码的相关部分 th
  • 来自 OpenCV 的外部参数

    我正在使用 OpenCV 来校准立体相机对 我拍摄了各种校准照片 并且使用 cv2 calibrateCamera 对内在参数进行了令人满意的拟合 然而 目前尚不清楚如何获取外部参数 该函数仅返回cameraMatrix 尽管它很有用 但实
  • Python:opencv warpPerspective 既不接受 2 个也不接受 3 个参数

    我发现单应矩阵如下特征匹配 单应性教程 https docs opencv org 3 4 1 d1 de0 tutorial py feature homography html using M mask cv2 findHomograp
  • 我可以使用 openCV 比较两张不同图像上的两张脸吗?

    我对 openCV 很陌生 我看到它可以计算出脸部并返回一个矩形来指示脸部 我想知道 openCV 是否可以访问两张包含一张脸的图像 并且我希望 openCV 返回这两个人是否相同的可能性 Thanks OpenCV 不提供完整的人脸识别引
  • 曲线/路径骨架二值图像处理

    我正在尝试开发一个可以处理图像骨架的路径 曲线的代码 我想要一个来自两点之间骨架的点向量 该代码在添加一些点后结束 我没有找到解决方案 include opencv2 highgui highgui hpp include opencv2
  • 多视图几何

    我从相距一定距离的两台相同品牌的相机捕获了两张图像 捕获了相同的场景 我想计算两个相机之间的现实世界旋转和平移 为了实现这一点 我首先提取了两张图像的 SIFT 特征并进行匹配 我现在有基本矩阵也单应性矩阵 然而无法进一步进行 有很多混乱
  • 无法在 Windows 7 机器中使用 OpenCV 2.4.3、Python 2.7 打开“.mp4”视频文件

    我目前正在进行一个涉及读取 mp4 视频文件的项目 我遇到的问题是它在Windows 7机器上使用Python 2 7 32位 OpenCV 2 4 3 cv2 pyd 代码片段如下 try video cv2 VideoCapture v
  • opencv形态扩张滤波器作为最大滤波器

    就像中值滤波器的定义一样 我可以将 最大滤波器 定义为局部窗口 例如dst x y max 3x3 局部窗口像素 但我在opencv中找不到这样的过滤器 最接近的是 dilate 函数 然后我使用 dilate 函数的默认配置 但结果不正确
  • 如何将输出视频保存到 OpenCV 中的文件中

    我想将输出视频保存到文件中而不是显示它并尝试使用 cvcaptureimage 但仍然无法获得结果 include
  • ffmpeg AVFrame 到 opencv Mat 转换

    我目前正在开发一个使用 ffmpeg 解码接收到的帧的项目 解码后 我想将 AVFrame 转换为 opencv Mat 帧 以便我可以在 imShow 函数上播放它 我拥有的是字节流 我将其读入缓冲区 解码为 AVFrame f fope
  • OpenCV 2.4.3 中的阴影去除

    我正在使用 OpenCV 2 4 3 最新版本 使用内置的视频流检测前景GMG http docs opencv org modules gpu doc video html highlight gmg gpu 3a 3aGMG GPU算法
  • 如何使用 Python 裁剪图像中的矩形

    谁能给我关于如何裁剪两个矩形框并保存它的建议 我已经尝试过这段代码 但效果不佳 import cv2 import numpy as np Run the code with the image name keep pressing spa
  • OpenCV 错误:connectedComponents_sub1 中断言失败 (L.channels() == 1 && I.channels() == 1) [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我在 OpenCV python 中遇到以下错误 并用 google 搜索了很多 但无法解决 如果有人能为我提供一些线索
  • cv2.drawContours() - 取消填充字符内的圆圈(Python,OpenCV)

    根据 Silencer的建议 我使用了他发布的代码here https stackoverflow com questions 48244328 copy shape to blank canvas opencv python 482465
  • 二值图像中骨架上两点之间的最短路径

    我有一个二进制图像 其中包含图像的一个像素宽度骨架 您可能基本上知道 在这个二值图像中 我在骨架上有 1 在其他地方有 0 如何找到骨架上两个非零元素之间的最短距离 路径也应该在骨架本身上 我想使用 A star 算法的 C 实现 我找到了

随机推荐

  • 慢速协议-Slow Protocol-LACP

    慢速协议有三种 xff0c 包括802 3ah OAM LACP协议和Marker协议 慢速协议的特点 xff1a 1 xff0c 每秒钟传输的报文不超过10帧 xff1b 2 xff0c 报文不携带vlan tag xff1b 3 xff
  • fork() && fork() || fork()

    include lt unistd h gt include lt stdio h gt int main fork fork amp amp fork fork fork sleep 100 return 0 问题是不算main这个进程自
  • list_entry()详解

    Linux内核中 xff0c 获取节点地址的函数list entry 非常常用 xff0c 由于其定义有点晦涩 xff0c 先解析如下 xff1a list entry的宏定义 xff1a define list entry ptr typ
  • Linux 内核 hlist 详解

    在Linux内核中 xff0c hlist xff08 哈希链表 xff09 使用非常广泛 本文将对其数据结构和核心函数进行分析 和hlist相关的数据结构有两个 xff1a hlist head 和 hlist node hash桶的头结
  • 判断手机号码合法性

    问题描述 xff1a 我国大陆运营商的手机号码标准格式为 xff1a 国家码 43 手机号码 xff0c 例如 xff1a 8613912345678 特点如下 xff1a 1 长度13位 xff1b 2 以86的国家码打头 xff1b 3
  • linux c捕获信号

    linux c捕获信号 在程序中为了实现优雅退出 xff0c 需要对信号进行处理 xff0c 本文主要记录一下两个方面 xff1a 如何捕获SIGINT SIGTERM SIGQUIT等信号 xff0c 并进行处理 如何知道是哪个进程给自己
  • go语言获取发送信号的进程pid

    背景 今天在发布一个程序之前 xff0c 给qa提测的时候 xff0c qa反馈程序运行10几分钟之后 xff0c 退出了 排查过程 在程序中加日志 xff0c 发现程序捕获到了一个SIGTERM信号 xff0c 然后做了一些退出前的清理工
  • ubuntu-E:Encountered a section with no Package: header的解决办法

    刚才打开ubuntu xff0c 我的版本是12 04 正想使用sudo apt get install build essential 时 xff0c 出现了如下错误 xff1a E Encountered a section with
  • scrcpy源码阅读及在Ubuntu上的实现(一)——了解原理

    那开篇就问问为什么需要研究这个源码吧 xff1a 在移动互联网的时代下 xff0c 手机的功能是日益增加的 xff0c 要使工作变得更加的高效 xff0c 那么键盘鼠标其实是必不可少的 在许多软件的架构中 xff0c 其实并没有提供对应的桌
  • 文件或目录损坏且无法读取的解决办法

    方法很简单 用 chkdsk 命令即可 详解如下 开始 运行 输入 cmd 输入 chkdsk 盘符 f 等命令运行完即可 这里要注意的是 那个冒号后面要空一格 别跟着就写 34 f 34
  • Linux技巧-如何查看系统信息-硬盘、分区信息以及磁盘用量

    使用 hdparm 获得硬盘的生产厂家 xff0c 类型等基本信息 xff0c 这里我们之提供简单的使用 xff0c 以后 hdparm i dev sda 通过 smartctl命令来获取硬盘的详细信息 xff1a smartctl a
  • 朋友答App技术服务支持

    朋友答App有任何使用问题 xff0c 欢迎留言交流
  • Matlab调用Cuda程序

    目录 一 环境配置 1 GPU 43 VisualStudio 43 Matlab版本适配性查看 2 Matlab环境配置 二 使用Matlab编译CUDA工程 1 建立CUDA工程并编写GPU代码 2 编写可供Matlab编译的CUDA代
  • python函数参数*args**kwargs用法实例

    http www jb51 net article 44104 htm python当函数的参数不确定时 xff0c 可以使用 args和 kwargs args没有key值 xff0c kwargs有key值 下面看例子 复制代码 代码如
  • 简易图解移轴镜头 (Tilt-Shift Lens) 原理 简易图解移轴镜头 (Tilt-Shift Lens) 原理

    http fotomen cn 2012 10 tilt shift lens 移轴镜 Tilt Shift Lens 是颇昂贵的玩意 xff0c 例如 Canon 的 TS E 24mm f 3 5L II xff0c 官方零售价是 HK
  • GTA5最新线上小助手

    https wwr lanzoui com ivR9Wsuixmb 密码 4ug1
  • DELL-R730服务器U盘安装操作系统指南

    一 系统安装注意事项 xff1a 1 DELL服务器安装系统 xff0c 根据实际情况先做raid5 xff0c 因为我们有3块硬盘 xff1b 2 安装系统前先把U盘做成启动盘 xff0c 然后下载相应的阵列卡驱动 xff0c 阵列卡驱动
  • VCS2018 linux 安装

    VCS linux 安装 自己去网上找2018版本的vcs 和verdi xff0c 就不贴出来了 xff0c 这里把安装过程中遇到的一些问题留作记录 声明 xff1a 只做学术研究 xff0c 不做商业用途 xff0c 公司使用推荐购买正
  • Ubuntu mate 20.04及无vnc的Ubuntu 系统开启vnc

    Ubuntu mate 20 04及无vnc的Ubuntu 系统开启vnc 目录 Ubuntu mate 20 04及无vnc的Ubuntu 系统开启vnc1 介绍2 步骤 1 介绍 2 步骤 1 介绍 我学习ros机器人的过程中 xff0
  • OpenCV入门(四)——边缘检测

    目录 0x01 梯度算子 0x02 一阶微分算子 0x03 二阶微分算子 0x04 图像差分运算 0x05 非极大值抑制 0x06 基本边缘算子 Sobel 0x07 基本边缘算子 Laplace 0x08 基本边缘检测算子 Roberts