opencv3/C++霍夫圆/直线/椭圆检测

版权声明:归所有菜鸟所有 https://blog.csdn.net/weixin_41752475/article/details/89295741

霍夫直线检测

参数说明:

cv::HoughLinesP(
InputArray src, // 输入图像(8位灰度图像)
OutputArray lines, // 输出直线两点坐标(vector<Vec4i>)
double rho, // 生成极坐标时候的像素扫描步长
double theta, //生成极坐标时候的角度步长(一般取CV_PI/180)
int threshold, // 累加器阈值,获得足够交点的极坐标点才被看成是直线
double minLineLength=0;// 直线最小长度
double maxLineGap=0;// 直线最大间隔
)

示例:

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
	Mat src, dst;
	src = imread("3.jpg");
	if (src.empty())
	{
		printf("can not load image \n");
		return -1;
	}
	cvNamedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src);

	dst = Mat::zeros(src.size(), src.type());
	cvtColor(src, dst, CV_RGB2GRAY);
	Canny(dst, dst, 0, 200);
	vector<Vec4i> plines;
	HoughLinesP(dst, plines, 1, CV_PI / 180, 80, 10, 10);
	for (size_t i = 0; i < plines.size(); i++)
	{
		Vec4i points = plines[i];
		line(src, Point(points[0], points[1]), Point(points[2], points[3]), Scalar(0, 255, 255), 3, CV_AA);
	}
	cvNamedWindow("output", CV_WINDOW_AUTOSIZE);
	imshow("output", src);

	waitKey();
	return 0;
}

霍夫圆检测

霍夫圆检测对噪声比较敏感,一般要先对图像做中值滤波。
参数说明:

cv::HoughCircles(
InputArray image, // 输入图像 ,必须是8位的单通道灰度图像
OutputArray circles, // 输出结果,即圆信息(圆心+半径)
Int method, // 采用方法:HOUGH_GRADIENT
Double dp, // dp = 1; 
Double mindist, // 10 最短距离-可以分辨是两个圆的,否则认为是同心圆:src_gray.rows/8
Double param1, // 用于Canny的边缘阀值上限,下限被置为上限的一半
Double param2, // 中心点累加器阈值
Int minradius, // 最小半径
Int maxradius//最大半径 
)

示例:

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
    Mat src, dst;
    src = imread("line.jpg");
    if(src.empty())
    {
        printf("can not load image \n");
        return -1;
    }
    cvNamedWindow("input", CV_WINDOW_AUTOSIZE);
    imshow("input", src);
    cvtColor(src,src,CV_RGB2GRAY);
    dst = src.clone();
    cvtColor(dst,dst,CV_GRAY2RGB);
    //中值滤波
    medianBlur(src,src,3);
    vector<Vec3f> circles;
    HoughCircles(src,circles,CV_HOUGH_GRADIENT,1,100,45,30,45,220);
    for(size_t i = 0; i < circles.size(); i++)
    {
        Vec3f c = circles[i];
        circle(dst, Point(c[0], c[1]), c[2], Scalar(0,255,255), 3, CV_AA);
    }
    cvNamedWindow("output", CV_WINDOW_AUTOSIZE);
    imshow("output", dst);
    waitKey();
    return 0;
}

在这里插入图片描述

在这里插入图片描述

Matlab霍夫椭圆检测

I = imread('C:\Users\sartreck\Desktop\text.jpg');  
[m,n,L] = size(I);       %m图像的高度,n图像的宽度,L通道数  
if L>1          
    I = rgb2gray(I);  
end  
BW1 = edge(I,'sobel');    %自动选择阈值用Sobel算子进行边缘检测(二值化)  
  
figure(1)  
subplot(211)  
imshow(BW1); title('边缘检测');  
se = strel('square',2);  
BW=imdilate(BW1,se);%图像A1被结构元素B膨胀  
  
hough_circle=zeros(m,n,3);  
[Limage, num] = bwlabel(BW,8);   %num 连通区域个数  
for N=1:num   
    %[rows,cols] = find(BW);  % 找出二值图中的所有非零元素,并将这些元素的线性索引值返回到[rows,cols] 即找出边缘  
      [rows,cols] = find(Limage==N);  % 找出二值图中的所有非零元素,并将这些元素的线性索引值返回到[rows,cols] 即找出边缘  
      pointL=length(rows);      %非零元素个数,椭圆的周长  
  
        max_distan=zeros(m,n);  
        distant=zeros(1,pointL);  
        for i=1:m    
            for j=1:n  
                for k=1:pointL  
                    distant(k)=sqrt((i-rows(k))^2+(j-cols(k))^2); %计算所有点到椭圆边界的点的距离  
                end  
            max_distan(i,j)=max(distant);  %(i,j)点到椭圆边界的最大距离  
            end  
        end  
        min_distan=min(min(max_distan));   %图像中所有的点到椭圆边界最大距离的最小值,这个最小值对应的坐标位置就是椭圆的中心。  
  
  
        [center_yy,center_xx] = find(min_distan==max_distan);  %检索出椭圆中心的位置,  
        center_y=(min(center_yy)+max(center_yy))/2;            %由于计算误差,椭圆中心可能是一簇点,所以选择中心点  
        center_x=(min(center_xx)+max(center_xx))/2;            %center_x,center_y为椭圆的中心  
        a=min_distan;                                          %a为椭圆的长轴  
%%  下面进行Hough变换 %%%%%%
        hough_space = zeros(round(a+1),180);     %Hough空间  
        for k=1:pointL  
            for w=1:180      %theta  
                G=w*pi/180; %角度转换为弧度  
                XX=((cols(k)-center_x)*cos(G)+(rows(k)-center_y)*sin(G))^2/(a^2);  
                YY=(-(cols(k)-center_x)*sin(G)+(rows(k)-center_y)*cos(G))^2;  
                B=round(sqrt(abs(YY/(1-XX)))+1);  
                if(B>0&&B<=a)   %  计算时,B的值可能很大,这里进行异常处理  
                     hough_space(B,w)=hough_space(B,w)+1;  
                end  
            end  
        end  
  
     %%  搜索超过阈值的聚集点  
        max_para = max(max(max(hough_space)));  % 找出累积最大值  
  
        [bb,ww] = find(hough_space>=max_para);  %找出累积最大值在hough_space位置坐标(坐标值就是b和theta)  
        if(max_para<=pointL*0.33*0.25)     % 如果累积最大值不足一定的阈值则判断不存在椭圆  
           disp('No ellipse');   
           return ;  
        end  
        b=max(bb);                   %  b为椭圆的短轴  
        W=min(ww);                          % %theta  
        theta=W*pi/180;  
  
  
      %% 标记椭圆  
         
      for k=1:pointL  
                XXX=((cols(k)-center_x)*cos(theta)+(rows(k)-center_y)*sin(theta))^2/(a^2);  
                YYY=(-(cols(k)-center_x)*sin(theta)+(rows(k)-center_y)*cos(theta))^2/(b^2);  
                if((XXX+YYY)<=1)   %实心椭圆  
                 %if((XXX+YYY)<=1.1&&(XXX+YYY)>=0.99)  % 椭圆轮廓  
                    hough_circle(rows(k),cols(k),1) = 255;  
                      
                end  
      end  
       
end  
   subplot(212)  
   imshow(hough_circle);title('Hough变换');

在这里插入图片描述
在这里插入图片描述

opencv椭圆检测

.hellipse.h

#pragma once
#include "opencv2/core/core.hpp"  
#include "opencv2/highgui/highgui.hpp"  
#include "opencv2/imgproc/imgproc.hpp"  
#include "opencv2/features2d/features2d.hpp"    //需要添加该头文件  
#include <iostream>  
#include <vector>


using namespace cv;
using namespace std;

class Ellipse
{
public:
	void Computer_axy(vector<Point> contour, Size imgsize);
	int hough_ellipse(vector<Point> contour);
	Mat draw_Eliipse(Mat);
private:
	double a;    //半长轴
	double b;    //短轴
	double theta;   //椭圆的旋转角度
	Point point_center;   //椭圆中心的坐标    
};

inline void Ellipse::Computer_axy(vector<Point> contour, Size imgsize)
{
	float Ly, Lx, LL;
	double maxVal;
	Mat distance(1, contour.size(), CV_32FC1);      //每一点到轮廓的所有距离
	Mat max_distance(imgsize, CV_32FC1, Scalar(0));  //每一点到轮廓的最大距离

	for (int i = 0; i < max_distance.rows; i++)
	{
		for (int j = 0; j < max_distance.cols; j++)
		{
			for (int n = 0; n < contour.size(); n++)
			{
				Ly = (i - contour.at(n).y)*(i - contour.at(n).y);
				Lx = (j - contour.at(n).x)*(j - contour.at(n).x);
				LL = sqrt(Ly + Lx);
				distance.at<float>(n) = LL;
			}
			minMaxLoc(distance, NULL, &maxVal, NULL, NULL);
			max_distance.at<float>(i, j) = maxVal;
		}
	}
	double minVal = 0; //最大值一定要赋初值,否则运行时会报错
	Point minLoc;
	minMaxLoc(max_distance, &minVal, NULL, &minLoc, NULL);
	a = minVal;
	point_center = minLoc;
}

inline int Ellipse::hough_ellipse(vector<Point> contour)
{
	double G, XX, YY;
	int B;
	Mat hough_space(floor(a + 1), 180, CV_8UC1, Scalar(0));  //高度:a,宽度180

	for (int k = 0; k < contour.size(); k++)
	{
		for (int w = 0; w < 180; w++)
		{
			G = w * CV_PI / 180; //角度转换为弧度
			XX = pow(((contour.at(k).y - point_center.y)*cos(G) + (contour.at(k).x - point_center.x)*sin(G)), 2) / (a*a);
			YY = pow((-(contour.at(k).y - point_center.y)*sin(G) + (contour.at(k).x - point_center.x)*cos(G)), 2);

			B = floor(sqrt(abs(YY / (1 - XX))) + 1);
			if (B > 0 && B <= a)
			{
				hough_space.at<uchar>(B, w) += 1;
			}
		}
	}
	double Circumference;
	double maxVal = 0; //最大值一定要赋初值,否则运行时会报错
	Point maxLoc;
	minMaxLoc(hough_space, NULL, &maxVal, NULL, &maxLoc);
	b = maxLoc.y;
	theta = maxLoc.x;
	Circumference = 2 * CV_PI*b + 4 * (a - b);

	return maxVal;
}

inline Mat Ellipse::draw_Eliipse(Mat src)
{
	cout << "长轴:" << a << endl;
	cout << "短轴:" << b << endl;
	cout << "椭圆中心:" << point_center << endl;
	cout << "theta:" << theta << endl;
	ellipse(src, point_center, Size(b, a), theta, 0, 360, Scalar(0, 255, 0), 3);
	return  src;
}

.cpp

#include "opencv2/core/core.hpp"  
#include "opencv2/highgui/highgui.hpp"  
#include "opencv2/imgproc/imgproc.hpp"  
#include "opencv2/features2d/features2d.hpp"    //需要添加该头文件  
#include <iostream>  
#include <vector>
#include "Math.h"
#include "ellipse.h"


using namespace cv;
using namespace std;

int main()
{

	Mat src = imread("text.jpg");
	if (!src.data)
	{
		cout << "Read image error" << endl;
		return -1;
	}

	Mat dst;
	cvtColor(src, dst, CV_RGB2GRAY);
	//GaussianBlur(dst, dst, Size(3, 3), 0, 0);       //高斯模糊(Gaussian Blur)
	Canny(dst, dst, 100, 200, 3);                  //Canny边缘检测
	namedWindow("Canny", CV_WINDOW_AUTOSIZE);
	imshow("Canny", dst);

	//提取轮廓************************************************
	vector<vector<Point>>  contours;
	vector<Vec4i> hierarchy;
	findContours(dst, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
	//Hough变换************************************************
	int accumulate;   // Hough空间最大累积量
	Ellipse myellipse;
	Mat result(src.size(), CV_8UC3, Scalar(0));

	for (int i = 0; i < contours.size(); i++)
	{
		myellipse.Computer_axy(contours[i], dst.size());
		accumulate = myellipse.hough_ellipse(contours[i]);
		if (accumulate >= contours[i].size()*0.25)    // 判断是否超过给定阈值,判断是否为椭圆
			result = myellipse.draw_Eliipse(src);
		else
		{
			cout << "This profile is not an ellipse" << endl;
			break;
		}
	}

	namedWindow("Hough_result", CV_WINDOW_AUTOSIZE);
	imshow("Hough_result", result);

	waitKey();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41752475/article/details/89295741